From 52d4475430a0bc2815cc3f2d4686edd9b522d9c0 Mon Sep 17 00:00:00 2001 From: Nicolas Chaulet Date: Tue, 18 Jan 2022 09:14:59 -0500 Subject: [PATCH 001/108] [Fleet] Do not display add agent for managed policy in integration details (#123160) --- .../package_policy_agents_cell.test.tsx | 17 +++++++++++++++-- .../components/package_policy_agents_cell.tsx | 9 +++++---- .../detail/policies/package_policies.tsx | 2 +- .../package_policy_actions_menu.test.tsx | 18 ++++++++++++++++++ .../components/package_policy_actions_menu.tsx | 2 +- 5 files changed, 40 insertions(+), 8 deletions(-) diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/policies/components/package_policy_agents_cell.test.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/policies/components/package_policy_agents_cell.test.tsx index 6cb9aab005e777..ce1de40f1d59c7 100644 --- a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/policies/components/package_policy_agents_cell.test.tsx +++ b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/policies/components/package_policy_agents_cell.test.tsx @@ -10,12 +10,13 @@ import React from 'react'; import { act } from '@testing-library/react'; import { createIntegrationsTestRendererMock } from '../../../../../../../../mock'; +import type { AgentPolicy } from '../../../../../../types'; import { PackagePolicyAgentsCell } from './package_policy_agents_cell'; function renderCell({ agentCount = 0, - agentPolicyId = '123', + agentPolicy = {} as AgentPolicy, onAddAgent = () => {}, hasHelpPopover = false, }) { @@ -24,7 +25,7 @@ function renderCell({ return renderer.render( @@ -39,6 +40,18 @@ describe('PackagePolicyAgentsCell', () => { }); }); + test('it should not display add agent if policy is managed', async () => { + const utils = renderCell({ + agentCount: 0, + agentPolicy: { + is_managed: true, + } as AgentPolicy, + }); + await act(async () => { + expect(utils.queryByText('Add agent')).not.toBeInTheDocument(); + }); + }); + test('it should display only count if count > 0', async () => { const utils = renderCell({ agentCount: 9999 }); await act(async () => { diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/policies/components/package_policy_agents_cell.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/policies/components/package_policy_agents_cell.tsx index 28490316f83eb5..9471079902a902 100644 --- a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/policies/components/package_policy_agents_cell.tsx +++ b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/policies/components/package_policy_agents_cell.tsx @@ -11,6 +11,7 @@ import { EuiButton } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; import { LinkedAgentCount, AddAgentHelpPopover } from '../../../../../../components'; +import type { AgentPolicy } from '../../../../../../types'; const AddAgentButton = ({ onAddAgent }: { onAddAgent: () => void }) => ( @@ -38,21 +39,21 @@ const AddAgentButtonWithPopover = ({ onAddAgent }: { onAddAgent: () => void }) = }; export const PackagePolicyAgentsCell = ({ - agentPolicyId, + agentPolicy, agentCount = 0, onAddAgent, hasHelpPopover = false, }: { - agentPolicyId: string; + agentPolicy: AgentPolicy; agentCount?: number; hasHelpPopover?: boolean; onAddAgent: () => void; }) => { - if (agentCount > 0) { + if (agentCount > 0 || agentPolicy.is_managed) { return ( ); diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/policies/package_policies.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/policies/package_policies.tsx index c4f06d4d7d5aba..0007679398b86a 100644 --- a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/policies/package_policies.tsx +++ b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/policies/package_policies.tsx @@ -298,7 +298,7 @@ export const PackagePoliciesPage = ({ name, version }: PackagePoliciesPanelProps render({ agentPolicy, packagePolicy }: InMemoryPackagePolicyAndAgentPolicy) { return ( setFlyoutOpenForPolicyId(agentPolicy.id)} hasHelpPopover={showAddAgentHelpForPackagePolicyId === packagePolicy.id} diff --git a/x-pack/plugins/fleet/public/components/package_policy_actions_menu.test.tsx b/x-pack/plugins/fleet/public/components/package_policy_actions_menu.test.tsx index 63a3a93b7e8943..220e5ddb8f547b 100644 --- a/x-pack/plugins/fleet/public/components/package_policy_actions_menu.test.tsx +++ b/x-pack/plugins/fleet/public/components/package_policy_actions_menu.test.tsx @@ -119,3 +119,21 @@ test('Should be able to delete integration from a non-managed policy', async () expect(utils.queryByText('Delete integration')).not.toBeNull(); }); }); + +test('Should show add button if the policy is not managed and showAddAgent=true', async () => { + const agentPolicy = createMockAgentPolicy(); + const packagePolicy = createMockPackagePolicy({ hasUpgrade: true }); + const { utils } = renderMenu({ agentPolicy, packagePolicy, showAddAgent: true }); + await act(async () => { + expect(utils.queryByText('Add agent')).not.toBeNull(); + }); +}); + +test('Should not show add button if the policy is managed and showAddAgent=true', async () => { + const agentPolicy = createMockAgentPolicy({ is_managed: true }); + const packagePolicy = createMockPackagePolicy({ hasUpgrade: true }); + const { utils } = renderMenu({ agentPolicy, packagePolicy, showAddAgent: true }); + await act(async () => { + expect(utils.queryByText('Add agent')).toBeNull(); + }); +}); diff --git a/x-pack/plugins/fleet/public/components/package_policy_actions_menu.tsx b/x-pack/plugins/fleet/public/components/package_policy_actions_menu.tsx index 516f3d4dc55c18..6d090c886c467a 100644 --- a/x-pack/plugins/fleet/public/components/package_policy_actions_menu.tsx +++ b/x-pack/plugins/fleet/public/components/package_policy_actions_menu.tsx @@ -57,7 +57,7 @@ export const PackagePolicyActionsMenu: React.FunctionComponent<{ // defaultMessage="View integration" // /> // , - ...(showAddAgent + ...(showAddAgent && !agentPolicy.is_managed ? [ Date: Tue, 18 Jan 2022 09:18:00 -0500 Subject: [PATCH 002/108] [Event Log] Fixing call to update index alias to hidden (#122882) * Adding await * Changing the way alias updates are made * Updating unit tests Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../server/es/cluster_client_adapter.test.ts | 43 +++----- .../server/es/cluster_client_adapter.ts | 13 +-- .../plugins/event_log/server/es/init.test.ts | 100 +++++++++++++++--- x-pack/plugins/event_log/server/es/init.ts | 48 ++++++--- 4 files changed, 142 insertions(+), 62 deletions(-) diff --git a/x-pack/plugins/event_log/server/es/cluster_client_adapter.test.ts b/x-pack/plugins/event_log/server/es/cluster_client_adapter.test.ts index 314a6b9a31ef89..0d4f4136b42edd 100644 --- a/x-pack/plugins/event_log/server/es/cluster_client_adapter.test.ts +++ b/x-pack/plugins/event_log/server/es/cluster_client_adapter.test.ts @@ -454,13 +454,9 @@ describe('getExistingIndexAliases', () => { describe('setIndexAliasToHidden', () => { test('should call cluster with given index name and aliases', async () => { - await clusterClientAdapter.setIndexAliasToHidden('foo-bar-000001', { - aliases: { - 'foo-bar': { - is_write_index: true, - }, - }, - }); + await clusterClientAdapter.setIndexAliasToHidden('foo-bar', [ + { alias: 'foo-bar', indexName: 'foo-bar-000001', is_write_index: true }, + ]); expect(clusterClient.indices.updateAliases).toHaveBeenCalledWith({ body: { actions: [ @@ -477,18 +473,11 @@ describe('setIndexAliasToHidden', () => { }); }); - test('should update multiple aliases at once and preserve existing alias settings', async () => { - await clusterClientAdapter.setIndexAliasToHidden('foo-bar-000001', { - aliases: { - 'foo-bar': { - is_write_index: true, - }, - 'foo-b': { - index_routing: 'index', - routing: 'route', - }, - }, - }); + test('should update multiple indices for an alias at once and preserve existing alias settings', async () => { + await clusterClientAdapter.setIndexAliasToHidden('foo-bar', [ + { alias: 'foo-bar', indexName: 'foo-bar-000001', is_write_index: true }, + { alias: 'foo-bar', indexName: 'foo-bar-000002', index_routing: 'index', routing: 'route' }, + ]); expect(clusterClient.indices.updateAliases).toHaveBeenCalledWith({ body: { actions: [ @@ -502,8 +491,8 @@ describe('setIndexAliasToHidden', () => { }, { add: { - index: 'foo-bar-000001', - alias: 'foo-b', + index: 'foo-bar-000002', + alias: 'foo-bar', is_hidden: true, index_routing: 'index', routing: 'route', @@ -517,15 +506,11 @@ describe('setIndexAliasToHidden', () => { test('should throw error when call cluster throws an error', async () => { clusterClient.indices.updateAliases.mockRejectedValue(new Error('Fail')); await expect( - clusterClientAdapter.setIndexAliasToHidden('foo-bar-000001', { - aliases: { - 'foo-bar': { - is_write_index: true, - }, - }, - }) + clusterClientAdapter.setIndexAliasToHidden('foo-bar', [ + { alias: 'foo-bar', indexName: 'foo-bar-000001', is_write_index: true }, + ]) ).rejects.toThrowErrorMatchingInlineSnapshot( - `"error setting existing index aliases for index foo-bar-000001 to is_hidden: Fail"` + `"error setting existing index aliases for alias foo-bar to is_hidden: Fail"` ); }); }); diff --git a/x-pack/plugins/event_log/server/es/cluster_client_adapter.ts b/x-pack/plugins/event_log/server/es/cluster_client_adapter.ts index 205a8d10243fde..dd740aa5533b91 100644 --- a/x-pack/plugins/event_log/server/es/cluster_client_adapter.ts +++ b/x-pack/plugins/event_log/server/es/cluster_client_adapter.ts @@ -15,6 +15,7 @@ import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { fromKueryExpression, toElasticsearchQuery } from '@kbn/es-query'; import { IEvent, IValidatedEvent, SAVED_OBJECT_REL_PRIMARY } from '../types'; import { FindOptionsType } from '../event_log_client'; +import { ParsedIndexAlias } from './init'; export const EVENT_BUFFER_TIME = 1000; // milliseconds export const EVENT_BUFFER_LENGTH = 100; @@ -281,15 +282,15 @@ export class ClusterClientAdapter { try { const esClient = await this.elasticsearchClientPromise; await esClient.indices.updateAliases({ body: { - actions: Object.keys(currentAliases.aliases).map((aliasName) => { - const existingAliasOptions = pick(currentAliases.aliases[aliasName], [ + actions: currentAliasData.map((aliasData) => { + const existingAliasOptions = pick(aliasData, [ 'is_write_index', 'filter', 'index_routing', @@ -299,7 +300,7 @@ export class ClusterClientAdapter { let esContext = contextMock.create(); @@ -267,11 +267,10 @@ describe('initializeEs', () => { }); await initializeEs(esContext); - expect(esContext.esAdapter.getExistingIndexAliases).toHaveBeenCalled(); - expect(esContext.esAdapter.setIndexAliasToHidden).toHaveBeenCalledWith( - 'foo-bar-000001', - testAliases - ); + expect(esContext.esAdapter.getExistingIndexAliases).toHaveBeenCalledTimes(1); + expect(esContext.esAdapter.setIndexAliasToHidden).toHaveBeenCalledWith('foo-bar', [ + { alias: 'foo-bar', indexName: 'foo-bar-000001', is_write_index: true }, + ]); }); test(`should not update existing index aliases if any exist and are already hidden`, async () => { @@ -310,6 +309,9 @@ describe('initializeEs', () => { 'foo-bar': { is_write_index: true, }, + 'bar-foo': { + is_write_index: true, + }, }, }; esContext.esAdapter.getExistingIndexAliases.mockResolvedValue({ @@ -321,17 +323,18 @@ describe('initializeEs', () => { await initializeEs(esContext); expect(esContext.esAdapter.getExistingIndexAliases).toHaveBeenCalled(); - expect(esContext.esAdapter.setIndexAliasToHidden).toHaveBeenCalledWith( - 'foo-bar-000001', - testAliases - ); - expect(esContext.esAdapter.setIndexAliasToHidden).toHaveBeenCalledWith( - 'foo-bar-000002', - testAliases - ); + expect(esContext.esAdapter.setIndexAliasToHidden).toHaveBeenCalledTimes(2); + expect(esContext.esAdapter.setIndexAliasToHidden).toHaveBeenCalledWith('foo-bar', [ + { alias: 'foo-bar', indexName: 'foo-bar-000001', is_write_index: true }, + { alias: 'foo-bar', indexName: 'foo-bar-000002', is_write_index: true }, + ]); + expect(esContext.esAdapter.setIndexAliasToHidden).toHaveBeenCalledWith('bar-foo', [ + { alias: 'bar-foo', indexName: 'foo-bar-000001', is_write_index: true }, + { alias: 'bar-foo', indexName: 'foo-bar-000002', is_write_index: true }, + ]); expect(esContext.logger.error).toHaveBeenCalledTimes(1); expect(esContext.logger.error).toHaveBeenCalledWith( - `error setting existing \"foo-bar-000001\" index aliases - Fail` + `error setting existing \"foo-bar\" index aliases - Fail` ); expect(esContext.esAdapter.doesIlmPolicyExist).toHaveBeenCalled(); }); @@ -384,3 +387,70 @@ describe('initializeEs', () => { expect(esContext.esAdapter.createIndex).not.toHaveBeenCalled(); }); }); + +describe('parseIndexAliases', () => { + test('should parse IndicesGetAliasResponse into desired format', () => { + const indexGetAliasResponse = { + '.kibana-event-log-7.15.2-000003': { + aliases: { + '.kibana-event-log-7.15.2': { + is_write_index: true, + }, + another_alias: { + is_write_index: true, + }, + }, + }, + '.kibana-event-log-7.15.2-000002': { + aliases: { + '.kibana-event-log-7.15.2': { + is_write_index: false, + }, + }, + }, + '.kibana-event-log-7.15.2-000001': { + aliases: { + '.kibana-event-log-7.15.2': { + is_write_index: false, + }, + }, + }, + '.kibana-event-log-8.0.0-000001': { + aliases: { + '.kibana-event-log-8.0.0': { + is_write_index: true, + is_hidden: true, + }, + }, + }, + }; + expect(parseIndexAliases(indexGetAliasResponse)).toEqual([ + { + alias: '.kibana-event-log-7.15.2', + indexName: '.kibana-event-log-7.15.2-000003', + is_write_index: true, + }, + { + alias: 'another_alias', + indexName: '.kibana-event-log-7.15.2-000003', + is_write_index: true, + }, + { + alias: '.kibana-event-log-7.15.2', + indexName: '.kibana-event-log-7.15.2-000002', + is_write_index: false, + }, + { + alias: '.kibana-event-log-7.15.2', + indexName: '.kibana-event-log-7.15.2-000001', + is_write_index: false, + }, + { + alias: '.kibana-event-log-8.0.0', + indexName: '.kibana-event-log-8.0.0-000001', + is_hidden: true, + is_write_index: true, + }, + ]); + }); +}); diff --git a/x-pack/plugins/event_log/server/es/init.ts b/x-pack/plugins/event_log/server/es/init.ts index f9aa148ff024d9..4440102fcd3813 100644 --- a/x-pack/plugins/event_log/server/es/init.ts +++ b/x-pack/plugins/event_log/server/es/init.ts @@ -7,6 +7,7 @@ import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { asyncForEach } from '@kbn/std'; +import { groupBy } from 'lodash'; import { getIlmPolicy, getIndexTemplate } from './documents'; import { EsContext } from './context'; @@ -33,6 +34,22 @@ async function initializeEsResources(esContext: EsContext) { await steps.createInitialIndexIfNotExists(); } +export interface ParsedIndexAlias extends estypes.IndicesAliasDefinition { + indexName: string; + alias: string; + is_hidden?: boolean; +} + +export function parseIndexAliases(aliasInfo: estypes.IndicesGetAliasResponse): ParsedIndexAlias[] { + return Object.keys(aliasInfo).flatMap((indexName: string) => + Object.keys(aliasInfo[indexName].aliases).map((alias: string) => ({ + ...aliasInfo[indexName].aliases[alias], + indexName, + alias, + })) + ); +} + class EsInitializationSteps { constructor(private readonly esContext: EsContext) { this.esContext = esContext; @@ -56,7 +73,7 @@ class EsInitializationSteps { this.esContext.logger.error(`error getting existing index templates - ${err.message}`); } - asyncForEach(Object.keys(indexTemplates), async (indexTemplateName: string) => { + await asyncForEach(Object.keys(indexTemplates), async (indexTemplateName: string) => { try { const hidden: string | boolean = indexTemplates[indexTemplateName]?.settings?.index?.hidden; // Check to see if this index template is hidden @@ -93,7 +110,7 @@ class EsInitializationSteps { // should not block the rest of initialization, log the error and move on this.esContext.logger.error(`error getting existing indices - ${err.message}`); } - asyncForEach(Object.keys(indices), async (indexName: string) => { + await asyncForEach(Object.keys(indices), async (indexName: string) => { try { const hidden: string | boolean | undefined = indices[indexName]?.settings?.index?.hidden; @@ -125,22 +142,29 @@ class EsInitializationSteps { // should not block the rest of initialization, log the error and move on this.esContext.logger.error(`error getting existing index aliases - ${err.message}`); } - asyncForEach(Object.keys(indexAliases), async (indexName: string) => { + + // Flatten the results so we can group by index alias + const parsedAliasData = parseIndexAliases(indexAliases); + + // Group by index alias name + const indexAliasData = groupBy(parsedAliasData, 'alias'); + + await asyncForEach(Object.keys(indexAliasData), async (aliasName: string) => { try { - const aliases = indexAliases[indexName]?.aliases; - const hasNotHiddenAliases: boolean = Object.keys(aliases).some((alias: string) => { - return (aliases[alias] as estypes.IndicesAlias)?.is_hidden !== true; - }); - - if (hasNotHiddenAliases) { - this.esContext.logger.debug(`setting existing "${indexName}" index aliases to hidden.`); - await this.esContext.esAdapter.setIndexAliasToHidden(indexName, indexAliases[indexName]); + const aliasData = indexAliasData[aliasName]; + const isNotHidden = aliasData.some((data) => data.is_hidden !== true); + if (isNotHidden) { + this.esContext.logger.debug(`setting existing "${aliasName}" index alias to hidden.`); + await this.esContext.esAdapter.setIndexAliasToHidden( + aliasName, + indexAliasData[aliasName] + ); } } catch (err) { // errors when trying to set existing index aliases to is_hidden // should not block the rest of initialization, log the error and move on this.esContext.logger.error( - `error setting existing "${indexName}" index aliases - ${err.message}` + `error setting existing "${aliasName}" index aliases - ${err.message}` ); } }); From 5ad36d2a93f903fb1f09e90dd1a54877731e62a2 Mon Sep 17 00:00:00 2001 From: Shahzad Date: Tue, 18 Jan 2022 15:52:49 +0100 Subject: [PATCH 003/108] [Exploratory view] Update index pattern permission error (#122680) --- src/plugins/data_views/common/index.ts | 6 ++- x-pack/plugins/apm/ftr_e2e/cypress_start.ts | 4 +- .../create_apm_users_and_roles.ts | 4 +- .../create_apm_users_and_roles_cli.ts | 4 +- x-pack/plugins/observability/kibana.json | 2 +- .../hooks/use_app_index_pattern.tsx | 6 ++- .../series_editor/report_metric_options.tsx | 3 +- .../e2e/journeys/data_view_permissions.ts | 52 +++++++++++++++++++ x-pack/plugins/uptime/e2e/journeys/index.ts | 1 + x-pack/plugins/uptime/e2e/journeys/utils.ts | 13 +++-- x-pack/plugins/uptime/e2e/playwright_start.ts | 6 +++ x-pack/plugins/uptime/e2e/tsconfig.json | 7 ++- .../common/header/action_menu_content.tsx | 1 + 13 files changed, 96 insertions(+), 13 deletions(-) create mode 100644 x-pack/plugins/uptime/e2e/journeys/data_view_permissions.ts diff --git a/src/plugins/data_views/common/index.ts b/src/plugins/data_views/common/index.ts index 25d2ddd874256c..7253091e8115b6 100644 --- a/src/plugins/data_views/common/index.ts +++ b/src/plugins/data_views/common/index.ts @@ -59,7 +59,11 @@ export type { IndexPatternsContract, DataViewsContract } from './data_views'; export { IndexPatternsService, DataViewsService } from './data_views'; export type { IndexPatternListItem, DataViewListItem, TimeBasedDataView } from './data_views'; export { IndexPattern, DataView } from './data_views'; -export { DuplicateDataViewError, DataViewSavedObjectConflictError } from './errors'; +export { + DuplicateDataViewError, + DataViewSavedObjectConflictError, + DataViewInsufficientAccessError, +} from './errors'; export type { IndexPatternExpressionType, IndexPatternLoadStartDependencies, diff --git a/x-pack/plugins/apm/ftr_e2e/cypress_start.ts b/x-pack/plugins/apm/ftr_e2e/cypress_start.ts index 3abc627f9e2f0f..d65e428456b9d2 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress_start.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress_start.ts @@ -11,7 +11,7 @@ import { argv } from 'yargs'; import Url from 'url'; import cypress from 'cypress'; import { FtrProviderContext } from './ftr_provider_context'; -import { createApmUsersAndRoles } from '../scripts/create_apm_users_and_roles/create_apm_users_and_roles'; +import { createApmAndObsUsersAndRoles } from '../scripts/create_apm_users_and_roles/create_apm_users_and_roles'; import { esArchiverLoad, esArchiverUnload } from './cypress/tasks/es_archiver'; export async function cypressStart( @@ -27,7 +27,7 @@ export async function cypressStart( }); // Creates APM users - await createApmUsersAndRoles({ + await createApmAndObsUsersAndRoles({ elasticsearch: { username: config.get('servers.elasticsearch.username'), password: config.get('servers.elasticsearch.password'), diff --git a/x-pack/plugins/apm/scripts/create_apm_users_and_roles/create_apm_users_and_roles.ts b/x-pack/plugins/apm/scripts/create_apm_users_and_roles/create_apm_users_and_roles.ts index 708a8b62287be8..95d67301db2cea 100644 --- a/x-pack/plugins/apm/scripts/create_apm_users_and_roles/create_apm_users_and_roles.ts +++ b/x-pack/plugins/apm/scripts/create_apm_users_and_roles/create_apm_users_and_roles.ts @@ -21,7 +21,7 @@ export interface Kibana { hostname: string; } -export async function createApmUsersAndRoles({ +export async function createApmAndObsUsersAndRoles({ kibana, elasticsearch, }: { @@ -62,6 +62,8 @@ export async function createApmUsersAndRoles({ const users = [ { username: 'apm_read_user', roles: [KIBANA_READ_ROLE] }, { username: 'apm_power_user', roles: [KIBANA_POWER_ROLE] }, + { username: 'obs_read_user', roles: [KIBANA_READ_ROLE] }, + { username: 'obs_admin_user', roles: [KIBANA_POWER_ROLE] }, ]; // create users diff --git a/x-pack/plugins/apm/scripts/create_apm_users_and_roles/create_apm_users_and_roles_cli.ts b/x-pack/plugins/apm/scripts/create_apm_users_and_roles/create_apm_users_and_roles_cli.ts index 2b42fb3aeb6251..e8884cca3d7b04 100644 --- a/x-pack/plugins/apm/scripts/create_apm_users_and_roles/create_apm_users_and_roles_cli.ts +++ b/x-pack/plugins/apm/scripts/create_apm_users_and_roles/create_apm_users_and_roles_cli.ts @@ -9,7 +9,7 @@ import { argv } from 'yargs'; import { AbortError, isAxiosError } from './helpers/call_kibana'; -import { createApmUsersAndRoles } from './create_apm_users_and_roles'; +import { createApmAndObsUsersAndRoles } from './create_apm_users_and_roles'; import { getKibanaVersion } from './helpers/get_version'; async function init() { @@ -57,7 +57,7 @@ async function init() { const version = await getKibanaVersion({ elasticsearch, kibana }); console.log(`Connected to Kibana ${version}`); - const users = await createApmUsersAndRoles({ elasticsearch, kibana }); + const users = await createApmAndObsUsersAndRoles({ elasticsearch, kibana }); const credentials = users .map((u) => ` - ${u.username} / ${esPassword}`) .join('\n'); diff --git a/x-pack/plugins/observability/kibana.json b/x-pack/plugins/observability/kibana.json index 343e16f4a4095b..8074462fd90aa4 100644 --- a/x-pack/plugins/observability/kibana.json +++ b/x-pack/plugins/observability/kibana.json @@ -31,5 +31,5 @@ ], "ui": true, "server": true, - "requiredBundles": ["data", "kibanaReact", "kibanaUtils"] + "requiredBundles": ["data", "dataViews", "kibanaReact", "kibanaUtils"] } diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_app_index_pattern.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_app_index_pattern.tsx index c957d239ea278b..d9c1c28a6a727a 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_app_index_pattern.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_app_index_pattern.tsx @@ -14,6 +14,7 @@ import { ObservabilityPublicPluginsStart } from '../../../../plugin'; import { ObservabilityIndexPatterns } from '../utils/observability_index_patterns'; import { getDataHandler } from '../../../../data_handler'; import { useExploratoryView } from '../contexts/exploratory_view_config'; +import { DataViewInsufficientAccessError } from '../../../../../../../../src/plugins/data_views/common'; export interface IndexPatternContext { loading: boolean; @@ -89,7 +90,10 @@ export function IndexPatternContextProvider({ children }: ProviderProps) { } setLoading((prevState) => ({ ...prevState, [dataType]: false })); } catch (e) { - if ((e as HttpFetchError).body.error === 'Forbidden') { + if ( + e instanceof DataViewInsufficientAccessError || + (e as HttpFetchError).body === 'Forbidden' + ) { setIndexPatternErrors((prevState) => ({ ...prevState, [dataType]: e })); } setLoading((prevState) => ({ ...prevState, [dataType]: false })); diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/report_metric_options.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/report_metric_options.tsx index 5eec147379d25b..0aec19dc572b7d 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/report_metric_options.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/report_metric_options.tsx @@ -89,7 +89,8 @@ export function ReportMetricOptions({ seriesId, series, seriesConfig }: Props) { // TODO: Add a link to docs to explain how to add index patterns return ( - {indexPatternError.body.error === 'Forbidden' + {indexPatternError.body?.error === 'Forbidden' || + indexPatternError.name === 'DataViewInsufficientAccessError' ? NO_PERMISSIONS : indexPatternError.body.message} diff --git a/x-pack/plugins/uptime/e2e/journeys/data_view_permissions.ts b/x-pack/plugins/uptime/e2e/journeys/data_view_permissions.ts new file mode 100644 index 00000000000000..cf50e0d6b58ae4 --- /dev/null +++ b/x-pack/plugins/uptime/e2e/journeys/data_view_permissions.ts @@ -0,0 +1,52 @@ +/* + * 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 { journey, step, expect, before } from '@elastic/synthetics'; +import { loginToKibana, waitForLoadingToFinish } from './utils'; +import { byTestId } from './uptime.journey'; +import { callKibana } from '../../../apm/scripts/create_apm_users_and_roles/helpers/call_kibana'; + +journey('DataViewPermissions', async ({ page, params }) => { + before(async () => { + await waitForLoadingToFinish({ page }); + try { + await callKibana({ + elasticsearch: { username: 'elastic', password: 'changeme' }, + kibana: { hostname: params.kibanaUrl, roleSuffix: '' }, + options: { + method: 'DELETE', + url: '/api/saved_objects/index-pattern/synthetics_static_index_pattern_id_heartbeat_?force=false', + }, + }); + // eslint-disable-next-line no-empty + } catch (e) {} + }); + + const queryParams = new URLSearchParams({ + dateRangeStart: '2021-11-21T22:06:06.502Z', + dateRangeEnd: '2021-11-21T22:10:08.203Z', + }).toString(); + + const baseUrl = `${params.kibanaUrl}/app/uptime`; + + step('Go to uptime', async () => { + await page.goto(`${baseUrl}?${queryParams}`, { + waitUntil: 'networkidle', + }); + await loginToKibana({ page, user: { username: 'obs_read_user', password: 'changeme' } }); + }); + + step('Click explore data button', async () => { + await page.click(byTestId('uptimeExploreDataButton')); + await waitForLoadingToFinish({ page }); + await page.waitForSelector(`text=${permissionError}`); + expect(await page.$(`text=${permissionError}`)).toBeTruthy(); + }); +}); + +const permissionError = + "Unable to create Data View. You don't have the required permission, please contact your admin."; diff --git a/x-pack/plugins/uptime/e2e/journeys/index.ts b/x-pack/plugins/uptime/e2e/journeys/index.ts index 6bdea1beb016b9..e090a2dcd9c3bb 100644 --- a/x-pack/plugins/uptime/e2e/journeys/index.ts +++ b/x-pack/plugins/uptime/e2e/journeys/index.ts @@ -5,6 +5,7 @@ * 2.0. */ +export * from './data_view_permissions'; export * from './uptime.journey'; export * from './step_duration.journey'; export * from './alerts'; diff --git a/x-pack/plugins/uptime/e2e/journeys/utils.ts b/x-pack/plugins/uptime/e2e/journeys/utils.ts index 6d2f1dd5541086..a1bc7eea29ffed 100644 --- a/x-pack/plugins/uptime/e2e/journeys/utils.ts +++ b/x-pack/plugins/uptime/e2e/journeys/utils.ts @@ -14,11 +14,18 @@ export async function waitForLoadingToFinish({ page }: { page: Page }) { } } -export async function loginToKibana({ page }: { page: Page }) { - await page.fill('[data-test-subj=loginUsername]', 'elastic', { +export async function loginToKibana({ + page, + user, +}: { + page: Page; + user?: { username: string; password: string }; +}) { + await page.fill('[data-test-subj=loginUsername]', user?.username ?? 'elastic', { timeout: 60 * 1000, }); - await page.fill('[data-test-subj=loginPassword]', 'changeme'); + + await page.fill('[data-test-subj=loginPassword]', user?.password ?? 'changeme'); await page.click('[data-test-subj=loginSubmit]'); diff --git a/x-pack/plugins/uptime/e2e/playwright_start.ts b/x-pack/plugins/uptime/e2e/playwright_start.ts index 0581692e0e278f..8d208ed6873c6c 100644 --- a/x-pack/plugins/uptime/e2e/playwright_start.ts +++ b/x-pack/plugins/uptime/e2e/playwright_start.ts @@ -12,6 +12,7 @@ import { run as playwrightRun } from '@elastic/synthetics'; import { esArchiverLoad, esArchiverUnload } from './tasks/es_archiver'; import './journeys'; +import { createApmAndObsUsersAndRoles } from '../../apm/scripts/create_apm_users_and_roles/create_apm_users_and_roles'; const listOfJourneys = [ 'uptime', @@ -49,6 +50,11 @@ async function playwrightStart(getService: any, headless = true, match?: string) port: config.get('servers.kibana.port'), }); + await createApmAndObsUsersAndRoles({ + elasticsearch: { username: 'elastic', password: 'changeme' }, + kibana: { roleSuffix: 'e2e', hostname: kibanaUrl }, + }); + const res = await playwrightRun({ params: { kibanaUrl }, playwrightOptions: { headless, chromiumSandbox: false, timeout: 60 * 1000 }, diff --git a/x-pack/plugins/uptime/e2e/tsconfig.json b/x-pack/plugins/uptime/e2e/tsconfig.json index a9ec63a92fef80..7d5fdc316e8ee5 100644 --- a/x-pack/plugins/uptime/e2e/tsconfig.json +++ b/x-pack/plugins/uptime/e2e/tsconfig.json @@ -5,5 +5,10 @@ "compilerOptions": { "outDir": "target/types", "types": [ "node"], - } + }, + "references": [ + { + "path": "../../apm/tsconfig.json", + }, + ] } diff --git a/x-pack/plugins/uptime/public/components/common/header/action_menu_content.tsx b/x-pack/plugins/uptime/public/components/common/header/action_menu_content.tsx index b0fe387613f40e..501c74d1162695 100644 --- a/x-pack/plugins/uptime/public/components/common/header/action_menu_content.tsx +++ b/x-pack/plugins/uptime/public/components/common/header/action_menu_content.tsx @@ -115,6 +115,7 @@ export function ActionMenuContent({ config }: { config: UptimeConfig }): React.R href={syntheticExploratoryViewLink} color="text" iconType="visBarVerticalStacked" + data-test-subj={'uptimeExploreDataButton'} > {ANALYZE_DATA} From e9f45f63f29e057516dd1a808d7b0aa14237c673 Mon Sep 17 00:00:00 2001 From: Alexey Antonov Date: Tue, 18 Jan 2022 18:15:46 +0300 Subject: [PATCH 004/108] [Lens] Remove nested legend option from waffle (#123208) * [Lens] Remove nested legend option from waffle Closes: #123156 * Update toolbar.tsx * Update toolbar.tsx --- .../lens/public/pie_visualization/partition_charts_meta.ts | 2 ++ x-pack/plugins/lens/public/pie_visualization/toolbar.tsx | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/lens/public/pie_visualization/partition_charts_meta.ts b/x-pack/plugins/lens/public/pie_visualization/partition_charts_meta.ts index 2bafa5a1ff8e01..3d02c0f6d513ef 100644 --- a/x-pack/plugins/lens/public/pie_visualization/partition_charts_meta.ts +++ b/x-pack/plugins/lens/public/pie_visualization/partition_charts_meta.ts @@ -47,6 +47,7 @@ interface PartitionChartMeta { legend: { flat?: boolean; showValues?: boolean; + hideNestedLegendSwitch?: boolean; getShowLegendDefault?: (bucketColumns: DatatableColumn[]) => boolean; }; sortPredicate?: ( @@ -235,6 +236,7 @@ export const PartitionChartsMeta: Record = { legend: { flat: true, showValues: true, + hideNestedLegendSwitch: true, getShowLegendDefault: () => true, }, sortPredicate: diff --git a/x-pack/plugins/lens/public/pie_visualization/toolbar.tsx b/x-pack/plugins/lens/public/pie_visualization/toolbar.tsx index 6910a3ea0966c9..cebacd5c95863a 100644 --- a/x-pack/plugins/lens/public/pie_visualization/toolbar.tsx +++ b/x-pack/plugins/lens/public/pie_visualization/toolbar.tsx @@ -244,8 +244,8 @@ export function PieToolbar(props: VisualizationToolbarProps Date: Tue, 18 Jan 2022 16:33:35 +0100 Subject: [PATCH 005/108] [Lens] Implement rare terms (#121500) --- ...-plugin-core-public.doclinksstart.links.md | 1 + ...kibana-plugin-core-public.doclinksstart.md | 2 +- .../public/doc_links/doc_links_service.ts | 2 + src/core/public/public.api.md | 1 + .../data/common/search/aggs/agg_types.ts | 2 + .../common/search/aggs/aggs_service.test.ts | 2 + .../search/aggs/buckets/bucket_agg_types.ts | 1 + .../data/common/search/aggs/buckets/index.ts | 2 + .../search/aggs/buckets/multi_terms.test.ts | 2 +- .../common/search/aggs/buckets/multi_terms.ts | 4 +- .../search/aggs/buckets/rare_terms.test.ts | 103 ++++++++++ .../common/search/aggs/buckets/rare_terms.ts | 60 ++++++ .../search/aggs/buckets/rare_terms_fn.ts | 88 +++++++++ src/plugins/data/common/search/aggs/types.ts | 4 + .../public/search/aggs/aggs_service.test.ts | 4 +- .../heatmap/public/vis_type/heatmap.tsx | 3 + .../metric/public/metric_vis_type.ts | 1 + .../pie/public/sample_vis.test.mocks.ts | 2 + .../vis_types/pie/public/vis_type/pie.ts | 2 + .../vis_types/table/public/table_vis_type.ts | 2 + src/plugins/vis_types/vislib/public/gauge.ts | 1 + src/plugins/vis_types/vislib/public/goal.ts | 1 + .../xy/public/sample_vis.test.mocks.ts | 3 + .../vis_types/xy/public/vis_types/area.ts | 3 + .../xy/public/vis_types/histogram.ts | 3 + .../xy/public/vis_types/horizontal_bar.ts | 3 + .../vis_types/xy/public/vis_types/line.ts | 3 + .../run_pipeline/esaggs_rareterms.ts | 47 +++++ .../test_suites/run_pipeline/index.ts | 1 + .../workspace_panel_wrapper.tsx | 16 +- .../dimension_panel/dimension_editor.tsx | 16 ++ .../indexpattern.test.ts | 4 +- .../indexpattern_datasource/indexpattern.tsx | 4 +- .../definitions/terms/field_inputs.tsx | 1 + .../operations/definitions/terms/index.tsx | 126 ++++++++----- .../definitions/terms/terms.test.tsx | 87 ++++++++- .../operations/definitions/terms/types.ts | 5 +- .../definitions/terms/values_input.tsx | 40 ++-- .../indexpattern_datasource/utils.test.tsx | 76 +++++++- .../public/indexpattern_datasource/utils.tsx | 176 +++++++++++++----- x-pack/plugins/lens/public/types.ts | 6 +- 41 files changed, 778 insertions(+), 132 deletions(-) create mode 100644 src/plugins/data/common/search/aggs/buckets/rare_terms.test.ts create mode 100644 src/plugins/data/common/search/aggs/buckets/rare_terms.ts create mode 100644 src/plugins/data/common/search/aggs/buckets/rare_terms_fn.ts create mode 100644 test/interpreter_functional/test_suites/run_pipeline/esaggs_rareterms.ts diff --git a/docs/development/core/public/kibana-plugin-core-public.doclinksstart.links.md b/docs/development/core/public/kibana-plugin-core-public.doclinksstart.links.md index 154332ccc76f39..03862cedf5477b 100644 --- a/docs/development/core/public/kibana-plugin-core-public.doclinksstart.links.md +++ b/docs/development/core/public/kibana-plugin-core-public.doclinksstart.links.md @@ -147,6 +147,7 @@ readonly links: { readonly significant_terms: string; readonly terms: string; readonly terms_doc_count_error: string; + readonly rare_terms: string; readonly avg: string; readonly avg_bucket: string; readonly max_bucket: string; diff --git a/docs/development/core/public/kibana-plugin-core-public.doclinksstart.md b/docs/development/core/public/kibana-plugin-core-public.doclinksstart.md index 933c7c99486c7d..618aef54423bb0 100644 --- a/docs/development/core/public/kibana-plugin-core-public.doclinksstart.md +++ b/docs/development/core/public/kibana-plugin-core-public.doclinksstart.md @@ -17,5 +17,5 @@ export interface DocLinksStart | --- | --- | --- | | [DOC\_LINK\_VERSION](./kibana-plugin-core-public.doclinksstart.doc_link_version.md) | string | | | [ELASTIC\_WEBSITE\_URL](./kibana-plugin-core-public.doclinksstart.elastic_website_url.md) | string | | -| [links](./kibana-plugin-core-public.doclinksstart.links.md) | { readonly settings: string; readonly elasticStackGetStarted: string; readonly upgrade: { readonly upgradingElasticStack: string; }; readonly apm: { readonly kibanaSettings: string; readonly supportedServiceMaps: string; readonly customLinks: string; readonly droppedTransactionSpans: string; readonly upgrading: string; readonly metaData: string; }; readonly canvas: { readonly guide: string; }; readonly cloud: { readonly indexManagement: string; }; readonly console: { readonly guide: string; }; readonly dashboard: { readonly guide: string; readonly drilldowns: string; readonly drilldownsTriggerPicker: string; readonly urlDrilldownTemplateSyntax: string; readonly urlDrilldownVariables: string; }; readonly discover: Record<string, string>; readonly filebeat: { readonly base: string; readonly installation: string; readonly configuration: string; readonly elasticsearchOutput: string; readonly elasticsearchModule: string; readonly startup: string; readonly exportedFields: string; readonly suricataModule: string; readonly zeekModule: string; }; readonly auditbeat: { readonly base: string; readonly auditdModule: string; readonly systemModule: string; }; readonly metricbeat: { readonly base: string; readonly configure: string; readonly httpEndpoint: string; readonly install: string; readonly start: string; }; readonly appSearch: { readonly apiRef: string; readonly apiClients: string; readonly apiKeys: string; readonly authentication: string; readonly crawlRules: string; readonly curations: string; readonly duplicateDocuments: string; readonly entryPoints: string; readonly guide: string; readonly indexingDocuments: string; readonly indexingDocumentsSchema: string; readonly logSettings: string; readonly metaEngines: string; readonly precisionTuning: string; readonly relevanceTuning: string; readonly resultSettings: string; readonly searchUI: string; readonly security: string; readonly synonyms: string; readonly webCrawler: string; readonly webCrawlerEventLogs: string; }; readonly enterpriseSearch: { readonly configuration: string; readonly licenseManagement: string; readonly mailService: string; readonly usersAccess: string; }; readonly workplaceSearch: { readonly apiKeys: string; readonly box: string; readonly confluenceCloud: string; readonly confluenceServer: string; readonly customSources: string; readonly customSourcePermissions: string; readonly documentPermissions: string; readonly dropbox: string; readonly externalIdentities: string; readonly gitHub: string; readonly gettingStarted: string; readonly gmail: string; readonly googleDrive: string; readonly indexingSchedule: string; readonly jiraCloud: string; readonly jiraServer: string; readonly oneDrive: string; readonly permissions: string; readonly salesforce: string; readonly security: string; readonly serviceNow: string; readonly sharePoint: string; readonly slack: string; readonly synch: string; readonly zendesk: string; }; readonly heartbeat: { readonly base: string; }; readonly libbeat: { readonly getStarted: string; }; readonly logstash: { readonly base: string; }; readonly functionbeat: { readonly base: string; }; readonly winlogbeat: { readonly base: string; }; readonly aggs: { readonly composite: string; readonly composite\_missing\_bucket: string; readonly date\_histogram: string; readonly date\_range: string; readonly date\_format\_pattern: string; readonly filter: string; readonly filters: string; readonly geohash\_grid: string; readonly histogram: string; readonly ip\_range: string; readonly range: string; readonly significant\_terms: string; readonly terms: string; readonly terms\_doc\_count\_error: string; readonly avg: string; readonly avg\_bucket: string; readonly max\_bucket: string; readonly min\_bucket: string; readonly sum\_bucket: string; readonly cardinality: string; readonly count: string; readonly cumulative\_sum: string; readonly derivative: string; readonly geo\_bounds: string; readonly geo\_centroid: string; readonly max: string; readonly median: string; readonly min: string; readonly moving\_avg: string; readonly percentile\_ranks: string; readonly serial\_diff: string; readonly std\_dev: string; readonly sum: string; readonly top\_hits: string; }; readonly runtimeFields: { readonly overview: string; readonly mapping: string; }; readonly scriptedFields: { readonly scriptFields: string; readonly scriptAggs: string; readonly painless: string; readonly painlessApi: string; readonly painlessLangSpec: string; readonly painlessSyntax: string; readonly painlessWalkthrough: string; readonly luceneExpressions: string; }; readonly search: { readonly sessions: string; readonly sessionLimits: string; }; readonly indexPatterns: { readonly introduction: string; readonly fieldFormattersNumber: string; readonly fieldFormattersString: string; readonly runtimeFields: string; }; readonly addData: string; readonly kibana: { readonly guide: string; readonly autocompleteSuggestions: string; }; readonly upgradeAssistant: { readonly overview: string; readonly batchReindex: string; readonly remoteReindex: string; }; readonly rollupJobs: string; readonly elasticsearch: Record<string, string>; readonly siem: { readonly privileges: string; readonly guide: string; readonly gettingStarted: string; readonly ml: string; readonly ruleChangeLog: string; readonly detectionsReq: string; readonly networkMap: string; readonly troubleshootGaps: string; }; readonly securitySolution: { readonly trustedApps: string; readonly eventFilters: string; }; readonly query: { readonly eql: string; readonly kueryQuerySyntax: string; readonly luceneQuery: string; readonly luceneQuerySyntax: string; readonly percolate: string; readonly queryDsl: string; }; readonly date: { readonly dateMath: string; readonly dateMathIndexNames: string; }; readonly management: Record<string, string>; readonly ml: Record<string, string>; readonly transforms: Record<string, string>; readonly visualize: Record<string, string>; readonly apis: Readonly<{ bulkIndexAlias: string; byteSizeUnits: string; createAutoFollowPattern: string; createFollower: string; createIndex: string; createSnapshotLifecyclePolicy: string; createRoleMapping: string; createRoleMappingTemplates: string; createRollupJobsRequest: string; createApiKey: string; createPipeline: string; createTransformRequest: string; cronExpressions: string; executeWatchActionModes: string; indexExists: string; multiSearch: string; openIndex: string; putComponentTemplate: string; painlessExecute: string; painlessExecuteAPIContexts: string; putComponentTemplateMetadata: string; putSnapshotLifecyclePolicy: string; putIndexTemplateV1: string; putWatch: string; searchPreference: string; simulatePipeline: string; timeUnits: string; unfreezeIndex: string; updateTransform: string; }>; readonly observability: Readonly<{ guide: string; infrastructureThreshold: string; logsThreshold: string; metricsThreshold: string; monitorStatus: string; monitorUptime: string; tlsCertificate: string; uptimeDurationAnomaly: string; }>; readonly alerting: Record<string, string>; readonly maps: Readonly<{ guide: string; importGeospatialPrivileges: string; gdalTutorial: string; }>; readonly monitoring: Record<string, string>; readonly security: Readonly<{ apiKeyServiceSettings: string; clusterPrivileges: string; elasticsearchSettings: string; elasticsearchEnableSecurity: string; elasticsearchEnableApiKeys: string; indicesPrivileges: string; kibanaTLS: string; kibanaPrivileges: string; mappingRoles: string; mappingRolesFieldRules: string; runAsPrivilege: string; }>; readonly spaces: Readonly<{ kibanaLegacyUrlAliases: string; kibanaDisableLegacyUrlAliasesApi: string; }>; readonly watcher: Record<string, string>; readonly ccs: Record<string, string>; readonly plugins: { azureRepo: string; gcsRepo: string; hdfsRepo: string; s3Repo: string; snapshotRestoreRepos: string; mapperSize: string; }; readonly snapshotRestore: Record<string, string>; readonly ingest: Record<string, string>; readonly fleet: Readonly<{ beatsAgentComparison: string; guide: string; fleetServer: string; fleetServerAddFleetServer: string; settings: string; settingsFleetServerHostSettings: string; settingsFleetServerProxySettings: string; troubleshooting: string; elasticAgent: string; datastreams: string; datastreamsNamingScheme: string; installElasticAgent: string; installElasticAgentStandalone: string; upgradeElasticAgent: string; upgradeElasticAgent712lower: string; learnMoreBlog: string; apiKeysLearnMore: string; onPremRegistry: string; }>; readonly ecs: { readonly guide: string; }; readonly clients: { readonly guide: string; readonly goOverview: string; readonly javaIndex: string; readonly jsIntro: string; readonly netGuide: string; readonly perlGuide: string; readonly phpGuide: string; readonly pythonGuide: string; readonly rubyOverview: string; readonly rustGuide: string; }; readonly endpoints: { readonly troubleshooting: string; }; } | | +| [links](./kibana-plugin-core-public.doclinksstart.links.md) | { readonly settings: string; readonly elasticStackGetStarted: string; readonly upgrade: { readonly upgradingElasticStack: string; }; readonly apm: { readonly kibanaSettings: string; readonly supportedServiceMaps: string; readonly customLinks: string; readonly droppedTransactionSpans: string; readonly upgrading: string; readonly metaData: string; }; readonly canvas: { readonly guide: string; }; readonly cloud: { readonly indexManagement: string; }; readonly console: { readonly guide: string; }; readonly dashboard: { readonly guide: string; readonly drilldowns: string; readonly drilldownsTriggerPicker: string; readonly urlDrilldownTemplateSyntax: string; readonly urlDrilldownVariables: string; }; readonly discover: Record<string, string>; readonly filebeat: { readonly base: string; readonly installation: string; readonly configuration: string; readonly elasticsearchOutput: string; readonly elasticsearchModule: string; readonly startup: string; readonly exportedFields: string; readonly suricataModule: string; readonly zeekModule: string; }; readonly auditbeat: { readonly base: string; readonly auditdModule: string; readonly systemModule: string; }; readonly metricbeat: { readonly base: string; readonly configure: string; readonly httpEndpoint: string; readonly install: string; readonly start: string; }; readonly appSearch: { readonly apiRef: string; readonly apiClients: string; readonly apiKeys: string; readonly authentication: string; readonly crawlRules: string; readonly curations: string; readonly duplicateDocuments: string; readonly entryPoints: string; readonly guide: string; readonly indexingDocuments: string; readonly indexingDocumentsSchema: string; readonly logSettings: string; readonly metaEngines: string; readonly precisionTuning: string; readonly relevanceTuning: string; readonly resultSettings: string; readonly searchUI: string; readonly security: string; readonly synonyms: string; readonly webCrawler: string; readonly webCrawlerEventLogs: string; }; readonly enterpriseSearch: { readonly configuration: string; readonly licenseManagement: string; readonly mailService: string; readonly usersAccess: string; }; readonly workplaceSearch: { readonly apiKeys: string; readonly box: string; readonly confluenceCloud: string; readonly confluenceServer: string; readonly customSources: string; readonly customSourcePermissions: string; readonly documentPermissions: string; readonly dropbox: string; readonly externalIdentities: string; readonly gitHub: string; readonly gettingStarted: string; readonly gmail: string; readonly googleDrive: string; readonly indexingSchedule: string; readonly jiraCloud: string; readonly jiraServer: string; readonly oneDrive: string; readonly permissions: string; readonly salesforce: string; readonly security: string; readonly serviceNow: string; readonly sharePoint: string; readonly slack: string; readonly synch: string; readonly zendesk: string; }; readonly heartbeat: { readonly base: string; }; readonly libbeat: { readonly getStarted: string; }; readonly logstash: { readonly base: string; }; readonly functionbeat: { readonly base: string; }; readonly winlogbeat: { readonly base: string; }; readonly aggs: { readonly composite: string; readonly composite\_missing\_bucket: string; readonly date\_histogram: string; readonly date\_range: string; readonly date\_format\_pattern: string; readonly filter: string; readonly filters: string; readonly geohash\_grid: string; readonly histogram: string; readonly ip\_range: string; readonly range: string; readonly significant\_terms: string; readonly terms: string; readonly terms\_doc\_count\_error: string; readonly rare\_terms: string; readonly avg: string; readonly avg\_bucket: string; readonly max\_bucket: string; readonly min\_bucket: string; readonly sum\_bucket: string; readonly cardinality: string; readonly count: string; readonly cumulative\_sum: string; readonly derivative: string; readonly geo\_bounds: string; readonly geo\_centroid: string; readonly max: string; readonly median: string; readonly min: string; readonly moving\_avg: string; readonly percentile\_ranks: string; readonly serial\_diff: string; readonly std\_dev: string; readonly sum: string; readonly top\_hits: string; }; readonly runtimeFields: { readonly overview: string; readonly mapping: string; }; readonly scriptedFields: { readonly scriptFields: string; readonly scriptAggs: string; readonly painless: string; readonly painlessApi: string; readonly painlessLangSpec: string; readonly painlessSyntax: string; readonly painlessWalkthrough: string; readonly luceneExpressions: string; }; readonly search: { readonly sessions: string; readonly sessionLimits: string; }; readonly indexPatterns: { readonly introduction: string; readonly fieldFormattersNumber: string; readonly fieldFormattersString: string; readonly runtimeFields: string; }; readonly addData: string; readonly kibana: string; readonly upgradeAssistant: { readonly overview: string; readonly batchReindex: string; readonly remoteReindex: string; }; readonly rollupJobs: string; readonly elasticsearch: Record<string, string>; readonly siem: { readonly privileges: string; readonly guide: string; readonly gettingStarted: string; readonly ml: string; readonly ruleChangeLog: string; readonly detectionsReq: string; readonly networkMap: string; readonly troubleshootGaps: string; }; readonly securitySolution: { readonly trustedApps: string; readonly eventFilters: string; }; readonly query: { readonly eql: string; readonly kueryQuerySyntax: string; readonly luceneQuerySyntax: string; readonly percolate: string; readonly queryDsl: string; }; readonly date: { readonly dateMath: string; readonly dateMathIndexNames: string; }; readonly management: Record<string, string>; readonly ml: Record<string, string>; readonly transforms: Record<string, string>; readonly visualize: Record<string, string>; readonly apis: Readonly<{ bulkIndexAlias: string; byteSizeUnits: string; createAutoFollowPattern: string; createFollower: string; createIndex: string; createSnapshotLifecyclePolicy: string; createRoleMapping: string; createRoleMappingTemplates: string; createRollupJobsRequest: string; createApiKey: string; createPipeline: string; createTransformRequest: string; cronExpressions: string; executeWatchActionModes: string; indexExists: string; openIndex: string; putComponentTemplate: string; painlessExecute: string; painlessExecuteAPIContexts: string; putComponentTemplateMetadata: string; putSnapshotLifecyclePolicy: string; putIndexTemplateV1: string; putWatch: string; simulatePipeline: string; timeUnits: string; updateTransform: string; }>; readonly observability: Readonly<{ guide: string; infrastructureThreshold: string; logsThreshold: string; metricsThreshold: string; monitorStatus: string; monitorUptime: string; tlsCertificate: string; uptimeDurationAnomaly: string; }>; readonly alerting: Record<string, string>; readonly maps: Readonly<{ guide: string; importGeospatialPrivileges: string; gdalTutorial: string; }>; readonly monitoring: Record<string, string>; readonly security: Readonly<{ apiKeyServiceSettings: string; clusterPrivileges: string; elasticsearchSettings: string; elasticsearchEnableSecurity: string; elasticsearchEnableApiKeys: string; indicesPrivileges: string; kibanaTLS: string; kibanaPrivileges: string; mappingRoles: string; mappingRolesFieldRules: string; runAsPrivilege: string; }>; readonly spaces: Readonly<{ kibanaLegacyUrlAliases: string; kibanaDisableLegacyUrlAliasesApi: string; }>; readonly watcher: Record<string, string>; readonly ccs: Record<string, string>; readonly plugins: { azureRepo: string; gcsRepo: string; hdfsRepo: string; s3Repo: string; snapshotRestoreRepos: string; mapperSize: string; }; readonly snapshotRestore: Record<string, string>; readonly ingest: Record<string, string>; readonly fleet: Readonly<{ beatsAgentComparison: string; guide: string; fleetServer: string; fleetServerAddFleetServer: string; settings: string; settingsFleetServerHostSettings: string; settingsFleetServerProxySettings: string; troubleshooting: string; elasticAgent: string; datastreams: string; datastreamsNamingScheme: string; installElasticAgent: string; installElasticAgentStandalone: string; upgradeElasticAgent: string; upgradeElasticAgent712lower: string; learnMoreBlog: string; apiKeysLearnMore: string; onPremRegistry: string; }>; readonly ecs: { readonly guide: string; }; readonly clients: { readonly guide: string; readonly goOverview: string; readonly javaIndex: string; readonly jsIntro: string; readonly netGuide: string; readonly perlGuide: string; readonly phpGuide: string; readonly pythonGuide: string; readonly rubyOverview: string; readonly rustGuide: string; }; readonly endpoints: { readonly troubleshooting: string; }; } | | diff --git a/src/core/public/doc_links/doc_links_service.ts b/src/core/public/doc_links/doc_links_service.ts index 0c4bebc0bfbe82..c4e9ee553f5c30 100644 --- a/src/core/public/doc_links/doc_links_service.ts +++ b/src/core/public/doc_links/doc_links_service.ts @@ -179,6 +179,7 @@ export class DocLinksService { significant_terms: `${ELASTICSEARCH_DOCS}search-aggregations-bucket-significantterms-aggregation.html`, terms: `${ELASTICSEARCH_DOCS}search-aggregations-bucket-terms-aggregation.html`, terms_doc_count_error: `${ELASTICSEARCH_DOCS}search-aggregations-bucket-terms-aggregation.html#_per_bucket_document_count_error`, + rare_terms: `${ELASTICSEARCH_DOCS}search-aggregations-bucket-rare-terms-aggregation.html`, avg: `${ELASTICSEARCH_DOCS}search-aggregations-metrics-avg-aggregation.html`, avg_bucket: `${ELASTICSEARCH_DOCS}search-aggregations-pipeline-avg-bucket-aggregation.html`, max_bucket: `${ELASTICSEARCH_DOCS}search-aggregations-pipeline-max-bucket-aggregation.html`, @@ -746,6 +747,7 @@ export interface DocLinksStart { readonly significant_terms: string; readonly terms: string; readonly terms_doc_count_error: string; + readonly rare_terms: string; readonly avg: string; readonly avg_bucket: string; readonly max_bucket: string; diff --git a/src/core/public/public.api.md b/src/core/public/public.api.md index e4280f7cf90463..603d6f184dd6fe 100644 --- a/src/core/public/public.api.md +++ b/src/core/public/public.api.md @@ -630,6 +630,7 @@ export interface DocLinksStart { readonly significant_terms: string; readonly terms: string; readonly terms_doc_count_error: string; + readonly rare_terms: string; readonly avg: string; readonly avg_bucket: string; readonly max_bucket: string; diff --git a/src/plugins/data/common/search/aggs/agg_types.ts b/src/plugins/data/common/search/aggs/agg_types.ts index a7cdacf2e102d1..01ccd401c07acc 100644 --- a/src/plugins/data/common/search/aggs/agg_types.ts +++ b/src/plugins/data/common/search/aggs/agg_types.ts @@ -56,6 +56,7 @@ export const getAggTypes = () => ({ { name: BUCKET_TYPES.IP_RANGE, fn: buckets.getIpRangeBucketAgg }, { name: BUCKET_TYPES.TERMS, fn: buckets.getTermsBucketAgg }, { name: BUCKET_TYPES.MULTI_TERMS, fn: buckets.getMultiTermsBucketAgg }, + { name: BUCKET_TYPES.RARE_TERMS, fn: buckets.getRareTermsBucketAgg }, { name: BUCKET_TYPES.FILTER, fn: buckets.getFilterBucketAgg }, { name: BUCKET_TYPES.FILTERS, fn: buckets.getFiltersBucketAgg }, { name: BUCKET_TYPES.SIGNIFICANT_TERMS, fn: buckets.getSignificantTermsBucketAgg }, @@ -82,6 +83,7 @@ export const getAggTypesFunctions = () => [ buckets.aggDateHistogram, buckets.aggTerms, buckets.aggMultiTerms, + buckets.aggRareTerms, buckets.aggSampler, buckets.aggDiversifiedSampler, metrics.aggAvg, diff --git a/src/plugins/data/common/search/aggs/aggs_service.test.ts b/src/plugins/data/common/search/aggs/aggs_service.test.ts index f5a35338e0246c..998b8bf286b52b 100644 --- a/src/plugins/data/common/search/aggs/aggs_service.test.ts +++ b/src/plugins/data/common/search/aggs/aggs_service.test.ts @@ -68,6 +68,7 @@ describe('Aggs service', () => { "ip_range", "terms", "multi_terms", + "rare_terms", "filter", "filters", "significant_terms", @@ -120,6 +121,7 @@ describe('Aggs service', () => { "ip_range", "terms", "multi_terms", + "rare_terms", "filter", "filters", "significant_terms", diff --git a/src/plugins/data/common/search/aggs/buckets/bucket_agg_types.ts b/src/plugins/data/common/search/aggs/buckets/bucket_agg_types.ts index 08a773700e42fe..fcfbb432e30559 100644 --- a/src/plugins/data/common/search/aggs/buckets/bucket_agg_types.ts +++ b/src/plugins/data/common/search/aggs/buckets/bucket_agg_types.ts @@ -15,6 +15,7 @@ export enum BUCKET_TYPES { RANGE = 'range', TERMS = 'terms', MULTI_TERMS = 'multi_terms', + RARE_TERMS = 'rare_terms', SIGNIFICANT_TERMS = 'significant_terms', SIGNIFICANT_TEXT = 'significant_text', GEOHASH_GRID = 'geohash_grid', diff --git a/src/plugins/data/common/search/aggs/buckets/index.ts b/src/plugins/data/common/search/aggs/buckets/index.ts index 9ff7bccd16bd33..d9a5da5c827ac0 100644 --- a/src/plugins/data/common/search/aggs/buckets/index.ts +++ b/src/plugins/data/common/search/aggs/buckets/index.ts @@ -40,6 +40,8 @@ export * from './terms_fn'; export * from './terms'; export * from './multi_terms_fn'; export * from './multi_terms'; +export * from './rare_terms_fn'; +export * from './rare_terms'; export * from './sampler_fn'; export * from './sampler'; export * from './diversified_sampler_fn'; diff --git a/src/plugins/data/common/search/aggs/buckets/multi_terms.test.ts b/src/plugins/data/common/search/aggs/buckets/multi_terms.test.ts index 8788f554407726..7751c47575f429 100644 --- a/src/plugins/data/common/search/aggs/buckets/multi_terms.test.ts +++ b/src/plugins/data/common/search/aggs/buckets/multi_terms.test.ts @@ -127,7 +127,7 @@ describe('Multi Terms Agg', () => { 5, ], }, - "function": "aggTerms", + "function": "aggMultiTerms", "type": "function", }, ], diff --git a/src/plugins/data/common/search/aggs/buckets/multi_terms.ts b/src/plugins/data/common/search/aggs/buckets/multi_terms.ts index 02bf6bd12d3192..e98580fb99e1f6 100644 --- a/src/plugins/data/common/search/aggs/buckets/multi_terms.ts +++ b/src/plugins/data/common/search/aggs/buckets/multi_terms.ts @@ -12,7 +12,7 @@ import { i18n } from '@kbn/i18n'; import { BucketAggType } from './bucket_agg_type'; import { BUCKET_TYPES } from './bucket_agg_types'; import { createFilterMultiTerms } from './create_filter/multi_terms'; -import { aggTermsFnName } from './terms_fn'; +import { aggMultiTermsFnName } from './multi_terms_fn'; import { AggConfigSerialized, BaseAggParams } from '../types'; import { MultiFieldKey } from './multi_field_key'; @@ -41,7 +41,7 @@ export const getMultiTermsBucketAgg = () => { const keyCaches = new WeakMap(); return new BucketAggType({ name: BUCKET_TYPES.MULTI_TERMS, - expressionName: aggTermsFnName, + expressionName: aggMultiTermsFnName, title: termsTitle, makeLabel(agg) { const params = agg.params; diff --git a/src/plugins/data/common/search/aggs/buckets/rare_terms.test.ts b/src/plugins/data/common/search/aggs/buckets/rare_terms.test.ts new file mode 100644 index 00000000000000..8acbd95082a082 --- /dev/null +++ b/src/plugins/data/common/search/aggs/buckets/rare_terms.test.ts @@ -0,0 +1,103 @@ +/* + * 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. + */ + +import { AggConfigs } from '../agg_configs'; +import { mockAggTypesRegistry } from '../test_helpers'; +import { BUCKET_TYPES } from './bucket_agg_types'; +import type { IndexPatternField } from '../../..'; +import { IndexPattern } from '../../..'; + +describe('rare terms Agg', () => { + const getAggConfigs = (params: Record = {}) => { + const indexPattern = { + id: '1234', + title: 'logstash-*', + fields: [ + { + name: 'field', + type: 'string', + esTypes: ['string'], + aggregatable: true, + filterable: true, + searchable: true, + }, + { + name: 'string_field', + type: 'string', + esTypes: ['string'], + aggregatable: true, + filterable: true, + searchable: true, + }, + { + name: 'empty_number_field', + type: 'number', + esTypes: ['number'], + aggregatable: true, + filterable: true, + searchable: true, + }, + { + name: 'number_field', + type: 'number', + esTypes: ['number'], + aggregatable: true, + filterable: true, + searchable: true, + }, + ], + } as IndexPattern; + + indexPattern.fields.getByName = (name) => ({ name } as unknown as IndexPatternField); + indexPattern.fields.filter = () => indexPattern.fields; + + return new AggConfigs( + indexPattern, + [ + { + id: 'test', + params, + type: BUCKET_TYPES.RARE_TERMS, + }, + ], + { typesRegistry: mockAggTypesRegistry() } + ); + }; + + test('produces the expected expression ast', () => { + const aggConfigs = getAggConfigs({ + field: 'field', + max_doc_count: 5, + }); + expect(aggConfigs.aggs[0].toExpressionAst()).toMatchInlineSnapshot(` + Object { + "chain": Array [ + Object { + "arguments": Object { + "enabled": Array [ + true, + ], + "field": Array [ + "field", + ], + "id": Array [ + "test", + ], + "max_doc_count": Array [ + 5, + ], + }, + "function": "aggRareTerms", + "type": "function", + }, + ], + "type": "expression", + } + `); + }); +}); diff --git a/src/plugins/data/common/search/aggs/buckets/rare_terms.ts b/src/plugins/data/common/search/aggs/buckets/rare_terms.ts new file mode 100644 index 00000000000000..bc3c23b0262382 --- /dev/null +++ b/src/plugins/data/common/search/aggs/buckets/rare_terms.ts @@ -0,0 +1,60 @@ +/* + * 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. + */ + +import { i18n } from '@kbn/i18n'; + +import { BucketAggType } from './bucket_agg_type'; +import { BUCKET_TYPES } from './bucket_agg_types'; +import { createFilterTerms } from './create_filter/terms'; +import { aggRareTermsFnName } from './rare_terms_fn'; +import { BaseAggParams } from '../types'; + +import { KBN_FIELD_TYPES } from '../../../../common'; + +const termsTitle = i18n.translate('data.search.aggs.buckets.rareTermsTitle', { + defaultMessage: 'Rare terms', +}); + +export interface AggParamsRareTerms extends BaseAggParams { + field: string; + max_doc_count?: number; +} + +export const getRareTermsBucketAgg = () => { + return new BucketAggType({ + name: BUCKET_TYPES.RARE_TERMS, + expressionName: aggRareTermsFnName, + title: termsTitle, + makeLabel(agg) { + return i18n.translate('data.search.aggs.rareTerms.aggTypesLabel', { + defaultMessage: 'Rare terms of {fieldName}', + values: { + fieldName: agg.getFieldDisplayName(), + }, + }); + }, + createFilter: createFilterTerms, + params: [ + { + name: 'field', + type: 'field', + filterFieldTypes: [ + KBN_FIELD_TYPES.NUMBER, + KBN_FIELD_TYPES.BOOLEAN, + KBN_FIELD_TYPES.DATE, + KBN_FIELD_TYPES.IP, + KBN_FIELD_TYPES.STRING, + ], + }, + { + name: 'max_doc_count', + default: 1, + }, + ], + }); +}; diff --git a/src/plugins/data/common/search/aggs/buckets/rare_terms_fn.ts b/src/plugins/data/common/search/aggs/buckets/rare_terms_fn.ts new file mode 100644 index 00000000000000..bdb4556d186ad6 --- /dev/null +++ b/src/plugins/data/common/search/aggs/buckets/rare_terms_fn.ts @@ -0,0 +1,88 @@ +/* + * 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. + */ + +import { i18n } from '@kbn/i18n'; +import { ExpressionFunctionDefinition } from 'src/plugins/expressions/common'; +import { AggExpressionType, AggExpressionFunctionArgs, BUCKET_TYPES } from '../'; + +export const aggRareTermsFnName = 'aggRareTerms'; + +type Input = any; +type AggArgs = AggExpressionFunctionArgs; + +type Output = AggExpressionType; +type FunctionDefinition = ExpressionFunctionDefinition< + typeof aggRareTermsFnName, + Input, + AggArgs, + Output +>; + +export const aggRareTerms = (): FunctionDefinition => ({ + name: aggRareTermsFnName, + help: i18n.translate('data.search.aggs.function.buckets.rareTerms.help', { + defaultMessage: 'Generates a serialized agg config for a Rare-Terms agg', + }), + type: 'agg_type', + args: { + id: { + types: ['string'], + help: i18n.translate('data.search.aggs.buckets.rareTerms.id.help', { + defaultMessage: 'ID for this aggregation', + }), + }, + enabled: { + types: ['boolean'], + default: true, + help: i18n.translate('data.search.aggs.buckets.rareTerms.enabled.help', { + defaultMessage: 'Specifies whether this aggregation should be enabled', + }), + }, + schema: { + types: ['string'], + help: i18n.translate('data.search.aggs.buckets.rareTerms.schema.help', { + defaultMessage: 'Schema to use for this aggregation', + }), + }, + field: { + types: ['string'], + required: true, + help: i18n.translate('data.search.aggs.buckets.rareTerms.fields.help', { + defaultMessage: 'Field to use for this aggregation', + }), + }, + max_doc_count: { + types: ['number'], + help: i18n.translate('data.search.aggs.buckets.rareTerms.maxDocCount.help', { + defaultMessage: 'Maximum number of times a term is allowed to occur to qualify as rare', + }), + }, + json: { + types: ['string'], + help: i18n.translate('data.search.aggs.buckets.multiTerms.json.help', { + defaultMessage: 'Advanced json to include when the agg is sent to Elasticsearch', + }), + }, + }, + fn: (input, args) => { + const { id, enabled, schema, ...rest } = args; + + return { + type: 'agg_type', + value: { + id, + enabled, + schema, + type: BUCKET_TYPES.RARE_TERMS, + params: { + ...rest, + }, + }, + }; + }, +}); diff --git a/src/plugins/data/common/search/aggs/types.ts b/src/plugins/data/common/search/aggs/types.ts index 8f87c5aff56a38..34d773b0ba518e 100644 --- a/src/plugins/data/common/search/aggs/types.ts +++ b/src/plugins/data/common/search/aggs/types.ts @@ -68,6 +68,7 @@ import { AggParamsSum, AggParamsTerms, AggParamsMultiTerms, + AggParamsRareTerms, AggParamsTopHit, aggPercentileRanks, aggPercentiles, @@ -78,6 +79,7 @@ import { aggSum, aggTerms, aggMultiTerms, + aggRareTerms, aggTopHit, AggTypesRegistry, AggTypesRegistrySetup, @@ -166,6 +168,7 @@ export interface AggParamsMapping { [BUCKET_TYPES.DATE_HISTOGRAM]: AggParamsDateHistogram; [BUCKET_TYPES.TERMS]: AggParamsTerms; [BUCKET_TYPES.MULTI_TERMS]: AggParamsMultiTerms; + [BUCKET_TYPES.RARE_TERMS]: AggParamsRareTerms; [BUCKET_TYPES.SAMPLER]: AggParamsSampler; [BUCKET_TYPES.DIVERSIFIED_SAMPLER]: AggParamsDiversifiedSampler; [METRIC_TYPES.AVG]: AggParamsAvg; @@ -209,6 +212,7 @@ export interface AggFunctionsMapping { aggDateHistogram: ReturnType; aggTerms: ReturnType; aggMultiTerms: ReturnType; + aggRareTerms: ReturnType; aggAvg: ReturnType; aggBucketAvg: ReturnType; aggBucketMax: ReturnType; diff --git a/src/plugins/data/public/search/aggs/aggs_service.test.ts b/src/plugins/data/public/search/aggs/aggs_service.test.ts index 4a98a0e7e0ab63..b0e6e0327e6544 100644 --- a/src/plugins/data/public/search/aggs/aggs_service.test.ts +++ b/src/plugins/data/public/search/aggs/aggs_service.test.ts @@ -53,7 +53,7 @@ describe('AggsService - public', () => { test('registers default agg types', () => { service.setup(setupDeps); const start = service.start(startDeps); - expect(start.types.getAll().buckets.length).toBe(15); + expect(start.types.getAll().buckets.length).toBe(16); expect(start.types.getAll().metrics.length).toBe(23); }); @@ -69,7 +69,7 @@ describe('AggsService - public', () => { ); const start = service.start(startDeps); - expect(start.types.getAll().buckets.length).toBe(16); + expect(start.types.getAll().buckets.length).toBe(17); expect(start.types.getAll().buckets.some(({ name }) => name === 'foo')).toBe(true); expect(start.types.getAll().metrics.length).toBe(24); expect(start.types.getAll().metrics.some(({ name }) => name === 'bar')).toBe(true); diff --git a/src/plugins/vis_types/heatmap/public/vis_type/heatmap.tsx b/src/plugins/vis_types/heatmap/public/vis_type/heatmap.tsx index 4ce9afdf90aa54..f69a47beae280a 100644 --- a/src/plugins/vis_types/heatmap/public/vis_type/heatmap.tsx +++ b/src/plugins/vis_types/heatmap/public/vis_type/heatmap.tsx @@ -104,6 +104,7 @@ export const getHeatmapVisTypeDefinition = ({ '!filter', '!sampler', '!diversified_sampler', + '!rare_terms', '!multi_terms', '!significant_text', ], @@ -120,6 +121,7 @@ export const getHeatmapVisTypeDefinition = ({ '!filter', '!sampler', '!diversified_sampler', + '!rare_terms', '!multi_terms', '!significant_text', ], @@ -143,6 +145,7 @@ export const getHeatmapVisTypeDefinition = ({ '!filter', '!sampler', '!diversified_sampler', + '!rare_terms', '!multi_terms', '!significant_text', ], diff --git a/src/plugins/vis_types/metric/public/metric_vis_type.ts b/src/plugins/vis_types/metric/public/metric_vis_type.ts index f65ea79eee1e7f..12f68f3b0e17e8 100644 --- a/src/plugins/vis_types/metric/public/metric_vis_type.ts +++ b/src/plugins/vis_types/metric/public/metric_vis_type.ts @@ -92,6 +92,7 @@ export const createMetricVisTypeDefinition = (): VisTypeDefinition => '!filter', '!sampler', '!diversified_sampler', + '!rare_terms', '!multi_terms', '!significant_text', ], diff --git a/src/plugins/vis_types/pie/public/sample_vis.test.mocks.ts b/src/plugins/vis_types/pie/public/sample_vis.test.mocks.ts index ba2289203cc1a5..56f06207878860 100644 --- a/src/plugins/vis_types/pie/public/sample_vis.test.mocks.ts +++ b/src/plugins/vis_types/pie/public/sample_vis.test.mocks.ts @@ -93,6 +93,7 @@ export const samplePieVis = { '!filter', '!sampler', '!diversified_sampler', + '!rare_terms', '!multi_terms', '!significant_text', ], @@ -112,6 +113,7 @@ export const samplePieVis = { '!filter', '!sampler', '!diversified_sampler', + '!rare_terms', '!multi_terms', '!significant_text', ], diff --git a/src/plugins/vis_types/pie/public/vis_type/pie.ts b/src/plugins/vis_types/pie/public/vis_type/pie.ts index 55dd1de88842eb..827b25d541c9e8 100644 --- a/src/plugins/vis_types/pie/public/vis_type/pie.ts +++ b/src/plugins/vis_types/pie/public/vis_type/pie.ts @@ -93,6 +93,7 @@ export const getPieVisTypeDefinition = ({ '!filter', '!sampler', '!diversified_sampler', + '!rare_terms', '!multi_terms', '!significant_text', ], @@ -112,6 +113,7 @@ export const getPieVisTypeDefinition = ({ '!filter', '!sampler', '!diversified_sampler', + '!rare_terms', '!multi_terms', '!significant_text', ], diff --git a/src/plugins/vis_types/table/public/table_vis_type.ts b/src/plugins/vis_types/table/public/table_vis_type.ts index ba42d680d65db0..a432bd94dacb62 100644 --- a/src/plugins/vis_types/table/public/table_vis_type.ts +++ b/src/plugins/vis_types/table/public/table_vis_type.ts @@ -68,6 +68,7 @@ export const tableVisTypeDefinition: VisTypeDefinition = { '!diversified_sampler', '!multi_terms', '!significant_text', + '!rare_terms', ], }, { @@ -84,6 +85,7 @@ export const tableVisTypeDefinition: VisTypeDefinition = { '!diversified_sampler', '!multi_terms', '!significant_text', + '!rare_terms', ], }, ], diff --git a/src/plugins/vis_types/vislib/public/gauge.ts b/src/plugins/vis_types/vislib/public/gauge.ts index a29f152f836c45..128c0758bfd034 100644 --- a/src/plugins/vis_types/vislib/public/gauge.ts +++ b/src/plugins/vis_types/vislib/public/gauge.ts @@ -138,6 +138,7 @@ export const gaugeVisTypeDefinition: VisTypeDefinition = { '!filter', '!sampler', '!diversified_sampler', + '!rare_terms', '!multi_terms', '!significant_text', ], diff --git a/src/plugins/vis_types/vislib/public/goal.ts b/src/plugins/vis_types/vislib/public/goal.ts index 887979136792c8..9dd5fdbc92b5f0 100644 --- a/src/plugins/vis_types/vislib/public/goal.ts +++ b/src/plugins/vis_types/vislib/public/goal.ts @@ -102,6 +102,7 @@ export const goalVisTypeDefinition: VisTypeDefinition = { '!filter', '!sampler', '!diversified_sampler', + '!rare_terms', '!multi_terms', '!significant_text', ], diff --git a/src/plugins/vis_types/xy/public/sample_vis.test.mocks.ts b/src/plugins/vis_types/xy/public/sample_vis.test.mocks.ts index 6f33d1efca0f45..436a284b1657ae 100644 --- a/src/plugins/vis_types/xy/public/sample_vis.test.mocks.ts +++ b/src/plugins/vis_types/xy/public/sample_vis.test.mocks.ts @@ -155,6 +155,7 @@ export const sampleAreaVis = { '!filter', '!sampler', '!diversified_sampler', + '!rare_terms', '!multi_terms', '!significant_text', ], @@ -173,6 +174,7 @@ export const sampleAreaVis = { '!filter', '!sampler', '!diversified_sampler', + '!rare_terms', '!multi_terms', '!significant_text', ], @@ -191,6 +193,7 @@ export const sampleAreaVis = { '!filter', '!sampler', '!diversified_sampler', + '!rare_terms', '!multi_terms', '!significant_text', ], diff --git a/src/plugins/vis_types/xy/public/vis_types/area.ts b/src/plugins/vis_types/xy/public/vis_types/area.ts index 31da4082ca2b9f..d5e35dbc9f3de8 100644 --- a/src/plugins/vis_types/xy/public/vis_types/area.ts +++ b/src/plugins/vis_types/xy/public/vis_types/area.ts @@ -163,6 +163,7 @@ export const areaVisTypeDefinition = { '!filter', '!sampler', '!diversified_sampler', + '!rare_terms', '!multi_terms', '!significant_text', ], @@ -181,6 +182,7 @@ export const areaVisTypeDefinition = { '!filter', '!sampler', '!diversified_sampler', + '!rare_terms', '!multi_terms', '!significant_text', ], @@ -199,6 +201,7 @@ export const areaVisTypeDefinition = { '!filter', '!sampler', '!diversified_sampler', + '!rare_terms', '!multi_terms', '!significant_text', ], diff --git a/src/plugins/vis_types/xy/public/vis_types/histogram.ts b/src/plugins/vis_types/xy/public/vis_types/histogram.ts index 94a77b0483d4ca..c0b3e5f4e5073c 100644 --- a/src/plugins/vis_types/xy/public/vis_types/histogram.ts +++ b/src/plugins/vis_types/xy/public/vis_types/histogram.ts @@ -166,6 +166,7 @@ export const histogramVisTypeDefinition = { '!filter', '!sampler', '!diversified_sampler', + '!rare_terms', '!multi_terms', '!significant_text', ], @@ -184,6 +185,7 @@ export const histogramVisTypeDefinition = { '!filter', '!sampler', '!diversified_sampler', + '!rare_terms', '!multi_terms', '!significant_text', ], @@ -202,6 +204,7 @@ export const histogramVisTypeDefinition = { '!filter', '!sampler', '!diversified_sampler', + '!rare_terms', '!multi_terms', '!significant_text', ], diff --git a/src/plugins/vis_types/xy/public/vis_types/horizontal_bar.ts b/src/plugins/vis_types/xy/public/vis_types/horizontal_bar.ts index 351a71fc9169f5..f62e4e22871154 100644 --- a/src/plugins/vis_types/xy/public/vis_types/horizontal_bar.ts +++ b/src/plugins/vis_types/xy/public/vis_types/horizontal_bar.ts @@ -165,6 +165,7 @@ export const horizontalBarVisTypeDefinition = { '!filter', '!sampler', '!diversified_sampler', + '!rare_terms', '!multi_terms', '!significant_text', ], @@ -183,6 +184,7 @@ export const horizontalBarVisTypeDefinition = { '!filter', '!sampler', '!diversified_sampler', + '!rare_terms', '!multi_terms', '!significant_text', ], @@ -201,6 +203,7 @@ export const horizontalBarVisTypeDefinition = { '!filter', '!sampler', '!diversified_sampler', + '!rare_terms', '!multi_terms', '!significant_text', ], diff --git a/src/plugins/vis_types/xy/public/vis_types/line.ts b/src/plugins/vis_types/xy/public/vis_types/line.ts index 3ee9a1b28b0bd0..c14339bd1d6528 100644 --- a/src/plugins/vis_types/xy/public/vis_types/line.ts +++ b/src/plugins/vis_types/xy/public/vis_types/line.ts @@ -157,6 +157,7 @@ export const lineVisTypeDefinition = { '!filter', '!sampler', '!diversified_sampler', + '!rare_terms', '!multi_terms', '!significant_text', ], @@ -175,6 +176,7 @@ export const lineVisTypeDefinition = { '!filter', '!sampler', '!diversified_sampler', + '!rare_terms', '!multi_terms', '!significant_text', ], @@ -193,6 +195,7 @@ export const lineVisTypeDefinition = { '!filter', '!sampler', '!diversified_sampler', + '!rare_terms', '!multi_terms', '!significant_text', ], diff --git a/test/interpreter_functional/test_suites/run_pipeline/esaggs_rareterms.ts b/test/interpreter_functional/test_suites/run_pipeline/esaggs_rareterms.ts new file mode 100644 index 00000000000000..b52bd7904a256e --- /dev/null +++ b/test/interpreter_functional/test_suites/run_pipeline/esaggs_rareterms.ts @@ -0,0 +1,47 @@ +/* + * 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. + */ + +import expect from '@kbn/expect'; +import { DatatableRow } from 'src/plugins/expressions'; +import { ExpectExpression, expectExpressionProvider } from './helpers'; +import { FtrProviderContext } from '../../../functional/ftr_provider_context'; + +export default function ({ + getService, + updateBaselines, +}: FtrProviderContext & { updateBaselines: boolean }) { + let expectExpression: ExpectExpression; + + describe('esaggs_rareterms', () => { + before(() => { + expectExpression = expectExpressionProvider({ getService, updateBaselines }); + }); + + const timeRange = { + from: '2015-09-21T00:00:00Z', + to: '2015-09-22T00:00:00Z', + }; + + describe('aggRareTerms', () => { + it('can execute aggRareTerms', async () => { + const expression = ` + kibana_context timeRange={timerange from='${timeRange.from}' to='${timeRange.to}'} + | esaggs index={indexPatternLoad id='logstash-*'} + aggs={aggRareTerms id="1" enabled=true schema="bucket" field="geo.srcdest" max_doc_count=1} + aggs={aggCount id="2" enabled=true schema="metric"} + `; + const result = await expectExpression('rareterms', expression).getResponse(); + + expect(result.rows.length).to.be(1149); + result.rows.forEach((row: DatatableRow) => { + expect(row['col-1-2']).to.be(1); + }); + }); + }); + }); +} diff --git a/test/interpreter_functional/test_suites/run_pipeline/index.ts b/test/interpreter_functional/test_suites/run_pipeline/index.ts index 184a91a91f0952..97387fc0a965fc 100644 --- a/test/interpreter_functional/test_suites/run_pipeline/index.ts +++ b/test/interpreter_functional/test_suites/run_pipeline/index.ts @@ -46,5 +46,6 @@ export default function ({ getService, getPageObjects, loadTestFile }: FtrProvid loadTestFile(require.resolve('./esaggs_multiterms')); loadTestFile(require.resolve('./esaggs_sampler')); loadTestFile(require.resolve('./esaggs_significanttext')); + loadTestFile(require.resolve('./esaggs_rareterms')); }); } diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel_wrapper.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel_wrapper.tsx index f13ecb78593d9c..be230634886105 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel_wrapper.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel_wrapper.tsx @@ -19,6 +19,7 @@ import { updateVisualizationState, DatasourceStates, VisualizationState, + updateDatasourceState, } from '../../../state_management'; import { WorkspaceTitle } from './title'; @@ -60,6 +61,17 @@ export function WorkspacePanelWrapper({ }, [dispatchLens, activeVisualization] ); + const setDatasourceState = useCallback( + (updater: unknown, datasourceId: string) => { + dispatchLens( + updateDatasourceState({ + updater, + datasourceId, + }) + ); + }, + [dispatchLens] + ); const warningMessages: React.ReactNode[] = []; if (activeVisualization?.getWarningMessages) { warningMessages.push( @@ -70,7 +82,9 @@ export function WorkspacePanelWrapper({ const datasource = datasourceMap[datasourceId]; if (!datasourceState.isLoading && datasource.getWarningMessages) { warningMessages.push( - ...(datasource.getWarningMessages(datasourceState.state, framePublicAPI) || []) + ...(datasource.getWarningMessages(datasourceState.state, framePublicAPI, (updater) => + setDatasourceState(updater, datasourceId) + ) || []) ); } }); diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_editor.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_editor.tsx index 2b85e372432376..079580ce69896f 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_editor.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_editor.tsx @@ -634,6 +634,20 @@ export function DimensionEditor(props: DimensionEditorProps) { }, ]; + const defaultLabel = useMemo( + () => + String( + selectedColumn && + !selectedColumn.customLabel && + operationDefinitionMap[selectedColumn.operationType].getDefaultLabel( + selectedColumn, + state.indexPatterns[state.layers[layerId].indexPatternId], + state.layers[layerId].columns + ) + ), + [layerId, selectedColumn, state.indexPatterns, state.layers] + ); + return (
{hasTabs ? : null} @@ -750,6 +764,8 @@ export function DimensionEditor(props: DimensionEditorProps) {
{!incompleteInfo && selectedColumn && temporaryState === 'none' && ( { updateLayer({ diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.test.ts b/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.test.ts index cc88375e4137bc..4e358564c9f76b 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.test.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.test.ts @@ -1449,7 +1449,7 @@ describe('IndexPattern Data Source', () => { }); it('should return mismatched time shifts', () => { - const warnings = indexPatternDatasource.getWarningMessages!(state, framePublicAPI); + const warnings = indexPatternDatasource.getWarningMessages!(state, framePublicAPI, () => {}); expect(warnings!.map((item) => (item as React.ReactElement).props.id)).toMatchInlineSnapshot(` Array [ @@ -1462,7 +1462,7 @@ describe('IndexPattern Data Source', () => { it('should show different types of warning messages', () => { framePublicAPI.activeData!.first.columns[0].meta.sourceParams!.hasPrecisionError = true; - const warnings = indexPatternDatasource.getWarningMessages!(state, framePublicAPI); + const warnings = indexPatternDatasource.getWarningMessages!(state, framePublicAPI, () => {}); expect(warnings!.map((item) => (item as React.ReactElement).props.id)).toMatchInlineSnapshot(` Array [ diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.tsx index 81acac82355abf..005cbd4b119771 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.tsx @@ -527,10 +527,10 @@ export function getIndexPatternDatasource({ }); return messages.length ? messages : undefined; }, - getWarningMessages: (state, frame) => { + getWarningMessages: (state, frame, setState) => { return [ ...(getStateTimeShiftWarningMessages(state, frame) || []), - ...getPrecisionErrorWarningMessages(state, frame, core.docLinks), + ...getPrecisionErrorWarningMessages(state, frame, core.docLinks, setState), ]; }, checkIntegrity: (state) => { diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/field_inputs.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/field_inputs.tsx index de04e51ef872cb..e187b12f323c66 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/field_inputs.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/field_inputs.tsx @@ -109,6 +109,7 @@ export function FieldInputs({ label={i18n.translate('xpack.lens.indexPattern.terms.addField', { defaultMessage: 'Add field', })} + isDisabled={column.params.orderBy.type === 'rare'} /> ); diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/index.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/index.tsx index f58893e6988fce..a1164396f30e28 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/index.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/index.tsx @@ -20,7 +20,7 @@ import { } from '@elastic/eui'; import { AggFunctionsMapping } from '../../../../../../../../src/plugins/data/public'; import { buildExpressionFunction } from '../../../../../../../../src/plugins/expressions/public'; -import { updateColumnParam } from '../../layer_helpers'; +import { updateColumnParam, updateDefaultLabels } from '../../layer_helpers'; import type { DataType } from '../../../../types'; import { OperationDefinition } from '../index'; import { FieldBasedIndexPatternColumn } from '../column_types'; @@ -44,7 +44,15 @@ const missingFieldLabel = i18n.translate('xpack.lens.indexPattern.missingFieldLa defaultMessage: 'Missing field', }); -function ofName(name?: string, count: number = 0) { +function ofName(name?: string, count: number = 0, rare: boolean = false) { + if (rare) { + return i18n.translate('xpack.lens.indexPattern.rareTermsOf', { + defaultMessage: 'Rare values of {name}', + values: { + name: name ?? missingFieldLabel, + }, + }); + } if (count) { return i18n.translate('xpack.lens.indexPattern.multipleTermsOf', { defaultMessage: 'Top values of {name} + {count} {count, plural, one {other} other {others}}', @@ -64,6 +72,9 @@ function ofName(name?: string, count: number = 0) { const idPrefix = htmlIdGenerator()(); const DEFAULT_SIZE = 3; +// Elasticsearch limit +const MAXIMUM_MAX_DOC_COUNT = 100; +export const DEFAULT_MAX_DOC_COUNT = 1; const supportedTypes = new Set(['string', 'boolean', 'number', 'ip']); export const termsOperation: OperationDefinition = { @@ -141,6 +152,15 @@ export const termsOperation: OperationDefinition { + if (column.params?.orderBy.type === 'rare') { + return buildExpressionFunction('aggRareTerms', { + id: columnId, + enabled: true, + schema: 'segment', + field: column.sourceField, + max_doc_count: column.params.orderBy.maxDocCount, + }).toAst(); + } if (column.params?.secondaryFields?.length) { return buildExpressionFunction('aggMultiTerms', { id: columnId, @@ -183,7 +203,8 @@ export const termsOperation: OperationDefinition ofName( indexPattern.getFieldByName(column.sourceField)?.displayName, - column.params.secondaryFields?.length + column.params.secondaryFields?.length, + column.params.orderBy.type === 'rare' ), onFieldChange: (oldColumn, field) => { // reset the secondary fields @@ -194,7 +215,7 @@ export const termsOperation: OperationDefinition { const columns = layer.columns; const currentColumn = columns[thisColumnId] as TermsIndexPatternColumn; - if (currentColumn.params.orderBy.type === 'column' || currentColumn.params.orderBy.fallback) { + if ( + currentColumn.params.orderBy.type === 'column' || + (currentColumn.params.orderBy.type === 'alphabetical' && + currentColumn.params.orderBy.fallback) + ) { // check whether the column is still there and still a metric const columnSortedBy = currentColumn.params.orderBy.type === 'column' @@ -251,7 +276,11 @@ export const termsOperation: OperationDefinition 1 ? fields.slice(1) : undefined, @@ -319,7 +348,7 @@ export const termsOperation: OperationDefinition { updateLayer( updateColumnParam({ @@ -366,6 +407,25 @@ export const termsOperation: OperationDefinition + {currentColumn.params.orderBy.type === 'rare' && ( + { + updateLayer( + updateColumnParam({ + layer, + columnId, + paramName: 'orderBy', + value: { ...currentColumn.params.orderBy, maxDocCount: value }, + }) + ); + }} + /> + )} @@ -396,12 +456,15 @@ export const termsOperation: OperationDefinition) => { const newOrderByValue = fromValue(e.target.value); - const updatedLayer = updateColumnParam({ - layer, - columnId, - paramName: 'orderBy', - value: newOrderByValue, - }); + const updatedLayer = updateDefaultLabels( + updateColumnParam({ + layer, + columnId, + paramName: 'orderBy', + value: newOrderByValue, + }), + indexPattern + ); updateLayer( updateColumnParam({ layer: updatedLayer, @@ -434,6 +497,7 @@ export const termsOperation: OperationDefinition - {/* ) => - updateLayer( - updateColumnParam({ - layer, - columnId, - paramName: 'orderDirection', - value: e.target.value as 'asc' | 'desc', - }) - ) - } - aria-label={i18n.translate('xpack.lens.indexPattern.terms.orderBy', { - defaultMessage: 'Rank by', - })} - /> */} {!hasRestrictions && ( <> @@ -518,6 +550,7 @@ export const termsOperation: OperationDefinition updateLayer( updateColumnParam({ @@ -537,7 +570,8 @@ export const termsOperation: OperationDefinition { columnOrder: ['col1', 'col2'], columns: { col1: { - label: 'Top value of category', + label: 'Top values of source', dataType: 'string', isBucketed: true, operationType: 'terms', @@ -79,7 +79,7 @@ describe('terms', () => { sourceField: 'source', } as TermsIndexPatternColumn, col2: { - label: 'Count', + label: 'Count of records', dataType: 'number', isBucketed: false, sourceField: 'Records', @@ -112,6 +112,30 @@ describe('terms', () => { ); }); + it('should reflect rare terms params correctly', () => { + const termsColumn = layer.columns.col1 as TermsIndexPatternColumn; + const esAggsFn = termsOperation.toEsAggsFn( + { + ...termsColumn, + params: { ...termsColumn.params, orderBy: { type: 'rare', maxDocCount: 3 } }, + }, + 'col1', + {} as IndexPattern, + layer, + uiSettingsMock, + [] + ); + expect(esAggsFn).toEqual( + expect.objectContaining({ + function: 'aggRareTerms', + arguments: expect.objectContaining({ + field: ['source'], + max_doc_count: [3], + }), + }) + ); + }); + it('should not enable missing bucket if other bucket is not set', () => { const termsColumn = layer.columns.col1 as TermsIndexPatternColumn; const esAggsFn = termsOperation.toEsAggsFn( @@ -1379,6 +1403,64 @@ describe('terms', () => { expect(select.prop('disabled')).toEqual(false); }); + it('should disable missing bucket and other bucket setting for rarity sorting', () => { + const updateLayerSpy = jest.fn(); + const instance = shallow( + + ); + + const select1 = instance + .find('[data-test-subj="indexPattern-terms-missing-bucket"]') + .find(EuiSwitch); + + expect(select1.prop('disabled')).toEqual(true); + + const select2 = instance + .find('[data-test-subj="indexPattern-terms-other-bucket"]') + .find(EuiSwitch); + + expect(select2.prop('disabled')).toEqual(true); + }); + + it('should disable size input and show max doc count input', () => { + const updateLayerSpy = jest.fn(); + const instance = shallow( + + ); + + const numberInputs = instance.find(ValuesInput); + + expect(numberInputs).toHaveLength(2); + + expect(numberInputs.first().prop('disabled')).toBeTruthy(); + expect(numberInputs.last().prop('disabled')).toBeFalsy(); + expect(numberInputs.last().prop('value')).toEqual(3); + }); + it('should disable missing bucket setting if field is not a string', () => { const updateLayerSpy = jest.fn(); const instance = shallow( @@ -1462,6 +1544,7 @@ describe('terms', () => { expect(select.prop('options')!.map(({ value }) => value)).toEqual([ 'column$$$col2', 'alphabetical', + 'rare', ]); }); diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/types.ts b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/types.ts index a1b61880ade3f0..584893f1826667 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/types.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/types.ts @@ -13,7 +13,10 @@ export interface TermsIndexPatternColumn extends FieldBasedIndexPatternColumn { size: number; // if order is alphabetical, the `fallback` flag indicates whether it became alphabetical because there wasn't // another option or whether the user explicitly chose to make it alphabetical. - orderBy: { type: 'alphabetical'; fallback?: boolean } | { type: 'column'; columnId: string }; + orderBy: + | { type: 'alphabetical'; fallback?: boolean } + | { type: 'rare'; maxDocCount: number } + | { type: 'column'; columnId: string }; orderDirection: 'asc' | 'desc'; otherBucket?: boolean; missingBucket?: boolean; diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/values_input.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/values_input.tsx index a107893517ea3c..3130f2b8a5265d 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/values_input.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/values_input.tsx @@ -13,13 +13,20 @@ import { useDebounceWithOptions } from '../../../../shared_components'; export const ValuesInput = ({ value, onChange, + minValue = 1, + maxValue = 1000, + label = i18n.translate('xpack.lens.indexPattern.terms.size', { + defaultMessage: 'Number of values', + }), + disabled, }: { value: number; onChange: (value: number) => void; + minValue?: number; + maxValue?: number; + label?: string; + disabled?: boolean; }) => { - const MIN_NUMBER_OF_VALUES = 1; - const MAX_NUMBER_OF_VALUES = 1000; - const [inputValue, setInputValue] = useState(String(value)); useDebounceWithOptions( @@ -28,7 +35,7 @@ export const ValuesInput = ({ return; } const inputNumber = Number(inputValue); - onChange(Math.min(MAX_NUMBER_OF_VALUES, Math.max(inputNumber, MIN_NUMBER_OF_VALUES))); + onChange(Math.min(maxValue, Math.max(inputNumber, minValue))); }, { skipFirstRender: true }, 256, @@ -36,14 +43,12 @@ export const ValuesInput = ({ ); const isEmptyString = inputValue === ''; - const isHigherThanMax = !isEmptyString && Number(inputValue) > MAX_NUMBER_OF_VALUES; - const isLowerThanMin = !isEmptyString && Number(inputValue) < MIN_NUMBER_OF_VALUES; + const isHigherThanMax = !isEmptyString && Number(inputValue) > maxValue; + const isLowerThanMin = !isEmptyString && Number(inputValue) < minValue; return ( setInputValue(currentTarget.value)} - aria-label={i18n.translate('xpack.lens.indexPattern.terms.size', { - defaultMessage: 'Number of values', - })} + aria-label={label} onBlur={() => { if (inputValue === '') { return setInputValue(String(value)); } const inputNumber = Number(inputValue); - setInputValue( - String(Math.min(MAX_NUMBER_OF_VALUES, Math.max(inputNumber, MIN_NUMBER_OF_VALUES))) - ); + setInputValue(String(Math.min(maxValue, Math.max(inputNumber, minValue)))); }} /> diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/utils.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/utils.test.tsx index 05be5c66fe5da4..ede2a38605d3f0 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/utils.test.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/utils.test.tsx @@ -5,10 +5,13 @@ * 2.0. */ +import React from 'react'; +import { shallow } from 'enzyme'; import { getPrecisionErrorWarningMessages } from './utils'; -import type { IndexPatternPrivateState } from './types'; +import type { IndexPatternPrivateState, GenericIndexPatternColumn } from './types'; import type { FramePublicAPI } from '../types'; import type { DocLinksStart } from 'kibana/public'; +import { EuiButton } from '@elastic/eui'; describe('indexpattern_datasource utils', () => { describe('getPrecisionErrorWarningMessages', () => { @@ -17,12 +20,34 @@ describe('indexpattern_datasource utils', () => { let docLinks: DocLinksStart; beforeEach(() => { - state = {} as IndexPatternPrivateState; + state = { + layers: { + id: { + indexPatternId: 'one', + columns: { + col1: { + operationType: 'terms', + params: { + orderBy: { + type: 'alphabetical', + }, + }, + }, + }, + }, + }, + indexPatterns: { + one: { + getFieldByName: (x: string) => ({ name: x, displayName: x }), + }, + }, + } as unknown as IndexPatternPrivateState; framePublicAPI = { activeData: { id: { columns: [ { + id: 'col1', meta: { sourceParams: { hasPrecisionError: false, @@ -43,19 +68,60 @@ describe('indexpattern_datasource utils', () => { } as DocLinksStart; }); test('should not show precisionError if hasPrecisionError is false', () => { - expect(getPrecisionErrorWarningMessages(state, framePublicAPI, docLinks)).toHaveLength(0); + expect( + getPrecisionErrorWarningMessages(state, framePublicAPI, docLinks, () => {}) + ).toHaveLength(0); }); test('should not show precisionError if hasPrecisionError is not defined', () => { delete framePublicAPI.activeData!.id.columns[0].meta.sourceParams!.hasPrecisionError; - expect(getPrecisionErrorWarningMessages(state, framePublicAPI, docLinks)).toHaveLength(0); + expect( + getPrecisionErrorWarningMessages(state, framePublicAPI, docLinks, () => {}) + ).toHaveLength(0); }); test('should show precisionError if hasPrecisionError is true', () => { framePublicAPI.activeData!.id.columns[0].meta.sourceParams!.hasPrecisionError = true; - expect(getPrecisionErrorWarningMessages(state, framePublicAPI, docLinks)).toHaveLength(1); + expect( + getPrecisionErrorWarningMessages(state, framePublicAPI, docLinks, () => {}) + ).toHaveLength(1); + }); + + test('if has precision error and sorting is by count ascending, show fix action and switch to rare terms', () => { + framePublicAPI.activeData!.id.columns[0].meta.sourceParams!.hasPrecisionError = true; + state.layers.id.columnOrder = ['col1', 'col2']; + state.layers.id.columns = { + col1: { + operationType: 'terms', + sourceField: 'category', + params: { + orderBy: { + type: 'column', + columnId: 'col2', + }, + orderDirection: 'asc', + }, + } as unknown as GenericIndexPatternColumn, + col2: { + operationType: 'count', + } as unknown as GenericIndexPatternColumn, + }; + const setState = jest.fn(); + const warnings = getPrecisionErrorWarningMessages(state, framePublicAPI, docLinks, setState); + + expect(warnings).toHaveLength(1); + const DummyComponent = () => <>{warnings[0]}; + const warningUi = shallow(); + warningUi.find(EuiButton).simulate('click'); + const stateSetter = setState.mock.calls[0][0]; + const newState = stateSetter(state); + expect(newState.layers.id.columns.col1.label).toEqual('Rare values of category'); + expect(newState.layers.id.columns.col1.params.orderBy).toEqual({ + type: 'rare', + maxDocCount: 1, + }); }); }); }); diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/utils.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/utils.tsx index 76156b5a57a114..cc8a5c322782dd 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/utils.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/utils.tsx @@ -6,21 +6,31 @@ */ import React from 'react'; +import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; import type { DocLinksStart } from 'kibana/public'; -import { EuiLink, EuiTextColor } from '@elastic/eui'; +import { EuiLink, EuiTextColor, EuiButton, EuiSpacer } from '@elastic/eui'; import { DatatableColumn } from 'src/plugins/expressions'; -import type { FramePublicAPI } from '../types'; +import type { FramePublicAPI, StateSetter } from '../types'; import type { IndexPattern, IndexPatternLayer, IndexPatternPrivateState } from './types'; import type { ReferenceBasedIndexPatternColumn } from './operations/definitions/column_types'; -import { operationDefinitionMap, GenericIndexPatternColumn } from './operations'; +import { + operationDefinitionMap, + GenericIndexPatternColumn, + TermsIndexPatternColumn, + CountIndexPatternColumn, + updateColumnParam, + updateDefaultLabels, +} from './operations'; -import { getInvalidFieldMessage } from './operations/definitions/helpers'; +import { getInvalidFieldMessage, isColumnOfType } from './operations/definitions/helpers'; import { isQueryValid } from './operations/definitions/filters'; import { checkColumnForPrecisionError } from '../../../../../src/plugins/data/common'; import { hasField } from './pure_utils'; +import { mergeLayer } from './state_helpers'; +import { DEFAULT_MAX_DOC_COUNT } from './operations/definitions/terms'; export function isColumnInvalid( layer: IndexPatternLayer, @@ -80,53 +90,125 @@ export function fieldIsInvalid( export function getPrecisionErrorWarningMessages( state: IndexPatternPrivateState, { activeData }: FramePublicAPI, - docLinks: DocLinksStart + docLinks: DocLinksStart, + setState: StateSetter ) { const warningMessages: React.ReactNode[] = []; if (state && activeData) { - Object.values(activeData) - .reduce((acc: DatatableColumn[], { columns }) => [...acc, ...columns], []) - .forEach((column) => { - if (checkColumnForPrecisionError(column)) { - warningMessages.push( - {column.name}, - topValues: ( - - - - ), - filters: ( - - - - ), - link: ( - - - - ), - }} - /> - ); + Object.entries(activeData) + .reduce( + (acc, [layerId, { columns }]) => [ + ...acc, + ...columns.map((column) => ({ layerId, column })), + ], + [] as Array<{ layerId: string; column: DatatableColumn }> + ) + .forEach(({ layerId, column }) => { + const currentLayer = state.layers[layerId]; + const currentColumn = currentLayer?.columns[column.id]; + if (currentLayer && currentColumn && checkColumnForPrecisionError(column)) { + const indexPattern = state.indexPatterns[currentLayer.indexPatternId]; + const isAscendingCountSorting = + isColumnOfType('terms', currentColumn) && + currentColumn.params.orderBy.type === 'column' && + currentColumn.params.orderDirection === 'asc' && + isColumnOfType( + 'count', + currentLayer.columns[currentColumn.params.orderBy.columnId] + ); + if (!isAscendingCountSorting) { + warningMessages.push( + {column.name}, + topValues: ( + + + + ), + filters: ( + + + + ), + link: ( + + + + ), + }} + /> + ); + } else { + warningMessages.push( + <> + {column.name}, + link: ( + + + + ), + }} + /> + + { + setState((prevState) => + mergeLayer({ + state: prevState, + layerId, + newLayer: updateDefaultLabels( + updateColumnParam({ + layer: currentLayer, + columnId: column.id, + paramName: 'orderBy', + value: { + type: 'rare', + maxDocCount: DEFAULT_MAX_DOC_COUNT, + }, + }), + indexPattern + ), + }) + ); + }} + > + {i18n.translate('xpack.lens.indexPattern.switchToRare', { + defaultMessage: 'Rank by rarity', + })} + + + ); + } } }); } diff --git a/x-pack/plugins/lens/public/types.ts b/x-pack/plugins/lens/public/types.ts index 7ea5ff232607a7..27a214cd2fb2e5 100644 --- a/x-pack/plugins/lens/public/types.ts +++ b/x-pack/plugins/lens/public/types.ts @@ -280,7 +280,11 @@ export interface Datasource { /** * The frame calls this function to display warnings about visualization */ - getWarningMessages?: (state: T, frame: FramePublicAPI) => React.ReactNode[] | undefined; + getWarningMessages?: ( + state: T, + frame: FramePublicAPI, + setState: StateSetter + ) => React.ReactNode[] | undefined; /** * Checks if the visualization created is time based, for example date histogram */ From a8247ff7d747e6c94e5b31a9b66d8910aa100a7a Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Tue, 18 Jan 2022 15:38:11 +0000 Subject: [PATCH 006/108] fix(NA): missing build dependencies on @kbn/storybook (#123228) --- packages/kbn-storybook/BUILD.bazel | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/kbn-storybook/BUILD.bazel b/packages/kbn-storybook/BUILD.bazel index 729a60f8f7dc8b..873167674dd78e 100644 --- a/packages/kbn-storybook/BUILD.bazel +++ b/packages/kbn-storybook/BUILD.bazel @@ -33,6 +33,8 @@ RUNTIME_DEPS = [ "//packages/kbn-ui-shared-deps-npm", "//packages/kbn-ui-shared-deps-src", "//packages/kbn-utils", + "@npm//@elastic/eui", + "@npm//@emotion/cache", "@npm//@storybook/addons", "@npm//@storybook/api", "@npm//@storybook/components", @@ -52,6 +54,8 @@ TYPES_DEPS = [ "//packages/kbn-ui-shared-deps-npm:npm_module_types", "//packages/kbn-ui-shared-deps-src", "//packages/kbn-utils:npm_module_types", + "@npm//@elastic/eui", + "@npm//@emotion/cache", "@npm//@storybook/addons", "@npm//@storybook/api", "@npm//@storybook/components", From 4d771c328f3bf4b20e1faee67538cb74b66edd88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Fern=C3=A1ndez=20G=C3=B3mez?= Date: Tue, 18 Jan 2022 16:40:33 +0100 Subject: [PATCH 007/108] [Unified observability] Extract `ObservabilityIndexPatterns` from exploratory view (#122132) --- .../exploratory_view/embeddable/index.tsx | 6 +- .../exploratory_view.test.tsx | 6 +- .../hooks/use_app_index_pattern.tsx | 6 +- .../utils/observability_data_views/index.ts | 8 +++ .../observability_data_views.test.ts} | 24 +++---- .../observability_data_views.ts} | 69 ++++++++++--------- 6 files changed, 64 insertions(+), 55 deletions(-) create mode 100644 x-pack/plugins/observability/public/utils/observability_data_views/index.ts rename x-pack/plugins/observability/public/{components/shared/exploratory_view/utils/observability_index_patterns.test.ts => utils/observability_data_views/observability_data_views.test.ts} (81%) rename x-pack/plugins/observability/public/{components/shared/exploratory_view/utils/observability_index_patterns.ts => utils/observability_data_views/observability_data_views.ts} (63%) diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/embeddable/index.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/embeddable/index.tsx index e68ddfe55e6f50..7b0e2d10c0d3bc 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/embeddable/index.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/embeddable/index.tsx @@ -9,7 +9,7 @@ import React, { useCallback, useEffect, useState } from 'react'; import { EuiLoadingSpinner } from '@elastic/eui'; import { CoreStart } from 'kibana/public'; import type { ExploratoryEmbeddableProps, ExploratoryEmbeddableComponentProps } from './embeddable'; -import { ObservabilityIndexPatterns } from '../utils/observability_index_patterns'; +import { ObservabilityDataViews } from '../../../../utils/observability_data_views'; import { ObservabilityPublicPluginsStart } from '../../../../plugin'; import type { IndexPatternState } from '../hooks/use_app_index_pattern'; import { EuiThemeProvider } from '../../../../../../../../src/plugins/kibana_react/common'; @@ -43,8 +43,8 @@ export function getExploratoryViewEmbeddable( setLoading(true); try { - const obsvIndexP = new ObservabilityIndexPatterns(plugins.data); - const indPattern = await obsvIndexP.getIndexPattern( + const obsvIndexP = new ObservabilityDataViews(plugins.data); + const indPattern = await obsvIndexP.getDataView( dataType, dataTypesIndexPatterns?.[dataType] ); diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/exploratory_view.test.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/exploratory_view.test.tsx index 87ae00b3c72e75..458bcc0ea4a5f9 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/exploratory_view.test.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/exploratory_view.test.tsx @@ -9,7 +9,7 @@ import React from 'react'; import { screen } from '@testing-library/dom'; import { render, mockAppIndexPattern } from './rtl_helpers'; import { ExploratoryView } from './exploratory_view'; -import * as obsvInd from './utils/observability_index_patterns'; +import * as obsvDataViews from '../../../utils/observability_data_views/observability_data_views'; import * as pluginHook from '../../../hooks/use_plugin_context'; import { createStubIndexPattern } from '../../../../../../../src/plugins/data/common/stubs'; @@ -40,8 +40,8 @@ describe('ExploratoryView', () => { }, }); - jest.spyOn(obsvInd, 'ObservabilityIndexPatterns').mockReturnValue({ - getIndexPattern: jest.fn().mockReturnValue(indexPattern), + jest.spyOn(obsvDataViews, 'ObservabilityDataViews').mockReturnValue({ + getDataView: jest.fn().mockReturnValue(indexPattern), } as any); }); diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_app_index_pattern.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_app_index_pattern.tsx index d9c1c28a6a727a..c865d8e6dca5e0 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_app_index_pattern.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/hooks/use_app_index_pattern.tsx @@ -11,7 +11,7 @@ import { IndexPattern } from '../../../../../../../../src/plugins/data/common'; import { AppDataType } from '../types'; import { useKibana } from '../../../../../../../../src/plugins/kibana_react/public'; import { ObservabilityPublicPluginsStart } from '../../../../plugin'; -import { ObservabilityIndexPatterns } from '../utils/observability_index_patterns'; +import { ObservabilityDataViews } from '../../../../utils/observability_data_views'; import { getDataHandler } from '../../../../data_handler'; import { useExploratoryView } from '../contexts/exploratory_view_config'; import { DataViewInsufficientAccessError } from '../../../../../../../../src/plugins/data_views/common'; @@ -83,8 +83,8 @@ export function IndexPatternContextProvider({ children }: ProviderProps) { setHasAppData((prevState) => ({ ...prevState, [dataType]: hasDataT })); if (hasDataT && indices) { - const obsvIndexP = new ObservabilityIndexPatterns(data); - const indPattern = await obsvIndexP.getIndexPattern(dataType, indices); + const obsvIndexP = new ObservabilityDataViews(data); + const indPattern = await obsvIndexP.getDataView(dataType, indices); setIndexPatterns((prevState) => ({ ...prevState, [dataType]: indPattern })); } diff --git a/x-pack/plugins/observability/public/utils/observability_data_views/index.ts b/x-pack/plugins/observability/public/utils/observability_data_views/index.ts new file mode 100644 index 00000000000000..571f5ea4c11a25 --- /dev/null +++ b/x-pack/plugins/observability/public/utils/observability_data_views/index.ts @@ -0,0 +1,8 @@ +/* + * 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 * from './observability_data_views'; diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/utils/observability_index_patterns.test.ts b/x-pack/plugins/observability/public/utils/observability_data_views/observability_data_views.test.ts similarity index 81% rename from x-pack/plugins/observability/public/components/shared/exploratory_view/utils/observability_index_patterns.test.ts rename to x-pack/plugins/observability/public/utils/observability_data_views/observability_data_views.test.ts index a8c5c1a0a3b79e..78899e9cabca0e 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/utils/observability_index_patterns.test.ts +++ b/x-pack/plugins/observability/public/utils/observability_data_views/observability_data_views.test.ts @@ -5,9 +5,9 @@ * 2.0. */ -import { indexPatternList, ObservabilityIndexPatterns } from './observability_index_patterns'; -import { mockCore, mockIndexPattern } from '../rtl_helpers'; -import { SavedObjectNotFound } from '../../../../../../../../src/plugins/kibana_utils/public'; +import { dataViewList, ObservabilityDataViews } from './observability_data_views'; +import { mockCore, mockIndexPattern } from '../../components/shared/exploratory_view/rtl_helpers'; +import { SavedObjectNotFound } from '../../../../../../src/plugins/kibana_utils/public'; const fieldFormats = { 'transaction.duration.us': { @@ -70,13 +70,13 @@ const fieldFormats = { describe('ObservabilityIndexPatterns', function () { const { data } = mockCore(); data!.indexPatterns.get = jest.fn().mockReturnValue({ title: 'index-*' }); - data!.indexPatterns.createAndSave = jest.fn().mockReturnValue({ id: indexPatternList.ux }); + data!.indexPatterns.createAndSave = jest.fn().mockReturnValue({ id: dataViewList.ux }); data!.indexPatterns.updateSavedObject = jest.fn(); it('should return index pattern for app', async function () { - const obsv = new ObservabilityIndexPatterns(data!); + const obsv = new ObservabilityDataViews(data!); - const indexP = await obsv.getIndexPattern('ux', 'heartbeat-8*,synthetics-*'); + const indexP = await obsv.getDataView('ux', 'heartbeat-8*,synthetics-*'); expect(indexP).toEqual({ id: 'rum_static_index_pattern_id' }); @@ -91,13 +91,13 @@ describe('ObservabilityIndexPatterns', function () { throw new SavedObjectNotFound('index_pattern'); }); - data!.indexPatterns.createAndSave = jest.fn().mockReturnValue({ id: indexPatternList.ux }); + data!.indexPatterns.createAndSave = jest.fn().mockReturnValue({ id: dataViewList.ux }); - const obsv = new ObservabilityIndexPatterns(data!); + const obsv = new ObservabilityDataViews(data!); - const indexP = await obsv.getIndexPattern('ux', 'trace-*,apm-*'); + const indexP = await obsv.getDataView('ux', 'trace-*,apm-*'); - expect(indexP).toEqual({ id: indexPatternList.ux }); + expect(indexP).toEqual({ id: dataViewList.ux }); expect(data?.indexPatterns.createAndSave).toHaveBeenCalledWith({ fieldFormats, @@ -110,7 +110,7 @@ describe('ObservabilityIndexPatterns', function () { }); it('should return getFieldFormats', function () { - const obsv = new ObservabilityIndexPatterns(data!); + const obsv = new ObservabilityDataViews(data!); expect(obsv.getFieldFormats('ux')).toEqual(fieldFormats); }); @@ -118,7 +118,7 @@ describe('ObservabilityIndexPatterns', function () { it('should validate field formats', async function () { mockIndexPattern.getFormatterForField = jest.fn().mockReturnValue({ params: () => {} }); - const obsv = new ObservabilityIndexPatterns(data!); + const obsv = new ObservabilityDataViews(data!); await obsv.validateFieldFormats('ux', mockIndexPattern); diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/utils/observability_index_patterns.ts b/x-pack/plugins/observability/public/utils/observability_data_views/observability_data_views.ts similarity index 63% rename from x-pack/plugins/observability/public/components/shared/exploratory_view/utils/observability_index_patterns.ts rename to x-pack/plugins/observability/public/utils/observability_data_views/observability_data_views.ts index b35acaae6fe80c..eb66894772dfd8 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/utils/observability_index_patterns.ts +++ b/x-pack/plugins/observability/public/utils/observability_data_views/observability_data_views.ts @@ -6,18 +6,19 @@ */ import type { FieldFormat as IFieldFormat } from 'src/plugins/field_formats/common'; -import { SavedObjectNotFound } from '../../../../../../../../src/plugins/kibana_utils/public'; +import { SavedObjectNotFound } from '../../../../../../src/plugins/kibana_utils/public'; +import { DataPublicPluginStart } from '../../../../../../src/plugins/data/public'; +import type { DataView, DataViewSpec } from '../../../../../../src/plugins/data/common'; +import { rumFieldFormats } from '../../components/shared/exploratory_view/configurations/rum/field_formats'; +import { syntheticsFieldFormats } from '../../components/shared/exploratory_view/configurations/synthetics/field_formats'; import { - DataPublicPluginStart, - IndexPattern, - IndexPatternSpec, -} from '../../../../../../../../src/plugins/data/public'; -import { rumFieldFormats } from '../configurations/rum/field_formats'; -import { syntheticsFieldFormats } from '../configurations/synthetics/field_formats'; -import { AppDataType, FieldFormat, FieldFormatParams } from '../types'; -import { apmFieldFormats } from '../configurations/apm/field_formats'; -import { getDataHandler } from '../../../../data_handler'; -import { infraMetricsFieldFormats } from '../configurations/infra_metrics/field_formats'; + AppDataType, + FieldFormat, + FieldFormatParams, +} from '../../components/shared/exploratory_view/types'; +import { apmFieldFormats } from '../../components/shared/exploratory_view/configurations/apm/field_formats'; +import { getDataHandler } from '../../data_handler'; +import { infraMetricsFieldFormats } from '../../components/shared/exploratory_view/configurations/infra_metrics/field_formats'; const appFieldFormats: Record = { infra_logs: null, @@ -32,7 +33,7 @@ function getFieldFormatsForApp(app: AppDataType) { return appFieldFormats[app]; } -export const indexPatternList: Record = { +export const dataViewList: Record = { synthetics: 'synthetics_static_index_pattern_id', apm: 'apm_static_index_pattern_id', ux: 'rum_static_index_pattern_id', @@ -54,11 +55,11 @@ const getAppIndicesWithPattern = (app: AppDataType, indices: string) => { return `${appToPatternMap?.[app] ?? app},${indices}`; }; -const getAppIndexPatternId = (app: AppDataType, indices: string) => { +const getAppDataViewId = (app: AppDataType, indices: string) => { // Replace characters / ? , " < > | * with _ const postfix = indices.replace(/[^A-Z0-9]+/gi, '_').toLowerCase(); - return `${indexPatternList?.[app] ?? app}_${postfix}`; + return `${dataViewList?.[app] ?? app}_${postfix}`; }; export function isParamsSame(param1: IFieldFormat['_params'], param2: FieldFormatParams) { @@ -75,50 +76,50 @@ export function isParamsSame(param1: IFieldFormat['_params'], param2: FieldForma return isSame; } -export class ObservabilityIndexPatterns { +export class ObservabilityDataViews { data?: DataPublicPluginStart; constructor(data: DataPublicPluginStart) { this.data = data; } - async createIndexPattern(app: AppDataType, indices: string) { + async createDataView(app: AppDataType, indices: string) { if (!this.data) { throw new Error('data is not defined'); } const appIndicesPattern = getAppIndicesWithPattern(app, indices); - return await this.data.indexPatterns.createAndSave({ + return await this.data.dataViews.createAndSave({ title: appIndicesPattern, - id: getAppIndexPatternId(app, indices), + id: getAppDataViewId(app, indices), timeFieldName: '@timestamp', fieldFormats: this.getFieldFormats(app), }); } // we want to make sure field formats remain same - async validateFieldFormats(app: AppDataType, indexPattern: IndexPattern) { + async validateFieldFormats(app: AppDataType, dataView: DataView) { const defaultFieldFormats = getFieldFormatsForApp(app); if (defaultFieldFormats && defaultFieldFormats.length > 0) { let isParamsDifferent = false; defaultFieldFormats.forEach(({ field, format }) => { - const fieldByName = indexPattern.getFieldByName(field); + const fieldByName = dataView.getFieldByName(field); if (fieldByName) { - const fieldFormat = indexPattern.getFormatterForField(fieldByName); + const fieldFormat = dataView.getFormatterForField(fieldByName); const params = fieldFormat.params(); if (!isParamsSame(params, format.params) || format.id !== fieldFormat.type.id) { - indexPattern.setFieldFormat(field, format); + dataView.setFieldFormat(field, format); isParamsDifferent = true; } } }); if (isParamsDifferent) { - await this.data?.indexPatterns.updateSavedObject(indexPattern); + await this.data?.dataViews.updateSavedObject(dataView); } } } getFieldFormats(app: AppDataType) { - const fieldFormatMap: IndexPatternSpec['fieldFormats'] = {}; + const fieldFormatMap: DataViewSpec['fieldFormats'] = {}; (appFieldFormats?.[app] ?? []).forEach(({ field, format }) => { fieldFormatMap[field] = format; @@ -140,7 +141,7 @@ export class ObservabilityIndexPatterns { } } - async getIndexPattern(app: AppDataType, indices?: string): Promise { + async getDataView(app: AppDataType, indices?: string): Promise { if (!this.data) { throw new Error('data is not defined'); } @@ -151,22 +152,22 @@ export class ObservabilityIndexPatterns { if (appIndices) { try { - const indexPatternId = getAppIndexPatternId(app, appIndices); - const indexPatternTitle = getAppIndicesWithPattern(app, appIndices); - // we will get index pattern by id - const indexPattern = await this.data?.indexPatterns.get(indexPatternId); + const dataViewId = getAppDataViewId(app, appIndices); + const dataViewTitle = getAppIndicesWithPattern(app, appIndices); + // we will get the data view by id + const dataView = await this.data?.indexPatterns.get(dataViewId); // and make sure title matches, otherwise, we will need to create it - if (indexPattern.title !== indexPatternTitle) { - return await this.createIndexPattern(app, appIndices); + if (dataView.title !== dataViewTitle) { + return await this.createDataView(app, appIndices); } // this is intentional a non blocking call, so no await clause - this.validateFieldFormats(app, indexPattern); - return indexPattern; + this.validateFieldFormats(app, dataView); + return dataView; } catch (e: unknown) { if (e instanceof SavedObjectNotFound) { - return await this.createIndexPattern(app, appIndices); + return await this.createDataView(app, appIndices); } } } From 8ac8d6910ccba857eef89c93ed87d555e2bf7530 Mon Sep 17 00:00:00 2001 From: Nicolas Chaulet Date: Tue, 18 Jan 2022 11:19:43 -0500 Subject: [PATCH 008/108] [Fleet] Fix hide enrollment key tooltip (#123188) --- .../sections/agents/enrollment_token_list_page/index.tsx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/enrollment_token_list_page/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/enrollment_token_list_page/index.tsx index 72160fb4ae8973..2dd323b9b52c1e 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/enrollment_token_list_page/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/enrollment_token_list_page/index.tsx @@ -96,7 +96,6 @@ const ApiKeyField: React.FunctionComponent<{ apiKeyId: string }> = ({ apiKeyId } }) } color="text" - isDisabled={state === 'LOADING'} onClick={toggleKey} iconType={state === 'VISIBLE' ? 'eyeClosed' : 'eye'} /> @@ -269,6 +268,10 @@ export const EnrollmentTokenListPage: React.FunctionComponent<{}> = () => { }, ]; + const isLoading = + (enrollmentAPIKeysRequest.isLoading && enrollmentAPIKeysRequest.isInitialRequest) || + (agentPoliciesRequest.isLoading && agentPoliciesRequest.isInitialRequest); + return ( {isModalOpen && ( @@ -312,10 +315,10 @@ export const EnrollmentTokenListPage: React.FunctionComponent<{}> = () => { - loading={enrollmentAPIKeysRequest.isLoading && enrollmentAPIKeysRequest.isInitialRequest} + loading={isLoading} hasActions={true} noItemsMessage={ - enrollmentAPIKeysRequest.isLoading && enrollmentAPIKeysRequest.isInitialRequest ? ( + isLoading ? ( Date: Tue, 18 Jan 2022 10:20:51 -0600 Subject: [PATCH 009/108] [DOCS] Updates the CentOS base image to Ubuntu (#123242) --- docs/setup/docker.asciidoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/setup/docker.asciidoc b/docs/setup/docker.asciidoc index df140dbd00b701..3128ff98269fa3 100644 --- a/docs/setup/docker.asciidoc +++ b/docs/setup/docker.asciidoc @@ -5,7 +5,7 @@ ++++ Docker images for {kib} are available from the Elastic Docker registry. The -base image is https://hub.docker.com/_/kibana[kibana]. +base image is https://hub.docker.com/_/ubuntu[ubuntu:20.04]. A list of all published Docker images and tags is available at https://www.docker.elastic.co[www.docker.elastic.co]. The source code is in From 564596376d7013ca6aa9c6c878a149086b3b4358 Mon Sep 17 00:00:00 2001 From: Dima Arnautov Date: Tue, 18 Jan 2022 17:51:17 +0100 Subject: [PATCH 010/108] [ML] Fix breadcrumbs inconsistencies and titles capitalisation (#123019) * fix model management breadcrumbs * fix anomaly detection breadcrumbs * fix dfa breadcrumbs * add data vis side nav items * fix i18n * change data vis cards titles * fix data view data vis breadcrumbs * match tab names with page header * update i18n * model management fixes * make the last element of the breadcrumbs disabled * highlight active side nav element for nested routed * update data vis page text * remove unused translation --- .../components/ml_page/ml_page.tsx | 2 +- .../components/ml_page/side_nav.tsx | 42 +++++++++++++++++-- .../pages/analytics_management/page.tsx | 2 +- .../datavisualizer_selector.tsx | 11 ++--- .../application/jobs/jobs_list/jobs.tsx | 2 +- .../public/application/routing/breadcrumbs.ts | 16 ++++--- .../analytics_job_creation.tsx | 8 ++-- .../analytics_job_exploration.tsx | 1 - .../analytics_jobs_list.tsx | 9 +--- .../routes/datavisualizer/datavisualizer.tsx | 2 +- .../routes/datavisualizer/index_based.tsx | 6 +-- .../application/routing/routes/jobs_list.tsx | 8 +--- .../routes/new_job/index_or_search.tsx | 16 ++++++- .../application/routing/routes/overview.tsx | 3 +- .../routing/routes/settings/calendar_list.tsx | 3 +- .../routes/settings/calendar_new_edit.tsx | 5 +-- .../routing/routes/settings/filter_list.tsx | 3 +- .../routes/settings/filter_list_new_edit.tsx | 6 +-- .../routing/routes/settings/settings.tsx | 3 +- .../routes/trained_models/models_list.tsx | 9 +--- .../routes/trained_models/nodes_list.tsx | 9 +--- .../models_management/models_list.tsx | 26 ------------ .../trained_models/navigation_bar.tsx | 4 +- .../application/trained_models/page.tsx | 42 ++++++++++++++----- .../translations/translations/ja-JP.json | 5 --- .../translations/translations/zh-CN.json | 5 --- 26 files changed, 124 insertions(+), 124 deletions(-) diff --git a/x-pack/plugins/ml/public/application/components/ml_page/ml_page.tsx b/x-pack/plugins/ml/public/application/components/ml_page/ml_page.tsx index d399409f95c9ba..f7f715a598c94a 100644 --- a/x-pack/plugins/ml/public/application/components/ml_page/ml_page.tsx +++ b/x-pack/plugins/ml/public/application/components/ml_page/ml_page.tsx @@ -98,7 +98,7 @@ export const MlPage: FC<{ pageDeps: PageDependencies }> = React.memo(({ pageDeps { id: '', name: '', - items: useSideNavItems(activeRoute.id), + items: useSideNavItems(activeRoute), }, ], }} diff --git a/x-pack/plugins/ml/public/application/components/ml_page/side_nav.tsx b/x-pack/plugins/ml/public/application/components/ml_page/side_nav.tsx index 6bb410668c6ac8..bb0092621c04b9 100644 --- a/x-pack/plugins/ml/public/application/components/ml_page/side_nav.tsx +++ b/x-pack/plugins/ml/public/application/components/ml_page/side_nav.tsx @@ -13,6 +13,7 @@ import { useUrlState } from '../../util/url_state'; import { useMlKibana, useMlLocator, useNavigateToPath } from '../../contexts/kibana'; import { isFullLicense } from '../../license'; import { ML_APP_NAME } from '../../../../common/constants/app'; +import type { MlRoute } from '../../routing'; export type TabId = | 'access-denied' @@ -20,12 +21,14 @@ export type TabId = | 'data_frame_analytics' | 'trained_models' | 'datavisualizer' + | 'data_view_datavisualizer' + | 'filedatavisualizer' | 'overview' | 'settings'; export interface Tab { id: TabId; - name: any; + name: string; disabled: boolean; betaTag?: JSX.Element; items?: Tab[]; @@ -76,6 +79,22 @@ function getTabs(disableLinks: boolean): Tab[] { defaultMessage: 'Data Visualizer', }), disabled: false, + items: [ + { + id: 'filedatavisualizer', + name: i18n.translate('xpack.ml.navMenu.fileDataVisualizerLinkText', { + defaultMessage: 'File', + }), + disabled: false, + }, + { + id: 'data_view_datavisualizer', + name: i18n.translate('xpack.ml.navMenu.dataViewDataVisualizerLinkText', { + defaultMessage: 'Data View', + }), + disabled: false, + }, + ], }, ]; } @@ -119,6 +138,20 @@ export const TAB_DATA: Record = { defaultMessage: 'Data Visualizer', }), }, + data_view_datavisualizer: { + testSubject: 'mlMainTab dataVisualizer dataViewDatavisualizer', + name: i18n.translate('xpack.ml.dataViewDataVisualizerTabLabel', { + defaultMessage: 'Data View', + }), + pathId: 'datavisualizer_index_select', + }, + filedatavisualizer: { + testSubject: 'mlMainTab dataVisualizer fileDatavisualizer', + name: i18n.translate('xpack.ml.fileDataVisualizerTabLabel', { + defaultMessage: 'File', + }), + pathId: 'filedatavisualizer', + }, settings: { testSubject: 'mlMainTab settings', name: i18n.translate('xpack.ml.settingsTabLabel', { @@ -133,7 +166,8 @@ export const TAB_DATA: Record = { }, }; -export function useSideNavItems(activeRouteId: string | undefined) { +export function useSideNavItems(activeRoute: MlRoute | undefined) { + const activeRouteId = activeRoute?.id; const { services: { chrome: { docTitle }, @@ -174,7 +208,7 @@ export function useSideNavItems(activeRouteId: string | undefined) { const tabs = getTabs(!isFullLicense()); - function getTabItem(tab: Tab): EuiSideNavItemType { + function getTabItem(tab: Tab): EuiSideNavItemType { const { id, disabled, items } = tab; const testSubject = TAB_DATA[id].testSubject; const defaultPathId = (TAB_DATA[id].pathId || id) as MlLocatorParams['page']; @@ -182,7 +216,7 @@ export function useSideNavItems(activeRouteId: string | undefined) { return { id, name: tab.name, - isSelected: id === activeRouteId, + isSelected: id === activeRouteId || activeRoute?.path.includes(`${id}/`), disabled, onClick: () => { redirectToTab(defaultPathId); diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/page.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/page.tsx index 1356fe180fe202..59767216b79e87 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/page.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/page.tsx @@ -59,7 +59,7 @@ export const Page: FC = () => { diff --git a/x-pack/plugins/ml/public/application/datavisualizer/datavisualizer_selector.tsx b/x-pack/plugins/ml/public/application/datavisualizer/datavisualizer_selector.tsx index dc48d71a7d492d..4ddf3b8e4810ec 100644 --- a/x-pack/plugins/ml/public/application/datavisualizer/datavisualizer_selector.tsx +++ b/x-pack/plugins/ml/public/application/datavisualizer/datavisualizer_selector.tsx @@ -102,7 +102,7 @@ export const DatavisualizerSelector: FC = () => { title={ } description={ @@ -134,15 +134,10 @@ export const DatavisualizerSelector: FC = () => { title={ - } - description={ - } + description={''} footer={ = (props) => { return ( <> - + diff --git a/x-pack/plugins/ml/public/application/routing/breadcrumbs.ts b/x-pack/plugins/ml/public/application/routing/breadcrumbs.ts index ad11c879b29183..051371f6ae8342 100644 --- a/x-pack/plugins/ml/public/application/routing/breadcrumbs.ts +++ b/x-pack/plugins/ml/public/application/routing/breadcrumbs.ts @@ -42,8 +42,8 @@ export const DATA_FRAME_ANALYTICS_BREADCRUMB: ChromeBreadcrumb = Object.freeze({ }); export const TRAINED_MODELS: ChromeBreadcrumb = Object.freeze({ - text: i18n.translate('xpack.ml.trainedModelsLabel', { - defaultMessage: 'Trained Models', + text: i18n.translate('xpack.ml.modelManagementLabel', { + defaultMessage: 'Model Management', }), href: '/trained_models', }); @@ -101,12 +101,16 @@ export const breadcrumbOnClickFactory = ( export const getBreadcrumbWithUrlForApp = ( breadcrumbName: Breadcrumb, - navigateToPath: NavigateToPath, - basePath: string + navigateToPath?: NavigateToPath, + basePath?: string ): EuiBreadcrumb => { return { text: breadcrumbs[breadcrumbName].text, - href: `${basePath}/app/ml${breadcrumbs[breadcrumbName].href}`, - onClick: breadcrumbOnClickFactory(breadcrumbs[breadcrumbName].href, navigateToPath), + ...(navigateToPath && basePath + ? { + href: `${basePath}/app/ml${breadcrumbs[breadcrumbName].href}`, + onClick: breadcrumbOnClickFactory(breadcrumbs[breadcrumbName].href, navigateToPath), + } + : {}), }; }; diff --git a/x-pack/plugins/ml/public/application/routing/routes/data_frame_analytics/analytics_job_creation.tsx b/x-pack/plugins/ml/public/application/routing/routes/data_frame_analytics/analytics_job_creation.tsx index e550eaa338b08b..335b041c816a4e 100644 --- a/x-pack/plugins/ml/public/application/routing/routes/data_frame_analytics/analytics_job_creation.tsx +++ b/x-pack/plugins/ml/public/application/routing/routes/data_frame_analytics/analytics_job_creation.tsx @@ -16,7 +16,7 @@ import { MlRoute, PageLoader, PageProps } from '../../router'; import { useResolver } from '../../use_resolver'; import { basicResolvers } from '../../resolvers'; import { Page } from '../../../data_frame_analytics/pages/analytics_creation'; -import { breadcrumbOnClickFactory, getBreadcrumbWithUrlForApp } from '../../breadcrumbs'; +import { getBreadcrumbWithUrlForApp } from '../../breadcrumbs'; import { loadNewJobCapabilities, DATA_FRAME_ANALYTICS, @@ -30,11 +30,11 @@ export const analyticsJobsCreationRouteFactory = ( render: (props, deps) => , breadcrumbs: [ getBreadcrumbWithUrlForApp('ML_BREADCRUMB', navigateToPath, basePath), + getBreadcrumbWithUrlForApp('DATA_FRAME_ANALYTICS_BREADCRUMB', navigateToPath, basePath), { - text: i18n.translate('xpack.ml.dataFrameAnalyticsBreadcrumbs.dataFrameManagementLabel', { - defaultMessage: 'Data Frame Analytics', + text: i18n.translate('xpack.ml.dataFrameAnalyticsBreadcrumbs.dataFrameCreationLabel', { + defaultMessage: 'Create job', }), - onClick: breadcrumbOnClickFactory('/data_frame_analytics', navigateToPath), }, ], }); diff --git a/x-pack/plugins/ml/public/application/routing/routes/data_frame_analytics/analytics_job_exploration.tsx b/x-pack/plugins/ml/public/application/routing/routes/data_frame_analytics/analytics_job_exploration.tsx index 49a756fd12ced5..88502bd86f08cf 100644 --- a/x-pack/plugins/ml/public/application/routing/routes/data_frame_analytics/analytics_job_exploration.tsx +++ b/x-pack/plugins/ml/public/application/routing/routes/data_frame_analytics/analytics_job_exploration.tsx @@ -33,7 +33,6 @@ export const analyticsJobExplorationRouteFactory = ( text: i18n.translate('xpack.ml.dataFrameAnalyticsBreadcrumbs.dataFrameExplorationLabel', { defaultMessage: 'Exploration', }), - href: '', }, ], }); diff --git a/x-pack/plugins/ml/public/application/routing/routes/data_frame_analytics/analytics_jobs_list.tsx b/x-pack/plugins/ml/public/application/routing/routes/data_frame_analytics/analytics_jobs_list.tsx index 6e645e2373dc1d..b62cd749243a4c 100644 --- a/x-pack/plugins/ml/public/application/routing/routes/data_frame_analytics/analytics_jobs_list.tsx +++ b/x-pack/plugins/ml/public/application/routing/routes/data_frame_analytics/analytics_jobs_list.tsx @@ -6,7 +6,6 @@ */ import React, { FC } from 'react'; -import { i18n } from '@kbn/i18n'; import { NavigateToPath } from '../../../contexts/kibana'; @@ -25,13 +24,7 @@ export const analyticsJobsListRouteFactory = ( render: (props, deps) => , breadcrumbs: [ getBreadcrumbWithUrlForApp('ML_BREADCRUMB', navigateToPath, basePath), - getBreadcrumbWithUrlForApp('DATA_FRAME_ANALYTICS_BREADCRUMB', navigateToPath, basePath), - { - text: i18n.translate('xpack.ml.dataFrameAnalyticsBreadcrumbs.dataFrameListLabel', { - defaultMessage: 'Job Management', - }), - href: '', - }, + getBreadcrumbWithUrlForApp('DATA_FRAME_ANALYTICS_BREADCRUMB'), ], 'data-test-subj': 'mlPageDataFrameAnalytics', enableDatePicker: true, diff --git a/x-pack/plugins/ml/public/application/routing/routes/datavisualizer/datavisualizer.tsx b/x-pack/plugins/ml/public/application/routing/routes/datavisualizer/datavisualizer.tsx index 1ff37ebe52f1b2..c45d5f94c238f1 100644 --- a/x-pack/plugins/ml/public/application/routing/routes/datavisualizer/datavisualizer.tsx +++ b/x-pack/plugins/ml/public/application/routing/routes/datavisualizer/datavisualizer.tsx @@ -26,7 +26,7 @@ export const selectorRouteFactory = ( render: (props, deps) => , breadcrumbs: [ getBreadcrumbWithUrlForApp('ML_BREADCRUMB', navigateToPath, basePath), - getBreadcrumbWithUrlForApp('DATA_VISUALIZER_BREADCRUMB', navigateToPath, basePath), + getBreadcrumbWithUrlForApp('DATA_VISUALIZER_BREADCRUMB'), ], }); diff --git a/x-pack/plugins/ml/public/application/routing/routes/datavisualizer/index_based.tsx b/x-pack/plugins/ml/public/application/routing/routes/datavisualizer/index_based.tsx index b94ee5882ca285..1ae2445e19a1c1 100644 --- a/x-pack/plugins/ml/public/application/routing/routes/datavisualizer/index_based.tsx +++ b/x-pack/plugins/ml/public/application/routing/routes/datavisualizer/index_based.tsx @@ -25,15 +25,15 @@ export const indexBasedRouteFactory = ( navigateToPath: NavigateToPath, basePath: string ): MlRoute => ({ - id: 'datavisualizer', + id: 'data_view_datavisualizer', path: '/jobs/new_job/datavisualizer', render: (props, deps) => , breadcrumbs: [ getBreadcrumbWithUrlForApp('ML_BREADCRUMB', navigateToPath, basePath), getBreadcrumbWithUrlForApp('DATA_VISUALIZER_BREADCRUMB', navigateToPath, basePath), { - text: i18n.translate('xpack.ml.dataFrameAnalyticsBreadcrumbs.indexLabel', { - defaultMessage: 'Index', + text: i18n.translate('xpack.ml.dataFrameAnalyticsBreadcrumbs.dataViewLabel', { + defaultMessage: 'Data View', }), href: '', }, diff --git a/x-pack/plugins/ml/public/application/routing/routes/jobs_list.tsx b/x-pack/plugins/ml/public/application/routing/routes/jobs_list.tsx index b3e1208871f951..9b4f020ca1fc33 100644 --- a/x-pack/plugins/ml/public/application/routing/routes/jobs_list.tsx +++ b/x-pack/plugins/ml/public/application/routing/routes/jobs_list.tsx @@ -32,13 +32,7 @@ export const jobListRouteFactory = (navigateToPath: NavigateToPath, basePath: st render: (props, deps) => , breadcrumbs: [ getBreadcrumbWithUrlForApp('ML_BREADCRUMB', navigateToPath, basePath), - getBreadcrumbWithUrlForApp('ANOMALY_DETECTION_BREADCRUMB', navigateToPath, basePath), - { - text: i18n.translate('xpack.ml.anomalyDetection.jobManagementLabel', { - defaultMessage: 'Job Management', - }), - href: '', - }, + getBreadcrumbWithUrlForApp('ANOMALY_DETECTION_BREADCRUMB'), ], 'data-test-subj': 'mlPageJobManagement', enableDatePicker: true, diff --git a/x-pack/plugins/ml/public/application/routing/routes/new_job/index_or_search.tsx b/x-pack/plugins/ml/public/application/routing/routes/new_job/index_or_search.tsx index e92bac32debcbd..69246ad69965a1 100644 --- a/x-pack/plugins/ml/public/application/routing/routes/new_job/index_or_search.tsx +++ b/x-pack/plugins/ml/public/application/routing/routes/new_job/index_or_search.tsx @@ -34,13 +34,24 @@ const getBreadcrumbs = (navigateToPath: NavigateToPath, basePath: string) => [ getBreadcrumbWithUrlForApp('ML_BREADCRUMB', navigateToPath, basePath), getBreadcrumbWithUrlForApp('ANOMALY_DETECTION_BREADCRUMB', navigateToPath, basePath), { - text: i18n.translate('xpack.ml.jobsBreadcrumbs.selectIndexOrSearchLabel', { + text: i18n.translate('xpack.ml.jobsBreadcrumbs.createJobLabel', { defaultMessage: 'Create job', }), href: '', }, ]; +const getDataVisBreadcrumbs = (navigateToPath: NavigateToPath, basePath: string) => [ + getBreadcrumbWithUrlForApp('ML_BREADCRUMB', navigateToPath, basePath), + getBreadcrumbWithUrlForApp('DATA_VISUALIZER_BREADCRUMB', navigateToPath, basePath), + { + text: i18n.translate('xpack.ml.jobsBreadcrumbs.selectDateViewLabel', { + defaultMessage: 'Data View', + }), + href: '', + }, +]; + export const indexOrSearchRouteFactory = ( navigateToPath: NavigateToPath, basePath: string @@ -61,6 +72,7 @@ export const dataVizIndexOrSearchRouteFactory = ( navigateToPath: NavigateToPath, basePath: string ): MlRoute => ({ + id: 'data_view_datavisualizer', path: '/datavisualizer_index_select', render: (props, deps) => ( ), - breadcrumbs: getBreadcrumbs(navigateToPath, basePath), + breadcrumbs: getDataVisBreadcrumbs(navigateToPath, basePath), }); const PageWrapper: FC = ({ nextStepPath, deps, mode }) => { diff --git a/x-pack/plugins/ml/public/application/routing/routes/overview.tsx b/x-pack/plugins/ml/public/application/routing/routes/overview.tsx index 1e3c3c595e6d9b..1a954f72f17e46 100644 --- a/x-pack/plugins/ml/public/application/routing/routes/overview.tsx +++ b/x-pack/plugins/ml/public/application/routing/routes/overview.tsx @@ -20,7 +20,7 @@ import { checkGetJobsCapabilitiesResolver } from '../../capabilities/check_capab import { getMlNodeCount } from '../../ml_nodes_check'; import { loadMlServerInfo } from '../../services/ml_server_info'; import { useTimefilter } from '../../contexts/kibana'; -import { breadcrumbOnClickFactory, getBreadcrumbWithUrlForApp } from '../breadcrumbs'; +import { getBreadcrumbWithUrlForApp } from '../breadcrumbs'; const OverviewPage = React.lazy(() => import('../../overview/overview_page')); @@ -41,7 +41,6 @@ export const overviewRouteFactory = ( text: i18n.translate('xpack.ml.overview.overviewLabel', { defaultMessage: 'Overview', }), - onClick: breadcrumbOnClickFactory('/overview', navigateToPath), }, ], 'data-test-subj': 'mlPageOverview', diff --git a/x-pack/plugins/ml/public/application/routing/routes/settings/calendar_list.tsx b/x-pack/plugins/ml/public/application/routing/routes/settings/calendar_list.tsx index 08949d5d514b2b..c70bf6529f6b15 100644 --- a/x-pack/plugins/ml/public/application/routing/routes/settings/calendar_list.tsx +++ b/x-pack/plugins/ml/public/application/routing/routes/settings/calendar_list.tsx @@ -30,8 +30,9 @@ export const calendarListRouteFactory = ( render: (props, deps) => , breadcrumbs: [ getBreadcrumbWithUrlForApp('ML_BREADCRUMB', navigateToPath, basePath), + getBreadcrumbWithUrlForApp('ANOMALY_DETECTION_BREADCRUMB', navigateToPath, basePath), getBreadcrumbWithUrlForApp('SETTINGS_BREADCRUMB', navigateToPath, basePath), - getBreadcrumbWithUrlForApp('CALENDAR_MANAGEMENT_BREADCRUMB', navigateToPath, basePath), + getBreadcrumbWithUrlForApp('CALENDAR_MANAGEMENT_BREADCRUMB'), ], }); diff --git a/x-pack/plugins/ml/public/application/routing/routes/settings/calendar_new_edit.tsx b/x-pack/plugins/ml/public/application/routing/routes/settings/calendar_new_edit.tsx index 05f9f92479f45c..ba5c9cf5a337bf 100644 --- a/x-pack/plugins/ml/public/application/routing/routes/settings/calendar_new_edit.tsx +++ b/x-pack/plugins/ml/public/application/routing/routes/settings/calendar_new_edit.tsx @@ -21,7 +21,7 @@ import { } from '../../../capabilities/check_capabilities'; import { checkMlNodesAvailable } from '../../../ml_nodes_check/check_ml_nodes'; import { NewCalendar } from '../../../settings/calendars'; -import { breadcrumbOnClickFactory, getBreadcrumbWithUrlForApp } from '../../breadcrumbs'; +import { getBreadcrumbWithUrlForApp } from '../../breadcrumbs'; import { useCreateAndNavigateToMlLink } from '../../../contexts/kibana/use_create_url'; import { ML_PAGES } from '../../../../../common/constants/locator'; @@ -42,13 +42,13 @@ export const newCalendarRouteFactory = ( render: (props, deps) => , breadcrumbs: [ getBreadcrumbWithUrlForApp('ML_BREADCRUMB', navigateToPath, basePath), + getBreadcrumbWithUrlForApp('ANOMALY_DETECTION_BREADCRUMB', navigateToPath, basePath), getBreadcrumbWithUrlForApp('SETTINGS_BREADCRUMB', navigateToPath, basePath), getBreadcrumbWithUrlForApp('CALENDAR_MANAGEMENT_BREADCRUMB', navigateToPath, basePath), { text: i18n.translate('xpack.ml.settings.breadcrumbs.calendarManagement.createLabel', { defaultMessage: 'Create', }), - onClick: breadcrumbOnClickFactory('/settings/calendars_list/new_calendar', navigateToPath), }, ], }); @@ -67,7 +67,6 @@ export const editCalendarRouteFactory = ( text: i18n.translate('xpack.ml.settings.breadcrumbs.calendarManagement.editLabel', { defaultMessage: 'Edit', }), - onClick: breadcrumbOnClickFactory('/settings/calendars_list/edit_calendar', navigateToPath), }, ], }); diff --git a/x-pack/plugins/ml/public/application/routing/routes/settings/filter_list.tsx b/x-pack/plugins/ml/public/application/routing/routes/settings/filter_list.tsx index 8e956ecf59d5d5..11599f01e74b9f 100644 --- a/x-pack/plugins/ml/public/application/routing/routes/settings/filter_list.tsx +++ b/x-pack/plugins/ml/public/application/routing/routes/settings/filter_list.tsx @@ -31,8 +31,9 @@ export const filterListRouteFactory = ( render: (props, deps) => , breadcrumbs: [ getBreadcrumbWithUrlForApp('ML_BREADCRUMB', navigateToPath, basePath), + getBreadcrumbWithUrlForApp('ANOMALY_DETECTION_BREADCRUMB', navigateToPath, basePath), getBreadcrumbWithUrlForApp('SETTINGS_BREADCRUMB', navigateToPath, basePath), - getBreadcrumbWithUrlForApp('FILTER_LISTS_BREADCRUMB', navigateToPath, basePath), + getBreadcrumbWithUrlForApp('FILTER_LISTS_BREADCRUMB'), ], }); diff --git a/x-pack/plugins/ml/public/application/routing/routes/settings/filter_list_new_edit.tsx b/x-pack/plugins/ml/public/application/routing/routes/settings/filter_list_new_edit.tsx index cf320632106242..0c372e58e2f98a 100644 --- a/x-pack/plugins/ml/public/application/routing/routes/settings/filter_list_new_edit.tsx +++ b/x-pack/plugins/ml/public/application/routing/routes/settings/filter_list_new_edit.tsx @@ -22,7 +22,7 @@ import { import { checkMlNodesAvailable } from '../../../ml_nodes_check/check_ml_nodes'; import { EditFilterList } from '../../../settings/filter_lists'; -import { breadcrumbOnClickFactory, getBreadcrumbWithUrlForApp } from '../../breadcrumbs'; +import { getBreadcrumbWithUrlForApp } from '../../breadcrumbs'; import { useCreateAndNavigateToMlLink } from '../../../contexts/kibana/use_create_url'; import { ML_PAGES } from '../../../../../common/constants/locator'; @@ -43,14 +43,13 @@ export const newFilterListRouteFactory = ( render: (props, deps) => , breadcrumbs: [ getBreadcrumbWithUrlForApp('ML_BREADCRUMB', navigateToPath, basePath), + getBreadcrumbWithUrlForApp('ANOMALY_DETECTION_BREADCRUMB', navigateToPath, basePath), getBreadcrumbWithUrlForApp('SETTINGS_BREADCRUMB', navigateToPath, basePath), getBreadcrumbWithUrlForApp('FILTER_LISTS_BREADCRUMB', navigateToPath, basePath), - { text: i18n.translate('xpack.ml.settings.breadcrumbs.filterLists.createLabel', { defaultMessage: 'Create', }), - onClick: breadcrumbOnClickFactory('/settings/filter_lists/new', navigateToPath), }, ], }); @@ -69,7 +68,6 @@ export const editFilterListRouteFactory = ( text: i18n.translate('xpack.ml.settings.breadcrumbs.filterLists.editLabel', { defaultMessage: 'Edit', }), - onClick: breadcrumbOnClickFactory('/settings/filter_lists/edit', navigateToPath), }, ], }); diff --git a/x-pack/plugins/ml/public/application/routing/routes/settings/settings.tsx b/x-pack/plugins/ml/public/application/routing/routes/settings/settings.tsx index b3dc387975a083..2611674f0d8690 100644 --- a/x-pack/plugins/ml/public/application/routing/routes/settings/settings.tsx +++ b/x-pack/plugins/ml/public/application/routing/routes/settings/settings.tsx @@ -31,7 +31,8 @@ export const settingsRouteFactory = ( render: (props, deps) => , breadcrumbs: [ getBreadcrumbWithUrlForApp('ML_BREADCRUMB', navigateToPath, basePath), - getBreadcrumbWithUrlForApp('SETTINGS_BREADCRUMB', navigateToPath, basePath), + getBreadcrumbWithUrlForApp('ANOMALY_DETECTION_BREADCRUMB', navigateToPath, basePath), + getBreadcrumbWithUrlForApp('SETTINGS_BREADCRUMB'), ], }); diff --git a/x-pack/plugins/ml/public/application/routing/routes/trained_models/models_list.tsx b/x-pack/plugins/ml/public/application/routing/routes/trained_models/models_list.tsx index 1166afb36055d5..0231bca003c876 100644 --- a/x-pack/plugins/ml/public/application/routing/routes/trained_models/models_list.tsx +++ b/x-pack/plugins/ml/public/application/routing/routes/trained_models/models_list.tsx @@ -6,7 +6,6 @@ */ import React, { FC } from 'react'; -import { i18n } from '@kbn/i18n'; import { NavigateToPath } from '../../../contexts/kibana'; import { MlRoute, PageLoader, PageProps } from '../../router'; @@ -24,13 +23,7 @@ export const modelsListRouteFactory = ( render: (props, deps) => , breadcrumbs: [ getBreadcrumbWithUrlForApp('ML_BREADCRUMB', navigateToPath, basePath), - getBreadcrumbWithUrlForApp('TRAINED_MODELS', navigateToPath, basePath), - { - text: i18n.translate('xpack.ml.trainedModelsBreadcrumbs.modelsListLabel', { - defaultMessage: 'Model Management', - }), - href: '', - }, + getBreadcrumbWithUrlForApp('TRAINED_MODELS'), ], enableDatePicker: true, 'data-test-subj': 'mlPageModelManagement', diff --git a/x-pack/plugins/ml/public/application/routing/routes/trained_models/nodes_list.tsx b/x-pack/plugins/ml/public/application/routing/routes/trained_models/nodes_list.tsx index a6f4b4a7ff18a6..2a09aff7c42add 100644 --- a/x-pack/plugins/ml/public/application/routing/routes/trained_models/nodes_list.tsx +++ b/x-pack/plugins/ml/public/application/routing/routes/trained_models/nodes_list.tsx @@ -6,7 +6,6 @@ */ import React, { FC } from 'react'; -import { i18n } from '@kbn/i18n'; import { NavigateToPath, useTimefilter } from '../../../contexts/kibana'; @@ -24,13 +23,7 @@ export const nodesListRouteFactory = ( render: (props, deps) => , breadcrumbs: [ getBreadcrumbWithUrlForApp('ML_BREADCRUMB', navigateToPath, basePath), - getBreadcrumbWithUrlForApp('TRAINED_MODELS', navigateToPath, basePath), - { - text: i18n.translate('xpack.ml.trainedModelsBreadcrumbs.nodesListLabel', { - defaultMessage: 'Nodes Overview', - }), - href: '', - }, + getBreadcrumbWithUrlForApp('TRAINED_MODELS'), ], enableDatePicker: true, }); diff --git a/x-pack/plugins/ml/public/application/trained_models/models_management/models_list.tsx b/x-pack/plugins/ml/public/application/trained_models/models_management/models_list.tsx index 8b387e60ffce74..8bafabf35e1d5f 100644 --- a/x-pack/plugins/ml/public/application/trained_models/models_management/models_list.tsx +++ b/x-pack/plugins/ml/public/application/trained_models/models_management/models_list.tsx @@ -8,7 +8,6 @@ import React, { FC, useCallback, useEffect, useMemo, useState } from 'react'; import { EuiBadge, - EuiBetaBadge, EuiButton, EuiButtonIcon, EuiFlexGroup, @@ -50,7 +49,6 @@ import { FIELD_FORMAT_IDS } from '../../../../../../../src/plugins/field_formats import { useRefresh } from '../../routing/use_refresh'; import { DEPLOYMENT_STATE } from '../../../../common/constants/trained_models'; import { getUserConfirmationProvider } from './force_stop_dialog'; -import { MlPageHeader } from '../../components/page_header'; type Stats = Omit; @@ -687,30 +685,6 @@ export const ModelsList: FC = () => { return ( <> - - - - - - - - - - {modelsStats && ( diff --git a/x-pack/plugins/ml/public/application/trained_models/navigation_bar.tsx b/x-pack/plugins/ml/public/application/trained_models/navigation_bar.tsx index ec91499bdb7223..f32748e5d0c996 100644 --- a/x-pack/plugins/ml/public/application/trained_models/navigation_bar.tsx +++ b/x-pack/plugins/ml/public/application/trained_models/navigation_bar.tsx @@ -29,7 +29,7 @@ export const TrainedModelsNavigationBar: FC<{ { id: 'trained_models', name: i18n.translate('xpack.ml.trainedModels.modelsTabLabel', { - defaultMessage: 'Models', + defaultMessage: 'Trained Models', }), path: '/trained_models', testSubj: 'mlTrainedModelsTab', @@ -39,7 +39,7 @@ export const TrainedModelsNavigationBar: FC<{ { id: 'nodes', name: i18n.translate('xpack.ml.trainedModels.nodesTabLabel', { - defaultMessage: 'Nodes', + defaultMessage: 'Nodes Overview', }), path: '/trained_models/nodes', testSubj: 'mlNodesOverviewTab', diff --git a/x-pack/plugins/ml/public/application/trained_models/page.tsx b/x-pack/plugins/ml/public/application/trained_models/page.tsx index 493638f1a5febb..998bc7c0c01cc8 100644 --- a/x-pack/plugins/ml/public/application/trained_models/page.tsx +++ b/x-pack/plugins/ml/public/application/trained_models/page.tsx @@ -6,8 +6,10 @@ */ import React, { FC, useMemo } from 'react'; +import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; import { useLocation } from 'react-router-dom'; +import { EuiBetaBadge, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { ModelsList } from './models_management'; import { TrainedModelsNavigationBar } from './navigation_bar'; import { NodesList } from './nodes_overview'; @@ -19,19 +21,37 @@ export const Page: FC = () => { return ( <> - - {selectedTabId === 'trained_models' ? : null} - {selectedTabId === 'nodes' ? ( - <> - + + + + + + - - - - ) : null} + + + + + + {selectedTabId === 'trained_models' ? : null} + {selectedTabId === 'nodes' ? : null} ); }; diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 36f16182b17e9a..c796ff340eb0a3 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -15628,7 +15628,6 @@ "xpack.ml.anomalyChartsEmbeddable.setupModal.title": "異常エクスプローラーグラフ構成", "xpack.ml.anomalyChartsEmbeddable.title": "{jobIds}のML異常グラフ", "xpack.ml.anomalyDetection.anomalyExplorerLabel": "異常エクスプローラー", - "xpack.ml.anomalyDetection.jobManagementLabel": "ジョブ管理", "xpack.ml.anomalyDetection.singleMetricViewerLabel": "シングルメトリックビューアー", "xpack.ml.anomalyDetectionAlert.actionGroupName": "異常スコアが条件と一致しました", "xpack.ml.anomalyDetectionAlert.advancedSettingsLabel": "高度な設定", @@ -16204,9 +16203,6 @@ "xpack.ml.dataframe.stepDetailsForm.destinationIndexInvalidErrorLink": "インデックス名の制限に関する詳細。", "xpack.ml.dataFrameAnalyticsBreadcrumbs.analyticsMapLabel": "分析マップ", "xpack.ml.dataFrameAnalyticsBreadcrumbs.dataFrameExplorationLabel": "探索", - "xpack.ml.dataFrameAnalyticsBreadcrumbs.dataFrameListLabel": "ジョブ管理", - "xpack.ml.dataFrameAnalyticsBreadcrumbs.dataFrameManagementLabel": "データフレーム分析", - "xpack.ml.dataFrameAnalyticsBreadcrumbs.indexLabel": "インデックス", "xpack.ml.dataFrameAnalyticsLabel": "データフレーム分析", "xpack.ml.dataFrameAnalyticsTabLabel": "データフレーム分析", "xpack.ml.dataGrid.CcsWarningCalloutBody": "インデックスパターンのデータの取得中に問題が発生しました。ソースプレビューとクラスター横断検索を組み合わせることは、バージョン7.10以上ではサポートされていません。変換を構成して作成することはできます。", @@ -16471,7 +16467,6 @@ "xpack.ml.jobsBreadcrumbs.multiMetricLabel": "マルチメトリック", "xpack.ml.jobsBreadcrumbs.populationLabel": "集団", "xpack.ml.jobsBreadcrumbs.rareLabel": "ほとんどない", - "xpack.ml.jobsBreadcrumbs.selectIndexOrSearchLabel": "ジョブを作成", "xpack.ml.jobsBreadcrumbs.selectIndexOrSearchLabelRecognize": "認識されたインデックス", "xpack.ml.jobsBreadcrumbs.selectJobType": "ジョブを作成", "xpack.ml.jobsBreadcrumbs.singleMetricLabel": "シングルメトリック", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 4ec36c767a5d35..3388937227960f 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -15831,7 +15831,6 @@ "xpack.ml.anomalyChartsEmbeddable.setupModal.title": "异常浏览器图表配置", "xpack.ml.anomalyChartsEmbeddable.title": "{jobIds} 的 ML 异常图表", "xpack.ml.anomalyDetection.anomalyExplorerLabel": "Anomaly Explorer", - "xpack.ml.anomalyDetection.jobManagementLabel": "作业管理", "xpack.ml.anomalyDetection.singleMetricViewerLabel": "Single Metric Viewer", "xpack.ml.anomalyDetectionAlert.actionGroupName": "异常分数匹配条件", "xpack.ml.anomalyDetectionAlert.advancedSettingsLabel": "高级设置", @@ -16415,9 +16414,6 @@ "xpack.ml.dataframe.stepDetailsForm.destinationIndexInvalidErrorLink": "详细了解索引名称限制。", "xpack.ml.dataFrameAnalyticsBreadcrumbs.analyticsMapLabel": "分析地图", "xpack.ml.dataFrameAnalyticsBreadcrumbs.dataFrameExplorationLabel": "探查", - "xpack.ml.dataFrameAnalyticsBreadcrumbs.dataFrameListLabel": "作业管理", - "xpack.ml.dataFrameAnalyticsBreadcrumbs.dataFrameManagementLabel": "数据帧分析", - "xpack.ml.dataFrameAnalyticsBreadcrumbs.indexLabel": "索引", "xpack.ml.dataFrameAnalyticsLabel": "数据帧分析", "xpack.ml.dataFrameAnalyticsTabLabel": "数据帧分析", "xpack.ml.dataGrid.CcsWarningCalloutBody": "检索索引模式的数据时有问题。源预览和跨集群搜索仅在 7.10 及以上版本上受支持。可能需要配置和创建转换。", @@ -16703,7 +16699,6 @@ "xpack.ml.jobsBreadcrumbs.multiMetricLabel": "多指标", "xpack.ml.jobsBreadcrumbs.populationLabel": "填充", "xpack.ml.jobsBreadcrumbs.rareLabel": "极少", - "xpack.ml.jobsBreadcrumbs.selectIndexOrSearchLabel": "创建作业", "xpack.ml.jobsBreadcrumbs.selectIndexOrSearchLabelRecognize": "识别的索引", "xpack.ml.jobsBreadcrumbs.selectJobType": "创建作业", "xpack.ml.jobsBreadcrumbs.singleMetricLabel": "单一指标", From 159e409a99d474aeaee6f6010e8d7b54f7662f05 Mon Sep 17 00:00:00 2001 From: Shahzad Date: Tue, 18 Jan 2022 18:43:09 +0100 Subject: [PATCH 011/108] [Uptime] Remove unsafe from config (#123211) --- x-pack/plugins/uptime/common/config.ts | 14 +++----------- .../common/header/action_menu_content.tsx | 2 +- x-pack/plugins/uptime/public/routes.test.tsx | 2 +- x-pack/plugins/uptime/public/routes.tsx | 2 +- .../server/lib/saved_objects/saved_objects.ts | 2 +- x-pack/plugins/uptime/server/plugin.ts | 8 ++++---- .../synthetics_service/get_service_locations.ts | 2 +- .../uptime/server/rest_api/uptime_route_wrapper.ts | 2 +- x-pack/test/api_integration/config.ts | 8 ++++---- 9 files changed, 17 insertions(+), 25 deletions(-) diff --git a/x-pack/plugins/uptime/common/config.ts b/x-pack/plugins/uptime/common/config.ts index e9ea061fcf1600..3e8c6cc0092076 100644 --- a/x-pack/plugins/uptime/common/config.ts +++ b/x-pack/plugins/uptime/common/config.ts @@ -24,22 +24,14 @@ const uptimeConfig = schema.object({ index: schema.maybe(schema.string()), ui: schema.maybe( schema.object({ - unsafe: schema.maybe( + monitorManagement: schema.maybe( schema.object({ - monitorManagement: schema.maybe( - schema.object({ - enabled: schema.boolean(), - }) - ), + enabled: schema.boolean(), }) ), }) ), - unsafe: schema.maybe( - schema.object({ - service: serviceConfig, - }) - ), + service: schema.maybe(serviceConfig), }); export const config: PluginConfigDescriptor = { diff --git a/x-pack/plugins/uptime/public/components/common/header/action_menu_content.tsx b/x-pack/plugins/uptime/public/components/common/header/action_menu_content.tsx index 501c74d1162695..0600a629ad3e2b 100644 --- a/x-pack/plugins/uptime/public/components/common/header/action_menu_content.tsx +++ b/x-pack/plugins/uptime/public/components/common/header/action_menu_content.tsx @@ -73,7 +73,7 @@ export function ActionMenuContent({ config }: { config: UptimeConfig }): React.R return ( - {config.ui?.unsafe?.monitorManagement?.enabled && ( + {config.ui?.monitorManagement?.enabled && ( { ])('hides ui monitor management pages when feature flag is not enabled', (page, heading) => { const history = createMemoryHistory(); history.push(page); - render(, { + render(, { history, }); diff --git a/x-pack/plugins/uptime/public/routes.tsx b/x-pack/plugins/uptime/public/routes.tsx index d099d608ae8536..d462d35a15f566 100644 --- a/x-pack/plugins/uptime/public/routes.tsx +++ b/x-pack/plugins/uptime/public/routes.tsx @@ -186,7 +186,7 @@ const getRoutes = (config: UptimeConfig): RouteProps[] => { rightSideItems: [], }, }, - ...(config.ui?.unsafe?.monitorManagement?.enabled + ...(config.ui?.monitorManagement?.enabled ? [ { title: i18n.translate('xpack.uptime.addMonitorRoute.title', { diff --git a/x-pack/plugins/uptime/server/lib/saved_objects/saved_objects.ts b/x-pack/plugins/uptime/server/lib/saved_objects/saved_objects.ts index 5fc99816df006a..1f2dbc98edd1b3 100644 --- a/x-pack/plugins/uptime/server/lib/saved_objects/saved_objects.ts +++ b/x-pack/plugins/uptime/server/lib/saved_objects/saved_objects.ts @@ -26,7 +26,7 @@ export const registerUptimeSavedObjects = ( ) => { savedObjectsService.registerType(umDynamicSettings); - if (config?.unsafe?.service.enabled) { + if (config?.service?.enabled) { savedObjectsService.registerType(syntheticsMonitor); savedObjectsService.registerType(syntheticsServiceApiKey); diff --git a/x-pack/plugins/uptime/server/plugin.ts b/x-pack/plugins/uptime/server/plugin.ts index 4c076db0255ef2..2a7cc9c385b7af 100644 --- a/x-pack/plugins/uptime/server/plugin.ts +++ b/x-pack/plugins/uptime/server/plugin.ts @@ -73,11 +73,11 @@ export class Plugin implements PluginType { cloud: plugins.cloud, } as UptimeServerSetup; - if (this.server?.config?.unsafe?.service.enabled) { + if (this.server?.config?.service?.enabled) { this.syntheticService = new SyntheticsService( this.logger, this.server, - this.server.config.unsafe.service + this.server.config.service ); this.syntheticService.registerSyncTask(plugins.taskManager); @@ -98,7 +98,7 @@ export class Plugin implements PluginType { } public start(coreStart: CoreStart, plugins: UptimeCorePluginsStart) { - if (this.server?.config?.unsafe?.service.enabled) { + if (this.server?.config?.service?.enabled) { this.savedObjectsClient = new SavedObjectsClient( coreStart.savedObjects.createInternalRepository([syntheticsServiceApiKey.name]) ); @@ -115,7 +115,7 @@ export class Plugin implements PluginType { this.server.savedObjectsClient = this.savedObjectsClient; } - if (this.server?.config?.unsafe?.service?.enabled) { + if (this.server?.config?.service?.enabled) { this.syntheticService?.init(); this.syntheticService?.scheduleSyncTask(plugins.taskManager); if (this.server && this.syntheticService) { diff --git a/x-pack/plugins/uptime/server/rest_api/synthetics_service/get_service_locations.ts b/x-pack/plugins/uptime/server/rest_api/synthetics_service/get_service_locations.ts index dfd0dcd1a9107c..0c51a53e8fd03c 100644 --- a/x-pack/plugins/uptime/server/rest_api/synthetics_service/get_service_locations.ts +++ b/x-pack/plugins/uptime/server/rest_api/synthetics_service/get_service_locations.ts @@ -14,5 +14,5 @@ export const getServiceLocationsRoute: UMRestApiRouteFactory = () => ({ path: API_URLS.SERVICE_LOCATIONS, validate: {}, handler: async ({ server }): Promise => - getServiceLocations({ manifestUrl: server.config.unsafe!.service.manifestUrl }), + getServiceLocations({ manifestUrl: server.config.service!.manifestUrl }), }); diff --git a/x-pack/plugins/uptime/server/rest_api/uptime_route_wrapper.ts b/x-pack/plugins/uptime/server/rest_api/uptime_route_wrapper.ts index 47c25bca6f900b..4e40ce934a32e0 100644 --- a/x-pack/plugins/uptime/server/rest_api/uptime_route_wrapper.ts +++ b/x-pack/plugins/uptime/server/rest_api/uptime_route_wrapper.ts @@ -22,7 +22,7 @@ export const uptimeRouteWrapper: UMKibanaRouteWrapper = (uptimeRoute, server) => handler: async (context, request, response) => { const { client: esClient } = context.core.elasticsearch; let savedObjectsClient: SavedObjectsClientContract; - if (server.config?.unsafe?.service?.enabled) { + if (server.config?.service?.enabled) { savedObjectsClient = context.core.savedObjects.getClient({ includedHiddenTypes: [syntheticsServiceApiKey.name], }); diff --git a/x-pack/test/api_integration/config.ts b/x-pack/test/api_integration/config.ts index dde3b827bcdae2..87306e78b0edc1 100644 --- a/x-pack/test/api_integration/config.ts +++ b/x-pack/test/api_integration/config.ts @@ -35,10 +35,10 @@ export async function getApiIntegrationConfig({ readConfigFile }: FtrConfigProvi '--xpack.ruleRegistry.write.enabled=true', '--xpack.ruleRegistry.write.enabled=true', '--xpack.ruleRegistry.write.cache.enabled=false', - '--xpack.uptime.unsafe.service.enabled=true', - '--xpack.uptime.unsafe.service.password=test', - '--xpack.uptime.unsafe.service.manifestUrl=http://test.com', - '--xpack.uptime.unsafe.service.username=localKibanaIntegrationTestsUser', + '--xpack.uptime.service.enabled=true', + '--xpack.uptime.service.password=test', + '--xpack.uptime.service.manifestUrl=http://test.com', + '--xpack.uptime.service.username=localKibanaIntegrationTestsUser', `--xpack.securitySolution.enableExperimental=${JSON.stringify(['ruleRegistryEnabled'])}`, ], }, From 55e648004b3af0dc6cee894c712f0e5433e178d9 Mon Sep 17 00:00:00 2001 From: Marshall Main <55718608+marshallmain@users.noreply.github.com> Date: Tue, 18 Jan 2022 09:43:54 -0800 Subject: [PATCH 012/108] Write an execution log status when ES bulk request has errors (#122903) Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../create_persistence_rule_type_wrapper.ts | 8 +- .../server/utils/persistence_types.ts | 2 + .../rule_registry/server/utils/utils.test.ts | 288 ++++++++++++++++++ .../rule_registry/server/utils/utils.ts | 52 ++++ .../factories/bulk_create_factory.ts | 30 +- 5 files changed, 369 insertions(+), 11 deletions(-) create mode 100644 x-pack/plugins/rule_registry/server/utils/utils.test.ts create mode 100644 x-pack/plugins/rule_registry/server/utils/utils.ts diff --git a/x-pack/plugins/rule_registry/server/utils/create_persistence_rule_type_wrapper.ts b/x-pack/plugins/rule_registry/server/utils/create_persistence_rule_type_wrapper.ts index 2d914e5e0945e9..a23ae0d1b99c9d 100644 --- a/x-pack/plugins/rule_registry/server/utils/create_persistence_rule_type_wrapper.ts +++ b/x-pack/plugins/rule_registry/server/utils/create_persistence_rule_type_wrapper.ts @@ -10,6 +10,7 @@ import { chunk } from 'lodash'; import { ALERT_UUID, VERSION } from '@kbn/rule-data-utils'; import { getCommonAlertFields } from './get_common_alert_fields'; import { CreatePersistenceRuleTypeWrapper } from './persistence_types'; +import { errorAggregator } from './utils'; export const createPersistenceRuleTypeWrapper: CreatePersistenceRuleTypeWrapper = ({ logger, ruleDataClient }) => @@ -77,7 +78,7 @@ export const createPersistenceRuleTypeWrapper: CreatePersistenceRuleTypeWrapper } if (filteredAlerts.length === 0) { - return { createdAlerts: [] }; + return { createdAlerts: [], errors: {} }; } const augmentedAlerts = filteredAlerts.map((alert) => { @@ -102,7 +103,7 @@ export const createPersistenceRuleTypeWrapper: CreatePersistenceRuleTypeWrapper }); if (response == null) { - return { createdAlerts: [] }; + return { createdAlerts: [], errors: {} }; } return { @@ -116,10 +117,11 @@ export const createPersistenceRuleTypeWrapper: CreatePersistenceRuleTypeWrapper }; }) .filter((_, idx) => response.body.items[idx].create?.status === 201), + errors: errorAggregator(response.body, [409]), }; } else { logger.debug('Writing is disabled.'); - return { createdAlerts: [] }; + return { createdAlerts: [], errors: {} }; } }, }, diff --git a/x-pack/plugins/rule_registry/server/utils/persistence_types.ts b/x-pack/plugins/rule_registry/server/utils/persistence_types.ts index 61136b432a5520..70e37dd20e34d7 100644 --- a/x-pack/plugins/rule_registry/server/utils/persistence_types.ts +++ b/x-pack/plugins/rule_registry/server/utils/persistence_types.ts @@ -16,6 +16,7 @@ import { } from '../../../alerting/server'; import { WithoutReservedActionGroups } from '../../../alerting/common'; import { IRuleDataClient } from '../rule_data_client'; +import { BulkResponseErrorAggregation } from './utils'; export type PersistenceAlertService = ( alerts: Array<{ @@ -27,6 +28,7 @@ export type PersistenceAlertService = ( export interface PersistenceAlertServiceResult { createdAlerts: Array; + errors: BulkResponseErrorAggregation; } export interface PersistenceServices { diff --git a/x-pack/plugins/rule_registry/server/utils/utils.test.ts b/x-pack/plugins/rule_registry/server/utils/utils.test.ts new file mode 100644 index 00000000000000..57a8c7dd379365 --- /dev/null +++ b/x-pack/plugins/rule_registry/server/utils/utils.test.ts @@ -0,0 +1,288 @@ +/* + * 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 type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; + +import { errorAggregator } from './utils'; +import { BulkResponseErrorAggregation } from './utils'; + +const sampleBulkErrorItem = ( + { + status, + reason, + }: { + status: number; + reason: string; + } = { status: 400, reason: 'Invalid call' } +): { create: estypes.BulkResponseItem } => { + return { + create: { + _index: 'mock_index', + _id: '123', + _version: 1, + status, + _shards: { + total: 1, + successful: 0, + failed: 1, + }, + error: { + type: 'Invalid', + reason, + shard: 'shard 123', + index: 'mock_index', + }, + }, + }; +}; + +const sampleBulkItem = (): { create: estypes.BulkResponseItem } => { + return { + create: { + _index: 'mock_index', + _id: '123', + _version: 1, + status: 200, + result: 'some result here', + _shards: { + total: 1, + successful: 1, + failed: 0, + }, + }, + }; +}; + +const sampleEmptyBulkResponse = (): estypes.BulkResponse => ({ + took: 0, + errors: false, + items: [], +}); + +const sampleBulkError = (): estypes.BulkResponse => ({ + took: 0, + errors: true, + items: [sampleBulkErrorItem()], +}); + +const sampleBulkResponse = (): estypes.BulkResponse => ({ + took: 0, + errors: true, + items: [sampleBulkItem()], +}); + +describe('utils', () => { + describe('errorAggregator', () => { + test('it should aggregate with an empty object when given an empty bulk response', () => { + const empty = sampleEmptyBulkResponse(); + const aggregated = errorAggregator(empty, []); + const expected: BulkResponseErrorAggregation = {}; + expect(aggregated).toEqual(expected); + }); + + test('it should aggregate with an empty create object', () => { + const empty = sampleBulkResponse(); + empty.items = [{}]; + const aggregated = errorAggregator(empty, []); + const expected: BulkResponseErrorAggregation = {}; + expect(aggregated).toEqual(expected); + }); + + test('it should aggregate with an empty object when given a valid bulk response with no errors', () => { + const validResponse = sampleBulkResponse(); + const aggregated = errorAggregator(validResponse, []); + const expected: BulkResponseErrorAggregation = {}; + expect(aggregated).toEqual(expected); + }); + + test('it should aggregate with a single error when given a single error item', () => { + const singleError = sampleBulkError(); + const aggregated = errorAggregator(singleError, []); + const expected: BulkResponseErrorAggregation = { + 'Invalid call': { + count: 1, + statusCode: 400, + }, + }; + expect(aggregated).toEqual(expected); + }); + + test('it should aggregate two errors with a correct count when given the same two error items', () => { + const twoAggregatedErrors = sampleBulkError(); + const item1 = sampleBulkErrorItem(); + const item2 = sampleBulkErrorItem(); + twoAggregatedErrors.items = [item1, item2]; + const aggregated = errorAggregator(twoAggregatedErrors, []); + const expected: BulkResponseErrorAggregation = { + 'Invalid call': { + count: 2, + statusCode: 400, + }, + }; + expect(aggregated).toEqual(expected); + }); + + test('it should aggregate three errors with a correct count when given the same two error items', () => { + const twoAggregatedErrors = sampleBulkError(); + const item1 = sampleBulkErrorItem(); + const item2 = sampleBulkErrorItem(); + const item3 = sampleBulkErrorItem(); + twoAggregatedErrors.items = [item1, item2, item3]; + const aggregated = errorAggregator(twoAggregatedErrors, []); + const expected: BulkResponseErrorAggregation = { + 'Invalid call': { + count: 3, + statusCode: 400, + }, + }; + expect(aggregated).toEqual(expected); + }); + + test('it should aggregate two distinct errors with the correct count of 1 for each error type', () => { + const twoAggregatedErrors = sampleBulkError(); + const item1 = sampleBulkErrorItem({ status: 400, reason: 'Parse Error' }); + const item2 = sampleBulkErrorItem({ status: 500, reason: 'Bad Network' }); + twoAggregatedErrors.items = [item1, item2]; + const aggregated = errorAggregator(twoAggregatedErrors, []); + const expected: BulkResponseErrorAggregation = { + 'Parse Error': { + count: 1, + statusCode: 400, + }, + 'Bad Network': { + count: 1, + statusCode: 500, + }, + }; + expect(aggregated).toEqual(expected); + }); + + test('it should aggregate two of the same errors with the correct count of 2 for each error type', () => { + const twoAggregatedErrors = sampleBulkError(); + const item1 = sampleBulkErrorItem({ status: 400, reason: 'Parse Error' }); + const item2 = sampleBulkErrorItem({ status: 400, reason: 'Parse Error' }); + const item3 = sampleBulkErrorItem({ status: 500, reason: 'Bad Network' }); + const item4 = sampleBulkErrorItem({ status: 500, reason: 'Bad Network' }); + twoAggregatedErrors.items = [item1, item2, item3, item4]; + const aggregated = errorAggregator(twoAggregatedErrors, []); + const expected: BulkResponseErrorAggregation = { + 'Parse Error': { + count: 2, + statusCode: 400, + }, + 'Bad Network': { + count: 2, + statusCode: 500, + }, + }; + expect(aggregated).toEqual(expected); + }); + + test('it should aggregate three of the same errors with the correct count of 2 for each error type', () => { + const twoAggregatedErrors = sampleBulkError(); + const item1 = sampleBulkErrorItem({ status: 400, reason: 'Parse Error' }); + const item2 = sampleBulkErrorItem({ status: 400, reason: 'Parse Error' }); + const item3 = sampleBulkErrorItem({ status: 500, reason: 'Bad Network' }); + const item4 = sampleBulkErrorItem({ status: 500, reason: 'Bad Network' }); + const item5 = sampleBulkErrorItem({ status: 502, reason: 'Bad Gateway' }); + const item6 = sampleBulkErrorItem({ status: 502, reason: 'Bad Gateway' }); + twoAggregatedErrors.items = [item1, item2, item3, item4, item5, item6]; + const aggregated = errorAggregator(twoAggregatedErrors, []); + const expected: BulkResponseErrorAggregation = { + 'Parse Error': { + count: 2, + statusCode: 400, + }, + 'Bad Network': { + count: 2, + statusCode: 500, + }, + 'Bad Gateway': { + count: 2, + statusCode: 502, + }, + }; + expect(aggregated).toEqual(expected); + }); + + test('it should aggregate a mix of errors with the correct aggregate count of each', () => { + const twoAggregatedErrors = sampleBulkError(); + const item1 = sampleBulkErrorItem({ status: 400, reason: 'Parse Error' }); + const item2 = sampleBulkErrorItem({ status: 500, reason: 'Bad Network' }); + const item3 = sampleBulkErrorItem({ status: 500, reason: 'Bad Network' }); + const item4 = sampleBulkErrorItem({ status: 502, reason: 'Bad Gateway' }); + const item5 = sampleBulkErrorItem({ status: 502, reason: 'Bad Gateway' }); + const item6 = sampleBulkErrorItem({ status: 502, reason: 'Bad Gateway' }); + twoAggregatedErrors.items = [item1, item2, item3, item4, item5, item6]; + const aggregated = errorAggregator(twoAggregatedErrors, []); + const expected: BulkResponseErrorAggregation = { + 'Parse Error': { + count: 1, + statusCode: 400, + }, + 'Bad Network': { + count: 2, + statusCode: 500, + }, + 'Bad Gateway': { + count: 3, + statusCode: 502, + }, + }; + expect(aggregated).toEqual(expected); + }); + + test('it will ignore error single codes such as 409', () => { + const twoAggregatedErrors = sampleBulkError(); + const item1 = sampleBulkErrorItem({ status: 409, reason: 'Conflict Error' }); + const item2 = sampleBulkErrorItem({ status: 409, reason: 'Conflict Error' }); + const item3 = sampleBulkErrorItem({ status: 500, reason: 'Bad Network' }); + const item4 = sampleBulkErrorItem({ status: 502, reason: 'Bad Gateway' }); + const item5 = sampleBulkErrorItem({ status: 502, reason: 'Bad Gateway' }); + const item6 = sampleBulkErrorItem({ status: 502, reason: 'Bad Gateway' }); + twoAggregatedErrors.items = [item1, item2, item3, item4, item5, item6]; + const aggregated = errorAggregator(twoAggregatedErrors, [409]); + const expected: BulkResponseErrorAggregation = { + 'Bad Network': { + count: 1, + statusCode: 500, + }, + 'Bad Gateway': { + count: 3, + statusCode: 502, + }, + }; + expect(aggregated).toEqual(expected); + }); + + test('it will ignore two error codes such as 409 and 502', () => { + const twoAggregatedErrors = sampleBulkError(); + const item1 = sampleBulkErrorItem({ status: 409, reason: 'Conflict Error' }); + const item2 = sampleBulkErrorItem({ status: 409, reason: 'Conflict Error' }); + const item3 = sampleBulkErrorItem({ status: 500, reason: 'Bad Network' }); + const item4 = sampleBulkErrorItem({ status: 502, reason: 'Bad Gateway' }); + const item5 = sampleBulkErrorItem({ status: 502, reason: 'Bad Gateway' }); + const item6 = sampleBulkErrorItem({ status: 502, reason: 'Bad Gateway' }); + twoAggregatedErrors.items = [item1, item2, item3, item4, item5, item6]; + const aggregated = errorAggregator(twoAggregatedErrors, [409, 502]); + const expected: BulkResponseErrorAggregation = { + 'Bad Network': { + count: 1, + statusCode: 500, + }, + }; + expect(aggregated).toEqual(expected); + }); + + test('it will return an empty object given valid inputs and status codes to ignore', () => { + const bulkResponse = sampleBulkResponse(); + const aggregated = errorAggregator(bulkResponse, [409, 502]); + const expected: BulkResponseErrorAggregation = {}; + expect(aggregated).toEqual(expected); + }); + }); +}); diff --git a/x-pack/plugins/rule_registry/server/utils/utils.ts b/x-pack/plugins/rule_registry/server/utils/utils.ts new file mode 100644 index 00000000000000..2d5d3766e19b25 --- /dev/null +++ b/x-pack/plugins/rule_registry/server/utils/utils.ts @@ -0,0 +1,52 @@ +/* + * 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 type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; + +export type BulkResponseErrorAggregation = Record; + +/** + * Given a BulkResponse this will return an aggregation based on the errors if any exist + * from the BulkResponse. Errors are aggregated on the reason as the unique key. + * + * Example would be: + * { + * 'Parse Error': { + * count: 100, + * statusCode: 400, + * }, + * 'Internal server error': { + * count: 3, + * statusCode: 500, + * } + * } + * If this does not return any errors then you will get an empty object like so: {} + * @param response The bulk response to aggregate based on the error message + * @param ignoreStatusCodes Optional array of status codes to ignore when creating aggregate error messages + * @returns The aggregated example as shown above. + */ +export const errorAggregator = ( + response: estypes.BulkResponse, + ignoreStatusCodes: number[] +): BulkResponseErrorAggregation => { + return response.items.reduce((accum, item) => { + if (item.create?.error != null && !ignoreStatusCodes.includes(item.create.status)) { + if (accum[item.create.error.reason] == null) { + accum[item.create.error.reason] = { + count: 1, + statusCode: item.create.status, + }; + } else { + accum[item.create.error.reason] = { + count: accum[item.create.error.reason].count + 1, + statusCode: item.create.status, + }; + } + } + return accum; + }, {}); +}; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/bulk_create_factory.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/bulk_create_factory.ts index 07b93f04e965f6..efe02f2ec6b7a1 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/bulk_create_factory.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/bulk_create_factory.ts @@ -6,6 +6,7 @@ */ import { performance } from 'perf_hooks'; +import { isEmpty } from 'lodash'; import { Logger } from 'kibana/server'; import { BaseHit } from '../../../../../common/detection_engine/types'; @@ -44,7 +45,7 @@ export const bulkCreateFactory = const start = performance.now(); - const { createdAlerts } = await alertWithPersistence( + const { createdAlerts, errors } = await alertWithPersistence( wrappedDocs.map((doc) => ({ _id: doc._id, // `fields` should have already been merged into `doc._source` @@ -61,11 +62,24 @@ export const bulkCreateFactory = ) ); - return { - errors: [], - success: true, - bulkCreateDuration: makeFloatString(end - start), - createdItemsCount: createdAlerts.length, - createdItems: createdAlerts, - }; + if (!isEmpty(errors)) { + logger.debug( + buildRuleMessage(`[-] bulkResponse had errors with responses of: ${JSON.stringify(errors)}`) + ); + return { + errors: Object.keys(errors), + success: false, + bulkCreateDuration: makeFloatString(end - start), + createdItemsCount: createdAlerts.length, + createdItems: createdAlerts, + }; + } else { + return { + errors: [], + success: true, + bulkCreateDuration: makeFloatString(end - start), + createdItemsCount: createdAlerts.length, + createdItems: createdAlerts, + }; + } }; From 3a59ba4b2190f50915a8579735922d70b3757a8d Mon Sep 17 00:00:00 2001 From: Marshall Main <55718608+marshallmain@users.noreply.github.com> Date: Tue, 18 Jan 2022 09:44:17 -0800 Subject: [PATCH 013/108] [Security Solution] Add runtime field support to query signals route (#122738) * Add runtime field support to query signals route * Fix tests Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../request/query_signals_index_schema.ts | 1 + .../alerts_count_panel/helpers.tsx | 5 ++- .../alerts_kpis/alerts_count_panel/index.tsx | 18 +++++++--- .../alerts_histogram_panel/helpers.tsx | 5 ++- .../alerts_histogram_panel/index.test.tsx | 2 ++ .../alerts_histogram_panel/index.tsx | 15 +++++--- .../detection_engine/detection_engine.tsx | 13 +++++-- .../detection_engine/rules/details/index.tsx | 11 ++++-- .../routes/signals/query_signals_route.ts | 4 ++- .../basic/tests/query_signals.ts | 35 +++++++++++++++++++ 10 files changed, 93 insertions(+), 16 deletions(-) diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/query_signals_index_schema.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/query_signals_index_schema.ts index ed3664b6792b3b..083c60a0a85270 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/query_signals_index_schema.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/query_signals_index_schema.ts @@ -15,6 +15,7 @@ export const querySignalsSchema = t.exact( size: PositiveInteger, track_total_hits: t.boolean, _source: t.array(t.string), + runtime_mappings: t.unknown, }) ); diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_count_panel/helpers.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_count_panel/helpers.tsx index cd407a125cdb65..141df7a154c944 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_count_panel/helpers.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_count_panel/helpers.tsx @@ -5,6 +5,7 @@ * 2.0. */ +import { MappingRuntimeFields } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { DEFAULT_MAX_TABLE_QUERY_SIZE } from '../../../../../common/constants'; export const getAlertsCountQuery = ( @@ -13,7 +14,8 @@ export const getAlertsCountQuery = ( to: string, additionalFilters: Array<{ bool: { filter: unknown[]; should: unknown[]; must_not: unknown[]; must: unknown[] }; - }> = [] + }> = [], + runtimeMappings?: MappingRuntimeFields ) => { return { size: 0, @@ -43,5 +45,6 @@ export const getAlertsCountQuery = ( ], }, }, + runtime_mappings: runtimeMappings, }; }; diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_count_panel/index.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_count_panel/index.tsx index b69f4f1f498f9e..04b8f482fd1213 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_count_panel/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_count_panel/index.tsx @@ -5,6 +5,7 @@ * 2.0. */ +import { MappingRuntimeFields } from '@elastic/elasticsearch/lib/api/types'; import React, { memo, useMemo, useState, useEffect } from 'react'; import uuid from 'uuid'; @@ -30,10 +31,11 @@ interface AlertsCountPanelProps { filters?: Filter[]; query?: Query; signalIndexName: string | null; + runtimeMappings?: MappingRuntimeFields; } export const AlertsCountPanel = memo( - ({ filters, query, signalIndexName }) => { + ({ filters, query, signalIndexName, runtimeMappings }) => { const { to, from, deleteQuery, setQuery } = useGlobalTime(); // create a unique, but stable (across re-renders) query id @@ -70,13 +72,21 @@ export const AlertsCountPanel = memo( request, refetch, } = useQueryAlerts<{}, AlertsCountAggregation>({ - query: getAlertsCountQuery(selectedStackByOption, from, to, additionalFilters), + query: getAlertsCountQuery( + selectedStackByOption, + from, + to, + additionalFilters, + runtimeMappings + ), indexName: signalIndexName, }); useEffect(() => { - setAlertsQuery(getAlertsCountQuery(selectedStackByOption, from, to, additionalFilters)); - }, [setAlertsQuery, selectedStackByOption, from, to, additionalFilters]); + setAlertsQuery( + getAlertsCountQuery(selectedStackByOption, from, to, additionalFilters, runtimeMappings) + ); + }, [setAlertsQuery, selectedStackByOption, from, to, additionalFilters, runtimeMappings]); useInspectButton({ setQuery, diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_histogram_panel/helpers.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_histogram_panel/helpers.tsx index a4768ac3c4c8f2..1f5c67c61b9e2e 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_histogram_panel/helpers.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_histogram_panel/helpers.tsx @@ -5,6 +5,7 @@ * 2.0. */ +import { MappingRuntimeFields } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { isEmpty } from 'lodash/fp'; import moment from 'moment'; @@ -37,7 +38,8 @@ export const getAlertsHistogramQuery = ( to: string, additionalFilters: Array<{ bool: { filter: unknown[]; should: unknown[]; must_not: unknown[]; must: unknown[] }; - }> + }>, + runtimeMappings?: MappingRuntimeFields ) => { return { aggs: { @@ -79,6 +81,7 @@ export const getAlertsHistogramQuery = ( ], }, }, + runtime_mappings: runtimeMappings, }; }; diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_histogram_panel/index.test.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_histogram_panel/index.test.tsx index eb06f85a0a76fe..29e18a1c49c12e 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_histogram_panel/index.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_histogram_panel/index.test.tsx @@ -197,6 +197,7 @@ describe('AlertsHistogramPanel', () => { }, }, ], + undefined, ]); }); wrapper.unmount(); @@ -250,6 +251,7 @@ describe('AlertsHistogramPanel', () => { }, }, ], + undefined, ]); }); wrapper.unmount(); diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_histogram_panel/index.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_histogram_panel/index.tsx index 2e029d43cc7173..571f656389f6a7 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_histogram_panel/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_kpis/alerts_histogram_panel/index.tsx @@ -5,6 +5,7 @@ * 2.0. */ +import { MappingRuntimeFields } from '@elastic/elasticsearch/lib/api/types'; import type { Position } from '@elastic/charts'; import { EuiFlexGroup, EuiFlexItem, EuiTitleSize } from '@elastic/eui'; import numeral from '@elastic/numeral'; @@ -76,6 +77,7 @@ interface AlertsHistogramPanelProps { timelineId?: string; title?: string; updateDateRange: UpdateDateRange; + runtimeMappings?: MappingRuntimeFields; } const NO_LEGEND_DATA: LegendItem[] = []; @@ -100,6 +102,7 @@ export const AlertsHistogramPanel = memo( title = i18n.HISTOGRAM_HEADER, updateDateRange, titleSize = 'm', + runtimeMappings, }) => { const { to, from, deleteQuery, setQuery } = useGlobalTime(false); @@ -125,7 +128,8 @@ export const AlertsHistogramPanel = memo( selectedStackByOption, from, to, - buildCombinedQueries(combinedQueries) + buildCombinedQueries(combinedQueries), + runtimeMappings ), indexName: signalIndexName, }); @@ -231,15 +235,18 @@ export const AlertsHistogramPanel = memo( selectedStackByOption, from, to, - !isEmpty(converted) ? [converted] : [] + !isEmpty(converted) ? [converted] : [], + runtimeMappings ) ); } catch (e) { setIsInspectDisabled(true); - setAlertsQuery(getAlertsHistogramQuery(selectedStackByOption, from, to, [])); + setAlertsQuery( + getAlertsHistogramQuery(selectedStackByOption, from, to, [], runtimeMappings) + ); } // eslint-disable-next-line react-hooks/exhaustive-deps - }, [selectedStackByOption, from, to, query, filters, combinedQueries]); + }, [selectedStackByOption, from, to, query, filters, combinedQueries, runtimeMappings]); const linkButton = useMemo(() => { if (showLinkToAlerts) { diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/detection_engine.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/detection_engine.tsx index 8ad6716670c320..7702f38c7ab901 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/detection_engine.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/detection_engine.tsx @@ -130,10 +130,17 @@ const DetectionEnginePageComponent: React.FC = ({ ] = useUserData(); const { loading: listsConfigLoading, needsConfiguration: needsListsConfiguration } = useListsConfig(); + + const { + indexPattern, + runtimeMappings, + loading: isLoadingIndexPattern, + } = useSourcererDataView(SourcererScopeName.detections); + const { formatUrl } = useFormatUrl(SecurityPageName.rules); const [showBuildingBlockAlerts, setShowBuildingBlockAlerts] = useState(false); const [showOnlyThreatIndicatorAlerts, setShowOnlyThreatIndicatorAlerts] = useState(false); - const loading = userInfoLoading || listsConfigLoading; + const loading = userInfoLoading || listsConfigLoading || isLoadingIndexPattern; const { application: { navigateToUrl }, timelines: timelinesUi, @@ -212,8 +219,6 @@ const DetectionEnginePageComponent: React.FC = ({ [setShowOnlyThreatIndicatorAlerts] ); - const { indexPattern } = useSourcererDataView(SourcererScopeName.detections); - const { signalIndexNeedsInit, pollForSignalIndex } = useSignalHelpers(); const onSkipFocusBeforeEventsTable = useCallback(() => { @@ -340,6 +345,7 @@ const DetectionEnginePageComponent: React.FC = ({ filters={alertsHistogramDefaultFilters} query={query} signalIndexName={signalIndexName} + runtimeMappings={runtimeMappings} /> @@ -351,6 +357,7 @@ const DetectionEnginePageComponent: React.FC = ({ titleSize={'s'} signalIndexName={signalIndexName} updateDateRange={updateDateRangeCallback} + runtimeMappings={runtimeMappings} /> diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/index.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/index.tsx index b9f73dd03c106b..03d43e3969c10e 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/index.tsx @@ -208,7 +208,14 @@ const RuleDetailsPageComponent: React.FC = ({ ] = useUserData(); const { loading: listsConfigLoading, needsConfiguration: needsListsConfiguration } = useListsConfig(); - const loading = userInfoLoading || listsConfigLoading; + + const { + indexPattern, + runtimeMappings, + loading: isLoadingIndexPattern, + } = useSourcererDataView(SourcererScopeName.detections); + + const loading = userInfoLoading || listsConfigLoading || isLoadingIndexPattern; const { detailName: ruleId } = useParams<{ detailName: string }>(); const { rule: maybeRule, @@ -601,7 +608,6 @@ const RuleDetailsPageComponent: React.FC = ({ [setShowOnlyThreatIndicatorAlerts] ); - const { indexPattern } = useSourcererDataView(SourcererScopeName.detections); const exceptionLists = useMemo((): { lists: ExceptionListIdentifiers[]; allowedExceptionListTypes: ExceptionListTypeEnum[]; @@ -819,6 +825,7 @@ const RuleDetailsPageComponent: React.FC = ({ signalIndexName={signalIndexName} defaultStackByOption={defaultRuleStackByOption} updateDateRange={updateDateRangeCallback} + runtimeMappings={runtimeMappings} /> diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/query_signals_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/query_signals_route.ts index 1c3fb8cac4e4d5..def203f534ad3a 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/query_signals_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/query_signals_route.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { MappingRuntimeFields } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { transformError } from '@kbn/securitysolution-es-utils'; import type { SecuritySolutionPluginRouter } from '../../../../types'; import { DETECTION_ENGINE_QUERY_SIGNALS_URL } from '../../../../../common/constants'; @@ -35,7 +36,7 @@ export const querySignalsRoute = ( }, async (context, request, response) => { // eslint-disable-next-line @typescript-eslint/naming-convention - const { query, aggs, _source, track_total_hits, size } = request.body; + const { query, aggs, _source, track_total_hits, size, runtime_mappings } = request.body; const siemResponse = buildSiemResponse(response); if ( query == null && @@ -61,6 +62,7 @@ export const querySignalsRoute = ( _source, track_total_hits, size, + runtime_mappings: runtime_mappings as MappingRuntimeFields, }, ignore_unavailable: true, }); diff --git a/x-pack/test/detection_engine_api_integration/basic/tests/query_signals.ts b/x-pack/test/detection_engine_api_integration/basic/tests/query_signals.ts index 1c0c222c38bebb..3ef0a12cf70dc8 100644 --- a/x-pack/test/detection_engine_api_integration/basic/tests/query_signals.ts +++ b/x-pack/test/detection_engine_api_integration/basic/tests/query_signals.ts @@ -106,6 +106,41 @@ export default ({ getService }: FtrProviderContext) => { }); }); + describe('runtime fields', () => { + before(async () => { + await esArchiver.load('x-pack/test/functional/es_archives/endpoint/resolver/signals'); + await createSignalsIndex(supertest, log); + }); + after(async () => { + await esArchiver.unload('x-pack/test/functional/es_archives/endpoint/resolver/signals'); + await deleteSignalsIndex(supertest, log); + }); + + it('should be able to filter using a runtime field defined in the request', async () => { + const query = { + query: { + bool: { + should: [{ match_phrase: { signal_status_querytime: 'open' } }], + }, + }, + runtime_mappings: { + signal_status_querytime: { + type: 'keyword', + script: { + source: `emit(doc['signal.status'].value)`, + }, + }, + }, + }; + const { body } = await supertest + .post(DETECTION_ENGINE_QUERY_SIGNALS_URL) + .set('kbn-xsrf', 'true') + .send(query) + .expect(200); + expect(body.hits.total.value).to.eql(3); + }); + }); + describe('find_alerts_route', () => { describe('validation checks', () => { it('should not give errors when querying and the signals index does not exist yet', async () => { From b5aadc26b5a8a96e5ccabc03454d66c84e81eb92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cau=C3=AA=20Marcondes?= <55978943+cauemarcondes@users.noreply.github.com> Date: Tue, 18 Jan 2022 14:51:41 -0300 Subject: [PATCH 014/108] [APM] Only show span.sync badge when relevant (#123038) * only show sync badge when its not the default behaviour of each language * fixing storybook Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../waterfall/span_flyout/index.tsx | 2 +- .../waterfall/sync_badge.stories.tsx | 23 +++++- .../waterfall/sync_badge.test.tsx | 82 +++++++++++++++++++ .../waterfall/sync_badge.tsx | 72 +++++++++++----- .../waterfall/waterfall_item.tsx | 7 +- 5 files changed, 161 insertions(+), 25 deletions(-) create mode 100644 x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/sync_badge.test.tsx diff --git a/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/span_flyout/index.tsx b/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/span_flyout/index.tsx index 57bfc2b61fc536..0087b0f9d1facb 100644 --- a/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/span_flyout/index.tsx +++ b/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/span_flyout/index.tsx @@ -211,7 +211,7 @@ export function SpanFlyout({ - + , ]} /> diff --git a/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/sync_badge.stories.tsx b/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/sync_badge.stories.tsx index 6b52fbe2d784aa..dea05961c4cef5 100644 --- a/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/sync_badge.stories.tsx +++ b/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/sync_badge.stories.tsx @@ -15,10 +15,27 @@ export default { sync: { control: { type: 'inline-radio', options: [true, false, undefined] }, }, + agentName: { + control: { + type: 'select', + options: [ + 'nodejs', + 'js-base', + 'rum-js', + 'php', + 'python', + 'dotnet', + 'iOS/swift', + 'ruby', + 'java', + 'go', + ], + }, + }, }, }; -export function Example({ sync }: SyncBadgeProps) { - return ; +export function Example({ sync, agentName }: SyncBadgeProps) { + return ; } -Example.args = { sync: true } as SyncBadgeProps; +Example.args = { sync: true, agentName: 'nodejs' } as SyncBadgeProps; diff --git a/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/sync_badge.test.tsx b/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/sync_badge.test.tsx new file mode 100644 index 00000000000000..b73532cfab8125 --- /dev/null +++ b/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/sync_badge.test.tsx @@ -0,0 +1,82 @@ +/* + * 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 { getSyncLabel } from './sync_badge'; + +describe('Sync badge', () => { + describe('Nodejs', () => { + it('shows blocking badge', () => { + expect(getSyncLabel('nodejs', true)).toBe('blocking'); + }); + it('does not show async badge', () => { + expect(getSyncLabel('nodejs', false)).toBeUndefined(); + }); + }); + describe('PHP', () => { + it('does not show blocking badge', () => { + expect(getSyncLabel('php', true)).toBeUndefined(); + }); + it('shows async badge', () => { + expect(getSyncLabel('php', false)).toBe('async'); + }); + }); + describe('Python', () => { + it('does not show blocking badge', () => { + expect(getSyncLabel('python', true)).toBeUndefined(); + }); + it('shows async badge', () => { + expect(getSyncLabel('python', false)).toBe('async'); + }); + }); + describe('.NET', () => { + it('does not show blocking badge', () => { + expect(getSyncLabel('dotnet', true)).toBeUndefined(); + }); + it('shows async badge', () => { + expect(getSyncLabel('dotnet', false)).toBe('async'); + }); + }); + describe('iOS', () => { + it('does not show blocking badge', () => { + expect(getSyncLabel('iOS/swift', true)).toBeUndefined(); + }); + it('shows async badge', () => { + expect(getSyncLabel('iOS/swift', false)).toBe('async'); + }); + }); + describe('Ruby', () => { + it('does not show blocking badge', () => { + expect(getSyncLabel('ruby', true)).toBeUndefined(); + }); + it('shows async badge', () => { + expect(getSyncLabel('ruby', false)).toBe('async'); + }); + }); + describe('Java', () => { + it('does not show blocking badge', () => { + expect(getSyncLabel('java', true)).toBeUndefined(); + }); + it('shows async badge', () => { + expect(getSyncLabel('java', false)).toBe('async'); + }); + }); + describe('JS', () => { + it('shows blocking badge', () => { + expect(getSyncLabel('js-base', true)).toBe('blocking'); + }); + it('does not show async badge', () => { + expect(getSyncLabel('js-base', false)).toBeUndefined(); + }); + }); + describe('RUM', () => { + it('shows blocking badge', () => { + expect(getSyncLabel('rum-js', true)).toBe('blocking'); + }); + it('does not show async badge', () => { + expect(getSyncLabel('rum-js', false)).toBeUndefined(); + }); + }); +}); diff --git a/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/sync_badge.tsx b/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/sync_badge.tsx index fe74f3d51c8bc3..a51d710bf39616 100644 --- a/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/sync_badge.tsx +++ b/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/sync_badge.tsx @@ -8,33 +8,65 @@ import { EuiBadge } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import React from 'react'; +import { AgentName } from '../../../../../../../typings/es_schemas/ui/fields/agent'; export interface SyncBadgeProps { /** * Is the request synchronous? True will show blocking, false will show async. */ sync?: boolean; + agentName: AgentName; } -export function SyncBadge({ sync }: SyncBadgeProps) { - switch (sync) { - case true: - return ( - - {i18n.translate('xpack.apm.transactionDetails.syncBadgeBlocking', { - defaultMessage: 'blocking', - })} - - ); - case false: - return ( - - {i18n.translate('xpack.apm.transactionDetails.syncBadgeAsync', { - defaultMessage: 'async', - })} - - ); - default: - return null; +const BLOCKING_LABEL = i18n.translate( + 'xpack.apm.transactionDetails.syncBadgeBlocking', + { + defaultMessage: 'blocking', } +); + +const ASYNC_LABEL = i18n.translate( + 'xpack.apm.transactionDetails.syncBadgeAsync', + { + defaultMessage: 'async', + } +); + +// true will show blocking, false will show async. +// otel doesn't set sync field +const agentsSyncMap: Record = { + nodejs: true, + 'js-base': true, + 'rum-js': true, + php: false, + python: false, + dotnet: false, + 'iOS/swift': false, + ruby: false, + java: false, + go: false, +}; + +export function getSyncLabel(agentName: AgentName, sync?: boolean) { + if (sync === undefined) { + return; + } + + const agentSyncValue = agentsSyncMap[agentName]; + if (sync && agentSyncValue) { + return BLOCKING_LABEL; + } + + if (!sync && !agentSyncValue) { + return ASYNC_LABEL; + } +} + +export function SyncBadge({ sync, agentName }: SyncBadgeProps) { + const syncLabel = getSyncLabel(agentName, sync); + if (!syncLabel) { + return null; + } + + return {syncLabel}; } diff --git a/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/waterfall_item.tsx b/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/waterfall_item.tsx index 056a2847c68bf8..d8942cab36f77c 100644 --- a/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/waterfall_item.tsx +++ b/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/waterfall_item.tsx @@ -228,7 +228,12 @@ export function WaterfallItem({ - {item.docType === 'span' && } + {item.docType === 'span' && ( + + )} ); From 7a70f857f35ad8d435d5c889b6f475e70bd69a34 Mon Sep 17 00:00:00 2001 From: Brian Seeders Date: Tue, 18 Jan 2022 13:03:24 -0500 Subject: [PATCH 015/108] [package-testing] Fix docker testing (#123249) --- .buildkite/scripts/common/env.sh | 3 +++ .buildkite/scripts/steps/package_testing/build.sh | 5 +++-- .buildkite/scripts/steps/package_testing/test.sh | 2 +- test/package/roles/install_kibana_docker/tasks/main.yml | 8 ++++---- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/.buildkite/scripts/common/env.sh b/.buildkite/scripts/common/env.sh index 43e02500313770..1f7c289c80fd40 100755 --- a/.buildkite/scripts/common/env.sh +++ b/.buildkite/scripts/common/env.sh @@ -22,6 +22,9 @@ KIBANA_PKG_BRANCH="$(jq -r .branch "$KIBANA_DIR/package.json")" export KIBANA_PKG_BRANCH export KIBANA_BASE_BRANCH="$KIBANA_PKG_BRANCH" +KIBANA_PKG_VERSION="$(jq -r .version "$KIBANA_DIR/package.json")" +export KIBANA_PKG_VERSION + export GECKODRIVER_CDNURL="https://us-central1-elastic-kibana-184716.cloudfunctions.net/kibana-ci-proxy-cache" export CHROMEDRIVER_CDNURL="https://us-central1-elastic-kibana-184716.cloudfunctions.net/kibana-ci-proxy-cache" export RE2_DOWNLOAD_MIRROR="https://us-central1-elastic-kibana-184716.cloudfunctions.net/kibana-ci-proxy-cache" diff --git a/.buildkite/scripts/steps/package_testing/build.sh b/.buildkite/scripts/steps/package_testing/build.sh index 813713dff2fe3c..e132128c250b53 100755 --- a/.buildkite/scripts/steps/package_testing/build.sh +++ b/.buildkite/scripts/steps/package_testing/build.sh @@ -4,9 +4,10 @@ set -euo pipefail .buildkite/scripts/bootstrap.sh -echo "--- Build Kibana Distribution" node scripts/build --all-platforms --debug --skip-docker-cloud --skip-docker-ubi --skip-docker-contexts +DOCKER_FILE="kibana-$KIBANA_PKG_VERSION-SNAPSHOT-docker-image.tar.gz" + cd target -buildkite-agent artifact upload "./*-docker-image.tar.gz;./*.deb;./*.rpm" +buildkite-agent artifact upload "./$DOCKER_FILE;./*.deb;./*.rpm" cd .. diff --git a/.buildkite/scripts/steps/package_testing/test.sh b/.buildkite/scripts/steps/package_testing/test.sh index eb2f20eea45259..8fcb665b67a979 100755 --- a/.buildkite/scripts/steps/package_testing/test.sh +++ b/.buildkite/scripts/steps/package_testing/test.sh @@ -15,7 +15,7 @@ elif [[ "$TEST_PACKAGE" == "rpm" ]]; then buildkite-agent artifact download 'kibana-*.rpm' . --build "${KIBANA_BUILD_ID:-$BUILDKITE_BUILD_ID}" KIBANA_IP_ADDRESS="192.168.50.6" elif [[ "$TEST_PACKAGE" == "docker" ]]; then - buildkite-agent artifact download 'kibana-*-docker-image.tar.gz' . --build "${KIBANA_BUILD_ID:-$BUILDKITE_BUILD_ID}" + buildkite-agent artifact download "kibana-$KIBANA_PKG_VERSION-SNAPSHOT-docker-image.tar.gz" . --build "${KIBANA_BUILD_ID:-$BUILDKITE_BUILD_ID}" KIBANA_IP_ADDRESS="192.168.50.7" fi cd .. diff --git a/test/package/roles/install_kibana_docker/tasks/main.yml b/test/package/roles/install_kibana_docker/tasks/main.yml index 6d2f0a2caed1c1..c883a3ece2a149 100644 --- a/test/package/roles/install_kibana_docker/tasks/main.yml +++ b/test/package/roles/install_kibana_docker/tasks/main.yml @@ -7,8 +7,8 @@ - name: load image become: yes docker_image: - name: kibana - load_path: "{{ kibana_docker.files[0].path }}" + name: "{{ kibana_docker.files[0].path | basename| regex_replace('kibana-(.*)-docker-image.tar.gz', 'docker.elastic.co/kibana/kibana:\\1') }}" + load_path: '{{ kibana_docker.files[0].path }}' timeout: 300 source: load state: present @@ -22,5 +22,5 @@ env: SERVER_HOST: 0.0.0.0 ELASTICSEARCH_HOSTS: http://192.168.50.1:9200 - ELASTICSEARCH_USERNAME: "{{ elasticsearch_username }}" - ELASTICSEARCH_PASSWORD: "{{ elasticsearch_password }}" + ELASTICSEARCH_USERNAME: '{{ elasticsearch_username }}' + ELASTICSEARCH_PASSWORD: '{{ elasticsearch_password }}' From f8d932f70a744f1ebbe6fa2afeb0bcef292fff37 Mon Sep 17 00:00:00 2001 From: Quynh Nguyen <43350163+qn895@users.noreply.github.com> Date: Tue, 18 Jan 2022 12:19:33 -0600 Subject: [PATCH 016/108] [ML] Fix runtime field validations not supporting special script types (#122469) * Fix validations not handling extra things like params or lang * Add translations Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../common/utils/runtime_field_utils.ts | 9 +++-- x-pack/plugins/file_upload/server/schemas.ts | 5 ++- .../server/utils/runtime_field_utils.ts | 9 +++-- .../common/util/runtime_field_utils.test.ts | 39 ++++++++++++++++++- .../ml/common/util/runtime_field_utils.ts | 12 +++--- .../routes/schemas/runtime_mappings_schema.ts | 5 ++- .../transform/common/api_schemas/common.ts | 36 +++++++---------- .../transform/common/shared_imports.ts | 1 + 8 files changed, 77 insertions(+), 39 deletions(-) diff --git a/x-pack/plugins/data_visualizer/common/utils/runtime_field_utils.ts b/x-pack/plugins/data_visualizer/common/utils/runtime_field_utils.ts index a088685f03f543..a9ec27c7b1577c 100644 --- a/x-pack/plugins/data_visualizer/common/utils/runtime_field_utils.ts +++ b/x-pack/plugins/data_visualizer/common/utils/runtime_field_utils.ts @@ -14,11 +14,12 @@ export function isRuntimeField(arg: unknown): arg is estypes.MappingRuntimeField return ( ((isPopulatedObject(arg, ['type']) && Object.keys(arg).length === 1) || (isPopulatedObject(arg, ['type', 'script']) && - Object.keys(arg).length === 2 && + // Can be a string (typeof arg.script === 'string' || - (isPopulatedObject(arg.script, ['source']) && - Object.keys(arg.script).length === 1 && - typeof arg.script.source === 'string')))) && + // Can be InlineScript + (isPopulatedObject(arg.script, ['source']) && typeof arg.script.source === 'string') || + // Can be StoredScriptId + (isPopulatedObject(arg.script, ['id']) && typeof arg.script.id === 'string')))) && RUNTIME_FIELD_TYPES.includes(arg.type as RuntimeType) ); } diff --git a/x-pack/plugins/file_upload/server/schemas.ts b/x-pack/plugins/file_upload/server/schemas.ts index baf7ed864f2e63..b7250b45a82f9d 100644 --- a/x-pack/plugins/file_upload/server/schemas.ts +++ b/x-pack/plugins/file_upload/server/schemas.ts @@ -6,6 +6,7 @@ */ import { schema } from '@kbn/config-schema'; +import { i18n } from '@kbn/i18n'; import { isRuntimeField } from './utils/runtime_field_utils'; export const analyzeFileQuerySchema = schema.object({ @@ -48,7 +49,9 @@ export const runtimeMappingsSchema = schema.object( unknowns: 'allow', validate: (v: object) => { if (Object.values(v).some((o) => !isRuntimeField(o))) { - return 'Invalid runtime field'; + return i18n.translate('xpack.fileUpload.invalidRuntimeFieldMessage', { + defaultMessage: 'Invalid runtime field', + }); } }, } diff --git a/x-pack/plugins/file_upload/server/utils/runtime_field_utils.ts b/x-pack/plugins/file_upload/server/utils/runtime_field_utils.ts index fa2c874613b3d8..7ae8242fc99659 100644 --- a/x-pack/plugins/file_upload/server/utils/runtime_field_utils.ts +++ b/x-pack/plugins/file_upload/server/utils/runtime_field_utils.ts @@ -15,11 +15,12 @@ export function isRuntimeField(arg: unknown): arg is estypes.MappingRuntimeField return ( ((isPopulatedObject(arg, ['type']) && Object.keys(arg).length === 1) || (isPopulatedObject(arg, ['type', 'script']) && - Object.keys(arg).length === 2 && + // Can be a string (typeof arg.script === 'string' || - (isPopulatedObject(arg.script, ['source']) && - Object.keys(arg.script).length === 1 && - typeof arg.script.source === 'string')))) && + // Can be InlineScript + (isPopulatedObject(arg.script, ['source']) && typeof arg.script.source === 'string') || + // Can be StoredScriptId + (isPopulatedObject(arg.script, ['id']) && typeof arg.script.id === 'string')))) && RUNTIME_FIELD_TYPES.includes(arg.type as RuntimeType) ); } diff --git a/x-pack/plugins/ml/common/util/runtime_field_utils.test.ts b/x-pack/plugins/ml/common/util/runtime_field_utils.test.ts index e7f92306668981..6aa50753445565 100644 --- a/x-pack/plugins/ml/common/util/runtime_field_utils.test.ts +++ b/x-pack/plugins/ml/common/util/runtime_field_utils.test.ts @@ -30,7 +30,9 @@ describe('ML runtime field utils', () => { expect(isRuntimeField({ type: 'keyword' })).toBe(true); }); it('allows objects with both type and script attributes', () => { - expect(isRuntimeField({ type: 'keyword', script: 'some script' })).toBe(true); + expect( + isRuntimeField({ type: 'keyword', script: 'some script', format: 'some format' }) + ).toBe(true); }); }); @@ -90,6 +92,19 @@ describe('ML runtime field utils', () => { isRuntimeMappings({ fieldName1: { type: 'keyword' }, fieldName2: { type: 'keyword', script: 'some script as script' }, + fieldName3: { + type: 'keyword', + script: { + source: 'source script', + }, + }, + fieldName4: { + type: 'keyword', + script: { + source: 'source script', + params: {}, + }, + }, }) ).toBe(true); expect( @@ -97,6 +112,28 @@ describe('ML runtime field utils', () => { fieldName: { type: 'long', script: { source: 'some script as source' } }, }) ).toBe(true); + expect( + isRuntimeMappings({ + fieldName: { + type: 'long', + script: { + source: 'source script', + params: {}, + lang: 'lang', + }, + }, + }) + ).toBe(true); + expect( + isRuntimeMappings({ + fieldName: { + type: 'long', + script: { + id: 'a script id', + }, + }, + }) + ).toBe(true); }); }); }); diff --git a/x-pack/plugins/ml/common/util/runtime_field_utils.ts b/x-pack/plugins/ml/common/util/runtime_field_utils.ts index edda547d363e49..a9ec27c7b1577c 100644 --- a/x-pack/plugins/ml/common/util/runtime_field_utils.ts +++ b/x-pack/plugins/ml/common/util/runtime_field_utils.ts @@ -7,7 +7,6 @@ import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { isPopulatedObject } from './object_utils'; import { RUNTIME_FIELD_TYPES } from '../../../../../src/plugins/data/common'; -import type { RuntimeMappings } from '../types/fields'; type RuntimeType = typeof RUNTIME_FIELD_TYPES[number]; @@ -15,15 +14,16 @@ export function isRuntimeField(arg: unknown): arg is estypes.MappingRuntimeField return ( ((isPopulatedObject(arg, ['type']) && Object.keys(arg).length === 1) || (isPopulatedObject(arg, ['type', 'script']) && - Object.keys(arg).length === 2 && + // Can be a string (typeof arg.script === 'string' || - (isPopulatedObject(arg.script, ['source']) && - Object.keys(arg.script).length === 1 && - typeof arg.script.source === 'string')))) && + // Can be InlineScript + (isPopulatedObject(arg.script, ['source']) && typeof arg.script.source === 'string') || + // Can be StoredScriptId + (isPopulatedObject(arg.script, ['id']) && typeof arg.script.id === 'string')))) && RUNTIME_FIELD_TYPES.includes(arg.type as RuntimeType) ); } -export function isRuntimeMappings(arg: unknown): arg is RuntimeMappings { +export function isRuntimeMappings(arg: unknown): arg is estypes.MappingRuntimeFields { return isPopulatedObject(arg) && Object.values(arg).every((d) => isRuntimeField(d)); } diff --git a/x-pack/plugins/ml/server/routes/schemas/runtime_mappings_schema.ts b/x-pack/plugins/ml/server/routes/schemas/runtime_mappings_schema.ts index 36d4ba8cee5e9d..31d8d615c8e33d 100644 --- a/x-pack/plugins/ml/server/routes/schemas/runtime_mappings_schema.ts +++ b/x-pack/plugins/ml/server/routes/schemas/runtime_mappings_schema.ts @@ -6,6 +6,7 @@ */ import { schema } from '@kbn/config-schema'; +import { i18n } from '@kbn/i18n'; import { isRuntimeField } from '../../../common/util/runtime_field_utils'; export const runtimeMappingsSchema = schema.object( @@ -14,7 +15,9 @@ export const runtimeMappingsSchema = schema.object( unknowns: 'allow', validate: (v: object) => { if (Object.values(v).some((o) => !isRuntimeField(o))) { - return 'Invalid runtime field'; + return i18n.translate('xpack.ml.invalidRuntimeFieldMessage', { + defaultMessage: 'Invalid runtime field', + }); } }, } diff --git a/x-pack/plugins/transform/common/api_schemas/common.ts b/x-pack/plugins/transform/common/api_schemas/common.ts index d29059864a7dd0..285f3879681c71 100644 --- a/x-pack/plugins/transform/common/api_schemas/common.ts +++ b/x-pack/plugins/transform/common/api_schemas/common.ts @@ -6,8 +6,9 @@ */ import { schema, TypeOf } from '@kbn/config-schema'; - +import { i18n } from '@kbn/i18n'; import { TRANSFORM_STATE } from '../constants'; +import { isRuntimeField } from '../shared_imports'; export const transformIdsSchema = schema.arrayOf( schema.object({ @@ -57,26 +58,17 @@ export interface CommonResponseStatusSchema { } export const runtimeMappingsSchema = schema.maybe( - schema.recordOf( - schema.string(), - schema.object({ - type: schema.oneOf([ - schema.literal('keyword'), - schema.literal('long'), - schema.literal('double'), - schema.literal('date'), - schema.literal('ip'), - schema.literal('boolean'), - schema.literal('geo_point'), - ]), - script: schema.maybe( - schema.oneOf([ - schema.string(), - schema.object({ - source: schema.string(), - }), - ]) - ), - }) + schema.object( + {}, + { + unknowns: 'allow', + validate: (v: object) => { + if (Object.values(v).some((o) => !isRuntimeField(o))) { + return i18n.translate('xpack.transform.invalidRuntimeFieldMessage', { + defaultMessage: 'Invalid runtime field', + }); + } + }, + } ) ); diff --git a/x-pack/plugins/transform/common/shared_imports.ts b/x-pack/plugins/transform/common/shared_imports.ts index 22201cf7c0757d..2cc01a0dbfa57d 100644 --- a/x-pack/plugins/transform/common/shared_imports.ts +++ b/x-pack/plugins/transform/common/shared_imports.ts @@ -11,6 +11,7 @@ export { isPopulatedObject, isRuntimeMappings, patternValidator, + isRuntimeField, } from '../../ml/common'; export { RUNTIME_FIELD_TYPES } from '../../../../src/plugins/data/common'; From 726682cda1105cf13fb25ba4fd89a8247601a0e1 Mon Sep 17 00:00:00 2001 From: Madison Caldwell Date: Tue, 18 Jan 2022 14:02:09 -0500 Subject: [PATCH 017/108] Ensure alert ancestors are calculated correctly for EQL alerts (#123070) Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../factories/utils/build_alert.test.ts | 98 +++++++++++ .../signals/__mocks__/es_results.ts | 158 ++++++++++++++++++ .../lib/detection_engine/signals/types.ts | 5 + .../detection_engine/signals/utils.test.ts | 67 +++++++- .../lib/detection_engine/signals/utils.ts | 41 ++++- 5 files changed, 365 insertions(+), 4 deletions(-) diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/utils/build_alert.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/utils/build_alert.test.ts index 2fc650f353cd78..a39c5f77bc2891 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/utils/build_alert.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/utils/build_alert.test.ts @@ -7,6 +7,7 @@ import { ALERT_INSTANCE_ID, + ALERT_NAMESPACE, ALERT_REASON, ALERT_RISK_SCORE, ALERT_RULE_CONSUMER, @@ -514,4 +515,101 @@ describe('buildAlert', () => { ]; expect(ancestors).toEqual(expected); }); + + test('it builds an ancestor correctly if the parent is an alert', () => { + const docId = 'd5e8eb51-a6a0-456d-8a15-4b79bfec3d71'; + const sampleDoc = sampleDocNoSortIdWithTimestamp(docId); + const doc = { + ...sampleDoc, + _source: { + ...sampleDoc._source, + [TIMESTAMP]: new Date().toISOString(), + [EVENT_ACTION]: 'socket_opened', + [EVENT_KIND]: 'signal', + [EVENT_DATASET]: 'socket', + [EVENT_MODULE]: 'system', + [ALERT_UUID]: docId, + ...flattenWithPrefix(ALERT_NAMESPACE, { + depth: 1, + ancestors: [ + { + id: '730ddf9e-5a00-4f85-9ddf-5878ca511a87', + type: 'event', + index: 'myFakeSignalIndex', + depth: 0, + }, + ], + rule: { + uuid: '98c0bf9e-4d38-46f4-9a6a-8a820426256b', + }, + }), + }, + }; + const ancestors = buildAncestors(doc); + const expected: Ancestor[] = [ + { + id: '730ddf9e-5a00-4f85-9ddf-5878ca511a87', + type: 'event', + index: 'myFakeSignalIndex', + depth: 0, + }, + { + rule: '98c0bf9e-4d38-46f4-9a6a-8a820426256b', + id: 'd5e8eb51-a6a0-456d-8a15-4b79bfec3d71', + type: 'signal', + index: 'myFakeSignalIndex', + depth: 1, + }, + ]; + expect(ancestors).toEqual(expected); + }); + + test('it builds an ancestor correctly if the parent is a legacy alert', () => { + const docId = 'd5e8eb51-a6a0-456d-8a15-4b79bfec3d71'; + const sampleDoc = sampleDocNoSortIdWithTimestamp(docId); + const doc = { + ...sampleDoc, + _source: { + ...sampleDoc._source, + [TIMESTAMP]: new Date().toISOString(), + event: { + action: 'socket_opened', + dataset: 'socket', + kind: 'signal', + module: 'system', + }, + signal: { + depth: 1, + ancestors: [ + { + id: '730ddf9e-5a00-4f85-9ddf-5878ca511a87', + type: 'event', + index: 'myFakeSignalIndex', + depth: 0, + }, + ], + rule: { + id: '98c0bf9e-4d38-46f4-9a6a-8a820426256b', + }, + }, + }, + }; + const ancestors = buildAncestors(doc); + const expected: Ancestor[] = [ + { + id: '730ddf9e-5a00-4f85-9ddf-5878ca511a87', + type: 'event', + index: 'myFakeSignalIndex', + depth: 0, + }, + { + rule: '98c0bf9e-4d38-46f4-9a6a-8a820426256b', + id: 'd5e8eb51-a6a0-456d-8a15-4b79bfec3d71', + type: 'signal', + index: 'myFakeSignalIndex', + depth: 1, + }, + ]; + expect(ancestors).toEqual(expected); + }); }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/__mocks__/es_results.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/__mocks__/es_results.ts index 5bf62a41ec1407..6558c48a6af5d1 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/__mocks__/es_results.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/__mocks__/es_results.ts @@ -14,6 +14,7 @@ import type { SignalHit, WrappedSignalHit, AlertAttributes, + AlertSourceHit, } from '../types'; import { SavedObject } from '../../../../../../../../src/core/server'; import { loggingSystemMock } from '../../../../../../../../src/core/server/mocks'; @@ -25,6 +26,15 @@ import { RulesSchema } from '../../../../../common/detection_engine/schemas/resp import { RuleParams } from '../../schemas/rule_schemas'; import { getThreatMock } from '../../../../../common/detection_engine/schemas/types/threat.mock'; import { RuleExecutionStatus } from '../../../../../common/detection_engine/schemas/common/schemas'; +import { + ALERT_REASON, + ALERT_RULE_PARAMETERS, + ALERT_RULE_UUID, + ALERT_UUID, + ALERT_WORKFLOW_STATUS, + EVENT_KIND, +} from '@kbn/rule-data-utils'; +import { ALERT_ANCESTORS } from '../../../../../common/field_maps/field_names'; export const sampleRuleSO = (params: T): SavedObject> => { return { @@ -167,6 +177,122 @@ export const sampleDocNoSortId = ( sort: [], }); +export const sampleAlertDocNoSortId = ( + someUuid: string = sampleIdGuid, + ip?: string +): SignalSourceHit & { _source: Required['_source'] } => ({ + ...sampleDocNoSortId(someUuid, ip), + _source: { + event: { + kind: 'signal', + }, + signal: { + ancestors: [ + { + id: 'd5e8eb51-a6a0-456d-8a15-4b79bfec3d71', + type: 'event', + index: 'myFakeSignalIndex', + depth: 0, + }, + ], + reason: 'reasonable reason', + rule: { + id: '2e051244-b3c6-4779-a241-e1b4f0beceb9', + description: 'Descriptive description', + }, + status: 'open', + }, + }, + fields: {}, +}); + +export const sampleAlertDocAADNoSortId = ( + someUuid: string = sampleIdGuid, + ip?: string +): AlertSourceHit & { _source: Required['_source'] } => ({ + _index: 'myFakeSignalIndex', + _score: 100, + _version: 1, + _id: someUuid, + _source: { + someKey: 'someValue', + '@timestamp': '2020-04-20T21:27:45+0000', + source: { + ip: ip ?? '127.0.0.1', + }, + [EVENT_KIND]: 'signal', + [ALERT_UUID]: someUuid, + [ALERT_REASON]: 'reasonable reason', + [ALERT_WORKFLOW_STATUS]: 'open', + [ALERT_ANCESTORS]: [ + { + id: 'd5e8eb51-a6a0-456d-8a15-4b79bfec3d71', + type: 'event', + index: 'myFakeSignalIndex', + depth: 0, + }, + ], + [ALERT_RULE_UUID]: '2e051244-b3c6-4779-a241-e1b4f0beceb9', + [ALERT_RULE_PARAMETERS]: { + description: 'Descriptive description', + meta: { someMeta: 'someField' }, + timeline_id: 'some-timeline-id', + timeline_title: 'some-timeline-title', + risk_score: 50, + severity: 'high', + note: 'Noteworthy notes', + license: 'Elastic License', + author: ['Elastic'], + false_positives: [], + from: 'now-6m', + rule_id: 'rule-1', + max_signals: 10000, + risk_score_mapping: [], + severity_mapping: [], + to: 'now', + references: ['http://example.com', 'https://example.com'], + version: 1, + immutable: false, + namespace: 'default', + output_index: '', + building_block_type: undefined, + exceptions_list: [], + rule_name_override: undefined, + timestamp_override: undefined, + threat: [ + { + framework: 'MITRE ATT&CK', + tactic: { + id: 'TA0000', + name: 'test tactic', + reference: 'https://attack.mitre.org/tactics/TA0000/', + }, + technique: [ + { + id: 'T0000', + name: 'test technique', + reference: 'https://attack.mitre.org/techniques/T0000/', + subtechnique: [ + { + id: 'T0000.000', + name: 'test subtechnique', + reference: 'https://attack.mitre.org/techniques/T0000/000/', + }, + ], + }, + ], + }, + ], + }, + }, + fields: { + someKey: ['someValue'], + '@timestamp': ['2020-04-20T21:27:45+0000'], + 'source.ip': [ip ?? '127.0.0.1'], + }, + sort: [], +}); + export const sampleDocNoSortIdWithTimestamp = ( someUuid: string = sampleIdGuid, ip?: string @@ -183,6 +309,38 @@ export const sampleDocNoSortIdWithTimestamp = ( }; }; +export const sampleAlertDocNoSortIdWithTimestamp = ( + someUuid: string = sampleIdGuid, + ip?: string +): SignalSourceHit & { + _source: Required['_source'] & { '@timestamp': string }; +} => { + const doc = sampleAlertDocNoSortId(someUuid, ip); + return { + ...doc, + _source: { + ...doc._source, + '@timestamp': new Date().toISOString(), + }, + }; +}; + +export const sampleAlertDocAADNoSortIdWithTimestamp = ( + someUuid: string = sampleIdGuid, + ip?: string +): AlertSourceHit & { + _source: Required['_source'] & { '@timestamp': string }; +} => { + const doc = sampleAlertDocAADNoSortId(someUuid, ip); + return { + ...doc, + _source: { + ...doc._source, + '@timestamp': new Date().toISOString(), + }, + }; +}; + export const sampleDocSeverity = (severity?: unknown, fieldName?: string): SignalSourceHit => { const doc = { _index: 'myFakeSignalIndex', diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/types.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/types.ts index da0c2e7819c181..1af6e62d30ff7e 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/types.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/types.ts @@ -115,12 +115,16 @@ export interface SignalSource { }; rule: { id: string; + description?: string; false_positives?: string[]; immutable?: boolean; }; /** signal.depth was introduced in 7.10 and pre-7.10 signals do not have it. */ depth?: number; original_time?: string; + /** signal.reason was introduced in 7.15 and pre-7.15 signals do not have it. */ + reason?: string; + status?: string; threshold_result?: ThresholdResult; }; kibana?: SearchTypes; @@ -180,6 +184,7 @@ export type WrappedEventHit = BaseHit; export type AlertSearchResponse = estypes.SearchResponse; export type SignalSearchResponse = estypes.SearchResponse; export type SignalSourceHit = estypes.SearchHit; +export type AlertSourceHit = estypes.SearchHit; export type WrappedSignalHit = BaseHit; export type BaseSignalHit = estypes.SearchHit; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.test.ts index 6842cc5bda2304..b59922fbd7c9c1 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.test.ts @@ -8,7 +8,7 @@ import moment from 'moment'; import sinon from 'sinon'; import { TransportResult } from '@elastic/elasticsearch'; -import { ALERT_UUID } from '@kbn/rule-data-utils'; +import { ALERT_REASON, ALERT_RULE_PARAMETERS, ALERT_UUID } from '@kbn/rule-data-utils'; import { alertsMock, AlertServicesMock } from '../../../../../alerting/server/mocks'; import { listMock } from '../../../../../lists/server/mocks'; @@ -43,6 +43,7 @@ import { calculateTotal, getTotalHitsValue, isRACAlert, + getField, } from './utils'; import { BulkResponseErrorAggregation, SearchAfterAndBulkCreateReturnType } from './types'; import { @@ -57,6 +58,8 @@ import { sampleDocSearchResultsNoSortIdNoHits, sampleDocSearchResultsNoSortId, sampleDocNoSortId, + sampleAlertDocNoSortIdWithTimestamp, + sampleAlertDocAADNoSortIdWithTimestamp, } from './__mocks__/es_results'; import { ShardError } from '../../types'; import { ruleExecutionLogClientMock } from '../rule_execution_log/__mocks__/rule_execution_log_client'; @@ -1570,4 +1573,66 @@ describe('utils', () => { expect(isRACAlert({ 'kibana.alert.uuid': null })).toEqual(false); }); }); + + describe('getField', () => { + test('gets legacy field when legacy field name is passed in', () => { + const doc = sampleAlertDocNoSortIdWithTimestamp(); + const value = getField(doc, 'signal.reason'); + expect(value).toEqual('reasonable reason'); + }); + + test('gets AAD field when AAD field name is passed in', () => { + const doc = sampleAlertDocAADNoSortIdWithTimestamp(); + const value = getField(doc, ALERT_REASON); + expect(value).toEqual('reasonable reason'); + }); + + test('gets legacy field when AAD field name is passed in', () => { + const doc = sampleAlertDocNoSortIdWithTimestamp(); + const value = getField(doc, ALERT_REASON); + expect(value).toEqual('reasonable reason'); + }); + + test('gets AAD field when legacy field name is passed in', () => { + const doc = sampleAlertDocAADNoSortIdWithTimestamp(); + const value = getField(doc, 'signal.reason'); + expect(value).toEqual('reasonable reason'); + }); + + test('returns `undefined` when AAD field name does not exist', () => { + const doc = sampleAlertDocNoSortIdWithTimestamp(); + const value = getField(doc, 'kibana.alert.does_not_exist'); + expect(value).toEqual(undefined); + }); + + test('returns `undefined` when legacy field name does not exist', () => { + const doc = sampleAlertDocAADNoSortIdWithTimestamp(); + const value = getField(doc, 'signal.does_not_exist'); + expect(value).toEqual(undefined); + }); + + test('returns legacy rule param when AAD rule param is passed in', () => { + const doc = sampleAlertDocNoSortIdWithTimestamp(); + const value = getField(doc, `${ALERT_RULE_PARAMETERS}.description`); + expect(value).toEqual('Descriptive description'); + }); + + test('returns AAD rule param when legacy rule param is passed in', () => { + const doc = sampleAlertDocAADNoSortIdWithTimestamp(); + const value = getField(doc, 'signal.rule.description'); + expect(value).toEqual('Descriptive description'); + }); + + test('gets legacy rule param when legacy rule param is passed in', () => { + const doc = sampleAlertDocNoSortIdWithTimestamp(); + const value = getField(doc, 'signal.rule.description'); + expect(value).toEqual('Descriptive description'); + }); + + test('gets AAD rule param when AAD rule param is passed in', () => { + const doc = sampleAlertDocAADNoSortIdWithTimestamp(); + const value = getField(doc, `${ALERT_RULE_PARAMETERS}.description`); + expect(value).toEqual('Descriptive description'); + }); + }); }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.ts index 4efe356525c1e5..de2e8975788807 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.ts @@ -5,14 +5,14 @@ * 2.0. */ import { createHash } from 'crypto'; -import { chunk, get, isEmpty, partition } from 'lodash'; +import { chunk, get, invert, isEmpty, partition } from 'lodash'; import moment from 'moment'; import uuidv5 from 'uuid/v5'; import dateMath from '@elastic/datemath'; import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { TransportResult } from '@elastic/elasticsearch'; -import { ALERT_UUID, ALERT_RULE_UUID } from '@kbn/rule-data-utils'; +import { ALERT_UUID, ALERT_RULE_UUID, ALERT_RULE_PARAMETERS } from '@kbn/rule-data-utils'; import type { ListArray, ExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; import { MAX_EXCEPTION_LIST_SIZE } from '@kbn/securitysolution-list-constants'; import { hasLargeValueList } from '@kbn/securitysolution-list-utils'; @@ -997,14 +997,49 @@ export const isRACAlert = (event: unknown): event is RACAlert => { export const racFieldMappings: Record = { 'signal.rule.id': ALERT_RULE_UUID, + 'signal.rule.description': `${ALERT_RULE_PARAMETERS}.description`, + 'signal.rule.filters': `${ALERT_RULE_PARAMETERS}.filters`, + 'signal.rule.language': `${ALERT_RULE_PARAMETERS}.language`, + 'signal.rule.query': `${ALERT_RULE_PARAMETERS}.query`, + 'signal.rule.risk_score': `${ALERT_RULE_PARAMETERS}.riskScore`, + 'signal.rule.severity': `${ALERT_RULE_PARAMETERS}.severity`, + 'signal.rule.building_block_type': `${ALERT_RULE_PARAMETERS}.buildingBlockType`, + 'signal.rule.namespace': `${ALERT_RULE_PARAMETERS}.namespace`, + 'signal.rule.note': `${ALERT_RULE_PARAMETERS}.note`, + 'signal.rule.license': `${ALERT_RULE_PARAMETERS}.license`, + 'signal.rule.output_index': `${ALERT_RULE_PARAMETERS}.outputIndex`, + 'signal.rule.timeline_id': `${ALERT_RULE_PARAMETERS}.timelineId`, + 'signal.rule.timeline_title': `${ALERT_RULE_PARAMETERS}.timelineTitle`, + 'signal.rule.meta': `${ALERT_RULE_PARAMETERS}.meta`, + 'signal.rule.rule_name_override': `${ALERT_RULE_PARAMETERS}.ruleNameOverride`, + 'signal.rule.timestamp_override': `${ALERT_RULE_PARAMETERS}.timestampOverride`, + 'signal.rule.author': `${ALERT_RULE_PARAMETERS}.author`, + 'signal.rule.false_positives': `${ALERT_RULE_PARAMETERS}.falsePositives`, + 'signal.rule.from': `${ALERT_RULE_PARAMETERS}.from`, + 'signal.rule.rule_id': `${ALERT_RULE_PARAMETERS}.ruleId`, + 'signal.rule.max_signals': `${ALERT_RULE_PARAMETERS}.maxSignals`, + 'signal.rule.risk_score_mapping': `${ALERT_RULE_PARAMETERS}.riskScoreMapping`, + 'signal.rule.severity_mapping': `${ALERT_RULE_PARAMETERS}.severityMapping`, + 'signal.rule.threat': `${ALERT_RULE_PARAMETERS}.threat`, + 'signal.rule.to': `${ALERT_RULE_PARAMETERS}.to`, + 'signal.rule.references': `${ALERT_RULE_PARAMETERS}.references`, + 'signal.rule.version': `${ALERT_RULE_PARAMETERS}.version`, + 'signal.rule.exceptions_list': `${ALERT_RULE_PARAMETERS}.exceptionsList`, + 'signal.rule.immutable': `${ALERT_RULE_PARAMETERS}.immutable`, }; export const getField = (event: SimpleHit, field: string): T | undefined => { if (isWrappedRACAlert(event)) { const mappedField = racFieldMappings[field] ?? field.replace('signal', 'kibana.alert'); + const parts = mappedField.split('.'); + if (mappedField.includes(ALERT_RULE_PARAMETERS) && parts[parts.length - 1] !== 'parameters') { + const params = get(event._source, ALERT_RULE_PARAMETERS); + return get(params, parts[parts.length - 1]); + } return get(event._source, mappedField) as T; } else if (isWrappedSignalHit(event)) { - return get(event._source, field) as T; + const mappedField = invert(racFieldMappings)[field] ?? field.replace('kibana.alert', 'signal'); + return get(event._source, mappedField) as T; } else if (isWrappedEventHit(event)) { return get(event._source, field) as T; } From 5e4a61ada74a168fd8669b3e2839c51f45761a3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Fern=C3=A1ndez=20Haro?= Date: Tue, 18 Jan 2022 20:03:47 +0100 Subject: [PATCH 018/108] [Maps][Usage collection] Do not refresh Data Views (#123155) --- .../index_pattern_stats/index_pattern_stats_collector.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/maps/server/maps_telemetry/index_pattern_stats/index_pattern_stats_collector.ts b/x-pack/plugins/maps/server/maps_telemetry/index_pattern_stats/index_pattern_stats_collector.ts index 0e5bb32be4f800..f8fbf907bca94b 100644 --- a/x-pack/plugins/maps/server/maps_telemetry/index_pattern_stats/index_pattern_stats_collector.ts +++ b/x-pack/plugins/maps/server/maps_telemetry/index_pattern_stats/index_pattern_stats_collector.ts @@ -55,7 +55,7 @@ export class IndexPatternStatsCollector { let pointCount = 0; let shapeCount = 0; - const indexPatternIds = await this._indexPatternsService.getIds(true); + const indexPatternIds = await this._indexPatternsService.getIds(); await asyncForEach(indexPatternIds, async (indexPatternId) => { let indexPattern; try { From b69487bc60b7754a85956b9db01d7108ddfbc875 Mon Sep 17 00:00:00 2001 From: Brandon Morelli Date: Tue, 18 Jan 2022 11:53:47 -0800 Subject: [PATCH 019/108] Update troubleshooting.asciidoc (#122397) * Update troubleshooting.asciidoc * Update troubleshooting.asciidoc Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- docs/apm/troubleshooting.asciidoc | 68 +++++++++---------------------- 1 file changed, 20 insertions(+), 48 deletions(-) diff --git a/docs/apm/troubleshooting.asciidoc b/docs/apm/troubleshooting.asciidoc index 814a7d374506fe..4693ed7f0d6fb7 100644 --- a/docs/apm/troubleshooting.asciidoc +++ b/docs/apm/troubleshooting.asciidoc @@ -47,37 +47,14 @@ This section can help with any of the following: There are a number of factors that could be at play here. One important thing to double-check first is your index template. -*Index template* -An APM index template must exist for the APM app to work correctly. -By default, this index template is created by APM Server on startup. -However, this only happens if `setup.template.enabled` is `true` in `apm-server.yml`. -You can create the index template manually by running `apm-server setup`. +*Index templates* +For the APM app to work correctly, an index template must exist for each APM data stream. +By default, {fleet} sets up APM index templates when the APM integration is installed. Take note that index templates *cannot* be applied retroactively -- they are only applied at index creation time. More information is available in {apm-guide-ref}/apm-server-configuration.html[Set up and configure]. -You can check for the existence of an APM index template using the -{ref}/indices-get-template.html[Get index template API]. -If you're using the default index naming pattern, that request would be: - -[source,js] --------------------------------------------------- -GET /_template/apm-{version} --------------------------------------------------- -// CONSOLE - -*Using Logstash, Kafka, etc.* -If you're not outputting data directly from APM Server to Elasticsearch (perhaps you're using Logstash or Kafka), -then the index template will not be set up automatically. Instead, you'll need to -{apm-guide-ref}/apm-server-template.html[load the template manually]. - -*Using a custom index names* -This problem can also occur if you've customized the index name that you write APM data to. -If you change the default, you must also configure the `setup.template.name` and `setup.template.pattern` options. -See {apm-guide-ref}/configuration-template.html[Load the Elasticsearch index template]. -If the Elasticsearch index template has already been successfully loaded to the index, -you can customize the indices that the APM app uses to display data. -Navigate to *APM* > *Settings* > *Indices*, and change all `xpack.apm.indices.*` values to -include the new index pattern. For example: `customIndexName-*`. +You can check for the existence of APM index templates in Kibana. +Go to **Stack Management** > **Index Management** > **Index Templates** and search for `apm`. [float] [[troubleshooting-too-many-transactions]] @@ -164,20 +141,24 @@ You can also use the Agent's public API to manually set a name for the transacti === Fields are not searchable In Elasticsearch, index templates are used to define settings and mappings that determine how fields should be analyzed. -The recommended index template file for APM Server is installed by the APM Server packages. -This template, by default, enables and disables indexing on certain fields. +The recommended index templates for APM are installed by {fleet} when the Elastic APM integration is installed. +These templates, by default, enable and disable indexing on certain fields. As an example, some agents store cookie values in `http.request.cookies`. Since `http.request` has disabled dynamic indexing, and `http.request.cookies` is not declared in a custom mapping, the values in `http.request.cookies` are not indexed and thus not searchable. -*Ensure an index pattern exists* -As a first step, you should ensure the correct index pattern exists. -Open the main menu, then click *Stack Management > Index Patterns*. -In the pattern list, you should see an apm index pattern; The default is `apm-*`. -If you don't, the index pattern doesn't exist. See <> for information on how to fix this problem. +*Ensure an APM data view exists* +As a first step, you should ensure the correct data view exists. +In {kib}, go to *Stack Management* > *Data views*. +You should see the APM data view--the default is +`traces-apm*,apm-*,logs-apm*,apm-*,metrics-apm*,apm-*`. +If you don't, the data view doesn't exist. +To fix this, navigate to the APM app in {kib} and select *Add data*. +In the APM tutorial, click *Load Kibana objects* to create the APM data view. -Selecting the `apm-*` index pattern shows a listing of every field defined in the pattern. +If creating an APM data view doesn't solve the problem, +see <> for further troubleshooting. *Ensure a field is searchable* There are two things you can do to if you'd like to ensure a field is searchable: @@ -185,18 +166,9 @@ There are two things you can do to if you'd like to ensure a field is searchable 1. Index your additional data as {apm-guide-ref}/metadata.html[labels] instead. These are dynamic by default, which means they will be indexed and become searchable and aggregatable. -2. Use the `append_fields` feature. As an example, -adding the following to `apm-server.yml` will enable dynamic indexing for `http.request.cookies`: - -[source,yml] ----- -setup.template.enabled: true -setup.template.overwrite: true -setup.template.append_fields: - - name: http.request.cookies - type: object - dynamic: true ----- +2. Create a custom mapping for the field. +// link will be added in a later PR. +// docs will be added in https://github.com/elastic/apm-server/pull/6940 [float] [[service-map-rum-connections]] From e39faea65d8086c3061ec0ba9ae4ea945e2b2006 Mon Sep 17 00:00:00 2001 From: Brian Seeders Date: Tue, 18 Jan 2022 14:56:16 -0500 Subject: [PATCH 020/108] [bazel] Setup remote cache settings on bootstrap (#121445) --- .bazelrc.common | 3 + .gitignore | 3 +- packages/kbn-pm/dist/index.js | 1581 +++++++++-------- packages/kbn-pm/src/commands/bootstrap.ts | 4 + .../src/utils/bazel/setup_remote_cache.ts | 92 + 5 files changed, 945 insertions(+), 738 deletions(-) create mode 100644 packages/kbn-pm/src/utils/bazel/setup_remote_cache.ts diff --git a/.bazelrc.common b/.bazelrc.common index e210b06ed2706b..8d865f904d600a 100644 --- a/.bazelrc.common +++ b/.bazelrc.common @@ -132,6 +132,9 @@ coverage --instrument_test_targets # Metadata settings build --workspace_status_command="node ./src/dev/bazel_workspace_status.js" +# Load remote cache settings, if they exist +try-import %workspace%/.bazelrc.cache + # Load any settings specific to the current user. # .bazelrc.user should appear in .gitignore so that settings are not shared with team members # This needs to be last statement in this diff --git a/.gitignore b/.gitignore index cd79644e5d060c..7cf2e31ac0a010 100644 --- a/.gitignore +++ b/.gitignore @@ -87,8 +87,9 @@ report.asciidoc /bazel /bazel-* .bazelrc.user +.bazelrc.cache elastic-agent-* fleet-server-* elastic-agent.yml -fleet-server.yml \ No newline at end of file +fleet-server.yml diff --git a/packages/kbn-pm/dist/index.js b/packages/kbn-pm/dist/index.js index fc92d186981322..bf51f1a97e8dd2 100644 --- a/packages/kbn-pm/dist/index.js +++ b/packages/kbn-pm/dist/index.js @@ -94,7 +94,7 @@ __webpack_require__.r(__webpack_exports__); /* harmony import */ var _cli__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "run", function() { return _cli__WEBPACK_IMPORTED_MODULE_0__["run"]; }); -/* harmony import */ var _production__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(563); +/* harmony import */ var _production__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(564); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "buildBazelProductionProjects", function() { return _production__WEBPACK_IMPORTED_MODULE_1__["buildBazelProductionProjects"]; }); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "buildNonBazelProductionProjects", function() { return _production__WEBPACK_IMPORTED_MODULE_1__["buildNonBazelProductionProjects"]; }); @@ -108,7 +108,7 @@ __webpack_require__.r(__webpack_exports__); /* harmony import */ var _utils_package_json__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(343); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "transformDependencies", function() { return _utils_package_json__WEBPACK_IMPORTED_MODULE_4__["transformDependencies"]; }); -/* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(562); +/* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(563); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "getProjectPaths", function() { return _config__WEBPACK_IMPORTED_MODULE_5__["getProjectPaths"]; }); /* @@ -141,7 +141,7 @@ __webpack_require__.r(__webpack_exports__); /* harmony import */ var _kbn_dev_utils_tooling_log__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(5); /* harmony import */ var _kbn_dev_utils_tooling_log__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_kbn_dev_utils_tooling_log__WEBPACK_IMPORTED_MODULE_3__); /* harmony import */ var _commands__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(129); -/* harmony import */ var _run__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(557); +/* harmony import */ var _run__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(558); /* harmony import */ var _utils_log__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(220); /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one @@ -8819,12 +8819,12 @@ exports.ToolingLogCollectingWriter = ToolingLogCollectingWriter; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "commands", function() { return commands; }); /* harmony import */ var _bootstrap__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(130); -/* harmony import */ var _build__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(527); -/* harmony import */ var _clean__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(528); -/* harmony import */ var _reset__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(552); -/* harmony import */ var _run__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(553); -/* harmony import */ var _watch__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(555); -/* harmony import */ var _patch_native_modules__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(556); +/* harmony import */ var _build__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(528); +/* harmony import */ var _clean__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(529); +/* harmony import */ var _reset__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(553); +/* harmony import */ var _run__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(554); +/* harmony import */ var _watch__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(556); +/* harmony import */ var _patch_native_modules__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(557); /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one * or more contributor license agreements. Licensed under the Elastic License @@ -8868,6 +8868,7 @@ __webpack_require__.r(__webpack_exports__); /* harmony import */ var _utils_sort_package_json__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(411); /* harmony import */ var _utils_validate_dependencies__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(419); /* harmony import */ var _utils_bazel__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(421); +/* harmony import */ var _utils_bazel_setup_remote_cache__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(527); function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } @@ -8891,6 +8892,7 @@ function _defineProperty(obj, key, value) { if (key in obj) { Object.definePrope + const BootstrapCommand = { description: 'Install dependencies and crosslink projects', name: 'bootstrap', @@ -8920,7 +8922,9 @@ const BootstrapCommand = { await Object(_utils_bazel__WEBPACK_IMPORTED_MODULE_9__["ensureYarnIntegrityFileExists"])(Object(path__WEBPACK_IMPORTED_MODULE_0__["resolve"])(kibanaProjectPath, 'node_modules')); // Install bazel machinery tools if needed - await Object(_utils_bazel__WEBPACK_IMPORTED_MODULE_9__["installBazelTools"])(rootPath); // Bootstrap process for Bazel packages + await Object(_utils_bazel__WEBPACK_IMPORTED_MODULE_9__["installBazelTools"])(rootPath); // Setup remote cache settings in .bazelrc.cache if needed + + await Object(_utils_bazel_setup_remote_cache__WEBPACK_IMPORTED_MODULE_10__["setupRemoteCache"])(rootPath); // Bootstrap process for Bazel packages // Bazel is now managing dependencies so yarn install // will happen as part of this // @@ -58934,6 +58938,109 @@ function observeReadable(readable) { /* 527 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "setupRemoteCache", function() { return setupRemoteCache; }); +/* harmony import */ var dedent__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2); +/* harmony import */ var dedent__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(dedent__WEBPACK_IMPORTED_MODULE_0__); +/* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(132); +/* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(fs__WEBPACK_IMPORTED_MODULE_1__); +/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(4); +/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_2__); +/* harmony import */ var _child_process__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(221); +/* harmony import */ var _log__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(220); +/* + * 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. + */ + + + + + + +async function isVaultAvailable() { + try { + await Object(_child_process__WEBPACK_IMPORTED_MODULE_3__["spawn"])('vault', ['--version'], { + stdio: 'pipe' + }); + return true; + } catch { + return false; + } +} + +async function isElasticCommitter() { + try { + const { + stdout: email + } = await Object(_child_process__WEBPACK_IMPORTED_MODULE_3__["spawn"])('git', ['config', 'user.email'], { + stdio: 'pipe' + }); + return email.trim().endsWith('@elastic.co'); + } catch { + return false; + } +} + +async function setupRemoteCache(repoRootPath) { + // The remote cache is only for Elastic employees working locally (CI cache settings are handled elsewhere) + if (process.env.CI || !(await isElasticCommitter())) { + return; + } + + _log__WEBPACK_IMPORTED_MODULE_4__["log"].debug(`[bazel_tools] setting up remote cache settings if necessary`); + const settingsPath = Object(path__WEBPACK_IMPORTED_MODULE_2__["resolve"])(repoRootPath, '.bazelrc.cache'); + + if (Object(fs__WEBPACK_IMPORTED_MODULE_1__["existsSync"])(settingsPath)) { + _log__WEBPACK_IMPORTED_MODULE_4__["log"].debug(`[bazel_tools] remote cache settings already exist, skipping`); + return; + } + + if (!(await isVaultAvailable())) { + _log__WEBPACK_IMPORTED_MODULE_4__["log"].info('[bazel_tools] vault is not available, unable to setup remote cache settings.'); + _log__WEBPACK_IMPORTED_MODULE_4__["log"].info('[bazel_tools] building packages will work, but will be slower in many cases.'); + _log__WEBPACK_IMPORTED_MODULE_4__["log"].info('[bazel_tools] reach out to Operations if you need assistance with this.'); + return; + } + + let apiKey = ''; + + try { + const { + stdout + } = await Object(_child_process__WEBPACK_IMPORTED_MODULE_3__["spawn"])('vault', ['read', '-field=readonly-key', 'secret/kibana-issues/dev/bazel-remote-cache'], { + stdio: 'pipe' + }); + apiKey = stdout.trim(); + } catch (ex) { + _log__WEBPACK_IMPORTED_MODULE_4__["log"].info('[bazel_tools] unable to read bazel remote cache key from vault, are you authenticated?'); + _log__WEBPACK_IMPORTED_MODULE_4__["log"].info('[bazel_tools] building packages will work, but will be slower in many cases.'); + _log__WEBPACK_IMPORTED_MODULE_4__["log"].info('[bazel_tools] reach out to Operations if you need assistance with this.'); + _log__WEBPACK_IMPORTED_MODULE_4__["log"].info(`[bazel_tools] ${ex}`); + return; + } + + const contents = dedent__WEBPACK_IMPORTED_MODULE_0___default.a` + # V1 - This file is automatically generated by 'yarn kbn bootstrap' + # To regenerate this file, delete it and run 'yarn kbn bootstrap' again. + build --bes_results_url=https://app.buildbuddy.io/invocation/ + build --bes_backend=grpcs://cloud.buildbuddy.io + build --remote_cache=grpcs://cloud.buildbuddy.io + build --remote_timeout=3600 + build --remote_header=${apiKey} + `; + Object(fs__WEBPACK_IMPORTED_MODULE_1__["writeFileSync"])(settingsPath, contents); + _log__WEBPACK_IMPORTED_MODULE_4__["log"].info(`[bazel_tools] remote cache settings written to ${settingsPath}`); +} + +/***/ }), +/* 528 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "BuildCommand", function() { return BuildCommand; }); @@ -58965,7 +59072,7 @@ const BuildCommand = { }; /***/ }), -/* 528 */ +/* 529 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -58975,7 +59082,7 @@ __webpack_require__.r(__webpack_exports__); /* harmony import */ var dedent__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(dedent__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var del__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(240); /* harmony import */ var del__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(del__WEBPACK_IMPORTED_MODULE_1__); -/* harmony import */ var ora__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(529); +/* harmony import */ var ora__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(530); /* harmony import */ var ora__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(ora__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(4); /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_3__); @@ -59082,20 +59189,20 @@ const CleanCommand = { }; /***/ }), -/* 529 */ +/* 530 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const readline = __webpack_require__(530); -const chalk = __webpack_require__(531); -const cliCursor = __webpack_require__(534); -const cliSpinners = __webpack_require__(536); -const logSymbols = __webpack_require__(538); -const stripAnsi = __webpack_require__(544); -const wcwidth = __webpack_require__(546); -const isInteractive = __webpack_require__(550); -const MuteStream = __webpack_require__(551); +const readline = __webpack_require__(531); +const chalk = __webpack_require__(532); +const cliCursor = __webpack_require__(535); +const cliSpinners = __webpack_require__(537); +const logSymbols = __webpack_require__(539); +const stripAnsi = __webpack_require__(545); +const wcwidth = __webpack_require__(547); +const isInteractive = __webpack_require__(551); +const MuteStream = __webpack_require__(552); const TEXT = Symbol('text'); const PREFIX_TEXT = Symbol('prefixText'); @@ -59448,13 +59555,13 @@ module.exports.promise = (action, options) => { /***/ }), -/* 530 */ +/* 531 */ /***/ (function(module, exports) { module.exports = require("readline"); /***/ }), -/* 531 */ +/* 532 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -59464,7 +59571,7 @@ const {stdout: stdoutColor, stderr: stderrColor} = __webpack_require__(121); const { stringReplaceAll, stringEncaseCRLFWithFirstIndex -} = __webpack_require__(532); +} = __webpack_require__(533); // `supportsColor.level` → `ansiStyles.color[name]` mapping const levelMapping = [ @@ -59665,7 +59772,7 @@ const chalkTag = (chalk, ...strings) => { } if (template === undefined) { - template = __webpack_require__(533); + template = __webpack_require__(534); } return template(chalk, parts.join('')); @@ -59694,7 +59801,7 @@ module.exports = chalk; /***/ }), -/* 532 */ +/* 533 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -59740,7 +59847,7 @@ module.exports = { /***/ }), -/* 533 */ +/* 534 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -59881,12 +59988,12 @@ module.exports = (chalk, temporary) => { /***/ }), -/* 534 */ +/* 535 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const restoreCursor = __webpack_require__(535); +const restoreCursor = __webpack_require__(536); let isHidden = false; @@ -59923,7 +60030,7 @@ exports.toggle = (force, writableStream) => { /***/ }), -/* 535 */ +/* 536 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -59939,13 +60046,13 @@ module.exports = onetime(() => { /***/ }), -/* 536 */ +/* 537 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const spinners = Object.assign({}, __webpack_require__(537)); +const spinners = Object.assign({}, __webpack_require__(538)); const spinnersList = Object.keys(spinners); @@ -59963,18 +60070,18 @@ module.exports.default = spinners; /***/ }), -/* 537 */ +/* 538 */ /***/ (function(module) { module.exports = JSON.parse("{\"dots\":{\"interval\":80,\"frames\":[\"⠋\",\"⠙\",\"⠹\",\"⠸\",\"⠼\",\"⠴\",\"⠦\",\"⠧\",\"⠇\",\"⠏\"]},\"dots2\":{\"interval\":80,\"frames\":[\"⣾\",\"⣽\",\"⣻\",\"⢿\",\"⡿\",\"⣟\",\"⣯\",\"⣷\"]},\"dots3\":{\"interval\":80,\"frames\":[\"⠋\",\"⠙\",\"⠚\",\"⠞\",\"⠖\",\"⠦\",\"⠴\",\"⠲\",\"⠳\",\"⠓\"]},\"dots4\":{\"interval\":80,\"frames\":[\"⠄\",\"⠆\",\"⠇\",\"⠋\",\"⠙\",\"⠸\",\"⠰\",\"⠠\",\"⠰\",\"⠸\",\"⠙\",\"⠋\",\"⠇\",\"⠆\"]},\"dots5\":{\"interval\":80,\"frames\":[\"⠋\",\"⠙\",\"⠚\",\"⠒\",\"⠂\",\"⠂\",\"⠒\",\"⠲\",\"⠴\",\"⠦\",\"⠖\",\"⠒\",\"⠐\",\"⠐\",\"⠒\",\"⠓\",\"⠋\"]},\"dots6\":{\"interval\":80,\"frames\":[\"⠁\",\"⠉\",\"⠙\",\"⠚\",\"⠒\",\"⠂\",\"⠂\",\"⠒\",\"⠲\",\"⠴\",\"⠤\",\"⠄\",\"⠄\",\"⠤\",\"⠴\",\"⠲\",\"⠒\",\"⠂\",\"⠂\",\"⠒\",\"⠚\",\"⠙\",\"⠉\",\"⠁\"]},\"dots7\":{\"interval\":80,\"frames\":[\"⠈\",\"⠉\",\"⠋\",\"⠓\",\"⠒\",\"⠐\",\"⠐\",\"⠒\",\"⠖\",\"⠦\",\"⠤\",\"⠠\",\"⠠\",\"⠤\",\"⠦\",\"⠖\",\"⠒\",\"⠐\",\"⠐\",\"⠒\",\"⠓\",\"⠋\",\"⠉\",\"⠈\"]},\"dots8\":{\"interval\":80,\"frames\":[\"⠁\",\"⠁\",\"⠉\",\"⠙\",\"⠚\",\"⠒\",\"⠂\",\"⠂\",\"⠒\",\"⠲\",\"⠴\",\"⠤\",\"⠄\",\"⠄\",\"⠤\",\"⠠\",\"⠠\",\"⠤\",\"⠦\",\"⠖\",\"⠒\",\"⠐\",\"⠐\",\"⠒\",\"⠓\",\"⠋\",\"⠉\",\"⠈\",\"⠈\"]},\"dots9\":{\"interval\":80,\"frames\":[\"⢹\",\"⢺\",\"⢼\",\"⣸\",\"⣇\",\"⡧\",\"⡗\",\"⡏\"]},\"dots10\":{\"interval\":80,\"frames\":[\"⢄\",\"⢂\",\"⢁\",\"⡁\",\"⡈\",\"⡐\",\"⡠\"]},\"dots11\":{\"interval\":100,\"frames\":[\"⠁\",\"⠂\",\"⠄\",\"⡀\",\"⢀\",\"⠠\",\"⠐\",\"⠈\"]},\"dots12\":{\"interval\":80,\"frames\":[\"⢀⠀\",\"⡀⠀\",\"⠄⠀\",\"⢂⠀\",\"⡂⠀\",\"⠅⠀\",\"⢃⠀\",\"⡃⠀\",\"⠍⠀\",\"⢋⠀\",\"⡋⠀\",\"⠍⠁\",\"⢋⠁\",\"⡋⠁\",\"⠍⠉\",\"⠋⠉\",\"⠋⠉\",\"⠉⠙\",\"⠉⠙\",\"⠉⠩\",\"⠈⢙\",\"⠈⡙\",\"⢈⠩\",\"⡀⢙\",\"⠄⡙\",\"⢂⠩\",\"⡂⢘\",\"⠅⡘\",\"⢃⠨\",\"⡃⢐\",\"⠍⡐\",\"⢋⠠\",\"⡋⢀\",\"⠍⡁\",\"⢋⠁\",\"⡋⠁\",\"⠍⠉\",\"⠋⠉\",\"⠋⠉\",\"⠉⠙\",\"⠉⠙\",\"⠉⠩\",\"⠈⢙\",\"⠈⡙\",\"⠈⠩\",\"⠀⢙\",\"⠀⡙\",\"⠀⠩\",\"⠀⢘\",\"⠀⡘\",\"⠀⠨\",\"⠀⢐\",\"⠀⡐\",\"⠀⠠\",\"⠀⢀\",\"⠀⡀\"]},\"dots8Bit\":{\"interval\":80,\"frames\":[\"⠀\",\"⠁\",\"⠂\",\"⠃\",\"⠄\",\"⠅\",\"⠆\",\"⠇\",\"⡀\",\"⡁\",\"⡂\",\"⡃\",\"⡄\",\"⡅\",\"⡆\",\"⡇\",\"⠈\",\"⠉\",\"⠊\",\"⠋\",\"⠌\",\"⠍\",\"⠎\",\"⠏\",\"⡈\",\"⡉\",\"⡊\",\"⡋\",\"⡌\",\"⡍\",\"⡎\",\"⡏\",\"⠐\",\"⠑\",\"⠒\",\"⠓\",\"⠔\",\"⠕\",\"⠖\",\"⠗\",\"⡐\",\"⡑\",\"⡒\",\"⡓\",\"⡔\",\"⡕\",\"⡖\",\"⡗\",\"⠘\",\"⠙\",\"⠚\",\"⠛\",\"⠜\",\"⠝\",\"⠞\",\"⠟\",\"⡘\",\"⡙\",\"⡚\",\"⡛\",\"⡜\",\"⡝\",\"⡞\",\"⡟\",\"⠠\",\"⠡\",\"⠢\",\"⠣\",\"⠤\",\"⠥\",\"⠦\",\"⠧\",\"⡠\",\"⡡\",\"⡢\",\"⡣\",\"⡤\",\"⡥\",\"⡦\",\"⡧\",\"⠨\",\"⠩\",\"⠪\",\"⠫\",\"⠬\",\"⠭\",\"⠮\",\"⠯\",\"⡨\",\"⡩\",\"⡪\",\"⡫\",\"⡬\",\"⡭\",\"⡮\",\"⡯\",\"⠰\",\"⠱\",\"⠲\",\"⠳\",\"⠴\",\"⠵\",\"⠶\",\"⠷\",\"⡰\",\"⡱\",\"⡲\",\"⡳\",\"⡴\",\"⡵\",\"⡶\",\"⡷\",\"⠸\",\"⠹\",\"⠺\",\"⠻\",\"⠼\",\"⠽\",\"⠾\",\"⠿\",\"⡸\",\"⡹\",\"⡺\",\"⡻\",\"⡼\",\"⡽\",\"⡾\",\"⡿\",\"⢀\",\"⢁\",\"⢂\",\"⢃\",\"⢄\",\"⢅\",\"⢆\",\"⢇\",\"⣀\",\"⣁\",\"⣂\",\"⣃\",\"⣄\",\"⣅\",\"⣆\",\"⣇\",\"⢈\",\"⢉\",\"⢊\",\"⢋\",\"⢌\",\"⢍\",\"⢎\",\"⢏\",\"⣈\",\"⣉\",\"⣊\",\"⣋\",\"⣌\",\"⣍\",\"⣎\",\"⣏\",\"⢐\",\"⢑\",\"⢒\",\"⢓\",\"⢔\",\"⢕\",\"⢖\",\"⢗\",\"⣐\",\"⣑\",\"⣒\",\"⣓\",\"⣔\",\"⣕\",\"⣖\",\"⣗\",\"⢘\",\"⢙\",\"⢚\",\"⢛\",\"⢜\",\"⢝\",\"⢞\",\"⢟\",\"⣘\",\"⣙\",\"⣚\",\"⣛\",\"⣜\",\"⣝\",\"⣞\",\"⣟\",\"⢠\",\"⢡\",\"⢢\",\"⢣\",\"⢤\",\"⢥\",\"⢦\",\"⢧\",\"⣠\",\"⣡\",\"⣢\",\"⣣\",\"⣤\",\"⣥\",\"⣦\",\"⣧\",\"⢨\",\"⢩\",\"⢪\",\"⢫\",\"⢬\",\"⢭\",\"⢮\",\"⢯\",\"⣨\",\"⣩\",\"⣪\",\"⣫\",\"⣬\",\"⣭\",\"⣮\",\"⣯\",\"⢰\",\"⢱\",\"⢲\",\"⢳\",\"⢴\",\"⢵\",\"⢶\",\"⢷\",\"⣰\",\"⣱\",\"⣲\",\"⣳\",\"⣴\",\"⣵\",\"⣶\",\"⣷\",\"⢸\",\"⢹\",\"⢺\",\"⢻\",\"⢼\",\"⢽\",\"⢾\",\"⢿\",\"⣸\",\"⣹\",\"⣺\",\"⣻\",\"⣼\",\"⣽\",\"⣾\",\"⣿\"]},\"line\":{\"interval\":130,\"frames\":[\"-\",\"\\\\\",\"|\",\"/\"]},\"line2\":{\"interval\":100,\"frames\":[\"⠂\",\"-\",\"–\",\"—\",\"–\",\"-\"]},\"pipe\":{\"interval\":100,\"frames\":[\"┤\",\"┘\",\"┴\",\"└\",\"├\",\"┌\",\"┬\",\"┐\"]},\"simpleDots\":{\"interval\":400,\"frames\":[\". \",\".. \",\"...\",\" \"]},\"simpleDotsScrolling\":{\"interval\":200,\"frames\":[\". \",\".. \",\"...\",\" ..\",\" .\",\" \"]},\"star\":{\"interval\":70,\"frames\":[\"✶\",\"✸\",\"✹\",\"✺\",\"✹\",\"✷\"]},\"star2\":{\"interval\":80,\"frames\":[\"+\",\"x\",\"*\"]},\"flip\":{\"interval\":70,\"frames\":[\"_\",\"_\",\"_\",\"-\",\"`\",\"`\",\"'\",\"´\",\"-\",\"_\",\"_\",\"_\"]},\"hamburger\":{\"interval\":100,\"frames\":[\"☱\",\"☲\",\"☴\"]},\"growVertical\":{\"interval\":120,\"frames\":[\"▁\",\"▃\",\"▄\",\"▅\",\"▆\",\"▇\",\"▆\",\"▅\",\"▄\",\"▃\"]},\"growHorizontal\":{\"interval\":120,\"frames\":[\"▏\",\"▎\",\"▍\",\"▌\",\"▋\",\"▊\",\"▉\",\"▊\",\"▋\",\"▌\",\"▍\",\"▎\"]},\"balloon\":{\"interval\":140,\"frames\":[\" \",\".\",\"o\",\"O\",\"@\",\"*\",\" \"]},\"balloon2\":{\"interval\":120,\"frames\":[\".\",\"o\",\"O\",\"°\",\"O\",\"o\",\".\"]},\"noise\":{\"interval\":100,\"frames\":[\"▓\",\"▒\",\"░\"]},\"bounce\":{\"interval\":120,\"frames\":[\"⠁\",\"⠂\",\"⠄\",\"⠂\"]},\"boxBounce\":{\"interval\":120,\"frames\":[\"▖\",\"▘\",\"▝\",\"▗\"]},\"boxBounce2\":{\"interval\":100,\"frames\":[\"▌\",\"▀\",\"▐\",\"▄\"]},\"triangle\":{\"interval\":50,\"frames\":[\"◢\",\"◣\",\"◤\",\"◥\"]},\"arc\":{\"interval\":100,\"frames\":[\"◜\",\"◠\",\"◝\",\"◞\",\"◡\",\"◟\"]},\"circle\":{\"interval\":120,\"frames\":[\"◡\",\"⊙\",\"◠\"]},\"squareCorners\":{\"interval\":180,\"frames\":[\"◰\",\"◳\",\"◲\",\"◱\"]},\"circleQuarters\":{\"interval\":120,\"frames\":[\"◴\",\"◷\",\"◶\",\"◵\"]},\"circleHalves\":{\"interval\":50,\"frames\":[\"◐\",\"◓\",\"◑\",\"◒\"]},\"squish\":{\"interval\":100,\"frames\":[\"╫\",\"╪\"]},\"toggle\":{\"interval\":250,\"frames\":[\"⊶\",\"⊷\"]},\"toggle2\":{\"interval\":80,\"frames\":[\"▫\",\"▪\"]},\"toggle3\":{\"interval\":120,\"frames\":[\"□\",\"■\"]},\"toggle4\":{\"interval\":100,\"frames\":[\"■\",\"□\",\"▪\",\"▫\"]},\"toggle5\":{\"interval\":100,\"frames\":[\"▮\",\"▯\"]},\"toggle6\":{\"interval\":300,\"frames\":[\"ဝ\",\"၀\"]},\"toggle7\":{\"interval\":80,\"frames\":[\"⦾\",\"⦿\"]},\"toggle8\":{\"interval\":100,\"frames\":[\"◍\",\"◌\"]},\"toggle9\":{\"interval\":100,\"frames\":[\"◉\",\"◎\"]},\"toggle10\":{\"interval\":100,\"frames\":[\"㊂\",\"㊀\",\"㊁\"]},\"toggle11\":{\"interval\":50,\"frames\":[\"⧇\",\"⧆\"]},\"toggle12\":{\"interval\":120,\"frames\":[\"☗\",\"☖\"]},\"toggle13\":{\"interval\":80,\"frames\":[\"=\",\"*\",\"-\"]},\"arrow\":{\"interval\":100,\"frames\":[\"←\",\"↖\",\"↑\",\"↗\",\"→\",\"↘\",\"↓\",\"↙\"]},\"arrow2\":{\"interval\":80,\"frames\":[\"⬆️ \",\"↗️ \",\"➡️ \",\"↘️ \",\"⬇️ \",\"↙️ \",\"⬅️ \",\"↖️ \"]},\"arrow3\":{\"interval\":120,\"frames\":[\"▹▹▹▹▹\",\"▸▹▹▹▹\",\"▹▸▹▹▹\",\"▹▹▸▹▹\",\"▹▹▹▸▹\",\"▹▹▹▹▸\"]},\"bouncingBar\":{\"interval\":80,\"frames\":[\"[ ]\",\"[= ]\",\"[== ]\",\"[=== ]\",\"[ ===]\",\"[ ==]\",\"[ =]\",\"[ ]\",\"[ =]\",\"[ ==]\",\"[ ===]\",\"[====]\",\"[=== ]\",\"[== ]\",\"[= ]\"]},\"bouncingBall\":{\"interval\":80,\"frames\":[\"( ● )\",\"( ● )\",\"( ● )\",\"( ● )\",\"( ●)\",\"( ● )\",\"( ● )\",\"( ● )\",\"( ● )\",\"(● )\"]},\"smiley\":{\"interval\":200,\"frames\":[\"😄 \",\"😝 \"]},\"monkey\":{\"interval\":300,\"frames\":[\"🙈 \",\"🙈 \",\"🙉 \",\"🙊 \"]},\"hearts\":{\"interval\":100,\"frames\":[\"💛 \",\"💙 \",\"💜 \",\"💚 \",\"❤️ \"]},\"clock\":{\"interval\":100,\"frames\":[\"🕛 \",\"🕐 \",\"🕑 \",\"🕒 \",\"🕓 \",\"🕔 \",\"🕕 \",\"🕖 \",\"🕗 \",\"🕘 \",\"🕙 \",\"🕚 \"]},\"earth\":{\"interval\":180,\"frames\":[\"🌍 \",\"🌎 \",\"🌏 \"]},\"material\":{\"interval\":17,\"frames\":[\"█▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁\",\"██▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁\",\"███▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁\",\"████▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁\",\"██████▁▁▁▁▁▁▁▁▁▁▁▁▁▁\",\"██████▁▁▁▁▁▁▁▁▁▁▁▁▁▁\",\"███████▁▁▁▁▁▁▁▁▁▁▁▁▁\",\"████████▁▁▁▁▁▁▁▁▁▁▁▁\",\"█████████▁▁▁▁▁▁▁▁▁▁▁\",\"█████████▁▁▁▁▁▁▁▁▁▁▁\",\"██████████▁▁▁▁▁▁▁▁▁▁\",\"███████████▁▁▁▁▁▁▁▁▁\",\"█████████████▁▁▁▁▁▁▁\",\"██████████████▁▁▁▁▁▁\",\"██████████████▁▁▁▁▁▁\",\"▁██████████████▁▁▁▁▁\",\"▁██████████████▁▁▁▁▁\",\"▁██████████████▁▁▁▁▁\",\"▁▁██████████████▁▁▁▁\",\"▁▁▁██████████████▁▁▁\",\"▁▁▁▁█████████████▁▁▁\",\"▁▁▁▁██████████████▁▁\",\"▁▁▁▁██████████████▁▁\",\"▁▁▁▁▁██████████████▁\",\"▁▁▁▁▁██████████████▁\",\"▁▁▁▁▁██████████████▁\",\"▁▁▁▁▁▁██████████████\",\"▁▁▁▁▁▁██████████████\",\"▁▁▁▁▁▁▁█████████████\",\"▁▁▁▁▁▁▁█████████████\",\"▁▁▁▁▁▁▁▁████████████\",\"▁▁▁▁▁▁▁▁████████████\",\"▁▁▁▁▁▁▁▁▁███████████\",\"▁▁▁▁▁▁▁▁▁███████████\",\"▁▁▁▁▁▁▁▁▁▁██████████\",\"▁▁▁▁▁▁▁▁▁▁██████████\",\"▁▁▁▁▁▁▁▁▁▁▁▁████████\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁███████\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁▁██████\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█████\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█████\",\"█▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁████\",\"██▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁███\",\"██▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁███\",\"███▁▁▁▁▁▁▁▁▁▁▁▁▁▁███\",\"████▁▁▁▁▁▁▁▁▁▁▁▁▁▁██\",\"█████▁▁▁▁▁▁▁▁▁▁▁▁▁▁█\",\"█████▁▁▁▁▁▁▁▁▁▁▁▁▁▁█\",\"██████▁▁▁▁▁▁▁▁▁▁▁▁▁█\",\"████████▁▁▁▁▁▁▁▁▁▁▁▁\",\"█████████▁▁▁▁▁▁▁▁▁▁▁\",\"█████████▁▁▁▁▁▁▁▁▁▁▁\",\"█████████▁▁▁▁▁▁▁▁▁▁▁\",\"█████████▁▁▁▁▁▁▁▁▁▁▁\",\"███████████▁▁▁▁▁▁▁▁▁\",\"████████████▁▁▁▁▁▁▁▁\",\"████████████▁▁▁▁▁▁▁▁\",\"██████████████▁▁▁▁▁▁\",\"██████████████▁▁▁▁▁▁\",\"▁██████████████▁▁▁▁▁\",\"▁██████████████▁▁▁▁▁\",\"▁▁▁█████████████▁▁▁▁\",\"▁▁▁▁▁████████████▁▁▁\",\"▁▁▁▁▁████████████▁▁▁\",\"▁▁▁▁▁▁███████████▁▁▁\",\"▁▁▁▁▁▁▁▁█████████▁▁▁\",\"▁▁▁▁▁▁▁▁█████████▁▁▁\",\"▁▁▁▁▁▁▁▁▁█████████▁▁\",\"▁▁▁▁▁▁▁▁▁█████████▁▁\",\"▁▁▁▁▁▁▁▁▁▁█████████▁\",\"▁▁▁▁▁▁▁▁▁▁▁████████▁\",\"▁▁▁▁▁▁▁▁▁▁▁████████▁\",\"▁▁▁▁▁▁▁▁▁▁▁▁███████▁\",\"▁▁▁▁▁▁▁▁▁▁▁▁███████▁\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁███████\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁███████\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█████\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁████\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁████\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁████\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁███\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁███\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁██\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁██\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁██\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁\",\"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁\"]},\"moon\":{\"interval\":80,\"frames\":[\"🌑 \",\"🌒 \",\"🌓 \",\"🌔 \",\"🌕 \",\"🌖 \",\"🌗 \",\"🌘 \"]},\"runner\":{\"interval\":140,\"frames\":[\"🚶 \",\"🏃 \"]},\"pong\":{\"interval\":80,\"frames\":[\"▐⠂ ▌\",\"▐⠈ ▌\",\"▐ ⠂ ▌\",\"▐ ⠠ ▌\",\"▐ ⡀ ▌\",\"▐ ⠠ ▌\",\"▐ ⠂ ▌\",\"▐ ⠈ ▌\",\"▐ ⠂ ▌\",\"▐ ⠠ ▌\",\"▐ ⡀ ▌\",\"▐ ⠠ ▌\",\"▐ ⠂ ▌\",\"▐ ⠈ ▌\",\"▐ ⠂▌\",\"▐ ⠠▌\",\"▐ ⡀▌\",\"▐ ⠠ ▌\",\"▐ ⠂ ▌\",\"▐ ⠈ ▌\",\"▐ ⠂ ▌\",\"▐ ⠠ ▌\",\"▐ ⡀ ▌\",\"▐ ⠠ ▌\",\"▐ ⠂ ▌\",\"▐ ⠈ ▌\",\"▐ ⠂ ▌\",\"▐ ⠠ ▌\",\"▐ ⡀ ▌\",\"▐⠠ ▌\"]},\"shark\":{\"interval\":120,\"frames\":[\"▐|\\\\____________▌\",\"▐_|\\\\___________▌\",\"▐__|\\\\__________▌\",\"▐___|\\\\_________▌\",\"▐____|\\\\________▌\",\"▐_____|\\\\_______▌\",\"▐______|\\\\______▌\",\"▐_______|\\\\_____▌\",\"▐________|\\\\____▌\",\"▐_________|\\\\___▌\",\"▐__________|\\\\__▌\",\"▐___________|\\\\_▌\",\"▐____________|\\\\▌\",\"▐____________/|▌\",\"▐___________/|_▌\",\"▐__________/|__▌\",\"▐_________/|___▌\",\"▐________/|____▌\",\"▐_______/|_____▌\",\"▐______/|______▌\",\"▐_____/|_______▌\",\"▐____/|________▌\",\"▐___/|_________▌\",\"▐__/|__________▌\",\"▐_/|___________▌\",\"▐/|____________▌\"]},\"dqpb\":{\"interval\":100,\"frames\":[\"d\",\"q\",\"p\",\"b\"]},\"weather\":{\"interval\":100,\"frames\":[\"☀️ \",\"☀️ \",\"☀️ \",\"🌤 \",\"⛅️ \",\"🌥 \",\"☁️ \",\"🌧 \",\"🌨 \",\"🌧 \",\"🌨 \",\"🌧 \",\"🌨 \",\"⛈ \",\"🌨 \",\"🌧 \",\"🌨 \",\"☁️ \",\"🌥 \",\"⛅️ \",\"🌤 \",\"☀️ \",\"☀️ \"]},\"christmas\":{\"interval\":400,\"frames\":[\"🌲\",\"🎄\"]},\"grenade\":{\"interval\":80,\"frames\":[\"، \",\"′ \",\" ´ \",\" ‾ \",\" ⸌\",\" ⸊\",\" |\",\" ⁎\",\" ⁕\",\" ෴ \",\" ⁓\",\" \",\" \",\" \"]},\"point\":{\"interval\":125,\"frames\":[\"∙∙∙\",\"●∙∙\",\"∙●∙\",\"∙∙●\",\"∙∙∙\"]},\"layer\":{\"interval\":150,\"frames\":[\"-\",\"=\",\"≡\"]},\"betaWave\":{\"interval\":80,\"frames\":[\"ρββββββ\",\"βρβββββ\",\"ββρββββ\",\"βββρβββ\",\"ββββρββ\",\"βββββρβ\",\"ββββββρ\"]},\"aesthetic\":{\"interval\":80,\"frames\":[\"▰▱▱▱▱▱▱\",\"▰▰▱▱▱▱▱\",\"▰▰▰▱▱▱▱\",\"▰▰▰▰▱▱▱\",\"▰▰▰▰▰▱▱\",\"▰▰▰▰▰▰▱\",\"▰▰▰▰▰▰▰\",\"▰▱▱▱▱▱▱\"]}}"); /***/ }), -/* 538 */ +/* 539 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const chalk = __webpack_require__(539); +const chalk = __webpack_require__(540); const isSupported = process.platform !== 'win32' || process.env.CI || process.env.TERM === 'xterm-256color'; @@ -59996,16 +60103,16 @@ module.exports = isSupported ? main : fallbacks; /***/ }), -/* 539 */ +/* 540 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const escapeStringRegexp = __webpack_require__(357); -const ansiStyles = __webpack_require__(540); -const stdoutColor = __webpack_require__(541).stdout; +const ansiStyles = __webpack_require__(541); +const stdoutColor = __webpack_require__(542).stdout; -const template = __webpack_require__(543); +const template = __webpack_require__(544); const isSimpleWindowsTerm = process.platform === 'win32' && !(process.env.TERM || '').toLowerCase().startsWith('xterm'); @@ -60231,7 +60338,7 @@ module.exports.default = module.exports; // For TypeScript /***/ }), -/* 540 */ +/* 541 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -60404,13 +60511,13 @@ Object.defineProperty(module, 'exports', { /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(116)(module))) /***/ }), -/* 541 */ +/* 542 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const os = __webpack_require__(122); -const hasFlag = __webpack_require__(542); +const hasFlag = __webpack_require__(543); const env = process.env; @@ -60542,7 +60649,7 @@ module.exports = { /***/ }), -/* 542 */ +/* 543 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -60557,7 +60664,7 @@ module.exports = (flag, argv) => { /***/ }), -/* 543 */ +/* 544 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -60692,18 +60799,18 @@ module.exports = (chalk, tmp) => { /***/ }), -/* 544 */ +/* 545 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const ansiRegex = __webpack_require__(545); +const ansiRegex = __webpack_require__(546); module.exports = string => typeof string === 'string' ? string.replace(ansiRegex(), '') : string; /***/ }), -/* 545 */ +/* 546 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -60720,14 +60827,14 @@ module.exports = ({onlyFirst = false} = {}) => { /***/ }), -/* 546 */ +/* 547 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var defaults = __webpack_require__(547) -var combining = __webpack_require__(549) +var defaults = __webpack_require__(548) +var combining = __webpack_require__(550) var DEFAULTS = { nul: 0, @@ -60826,10 +60933,10 @@ function bisearch(ucs) { /***/ }), -/* 547 */ +/* 548 */ /***/ (function(module, exports, __webpack_require__) { -var clone = __webpack_require__(548); +var clone = __webpack_require__(549); module.exports = function(options, defaults) { options = options || {}; @@ -60844,7 +60951,7 @@ module.exports = function(options, defaults) { }; /***/ }), -/* 548 */ +/* 549 */ /***/ (function(module, exports, __webpack_require__) { var clone = (function() { @@ -61016,7 +61123,7 @@ if ( true && module.exports) { /***/ }), -/* 549 */ +/* 550 */ /***/ (function(module, exports) { module.exports = [ @@ -61072,7 +61179,7 @@ module.exports = [ /***/ }), -/* 550 */ +/* 551 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -61088,7 +61195,7 @@ module.exports = ({stream = process.stdout} = {}) => { /***/ }), -/* 551 */ +/* 552 */ /***/ (function(module, exports, __webpack_require__) { var Stream = __webpack_require__(173) @@ -61239,7 +61346,7 @@ MuteStream.prototype.close = proxy('close') /***/ }), -/* 552 */ +/* 553 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -61249,7 +61356,7 @@ __webpack_require__.r(__webpack_exports__); /* harmony import */ var dedent__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(dedent__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var del__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(240); /* harmony import */ var del__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(del__WEBPACK_IMPORTED_MODULE_1__); -/* harmony import */ var ora__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(529); +/* harmony import */ var ora__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(530); /* harmony import */ var ora__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(ora__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(4); /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_3__); @@ -61362,7 +61469,7 @@ const ResetCommand = { }; /***/ }), -/* 553 */ +/* 554 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -61372,7 +61479,7 @@ __webpack_require__.r(__webpack_exports__); /* harmony import */ var dedent__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(dedent__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var _utils_errors__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(341); /* harmony import */ var _utils_log__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(220); -/* harmony import */ var _utils_parallelize__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(554); +/* harmony import */ var _utils_parallelize__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(555); /* harmony import */ var _utils_projects__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(340); /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one @@ -61431,7 +61538,7 @@ const RunCommand = { }; /***/ }), -/* 554 */ +/* 555 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -61486,7 +61593,7 @@ async function parallelize(items, fn, concurrency = 4) { } /***/ }), -/* 555 */ +/* 556 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -61523,7 +61630,7 @@ const WatchCommand = { }; /***/ }), -/* 556 */ +/* 557 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -61603,7 +61710,7 @@ const PatchNativeModulesCommand = { }; /***/ }), -/* 557 */ +/* 558 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -61615,7 +61722,7 @@ __webpack_require__.r(__webpack_exports__); /* harmony import */ var _utils_log__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(220); /* harmony import */ var _utils_projects__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(340); /* harmony import */ var _utils_projects_tree__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(420); -/* harmony import */ var _utils_kibana__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(558); +/* harmony import */ var _utils_kibana__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(559); function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } @@ -61734,7 +61841,7 @@ function toArray(value) { } /***/ }), -/* 558 */ +/* 559 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -61744,13 +61851,13 @@ __webpack_require__.r(__webpack_exports__); /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(132); /* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(fs__WEBPACK_IMPORTED_MODULE_1__); -/* harmony import */ var multimatch__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(559); +/* harmony import */ var multimatch__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(560); /* harmony import */ var multimatch__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(multimatch__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var is_path_inside__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(333); /* harmony import */ var is_path_inside__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(is_path_inside__WEBPACK_IMPORTED_MODULE_3__); /* harmony import */ var _yarn_lock__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(408); /* harmony import */ var _projects__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(340); -/* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(562); +/* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(563); function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } @@ -61914,15 +62021,15 @@ class Kibana { } /***/ }), -/* 559 */ +/* 560 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const minimatch = __webpack_require__(247); const arrayUnion = __webpack_require__(242); -const arrayDiffer = __webpack_require__(560); -const arrify = __webpack_require__(561); +const arrayDiffer = __webpack_require__(561); +const arrify = __webpack_require__(562); module.exports = (list, patterns, options = {}) => { list = arrify(list); @@ -61946,7 +62053,7 @@ module.exports = (list, patterns, options = {}) => { /***/ }), -/* 560 */ +/* 561 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -61961,7 +62068,7 @@ module.exports = arrayDiffer; /***/ }), -/* 561 */ +/* 562 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -61991,7 +62098,7 @@ module.exports = arrify; /***/ }), -/* 562 */ +/* 563 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -62051,15 +62158,15 @@ function getProjectPaths({ } /***/ }), -/* 563 */ +/* 564 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); -/* harmony import */ var _build_bazel_production_projects__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(564); +/* harmony import */ var _build_bazel_production_projects__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(565); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "buildBazelProductionProjects", function() { return _build_bazel_production_projects__WEBPACK_IMPORTED_MODULE_0__["buildBazelProductionProjects"]; }); -/* harmony import */ var _build_non_bazel_production_projects__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(811); +/* harmony import */ var _build_non_bazel_production_projects__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(812); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "buildNonBazelProductionProjects", function() { return _build_non_bazel_production_projects__WEBPACK_IMPORTED_MODULE_1__["buildNonBazelProductionProjects"]; }); /* @@ -62073,19 +62180,19 @@ __webpack_require__.r(__webpack_exports__); /***/ }), -/* 564 */ +/* 565 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "buildBazelProductionProjects", function() { return buildBazelProductionProjects; }); -/* harmony import */ var cpy__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(565); +/* harmony import */ var cpy__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(566); /* harmony import */ var cpy__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(cpy__WEBPACK_IMPORTED_MODULE_0__); -/* harmony import */ var globby__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(777); +/* harmony import */ var globby__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(778); /* harmony import */ var globby__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(globby__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(4); /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_2__); -/* harmony import */ var _build_non_bazel_production_projects__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(811); +/* harmony import */ var _build_non_bazel_production_projects__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(812); /* harmony import */ var _utils_bazel__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(421); /* harmony import */ var _utils_fs__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(231); /* harmony import */ var _utils_log__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(220); @@ -62180,7 +62287,7 @@ async function applyCorrectPermissions(project, kibanaRoot, buildRoot) { } /***/ }), -/* 565 */ +/* 566 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -62188,14 +62295,14 @@ async function applyCorrectPermissions(project, kibanaRoot, buildRoot) { const EventEmitter = __webpack_require__(164); const path = __webpack_require__(4); const os = __webpack_require__(122); -const pMap = __webpack_require__(566); -const arrify = __webpack_require__(561); -const globby = __webpack_require__(569); -const hasGlob = __webpack_require__(761); -const cpFile = __webpack_require__(763); -const junk = __webpack_require__(773); -const pFilter = __webpack_require__(774); -const CpyError = __webpack_require__(776); +const pMap = __webpack_require__(567); +const arrify = __webpack_require__(562); +const globby = __webpack_require__(570); +const hasGlob = __webpack_require__(762); +const cpFile = __webpack_require__(764); +const junk = __webpack_require__(774); +const pFilter = __webpack_require__(775); +const CpyError = __webpack_require__(777); const defaultOptions = { ignoreJunk: true @@ -62346,12 +62453,12 @@ module.exports = (source, destination, { /***/ }), -/* 566 */ +/* 567 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const AggregateError = __webpack_require__(567); +const AggregateError = __webpack_require__(568); module.exports = async ( iterable, @@ -62434,12 +62541,12 @@ module.exports = async ( /***/ }), -/* 567 */ +/* 568 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const indentString = __webpack_require__(568); +const indentString = __webpack_require__(569); const cleanStack = __webpack_require__(338); const cleanInternalStack = stack => stack.replace(/\s+at .*aggregate-error\/index.js:\d+:\d+\)?/g, ''); @@ -62488,7 +62595,7 @@ module.exports = AggregateError; /***/ }), -/* 568 */ +/* 569 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -62530,17 +62637,17 @@ module.exports = (string, count = 1, options) => { /***/ }), -/* 569 */ +/* 570 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const fs = __webpack_require__(132); -const arrayUnion = __webpack_require__(570); +const arrayUnion = __webpack_require__(571); const glob = __webpack_require__(244); -const fastGlob = __webpack_require__(572); -const dirGlob = __webpack_require__(755); -const gitignore = __webpack_require__(758); +const fastGlob = __webpack_require__(573); +const dirGlob = __webpack_require__(756); +const gitignore = __webpack_require__(759); const DEFAULT_FILTER = () => false; @@ -62685,12 +62792,12 @@ module.exports.gitignore = gitignore; /***/ }), -/* 570 */ +/* 571 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var arrayUniq = __webpack_require__(571); +var arrayUniq = __webpack_require__(572); module.exports = function () { return arrayUniq([].concat.apply([], arguments)); @@ -62698,7 +62805,7 @@ module.exports = function () { /***/ }), -/* 571 */ +/* 572 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -62767,10 +62874,10 @@ if ('Set' in global) { /***/ }), -/* 572 */ +/* 573 */ /***/ (function(module, exports, __webpack_require__) { -const pkg = __webpack_require__(573); +const pkg = __webpack_require__(574); module.exports = pkg.async; module.exports.default = pkg.async; @@ -62783,19 +62890,19 @@ module.exports.generateTasks = pkg.generateTasks; /***/ }), -/* 573 */ +/* 574 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -var optionsManager = __webpack_require__(574); -var taskManager = __webpack_require__(575); -var reader_async_1 = __webpack_require__(726); -var reader_stream_1 = __webpack_require__(750); -var reader_sync_1 = __webpack_require__(751); -var arrayUtils = __webpack_require__(753); -var streamUtils = __webpack_require__(754); +var optionsManager = __webpack_require__(575); +var taskManager = __webpack_require__(576); +var reader_async_1 = __webpack_require__(727); +var reader_stream_1 = __webpack_require__(751); +var reader_sync_1 = __webpack_require__(752); +var arrayUtils = __webpack_require__(754); +var streamUtils = __webpack_require__(755); /** * Synchronous API. */ @@ -62861,7 +62968,7 @@ function isString(source) { /***/ }), -/* 574 */ +/* 575 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -62899,13 +63006,13 @@ exports.prepare = prepare; /***/ }), -/* 575 */ +/* 576 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -var patternUtils = __webpack_require__(576); +var patternUtils = __webpack_require__(577); /** * Generate tasks based on parent directory of each pattern. */ @@ -62996,16 +63103,16 @@ exports.convertPatternGroupToTask = convertPatternGroupToTask; /***/ }), -/* 576 */ +/* 577 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var path = __webpack_require__(4); -var globParent = __webpack_require__(577); +var globParent = __webpack_require__(578); var isGlob = __webpack_require__(266); -var micromatch = __webpack_require__(580); +var micromatch = __webpack_require__(581); var GLOBSTAR = '**'; /** * Return true for static pattern. @@ -63151,15 +63258,15 @@ exports.matchAny = matchAny; /***/ }), -/* 577 */ +/* 578 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var path = __webpack_require__(4); -var isglob = __webpack_require__(578); -var pathDirname = __webpack_require__(579); +var isglob = __webpack_require__(579); +var pathDirname = __webpack_require__(580); var isWin32 = __webpack_require__(122).platform() === 'win32'; module.exports = function globParent(str) { @@ -63182,7 +63289,7 @@ module.exports = function globParent(str) { /***/ }), -/* 578 */ +/* 579 */ /***/ (function(module, exports, __webpack_require__) { /*! @@ -63213,7 +63320,7 @@ module.exports = function isGlob(str) { /***/ }), -/* 579 */ +/* 580 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -63363,7 +63470,7 @@ module.exports.win32 = win32; /***/ }), -/* 580 */ +/* 581 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -63374,18 +63481,18 @@ module.exports.win32 = win32; */ var util = __webpack_require__(113); -var braces = __webpack_require__(581); -var toRegex = __webpack_require__(582); -var extend = __webpack_require__(694); +var braces = __webpack_require__(582); +var toRegex = __webpack_require__(583); +var extend = __webpack_require__(695); /** * Local dependencies */ -var compilers = __webpack_require__(696); -var parsers = __webpack_require__(722); -var cache = __webpack_require__(723); -var utils = __webpack_require__(724); +var compilers = __webpack_require__(697); +var parsers = __webpack_require__(723); +var cache = __webpack_require__(724); +var utils = __webpack_require__(725); var MAX_LENGTH = 1024 * 64; /** @@ -64247,7 +64354,7 @@ module.exports = micromatch; /***/ }), -/* 581 */ +/* 582 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -64257,18 +64364,18 @@ module.exports = micromatch; * Module dependencies */ -var toRegex = __webpack_require__(582); -var unique = __webpack_require__(602); -var extend = __webpack_require__(603); +var toRegex = __webpack_require__(583); +var unique = __webpack_require__(603); +var extend = __webpack_require__(604); /** * Local dependencies */ -var compilers = __webpack_require__(605); -var parsers = __webpack_require__(620); -var Braces = __webpack_require__(625); -var utils = __webpack_require__(606); +var compilers = __webpack_require__(606); +var parsers = __webpack_require__(621); +var Braces = __webpack_require__(626); +var utils = __webpack_require__(607); var MAX_LENGTH = 1024 * 64; var cache = {}; @@ -64572,16 +64679,16 @@ module.exports = braces; /***/ }), -/* 582 */ +/* 583 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var safe = __webpack_require__(583); -var define = __webpack_require__(589); -var extend = __webpack_require__(595); -var not = __webpack_require__(599); +var safe = __webpack_require__(584); +var define = __webpack_require__(590); +var extend = __webpack_require__(596); +var not = __webpack_require__(600); var MAX_LENGTH = 1024 * 64; /** @@ -64734,10 +64841,10 @@ module.exports.makeRe = makeRe; /***/ }), -/* 583 */ +/* 584 */ /***/ (function(module, exports, __webpack_require__) { -var parse = __webpack_require__(584); +var parse = __webpack_require__(585); var types = parse.types; module.exports = function (re, opts) { @@ -64783,13 +64890,13 @@ function isRegExp (x) { /***/ }), -/* 584 */ +/* 585 */ /***/ (function(module, exports, __webpack_require__) { -var util = __webpack_require__(585); -var types = __webpack_require__(586); -var sets = __webpack_require__(587); -var positions = __webpack_require__(588); +var util = __webpack_require__(586); +var types = __webpack_require__(587); +var sets = __webpack_require__(588); +var positions = __webpack_require__(589); module.exports = function(regexpStr) { @@ -65071,11 +65178,11 @@ module.exports.types = types; /***/ }), -/* 585 */ +/* 586 */ /***/ (function(module, exports, __webpack_require__) { -var types = __webpack_require__(586); -var sets = __webpack_require__(587); +var types = __webpack_require__(587); +var sets = __webpack_require__(588); // All of these are private and only used by randexp. @@ -65188,7 +65295,7 @@ exports.error = function(regexp, msg) { /***/ }), -/* 586 */ +/* 587 */ /***/ (function(module, exports) { module.exports = { @@ -65204,10 +65311,10 @@ module.exports = { /***/ }), -/* 587 */ +/* 588 */ /***/ (function(module, exports, __webpack_require__) { -var types = __webpack_require__(586); +var types = __webpack_require__(587); var INTS = function() { return [{ type: types.RANGE , from: 48, to: 57 }]; @@ -65292,10 +65399,10 @@ exports.anyChar = function() { /***/ }), -/* 588 */ +/* 589 */ /***/ (function(module, exports, __webpack_require__) { -var types = __webpack_require__(586); +var types = __webpack_require__(587); exports.wordBoundary = function() { return { type: types.POSITION, value: 'b' }; @@ -65315,7 +65422,7 @@ exports.end = function() { /***/ }), -/* 589 */ +/* 590 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -65328,8 +65435,8 @@ exports.end = function() { -var isobject = __webpack_require__(590); -var isDescriptor = __webpack_require__(591); +var isobject = __webpack_require__(591); +var isDescriptor = __webpack_require__(592); var define = (typeof Reflect !== 'undefined' && Reflect.defineProperty) ? Reflect.defineProperty : Object.defineProperty; @@ -65360,7 +65467,7 @@ module.exports = function defineProperty(obj, key, val) { /***/ }), -/* 590 */ +/* 591 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -65379,7 +65486,7 @@ module.exports = function isObject(val) { /***/ }), -/* 591 */ +/* 592 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -65392,9 +65499,9 @@ module.exports = function isObject(val) { -var typeOf = __webpack_require__(592); -var isAccessor = __webpack_require__(593); -var isData = __webpack_require__(594); +var typeOf = __webpack_require__(593); +var isAccessor = __webpack_require__(594); +var isData = __webpack_require__(595); module.exports = function isDescriptor(obj, key) { if (typeOf(obj) !== 'object') { @@ -65408,7 +65515,7 @@ module.exports = function isDescriptor(obj, key) { /***/ }), -/* 592 */ +/* 593 */ /***/ (function(module, exports) { var toString = Object.prototype.toString; @@ -65543,7 +65650,7 @@ function isBuffer(val) { /***/ }), -/* 593 */ +/* 594 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -65556,7 +65663,7 @@ function isBuffer(val) { -var typeOf = __webpack_require__(592); +var typeOf = __webpack_require__(593); // accessor descriptor properties var accessor = { @@ -65619,7 +65726,7 @@ module.exports = isAccessorDescriptor; /***/ }), -/* 594 */ +/* 595 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -65632,7 +65739,7 @@ module.exports = isAccessorDescriptor; -var typeOf = __webpack_require__(592); +var typeOf = __webpack_require__(593); module.exports = function isDataDescriptor(obj, prop) { // data descriptor properties @@ -65675,14 +65782,14 @@ module.exports = function isDataDescriptor(obj, prop) { /***/ }), -/* 595 */ +/* 596 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isExtendable = __webpack_require__(596); -var assignSymbols = __webpack_require__(598); +var isExtendable = __webpack_require__(597); +var assignSymbols = __webpack_require__(599); module.exports = Object.assign || function(obj/*, objects*/) { if (obj === null || typeof obj === 'undefined') { @@ -65742,7 +65849,7 @@ function isEnum(obj, key) { /***/ }), -/* 596 */ +/* 597 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -65755,7 +65862,7 @@ function isEnum(obj, key) { -var isPlainObject = __webpack_require__(597); +var isPlainObject = __webpack_require__(598); module.exports = function isExtendable(val) { return isPlainObject(val) || typeof val === 'function' || Array.isArray(val); @@ -65763,7 +65870,7 @@ module.exports = function isExtendable(val) { /***/ }), -/* 597 */ +/* 598 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -65776,7 +65883,7 @@ module.exports = function isExtendable(val) { -var isObject = __webpack_require__(590); +var isObject = __webpack_require__(591); function isObjectObject(o) { return isObject(o) === true @@ -65807,7 +65914,7 @@ module.exports = function isPlainObject(o) { /***/ }), -/* 598 */ +/* 599 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -65854,14 +65961,14 @@ module.exports = function(receiver, objects) { /***/ }), -/* 599 */ +/* 600 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var extend = __webpack_require__(600); -var safe = __webpack_require__(583); +var extend = __webpack_require__(601); +var safe = __webpack_require__(584); /** * The main export is a function that takes a `pattern` string and an `options` object. @@ -65933,14 +66040,14 @@ module.exports = toRegex; /***/ }), -/* 600 */ +/* 601 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isExtendable = __webpack_require__(601); -var assignSymbols = __webpack_require__(598); +var isExtendable = __webpack_require__(602); +var assignSymbols = __webpack_require__(599); module.exports = Object.assign || function(obj/*, objects*/) { if (obj === null || typeof obj === 'undefined') { @@ -66000,7 +66107,7 @@ function isEnum(obj, key) { /***/ }), -/* 601 */ +/* 602 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -66013,7 +66120,7 @@ function isEnum(obj, key) { -var isPlainObject = __webpack_require__(597); +var isPlainObject = __webpack_require__(598); module.exports = function isExtendable(val) { return isPlainObject(val) || typeof val === 'function' || Array.isArray(val); @@ -66021,7 +66128,7 @@ module.exports = function isExtendable(val) { /***/ }), -/* 602 */ +/* 603 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -66071,13 +66178,13 @@ module.exports.immutable = function uniqueImmutable(arr) { /***/ }), -/* 603 */ +/* 604 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isObject = __webpack_require__(604); +var isObject = __webpack_require__(605); module.exports = function extend(o/*, objects*/) { if (!isObject(o)) { o = {}; } @@ -66111,7 +66218,7 @@ function hasOwn(obj, key) { /***/ }), -/* 604 */ +/* 605 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -66131,13 +66238,13 @@ module.exports = function isExtendable(val) { /***/ }), -/* 605 */ +/* 606 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var utils = __webpack_require__(606); +var utils = __webpack_require__(607); module.exports = function(braces, options) { braces.compiler @@ -66420,25 +66527,25 @@ function hasQueue(node) { /***/ }), -/* 606 */ +/* 607 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var splitString = __webpack_require__(607); +var splitString = __webpack_require__(608); var utils = module.exports; /** * Module dependencies */ -utils.extend = __webpack_require__(603); -utils.flatten = __webpack_require__(610); -utils.isObject = __webpack_require__(590); -utils.fillRange = __webpack_require__(611); -utils.repeat = __webpack_require__(619); -utils.unique = __webpack_require__(602); +utils.extend = __webpack_require__(604); +utils.flatten = __webpack_require__(611); +utils.isObject = __webpack_require__(591); +utils.fillRange = __webpack_require__(612); +utils.repeat = __webpack_require__(620); +utils.unique = __webpack_require__(603); utils.define = function(obj, key, val) { Object.defineProperty(obj, key, { @@ -66770,7 +66877,7 @@ utils.escapeRegex = function(str) { /***/ }), -/* 607 */ +/* 608 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -66783,7 +66890,7 @@ utils.escapeRegex = function(str) { -var extend = __webpack_require__(608); +var extend = __webpack_require__(609); module.exports = function(str, options, fn) { if (typeof str !== 'string') { @@ -66948,14 +67055,14 @@ function keepEscaping(opts, str, idx) { /***/ }), -/* 608 */ +/* 609 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isExtendable = __webpack_require__(609); -var assignSymbols = __webpack_require__(598); +var isExtendable = __webpack_require__(610); +var assignSymbols = __webpack_require__(599); module.exports = Object.assign || function(obj/*, objects*/) { if (obj === null || typeof obj === 'undefined') { @@ -67015,7 +67122,7 @@ function isEnum(obj, key) { /***/ }), -/* 609 */ +/* 610 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -67028,7 +67135,7 @@ function isEnum(obj, key) { -var isPlainObject = __webpack_require__(597); +var isPlainObject = __webpack_require__(598); module.exports = function isExtendable(val) { return isPlainObject(val) || typeof val === 'function' || Array.isArray(val); @@ -67036,7 +67143,7 @@ module.exports = function isExtendable(val) { /***/ }), -/* 610 */ +/* 611 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -67065,7 +67172,7 @@ function flat(arr, res) { /***/ }), -/* 611 */ +/* 612 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -67079,10 +67186,10 @@ function flat(arr, res) { var util = __webpack_require__(113); -var isNumber = __webpack_require__(612); -var extend = __webpack_require__(615); -var repeat = __webpack_require__(617); -var toRegex = __webpack_require__(618); +var isNumber = __webpack_require__(613); +var extend = __webpack_require__(616); +var repeat = __webpack_require__(618); +var toRegex = __webpack_require__(619); /** * Return a range of numbers or letters. @@ -67280,7 +67387,7 @@ module.exports = fillRange; /***/ }), -/* 612 */ +/* 613 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -67293,7 +67400,7 @@ module.exports = fillRange; -var typeOf = __webpack_require__(613); +var typeOf = __webpack_require__(614); module.exports = function isNumber(num) { var type = typeOf(num); @@ -67309,10 +67416,10 @@ module.exports = function isNumber(num) { /***/ }), -/* 613 */ +/* 614 */ /***/ (function(module, exports, __webpack_require__) { -var isBuffer = __webpack_require__(614); +var isBuffer = __webpack_require__(615); var toString = Object.prototype.toString; /** @@ -67431,7 +67538,7 @@ module.exports = function kindOf(val) { /***/ }), -/* 614 */ +/* 615 */ /***/ (function(module, exports) { /*! @@ -67458,13 +67565,13 @@ function isSlowBuffer (obj) { /***/ }), -/* 615 */ +/* 616 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isObject = __webpack_require__(616); +var isObject = __webpack_require__(617); module.exports = function extend(o/*, objects*/) { if (!isObject(o)) { o = {}; } @@ -67498,7 +67605,7 @@ function hasOwn(obj, key) { /***/ }), -/* 616 */ +/* 617 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -67518,7 +67625,7 @@ module.exports = function isExtendable(val) { /***/ }), -/* 617 */ +/* 618 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -67595,7 +67702,7 @@ function repeat(str, num) { /***/ }), -/* 618 */ +/* 619 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -67608,8 +67715,8 @@ function repeat(str, num) { -var repeat = __webpack_require__(617); -var isNumber = __webpack_require__(612); +var repeat = __webpack_require__(618); +var isNumber = __webpack_require__(613); var cache = {}; function toRegexRange(min, max, options) { @@ -67896,7 +68003,7 @@ module.exports = toRegexRange; /***/ }), -/* 619 */ +/* 620 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -67921,14 +68028,14 @@ module.exports = function repeat(ele, num) { /***/ }), -/* 620 */ +/* 621 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var Node = __webpack_require__(621); -var utils = __webpack_require__(606); +var Node = __webpack_require__(622); +var utils = __webpack_require__(607); /** * Braces parsers @@ -68288,15 +68395,15 @@ function concatNodes(pos, node, parent, options) { /***/ }), -/* 621 */ +/* 622 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isObject = __webpack_require__(590); -var define = __webpack_require__(622); -var utils = __webpack_require__(623); +var isObject = __webpack_require__(591); +var define = __webpack_require__(623); +var utils = __webpack_require__(624); var ownNames; /** @@ -68787,7 +68894,7 @@ exports = module.exports = Node; /***/ }), -/* 622 */ +/* 623 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -68800,7 +68907,7 @@ exports = module.exports = Node; -var isDescriptor = __webpack_require__(591); +var isDescriptor = __webpack_require__(592); module.exports = function defineProperty(obj, prop, val) { if (typeof obj !== 'object' && typeof obj !== 'function') { @@ -68825,13 +68932,13 @@ module.exports = function defineProperty(obj, prop, val) { /***/ }), -/* 623 */ +/* 624 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var typeOf = __webpack_require__(624); +var typeOf = __webpack_require__(625); var utils = module.exports; /** @@ -69851,10 +69958,10 @@ function assert(val, message) { /***/ }), -/* 624 */ +/* 625 */ /***/ (function(module, exports, __webpack_require__) { -var isBuffer = __webpack_require__(614); +var isBuffer = __webpack_require__(615); var toString = Object.prototype.toString; /** @@ -69973,17 +70080,17 @@ module.exports = function kindOf(val) { /***/ }), -/* 625 */ +/* 626 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var extend = __webpack_require__(603); -var Snapdragon = __webpack_require__(626); -var compilers = __webpack_require__(605); -var parsers = __webpack_require__(620); -var utils = __webpack_require__(606); +var extend = __webpack_require__(604); +var Snapdragon = __webpack_require__(627); +var compilers = __webpack_require__(606); +var parsers = __webpack_require__(621); +var utils = __webpack_require__(607); /** * Customize Snapdragon parser and renderer @@ -70084,17 +70191,17 @@ module.exports = Braces; /***/ }), -/* 626 */ +/* 627 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var Base = __webpack_require__(627); -var define = __webpack_require__(657); -var Compiler = __webpack_require__(668); -var Parser = __webpack_require__(691); -var utils = __webpack_require__(671); +var Base = __webpack_require__(628); +var define = __webpack_require__(658); +var Compiler = __webpack_require__(669); +var Parser = __webpack_require__(692); +var utils = __webpack_require__(672); var regexCache = {}; var cache = {}; @@ -70265,20 +70372,20 @@ module.exports.Parser = Parser; /***/ }), -/* 627 */ +/* 628 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var util = __webpack_require__(113); -var define = __webpack_require__(628); -var CacheBase = __webpack_require__(629); -var Emitter = __webpack_require__(630); -var isObject = __webpack_require__(590); -var merge = __webpack_require__(651); -var pascal = __webpack_require__(654); -var cu = __webpack_require__(655); +var define = __webpack_require__(629); +var CacheBase = __webpack_require__(630); +var Emitter = __webpack_require__(631); +var isObject = __webpack_require__(591); +var merge = __webpack_require__(652); +var pascal = __webpack_require__(655); +var cu = __webpack_require__(656); /** * Optionally define a custom `cache` namespace to use. @@ -70707,7 +70814,7 @@ module.exports.namespace = namespace; /***/ }), -/* 628 */ +/* 629 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -70720,7 +70827,7 @@ module.exports.namespace = namespace; -var isDescriptor = __webpack_require__(591); +var isDescriptor = __webpack_require__(592); module.exports = function defineProperty(obj, prop, val) { if (typeof obj !== 'object' && typeof obj !== 'function') { @@ -70745,21 +70852,21 @@ module.exports = function defineProperty(obj, prop, val) { /***/ }), -/* 629 */ +/* 630 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isObject = __webpack_require__(590); -var Emitter = __webpack_require__(630); -var visit = __webpack_require__(631); -var toPath = __webpack_require__(634); -var union = __webpack_require__(636); -var del = __webpack_require__(642); -var get = __webpack_require__(639); -var has = __webpack_require__(647); -var set = __webpack_require__(650); +var isObject = __webpack_require__(591); +var Emitter = __webpack_require__(631); +var visit = __webpack_require__(632); +var toPath = __webpack_require__(635); +var union = __webpack_require__(637); +var del = __webpack_require__(643); +var get = __webpack_require__(640); +var has = __webpack_require__(648); +var set = __webpack_require__(651); /** * Create a `Cache` constructor that when instantiated will @@ -71013,7 +71120,7 @@ module.exports.namespace = namespace; /***/ }), -/* 630 */ +/* 631 */ /***/ (function(module, exports, __webpack_require__) { @@ -71182,7 +71289,7 @@ Emitter.prototype.hasListeners = function(event){ /***/ }), -/* 631 */ +/* 632 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -71195,8 +71302,8 @@ Emitter.prototype.hasListeners = function(event){ -var visit = __webpack_require__(632); -var mapVisit = __webpack_require__(633); +var visit = __webpack_require__(633); +var mapVisit = __webpack_require__(634); module.exports = function(collection, method, val) { var result; @@ -71219,7 +71326,7 @@ module.exports = function(collection, method, val) { /***/ }), -/* 632 */ +/* 633 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -71232,7 +71339,7 @@ module.exports = function(collection, method, val) { -var isObject = __webpack_require__(590); +var isObject = __webpack_require__(591); module.exports = function visit(thisArg, method, target, val) { if (!isObject(thisArg) && typeof thisArg !== 'function') { @@ -71259,14 +71366,14 @@ module.exports = function visit(thisArg, method, target, val) { /***/ }), -/* 633 */ +/* 634 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var util = __webpack_require__(113); -var visit = __webpack_require__(632); +var visit = __webpack_require__(633); /** * Map `visit` over an array of objects. @@ -71303,7 +71410,7 @@ function isObject(val) { /***/ }), -/* 634 */ +/* 635 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -71316,7 +71423,7 @@ function isObject(val) { -var typeOf = __webpack_require__(635); +var typeOf = __webpack_require__(636); module.exports = function toPath(args) { if (typeOf(args) !== 'arguments') { @@ -71343,10 +71450,10 @@ function filter(arr) { /***/ }), -/* 635 */ +/* 636 */ /***/ (function(module, exports, __webpack_require__) { -var isBuffer = __webpack_require__(614); +var isBuffer = __webpack_require__(615); var toString = Object.prototype.toString; /** @@ -71465,16 +71572,16 @@ module.exports = function kindOf(val) { /***/ }), -/* 636 */ +/* 637 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isObject = __webpack_require__(637); -var union = __webpack_require__(638); -var get = __webpack_require__(639); -var set = __webpack_require__(640); +var isObject = __webpack_require__(638); +var union = __webpack_require__(639); +var get = __webpack_require__(640); +var set = __webpack_require__(641); module.exports = function unionValue(obj, prop, value) { if (!isObject(obj)) { @@ -71502,7 +71609,7 @@ function arrayify(val) { /***/ }), -/* 637 */ +/* 638 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -71522,7 +71629,7 @@ module.exports = function isExtendable(val) { /***/ }), -/* 638 */ +/* 639 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -71558,7 +71665,7 @@ module.exports = function union(init) { /***/ }), -/* 639 */ +/* 640 */ /***/ (function(module, exports) { /*! @@ -71614,7 +71721,7 @@ function toString(val) { /***/ }), -/* 640 */ +/* 641 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -71627,10 +71734,10 @@ function toString(val) { -var split = __webpack_require__(607); -var extend = __webpack_require__(641); -var isPlainObject = __webpack_require__(597); -var isObject = __webpack_require__(637); +var split = __webpack_require__(608); +var extend = __webpack_require__(642); +var isPlainObject = __webpack_require__(598); +var isObject = __webpack_require__(638); module.exports = function(obj, prop, val) { if (!isObject(obj)) { @@ -71676,13 +71783,13 @@ function isValidKey(key) { /***/ }), -/* 641 */ +/* 642 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isObject = __webpack_require__(637); +var isObject = __webpack_require__(638); module.exports = function extend(o/*, objects*/) { if (!isObject(o)) { o = {}; } @@ -71716,7 +71823,7 @@ function hasOwn(obj, key) { /***/ }), -/* 642 */ +/* 643 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -71729,8 +71836,8 @@ function hasOwn(obj, key) { -var isObject = __webpack_require__(590); -var has = __webpack_require__(643); +var isObject = __webpack_require__(591); +var has = __webpack_require__(644); module.exports = function unset(obj, prop) { if (!isObject(obj)) { @@ -71755,7 +71862,7 @@ module.exports = function unset(obj, prop) { /***/ }), -/* 643 */ +/* 644 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -71768,9 +71875,9 @@ module.exports = function unset(obj, prop) { -var isObject = __webpack_require__(644); -var hasValues = __webpack_require__(646); -var get = __webpack_require__(639); +var isObject = __webpack_require__(645); +var hasValues = __webpack_require__(647); +var get = __webpack_require__(640); module.exports = function(obj, prop, noZero) { if (isObject(obj)) { @@ -71781,7 +71888,7 @@ module.exports = function(obj, prop, noZero) { /***/ }), -/* 644 */ +/* 645 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -71794,7 +71901,7 @@ module.exports = function(obj, prop, noZero) { -var isArray = __webpack_require__(645); +var isArray = __webpack_require__(646); module.exports = function isObject(val) { return val != null && typeof val === 'object' && isArray(val) === false; @@ -71802,7 +71909,7 @@ module.exports = function isObject(val) { /***/ }), -/* 645 */ +/* 646 */ /***/ (function(module, exports) { var toString = {}.toString; @@ -71813,7 +71920,7 @@ module.exports = Array.isArray || function (arr) { /***/ }), -/* 646 */ +/* 647 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -71856,7 +71963,7 @@ module.exports = function hasValue(o, noZero) { /***/ }), -/* 647 */ +/* 648 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -71869,9 +71976,9 @@ module.exports = function hasValue(o, noZero) { -var isObject = __webpack_require__(590); -var hasValues = __webpack_require__(648); -var get = __webpack_require__(639); +var isObject = __webpack_require__(591); +var hasValues = __webpack_require__(649); +var get = __webpack_require__(640); module.exports = function(val, prop) { return hasValues(isObject(val) && prop ? get(val, prop) : val); @@ -71879,7 +71986,7 @@ module.exports = function(val, prop) { /***/ }), -/* 648 */ +/* 649 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -71892,8 +71999,8 @@ module.exports = function(val, prop) { -var typeOf = __webpack_require__(649); -var isNumber = __webpack_require__(612); +var typeOf = __webpack_require__(650); +var isNumber = __webpack_require__(613); module.exports = function hasValue(val) { // is-number checks for NaN and other edge cases @@ -71946,10 +72053,10 @@ module.exports = function hasValue(val) { /***/ }), -/* 649 */ +/* 650 */ /***/ (function(module, exports, __webpack_require__) { -var isBuffer = __webpack_require__(614); +var isBuffer = __webpack_require__(615); var toString = Object.prototype.toString; /** @@ -72071,7 +72178,7 @@ module.exports = function kindOf(val) { /***/ }), -/* 650 */ +/* 651 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -72084,10 +72191,10 @@ module.exports = function kindOf(val) { -var split = __webpack_require__(607); -var extend = __webpack_require__(641); -var isPlainObject = __webpack_require__(597); -var isObject = __webpack_require__(637); +var split = __webpack_require__(608); +var extend = __webpack_require__(642); +var isPlainObject = __webpack_require__(598); +var isObject = __webpack_require__(638); module.exports = function(obj, prop, val) { if (!isObject(obj)) { @@ -72133,14 +72240,14 @@ function isValidKey(key) { /***/ }), -/* 651 */ +/* 652 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isExtendable = __webpack_require__(652); -var forIn = __webpack_require__(653); +var isExtendable = __webpack_require__(653); +var forIn = __webpack_require__(654); function mixinDeep(target, objects) { var len = arguments.length, i = 0; @@ -72204,7 +72311,7 @@ module.exports = mixinDeep; /***/ }), -/* 652 */ +/* 653 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -72217,7 +72324,7 @@ module.exports = mixinDeep; -var isPlainObject = __webpack_require__(597); +var isPlainObject = __webpack_require__(598); module.exports = function isExtendable(val) { return isPlainObject(val) || typeof val === 'function' || Array.isArray(val); @@ -72225,7 +72332,7 @@ module.exports = function isExtendable(val) { /***/ }), -/* 653 */ +/* 654 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -72248,7 +72355,7 @@ module.exports = function forIn(obj, fn, thisArg) { /***/ }), -/* 654 */ +/* 655 */ /***/ (function(module, exports) { /*! @@ -72275,14 +72382,14 @@ module.exports = pascalcase; /***/ }), -/* 655 */ +/* 656 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var util = __webpack_require__(113); -var utils = __webpack_require__(656); +var utils = __webpack_require__(657); /** * Expose class utils @@ -72647,7 +72754,7 @@ cu.bubble = function(Parent, events) { /***/ }), -/* 656 */ +/* 657 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -72661,10 +72768,10 @@ var utils = {}; * Lazily required module dependencies */ -utils.union = __webpack_require__(638); -utils.define = __webpack_require__(657); -utils.isObj = __webpack_require__(590); -utils.staticExtend = __webpack_require__(664); +utils.union = __webpack_require__(639); +utils.define = __webpack_require__(658); +utils.isObj = __webpack_require__(591); +utils.staticExtend = __webpack_require__(665); /** @@ -72675,7 +72782,7 @@ module.exports = utils; /***/ }), -/* 657 */ +/* 658 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -72688,7 +72795,7 @@ module.exports = utils; -var isDescriptor = __webpack_require__(658); +var isDescriptor = __webpack_require__(659); module.exports = function defineProperty(obj, prop, val) { if (typeof obj !== 'object' && typeof obj !== 'function') { @@ -72713,7 +72820,7 @@ module.exports = function defineProperty(obj, prop, val) { /***/ }), -/* 658 */ +/* 659 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -72726,9 +72833,9 @@ module.exports = function defineProperty(obj, prop, val) { -var typeOf = __webpack_require__(659); -var isAccessor = __webpack_require__(660); -var isData = __webpack_require__(662); +var typeOf = __webpack_require__(660); +var isAccessor = __webpack_require__(661); +var isData = __webpack_require__(663); module.exports = function isDescriptor(obj, key) { if (typeOf(obj) !== 'object') { @@ -72742,7 +72849,7 @@ module.exports = function isDescriptor(obj, key) { /***/ }), -/* 659 */ +/* 660 */ /***/ (function(module, exports) { var toString = Object.prototype.toString; @@ -72895,7 +73002,7 @@ function isBuffer(val) { /***/ }), -/* 660 */ +/* 661 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -72908,7 +73015,7 @@ function isBuffer(val) { -var typeOf = __webpack_require__(661); +var typeOf = __webpack_require__(662); // accessor descriptor properties var accessor = { @@ -72971,10 +73078,10 @@ module.exports = isAccessorDescriptor; /***/ }), -/* 661 */ +/* 662 */ /***/ (function(module, exports, __webpack_require__) { -var isBuffer = __webpack_require__(614); +var isBuffer = __webpack_require__(615); var toString = Object.prototype.toString; /** @@ -73093,7 +73200,7 @@ module.exports = function kindOf(val) { /***/ }), -/* 662 */ +/* 663 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -73106,7 +73213,7 @@ module.exports = function kindOf(val) { -var typeOf = __webpack_require__(663); +var typeOf = __webpack_require__(664); // data descriptor properties var data = { @@ -73155,10 +73262,10 @@ module.exports = isDataDescriptor; /***/ }), -/* 663 */ +/* 664 */ /***/ (function(module, exports, __webpack_require__) { -var isBuffer = __webpack_require__(614); +var isBuffer = __webpack_require__(615); var toString = Object.prototype.toString; /** @@ -73277,7 +73384,7 @@ module.exports = function kindOf(val) { /***/ }), -/* 664 */ +/* 665 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -73290,8 +73397,8 @@ module.exports = function kindOf(val) { -var copy = __webpack_require__(665); -var define = __webpack_require__(657); +var copy = __webpack_require__(666); +var define = __webpack_require__(658); var util = __webpack_require__(113); /** @@ -73374,15 +73481,15 @@ module.exports = extend; /***/ }), -/* 665 */ +/* 666 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var typeOf = __webpack_require__(666); -var copyDescriptor = __webpack_require__(667); -var define = __webpack_require__(657); +var typeOf = __webpack_require__(667); +var copyDescriptor = __webpack_require__(668); +var define = __webpack_require__(658); /** * Copy static properties, prototype properties, and descriptors from one object to another. @@ -73555,10 +73662,10 @@ module.exports.has = has; /***/ }), -/* 666 */ +/* 667 */ /***/ (function(module, exports, __webpack_require__) { -var isBuffer = __webpack_require__(614); +var isBuffer = __webpack_require__(615); var toString = Object.prototype.toString; /** @@ -73677,7 +73784,7 @@ module.exports = function kindOf(val) { /***/ }), -/* 667 */ +/* 668 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -73765,16 +73872,16 @@ function isObject(val) { /***/ }), -/* 668 */ +/* 669 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var use = __webpack_require__(669); -var define = __webpack_require__(657); +var use = __webpack_require__(670); +var define = __webpack_require__(658); var debug = __webpack_require__(205)('snapdragon:compiler'); -var utils = __webpack_require__(671); +var utils = __webpack_require__(672); /** * Create a new `Compiler` with the given `options`. @@ -73928,7 +74035,7 @@ Compiler.prototype = { // source map support if (opts.sourcemap) { - var sourcemaps = __webpack_require__(690); + var sourcemaps = __webpack_require__(691); sourcemaps(this); this.mapVisit(this.ast.nodes); this.applySourceMaps(); @@ -73949,7 +74056,7 @@ module.exports = Compiler; /***/ }), -/* 669 */ +/* 670 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -73962,7 +74069,7 @@ module.exports = Compiler; -var utils = __webpack_require__(670); +var utils = __webpack_require__(671); module.exports = function base(app, opts) { if (!utils.isObject(app) && typeof app !== 'function') { @@ -74077,7 +74184,7 @@ module.exports = function base(app, opts) { /***/ }), -/* 670 */ +/* 671 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -74091,8 +74198,8 @@ var utils = {}; * Lazily required module dependencies */ -utils.define = __webpack_require__(657); -utils.isObject = __webpack_require__(590); +utils.define = __webpack_require__(658); +utils.isObject = __webpack_require__(591); utils.isString = function(val) { @@ -74107,7 +74214,7 @@ module.exports = utils; /***/ }), -/* 671 */ +/* 672 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -74117,9 +74224,9 @@ module.exports = utils; * Module dependencies */ -exports.extend = __webpack_require__(641); -exports.SourceMap = __webpack_require__(672); -exports.sourceMapResolve = __webpack_require__(683); +exports.extend = __webpack_require__(642); +exports.SourceMap = __webpack_require__(673); +exports.sourceMapResolve = __webpack_require__(684); /** * Convert backslash in the given string to forward slashes @@ -74162,7 +74269,7 @@ exports.last = function(arr, n) { /***/ }), -/* 672 */ +/* 673 */ /***/ (function(module, exports, __webpack_require__) { /* @@ -74170,13 +74277,13 @@ exports.last = function(arr, n) { * Licensed under the New BSD license. See LICENSE.txt or: * http://opensource.org/licenses/BSD-3-Clause */ -exports.SourceMapGenerator = __webpack_require__(673).SourceMapGenerator; -exports.SourceMapConsumer = __webpack_require__(679).SourceMapConsumer; -exports.SourceNode = __webpack_require__(682).SourceNode; +exports.SourceMapGenerator = __webpack_require__(674).SourceMapGenerator; +exports.SourceMapConsumer = __webpack_require__(680).SourceMapConsumer; +exports.SourceNode = __webpack_require__(683).SourceNode; /***/ }), -/* 673 */ +/* 674 */ /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -74186,10 +74293,10 @@ exports.SourceNode = __webpack_require__(682).SourceNode; * http://opensource.org/licenses/BSD-3-Clause */ -var base64VLQ = __webpack_require__(674); -var util = __webpack_require__(676); -var ArraySet = __webpack_require__(677).ArraySet; -var MappingList = __webpack_require__(678).MappingList; +var base64VLQ = __webpack_require__(675); +var util = __webpack_require__(677); +var ArraySet = __webpack_require__(678).ArraySet; +var MappingList = __webpack_require__(679).MappingList; /** * An instance of the SourceMapGenerator represents a source map which is @@ -74598,7 +74705,7 @@ exports.SourceMapGenerator = SourceMapGenerator; /***/ }), -/* 674 */ +/* 675 */ /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -74638,7 +74745,7 @@ exports.SourceMapGenerator = SourceMapGenerator; * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -var base64 = __webpack_require__(675); +var base64 = __webpack_require__(676); // A single base 64 digit can contain 6 bits of data. For the base 64 variable // length quantities we use in the source map spec, the first bit is the sign, @@ -74744,7 +74851,7 @@ exports.decode = function base64VLQ_decode(aStr, aIndex, aOutParam) { /***/ }), -/* 675 */ +/* 676 */ /***/ (function(module, exports) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -74817,7 +74924,7 @@ exports.decode = function (charCode) { /***/ }), -/* 676 */ +/* 677 */ /***/ (function(module, exports) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -75240,7 +75347,7 @@ exports.compareByGeneratedPositionsInflated = compareByGeneratedPositionsInflate /***/ }), -/* 677 */ +/* 678 */ /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -75250,7 +75357,7 @@ exports.compareByGeneratedPositionsInflated = compareByGeneratedPositionsInflate * http://opensource.org/licenses/BSD-3-Clause */ -var util = __webpack_require__(676); +var util = __webpack_require__(677); var has = Object.prototype.hasOwnProperty; var hasNativeMap = typeof Map !== "undefined"; @@ -75367,7 +75474,7 @@ exports.ArraySet = ArraySet; /***/ }), -/* 678 */ +/* 679 */ /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -75377,7 +75484,7 @@ exports.ArraySet = ArraySet; * http://opensource.org/licenses/BSD-3-Clause */ -var util = __webpack_require__(676); +var util = __webpack_require__(677); /** * Determine whether mappingB is after mappingA with respect to generated @@ -75452,7 +75559,7 @@ exports.MappingList = MappingList; /***/ }), -/* 679 */ +/* 680 */ /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -75462,11 +75569,11 @@ exports.MappingList = MappingList; * http://opensource.org/licenses/BSD-3-Clause */ -var util = __webpack_require__(676); -var binarySearch = __webpack_require__(680); -var ArraySet = __webpack_require__(677).ArraySet; -var base64VLQ = __webpack_require__(674); -var quickSort = __webpack_require__(681).quickSort; +var util = __webpack_require__(677); +var binarySearch = __webpack_require__(681); +var ArraySet = __webpack_require__(678).ArraySet; +var base64VLQ = __webpack_require__(675); +var quickSort = __webpack_require__(682).quickSort; function SourceMapConsumer(aSourceMap) { var sourceMap = aSourceMap; @@ -76540,7 +76647,7 @@ exports.IndexedSourceMapConsumer = IndexedSourceMapConsumer; /***/ }), -/* 680 */ +/* 681 */ /***/ (function(module, exports) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -76657,7 +76764,7 @@ exports.search = function search(aNeedle, aHaystack, aCompare, aBias) { /***/ }), -/* 681 */ +/* 682 */ /***/ (function(module, exports) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -76777,7 +76884,7 @@ exports.quickSort = function (ary, comparator) { /***/ }), -/* 682 */ +/* 683 */ /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -76787,8 +76894,8 @@ exports.quickSort = function (ary, comparator) { * http://opensource.org/licenses/BSD-3-Clause */ -var SourceMapGenerator = __webpack_require__(673).SourceMapGenerator; -var util = __webpack_require__(676); +var SourceMapGenerator = __webpack_require__(674).SourceMapGenerator; +var util = __webpack_require__(677); // Matches a Windows-style `\r\n` newline or a `\n` newline used by all other // operating systems these days (capturing the result). @@ -77196,17 +77303,17 @@ exports.SourceNode = SourceNode; /***/ }), -/* 683 */ +/* 684 */ /***/ (function(module, exports, __webpack_require__) { // Copyright 2014, 2015, 2016, 2017 Simon Lydell // X11 (“MIT”) Licensed. (See LICENSE.) -var sourceMappingURL = __webpack_require__(684) -var resolveUrl = __webpack_require__(685) -var decodeUriComponent = __webpack_require__(686) -var urix = __webpack_require__(688) -var atob = __webpack_require__(689) +var sourceMappingURL = __webpack_require__(685) +var resolveUrl = __webpack_require__(686) +var decodeUriComponent = __webpack_require__(687) +var urix = __webpack_require__(689) +var atob = __webpack_require__(690) @@ -77504,7 +77611,7 @@ module.exports = { /***/ }), -/* 684 */ +/* 685 */ /***/ (function(module, exports, __webpack_require__) { var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_RESULT__;// Copyright 2014 Simon Lydell @@ -77567,7 +77674,7 @@ void (function(root, factory) { /***/ }), -/* 685 */ +/* 686 */ /***/ (function(module, exports, __webpack_require__) { // Copyright 2014 Simon Lydell @@ -77585,13 +77692,13 @@ module.exports = resolveUrl /***/ }), -/* 686 */ +/* 687 */ /***/ (function(module, exports, __webpack_require__) { // Copyright 2017 Simon Lydell // X11 (“MIT”) Licensed. (See LICENSE.) -var decodeUriComponent = __webpack_require__(687) +var decodeUriComponent = __webpack_require__(688) function customDecodeUriComponent(string) { // `decodeUriComponent` turns `+` into ` `, but that's not wanted. @@ -77602,7 +77709,7 @@ module.exports = customDecodeUriComponent /***/ }), -/* 687 */ +/* 688 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -77703,7 +77810,7 @@ module.exports = function (encodedURI) { /***/ }), -/* 688 */ +/* 689 */ /***/ (function(module, exports, __webpack_require__) { // Copyright 2014 Simon Lydell @@ -77726,7 +77833,7 @@ module.exports = urix /***/ }), -/* 689 */ +/* 690 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -77740,7 +77847,7 @@ module.exports = atob.atob = atob; /***/ }), -/* 690 */ +/* 691 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -77748,8 +77855,8 @@ module.exports = atob.atob = atob; var fs = __webpack_require__(132); var path = __webpack_require__(4); -var define = __webpack_require__(657); -var utils = __webpack_require__(671); +var define = __webpack_require__(658); +var utils = __webpack_require__(672); /** * Expose `mixin()`. @@ -77892,19 +77999,19 @@ exports.comment = function(node) { /***/ }), -/* 691 */ +/* 692 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var use = __webpack_require__(669); +var use = __webpack_require__(670); var util = __webpack_require__(113); -var Cache = __webpack_require__(692); -var define = __webpack_require__(657); +var Cache = __webpack_require__(693); +var define = __webpack_require__(658); var debug = __webpack_require__(205)('snapdragon:parser'); -var Position = __webpack_require__(693); -var utils = __webpack_require__(671); +var Position = __webpack_require__(694); +var utils = __webpack_require__(672); /** * Create a new `Parser` with the given `input` and `options`. @@ -78432,7 +78539,7 @@ module.exports = Parser; /***/ }), -/* 692 */ +/* 693 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -78539,13 +78646,13 @@ MapCache.prototype.del = function mapDelete(key) { /***/ }), -/* 693 */ +/* 694 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var define = __webpack_require__(657); +var define = __webpack_require__(658); /** * Store position for a node @@ -78560,14 +78667,14 @@ module.exports = function Position(start, parser) { /***/ }), -/* 694 */ +/* 695 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isExtendable = __webpack_require__(695); -var assignSymbols = __webpack_require__(598); +var isExtendable = __webpack_require__(696); +var assignSymbols = __webpack_require__(599); module.exports = Object.assign || function(obj/*, objects*/) { if (obj === null || typeof obj === 'undefined') { @@ -78627,7 +78734,7 @@ function isEnum(obj, key) { /***/ }), -/* 695 */ +/* 696 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -78640,7 +78747,7 @@ function isEnum(obj, key) { -var isPlainObject = __webpack_require__(597); +var isPlainObject = __webpack_require__(598); module.exports = function isExtendable(val) { return isPlainObject(val) || typeof val === 'function' || Array.isArray(val); @@ -78648,14 +78755,14 @@ module.exports = function isExtendable(val) { /***/ }), -/* 696 */ +/* 697 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var nanomatch = __webpack_require__(697); -var extglob = __webpack_require__(711); +var nanomatch = __webpack_require__(698); +var extglob = __webpack_require__(712); module.exports = function(snapdragon) { var compilers = snapdragon.compiler.compilers; @@ -78732,7 +78839,7 @@ function escapeExtglobs(compiler) { /***/ }), -/* 697 */ +/* 698 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -78743,17 +78850,17 @@ function escapeExtglobs(compiler) { */ var util = __webpack_require__(113); -var toRegex = __webpack_require__(582); -var extend = __webpack_require__(698); +var toRegex = __webpack_require__(583); +var extend = __webpack_require__(699); /** * Local dependencies */ -var compilers = __webpack_require__(700); -var parsers = __webpack_require__(701); -var cache = __webpack_require__(704); -var utils = __webpack_require__(706); +var compilers = __webpack_require__(701); +var parsers = __webpack_require__(702); +var cache = __webpack_require__(705); +var utils = __webpack_require__(707); var MAX_LENGTH = 1024 * 64; /** @@ -79577,14 +79684,14 @@ module.exports = nanomatch; /***/ }), -/* 698 */ +/* 699 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isExtendable = __webpack_require__(699); -var assignSymbols = __webpack_require__(598); +var isExtendable = __webpack_require__(700); +var assignSymbols = __webpack_require__(599); module.exports = Object.assign || function(obj/*, objects*/) { if (obj === null || typeof obj === 'undefined') { @@ -79644,7 +79751,7 @@ function isEnum(obj, key) { /***/ }), -/* 699 */ +/* 700 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -79657,7 +79764,7 @@ function isEnum(obj, key) { -var isPlainObject = __webpack_require__(597); +var isPlainObject = __webpack_require__(598); module.exports = function isExtendable(val) { return isPlainObject(val) || typeof val === 'function' || Array.isArray(val); @@ -79665,7 +79772,7 @@ module.exports = function isExtendable(val) { /***/ }), -/* 700 */ +/* 701 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -80011,15 +80118,15 @@ module.exports = function(nanomatch, options) { /***/ }), -/* 701 */ +/* 702 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var regexNot = __webpack_require__(599); -var toRegex = __webpack_require__(582); -var isOdd = __webpack_require__(702); +var regexNot = __webpack_require__(600); +var toRegex = __webpack_require__(583); +var isOdd = __webpack_require__(703); /** * Characters to use in negation regex (we want to "not" match @@ -80405,7 +80512,7 @@ module.exports.not = NOT_REGEX; /***/ }), -/* 702 */ +/* 703 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -80418,7 +80525,7 @@ module.exports.not = NOT_REGEX; -var isNumber = __webpack_require__(703); +var isNumber = __webpack_require__(704); module.exports = function isOdd(i) { if (!isNumber(i)) { @@ -80432,7 +80539,7 @@ module.exports = function isOdd(i) { /***/ }), -/* 703 */ +/* 704 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -80460,14 +80567,14 @@ module.exports = function isNumber(num) { /***/ }), -/* 704 */ +/* 705 */ /***/ (function(module, exports, __webpack_require__) { -module.exports = new (__webpack_require__(705))(); +module.exports = new (__webpack_require__(706))(); /***/ }), -/* 705 */ +/* 706 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -80480,7 +80587,7 @@ module.exports = new (__webpack_require__(705))(); -var MapCache = __webpack_require__(692); +var MapCache = __webpack_require__(693); /** * Create a new `FragmentCache` with an optional object to use for `caches`. @@ -80602,7 +80709,7 @@ exports = module.exports = FragmentCache; /***/ }), -/* 706 */ +/* 707 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -80615,14 +80722,14 @@ var path = __webpack_require__(4); * Module dependencies */ -var isWindows = __webpack_require__(707)(); -var Snapdragon = __webpack_require__(626); -utils.define = __webpack_require__(708); -utils.diff = __webpack_require__(709); -utils.extend = __webpack_require__(698); -utils.pick = __webpack_require__(710); -utils.typeOf = __webpack_require__(592); -utils.unique = __webpack_require__(602); +var isWindows = __webpack_require__(708)(); +var Snapdragon = __webpack_require__(627); +utils.define = __webpack_require__(709); +utils.diff = __webpack_require__(710); +utils.extend = __webpack_require__(699); +utils.pick = __webpack_require__(711); +utils.typeOf = __webpack_require__(593); +utils.unique = __webpack_require__(603); /** * Returns true if the given value is effectively an empty string @@ -80988,7 +81095,7 @@ utils.unixify = function(options) { /***/ }), -/* 707 */ +/* 708 */ /***/ (function(module, exports, __webpack_require__) { var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/*! @@ -81016,7 +81123,7 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_ /***/ }), -/* 708 */ +/* 709 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -81029,8 +81136,8 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_ -var isobject = __webpack_require__(590); -var isDescriptor = __webpack_require__(591); +var isobject = __webpack_require__(591); +var isDescriptor = __webpack_require__(592); var define = (typeof Reflect !== 'undefined' && Reflect.defineProperty) ? Reflect.defineProperty : Object.defineProperty; @@ -81061,7 +81168,7 @@ module.exports = function defineProperty(obj, key, val) { /***/ }), -/* 709 */ +/* 710 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -81115,7 +81222,7 @@ function diffArray(one, two) { /***/ }), -/* 710 */ +/* 711 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -81128,7 +81235,7 @@ function diffArray(one, two) { -var isObject = __webpack_require__(590); +var isObject = __webpack_require__(591); module.exports = function pick(obj, keys) { if (!isObject(obj) && typeof obj !== 'function') { @@ -81157,7 +81264,7 @@ module.exports = function pick(obj, keys) { /***/ }), -/* 711 */ +/* 712 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -81167,18 +81274,18 @@ module.exports = function pick(obj, keys) { * Module dependencies */ -var extend = __webpack_require__(641); -var unique = __webpack_require__(602); -var toRegex = __webpack_require__(582); +var extend = __webpack_require__(642); +var unique = __webpack_require__(603); +var toRegex = __webpack_require__(583); /** * Local dependencies */ -var compilers = __webpack_require__(712); -var parsers = __webpack_require__(718); -var Extglob = __webpack_require__(721); -var utils = __webpack_require__(720); +var compilers = __webpack_require__(713); +var parsers = __webpack_require__(719); +var Extglob = __webpack_require__(722); +var utils = __webpack_require__(721); var MAX_LENGTH = 1024 * 64; /** @@ -81495,13 +81602,13 @@ module.exports = extglob; /***/ }), -/* 712 */ +/* 713 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var brackets = __webpack_require__(713); +var brackets = __webpack_require__(714); /** * Extglob compilers @@ -81671,7 +81778,7 @@ module.exports = function(extglob) { /***/ }), -/* 713 */ +/* 714 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -81681,17 +81788,17 @@ module.exports = function(extglob) { * Local dependencies */ -var compilers = __webpack_require__(714); -var parsers = __webpack_require__(716); +var compilers = __webpack_require__(715); +var parsers = __webpack_require__(717); /** * Module dependencies */ var debug = __webpack_require__(205)('expand-brackets'); -var extend = __webpack_require__(641); -var Snapdragon = __webpack_require__(626); -var toRegex = __webpack_require__(582); +var extend = __webpack_require__(642); +var Snapdragon = __webpack_require__(627); +var toRegex = __webpack_require__(583); /** * Parses the given POSIX character class `pattern` and returns a @@ -81889,13 +81996,13 @@ module.exports = brackets; /***/ }), -/* 714 */ +/* 715 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var posix = __webpack_require__(715); +var posix = __webpack_require__(716); module.exports = function(brackets) { brackets.compiler @@ -81983,7 +82090,7 @@ module.exports = function(brackets) { /***/ }), -/* 715 */ +/* 716 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -82012,14 +82119,14 @@ module.exports = { /***/ }), -/* 716 */ +/* 717 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var utils = __webpack_require__(717); -var define = __webpack_require__(657); +var utils = __webpack_require__(718); +var define = __webpack_require__(658); /** * Text regex @@ -82238,14 +82345,14 @@ module.exports.TEXT_REGEX = TEXT_REGEX; /***/ }), -/* 717 */ +/* 718 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var toRegex = __webpack_require__(582); -var regexNot = __webpack_require__(599); +var toRegex = __webpack_require__(583); +var regexNot = __webpack_require__(600); var cached; /** @@ -82279,15 +82386,15 @@ exports.createRegex = function(pattern, include) { /***/ }), -/* 718 */ +/* 719 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var brackets = __webpack_require__(713); -var define = __webpack_require__(719); -var utils = __webpack_require__(720); +var brackets = __webpack_require__(714); +var define = __webpack_require__(720); +var utils = __webpack_require__(721); /** * Characters to use in text regex (we want to "not" match @@ -82442,7 +82549,7 @@ module.exports = parsers; /***/ }), -/* 719 */ +/* 720 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -82455,7 +82562,7 @@ module.exports = parsers; -var isDescriptor = __webpack_require__(591); +var isDescriptor = __webpack_require__(592); module.exports = function defineProperty(obj, prop, val) { if (typeof obj !== 'object' && typeof obj !== 'function') { @@ -82480,14 +82587,14 @@ module.exports = function defineProperty(obj, prop, val) { /***/ }), -/* 720 */ +/* 721 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var regex = __webpack_require__(599); -var Cache = __webpack_require__(705); +var regex = __webpack_require__(600); +var Cache = __webpack_require__(706); /** * Utils @@ -82556,7 +82663,7 @@ utils.createRegex = function(str) { /***/ }), -/* 721 */ +/* 722 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -82566,16 +82673,16 @@ utils.createRegex = function(str) { * Module dependencies */ -var Snapdragon = __webpack_require__(626); -var define = __webpack_require__(719); -var extend = __webpack_require__(641); +var Snapdragon = __webpack_require__(627); +var define = __webpack_require__(720); +var extend = __webpack_require__(642); /** * Local dependencies */ -var compilers = __webpack_require__(712); -var parsers = __webpack_require__(718); +var compilers = __webpack_require__(713); +var parsers = __webpack_require__(719); /** * Customize Snapdragon parser and renderer @@ -82641,16 +82748,16 @@ module.exports = Extglob; /***/ }), -/* 722 */ +/* 723 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var extglob = __webpack_require__(711); -var nanomatch = __webpack_require__(697); -var regexNot = __webpack_require__(599); -var toRegex = __webpack_require__(582); +var extglob = __webpack_require__(712); +var nanomatch = __webpack_require__(698); +var regexNot = __webpack_require__(600); +var toRegex = __webpack_require__(583); var not; /** @@ -82731,14 +82838,14 @@ function textRegex(pattern) { /***/ }), -/* 723 */ +/* 724 */ /***/ (function(module, exports, __webpack_require__) { -module.exports = new (__webpack_require__(705))(); +module.exports = new (__webpack_require__(706))(); /***/ }), -/* 724 */ +/* 725 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -82751,13 +82858,13 @@ var path = __webpack_require__(4); * Module dependencies */ -var Snapdragon = __webpack_require__(626); -utils.define = __webpack_require__(725); -utils.diff = __webpack_require__(709); -utils.extend = __webpack_require__(694); -utils.pick = __webpack_require__(710); -utils.typeOf = __webpack_require__(592); -utils.unique = __webpack_require__(602); +var Snapdragon = __webpack_require__(627); +utils.define = __webpack_require__(726); +utils.diff = __webpack_require__(710); +utils.extend = __webpack_require__(695); +utils.pick = __webpack_require__(711); +utils.typeOf = __webpack_require__(593); +utils.unique = __webpack_require__(603); /** * Returns true if the platform is windows, or `path.sep` is `\\`. @@ -83054,7 +83161,7 @@ utils.unixify = function(options) { /***/ }), -/* 725 */ +/* 726 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -83067,8 +83174,8 @@ utils.unixify = function(options) { -var isobject = __webpack_require__(590); -var isDescriptor = __webpack_require__(591); +var isobject = __webpack_require__(591); +var isDescriptor = __webpack_require__(592); var define = (typeof Reflect !== 'undefined' && Reflect.defineProperty) ? Reflect.defineProperty : Object.defineProperty; @@ -83099,7 +83206,7 @@ module.exports = function defineProperty(obj, key, val) { /***/ }), -/* 726 */ +/* 727 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -83118,9 +83225,9 @@ var __extends = (this && this.__extends) || (function () { }; })(); Object.defineProperty(exports, "__esModule", { value: true }); -var readdir = __webpack_require__(727); -var reader_1 = __webpack_require__(740); -var fs_stream_1 = __webpack_require__(744); +var readdir = __webpack_require__(728); +var reader_1 = __webpack_require__(741); +var fs_stream_1 = __webpack_require__(745); var ReaderAsync = /** @class */ (function (_super) { __extends(ReaderAsync, _super); function ReaderAsync() { @@ -83181,15 +83288,15 @@ exports.default = ReaderAsync; /***/ }), -/* 727 */ +/* 728 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const readdirSync = __webpack_require__(728); -const readdirAsync = __webpack_require__(736); -const readdirStream = __webpack_require__(739); +const readdirSync = __webpack_require__(729); +const readdirAsync = __webpack_require__(737); +const readdirStream = __webpack_require__(740); module.exports = exports = readdirAsyncPath; exports.readdir = exports.readdirAsync = exports.async = readdirAsyncPath; @@ -83273,7 +83380,7 @@ function readdirStreamStat (dir, options) { /***/ }), -/* 728 */ +/* 729 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -83281,11 +83388,11 @@ function readdirStreamStat (dir, options) { module.exports = readdirSync; -const DirectoryReader = __webpack_require__(729); +const DirectoryReader = __webpack_require__(730); let syncFacade = { - fs: __webpack_require__(734), - forEach: __webpack_require__(735), + fs: __webpack_require__(735), + forEach: __webpack_require__(736), sync: true }; @@ -83314,7 +83421,7 @@ function readdirSync (dir, options, internalOptions) { /***/ }), -/* 729 */ +/* 730 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -83323,9 +83430,9 @@ function readdirSync (dir, options, internalOptions) { const Readable = __webpack_require__(173).Readable; const EventEmitter = __webpack_require__(164).EventEmitter; const path = __webpack_require__(4); -const normalizeOptions = __webpack_require__(730); -const stat = __webpack_require__(732); -const call = __webpack_require__(733); +const normalizeOptions = __webpack_require__(731); +const stat = __webpack_require__(733); +const call = __webpack_require__(734); /** * Asynchronously reads the contents of a directory and streams the results @@ -83701,14 +83808,14 @@ module.exports = DirectoryReader; /***/ }), -/* 730 */ +/* 731 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const path = __webpack_require__(4); -const globToRegExp = __webpack_require__(731); +const globToRegExp = __webpack_require__(732); module.exports = normalizeOptions; @@ -83885,7 +83992,7 @@ function normalizeOptions (options, internalOptions) { /***/ }), -/* 731 */ +/* 732 */ /***/ (function(module, exports) { module.exports = function (glob, opts) { @@ -84022,13 +84129,13 @@ module.exports = function (glob, opts) { /***/ }), -/* 732 */ +/* 733 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const call = __webpack_require__(733); +const call = __webpack_require__(734); module.exports = stat; @@ -84103,7 +84210,7 @@ function symlinkStat (fs, path, lstats, callback) { /***/ }), -/* 733 */ +/* 734 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -84164,14 +84271,14 @@ function callOnce (fn) { /***/ }), -/* 734 */ +/* 735 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const fs = __webpack_require__(132); -const call = __webpack_require__(733); +const call = __webpack_require__(734); /** * A facade around {@link fs.readdirSync} that allows it to be called @@ -84235,7 +84342,7 @@ exports.lstat = function (path, callback) { /***/ }), -/* 735 */ +/* 736 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -84264,7 +84371,7 @@ function syncForEach (array, iterator, done) { /***/ }), -/* 736 */ +/* 737 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -84272,12 +84379,12 @@ function syncForEach (array, iterator, done) { module.exports = readdirAsync; -const maybe = __webpack_require__(737); -const DirectoryReader = __webpack_require__(729); +const maybe = __webpack_require__(738); +const DirectoryReader = __webpack_require__(730); let asyncFacade = { fs: __webpack_require__(132), - forEach: __webpack_require__(738), + forEach: __webpack_require__(739), async: true }; @@ -84319,7 +84426,7 @@ function readdirAsync (dir, options, callback, internalOptions) { /***/ }), -/* 737 */ +/* 738 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -84346,7 +84453,7 @@ module.exports = function maybe (cb, promise) { /***/ }), -/* 738 */ +/* 739 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -84382,7 +84489,7 @@ function asyncForEach (array, iterator, done) { /***/ }), -/* 739 */ +/* 740 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -84390,11 +84497,11 @@ function asyncForEach (array, iterator, done) { module.exports = readdirStream; -const DirectoryReader = __webpack_require__(729); +const DirectoryReader = __webpack_require__(730); let streamFacade = { fs: __webpack_require__(132), - forEach: __webpack_require__(738), + forEach: __webpack_require__(739), async: true }; @@ -84414,16 +84521,16 @@ function readdirStream (dir, options, internalOptions) { /***/ }), -/* 740 */ +/* 741 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var path = __webpack_require__(4); -var deep_1 = __webpack_require__(741); -var entry_1 = __webpack_require__(743); -var pathUtil = __webpack_require__(742); +var deep_1 = __webpack_require__(742); +var entry_1 = __webpack_require__(744); +var pathUtil = __webpack_require__(743); var Reader = /** @class */ (function () { function Reader(options) { this.options = options; @@ -84489,14 +84596,14 @@ exports.default = Reader; /***/ }), -/* 741 */ +/* 742 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -var pathUtils = __webpack_require__(742); -var patternUtils = __webpack_require__(576); +var pathUtils = __webpack_require__(743); +var patternUtils = __webpack_require__(577); var DeepFilter = /** @class */ (function () { function DeepFilter(options, micromatchOptions) { this.options = options; @@ -84579,7 +84686,7 @@ exports.default = DeepFilter; /***/ }), -/* 742 */ +/* 743 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -84610,14 +84717,14 @@ exports.makeAbsolute = makeAbsolute; /***/ }), -/* 743 */ +/* 744 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -var pathUtils = __webpack_require__(742); -var patternUtils = __webpack_require__(576); +var pathUtils = __webpack_require__(743); +var patternUtils = __webpack_require__(577); var EntryFilter = /** @class */ (function () { function EntryFilter(options, micromatchOptions) { this.options = options; @@ -84702,7 +84809,7 @@ exports.default = EntryFilter; /***/ }), -/* 744 */ +/* 745 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -84722,8 +84829,8 @@ var __extends = (this && this.__extends) || (function () { })(); Object.defineProperty(exports, "__esModule", { value: true }); var stream = __webpack_require__(173); -var fsStat = __webpack_require__(745); -var fs_1 = __webpack_require__(749); +var fsStat = __webpack_require__(746); +var fs_1 = __webpack_require__(750); var FileSystemStream = /** @class */ (function (_super) { __extends(FileSystemStream, _super); function FileSystemStream() { @@ -84773,14 +84880,14 @@ exports.default = FileSystemStream; /***/ }), -/* 745 */ +/* 746 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const optionsManager = __webpack_require__(746); -const statProvider = __webpack_require__(748); +const optionsManager = __webpack_require__(747); +const statProvider = __webpack_require__(749); /** * Asynchronous API. */ @@ -84811,13 +84918,13 @@ exports.statSync = statSync; /***/ }), -/* 746 */ +/* 747 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const fsAdapter = __webpack_require__(747); +const fsAdapter = __webpack_require__(748); function prepare(opts) { const options = Object.assign({ fs: fsAdapter.getFileSystemAdapter(opts ? opts.fs : undefined), @@ -84830,7 +84937,7 @@ exports.prepare = prepare; /***/ }), -/* 747 */ +/* 748 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -84853,7 +84960,7 @@ exports.getFileSystemAdapter = getFileSystemAdapter; /***/ }), -/* 748 */ +/* 749 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -84905,7 +85012,7 @@ exports.isFollowedSymlink = isFollowedSymlink; /***/ }), -/* 749 */ +/* 750 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -84936,7 +85043,7 @@ exports.default = FileSystem; /***/ }), -/* 750 */ +/* 751 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -84956,9 +85063,9 @@ var __extends = (this && this.__extends) || (function () { })(); Object.defineProperty(exports, "__esModule", { value: true }); var stream = __webpack_require__(173); -var readdir = __webpack_require__(727); -var reader_1 = __webpack_require__(740); -var fs_stream_1 = __webpack_require__(744); +var readdir = __webpack_require__(728); +var reader_1 = __webpack_require__(741); +var fs_stream_1 = __webpack_require__(745); var TransformStream = /** @class */ (function (_super) { __extends(TransformStream, _super); function TransformStream(reader) { @@ -85026,7 +85133,7 @@ exports.default = ReaderStream; /***/ }), -/* 751 */ +/* 752 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -85045,9 +85152,9 @@ var __extends = (this && this.__extends) || (function () { }; })(); Object.defineProperty(exports, "__esModule", { value: true }); -var readdir = __webpack_require__(727); -var reader_1 = __webpack_require__(740); -var fs_sync_1 = __webpack_require__(752); +var readdir = __webpack_require__(728); +var reader_1 = __webpack_require__(741); +var fs_sync_1 = __webpack_require__(753); var ReaderSync = /** @class */ (function (_super) { __extends(ReaderSync, _super); function ReaderSync() { @@ -85107,7 +85214,7 @@ exports.default = ReaderSync; /***/ }), -/* 752 */ +/* 753 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -85126,8 +85233,8 @@ var __extends = (this && this.__extends) || (function () { }; })(); Object.defineProperty(exports, "__esModule", { value: true }); -var fsStat = __webpack_require__(745); -var fs_1 = __webpack_require__(749); +var fsStat = __webpack_require__(746); +var fs_1 = __webpack_require__(750); var FileSystemSync = /** @class */ (function (_super) { __extends(FileSystemSync, _super); function FileSystemSync() { @@ -85173,7 +85280,7 @@ exports.default = FileSystemSync; /***/ }), -/* 753 */ +/* 754 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -85189,7 +85296,7 @@ exports.flatten = flatten; /***/ }), -/* 754 */ +/* 755 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -85210,13 +85317,13 @@ exports.merge = merge; /***/ }), -/* 755 */ +/* 756 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const path = __webpack_require__(4); -const pathType = __webpack_require__(756); +const pathType = __webpack_require__(757); const getExtensions = extensions => extensions.length > 1 ? `{${extensions.join(',')}}` : extensions[0]; @@ -85282,13 +85389,13 @@ module.exports.sync = (input, opts) => { /***/ }), -/* 756 */ +/* 757 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const fs = __webpack_require__(132); -const pify = __webpack_require__(757); +const pify = __webpack_require__(758); function type(fn, fn2, fp) { if (typeof fp !== 'string') { @@ -85331,7 +85438,7 @@ exports.symlinkSync = typeSync.bind(null, 'lstatSync', 'isSymbolicLink'); /***/ }), -/* 757 */ +/* 758 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -85422,17 +85529,17 @@ module.exports = (obj, opts) => { /***/ }), -/* 758 */ +/* 759 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const fs = __webpack_require__(132); const path = __webpack_require__(4); -const fastGlob = __webpack_require__(572); -const gitIgnore = __webpack_require__(759); +const fastGlob = __webpack_require__(573); +const gitIgnore = __webpack_require__(760); const pify = __webpack_require__(404); -const slash = __webpack_require__(760); +const slash = __webpack_require__(761); const DEFAULT_IGNORE = [ '**/node_modules/**', @@ -85530,7 +85637,7 @@ module.exports.sync = options => { /***/ }), -/* 759 */ +/* 760 */ /***/ (function(module, exports) { // A simple implementation of make-array @@ -85999,7 +86106,7 @@ module.exports = options => new IgnoreBase(options) /***/ }), -/* 760 */ +/* 761 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -86017,7 +86124,7 @@ module.exports = input => { /***/ }), -/* 761 */ +/* 762 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -86030,7 +86137,7 @@ module.exports = input => { -var isGlob = __webpack_require__(762); +var isGlob = __webpack_require__(763); module.exports = function hasGlob(val) { if (val == null) return false; @@ -86050,7 +86157,7 @@ module.exports = function hasGlob(val) { /***/ }), -/* 762 */ +/* 763 */ /***/ (function(module, exports, __webpack_require__) { /*! @@ -86081,17 +86188,17 @@ module.exports = function isGlob(str) { /***/ }), -/* 763 */ +/* 764 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const path = __webpack_require__(4); const {constants: fsConstants} = __webpack_require__(132); -const pEvent = __webpack_require__(764); -const CpFileError = __webpack_require__(767); -const fs = __webpack_require__(769); -const ProgressEmitter = __webpack_require__(772); +const pEvent = __webpack_require__(765); +const CpFileError = __webpack_require__(768); +const fs = __webpack_require__(770); +const ProgressEmitter = __webpack_require__(773); const cpFileAsync = async (source, destination, options, progressEmitter) => { let readError; @@ -86205,12 +86312,12 @@ module.exports.sync = (source, destination, options) => { /***/ }), -/* 764 */ +/* 765 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const pTimeout = __webpack_require__(765); +const pTimeout = __webpack_require__(766); const symbolAsyncIterator = Symbol.asyncIterator || '@@asyncIterator'; @@ -86501,12 +86608,12 @@ module.exports.iterator = (emitter, event, options) => { /***/ }), -/* 765 */ +/* 766 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const pFinally = __webpack_require__(766); +const pFinally = __webpack_require__(767); class TimeoutError extends Error { constructor(message) { @@ -86552,7 +86659,7 @@ module.exports.TimeoutError = TimeoutError; /***/ }), -/* 766 */ +/* 767 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -86574,12 +86681,12 @@ module.exports = (promise, onFinally) => { /***/ }), -/* 767 */ +/* 768 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const NestedError = __webpack_require__(768); +const NestedError = __webpack_require__(769); class CpFileError extends NestedError { constructor(message, nested) { @@ -86593,7 +86700,7 @@ module.exports = CpFileError; /***/ }), -/* 768 */ +/* 769 */ /***/ (function(module, exports, __webpack_require__) { var inherits = __webpack_require__(113).inherits; @@ -86649,16 +86756,16 @@ module.exports = NestedError; /***/ }), -/* 769 */ +/* 770 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const {promisify} = __webpack_require__(113); const fs = __webpack_require__(233); -const makeDir = __webpack_require__(770); -const pEvent = __webpack_require__(764); -const CpFileError = __webpack_require__(767); +const makeDir = __webpack_require__(771); +const pEvent = __webpack_require__(765); +const CpFileError = __webpack_require__(768); const stat = promisify(fs.stat); const lstat = promisify(fs.lstat); @@ -86755,7 +86862,7 @@ exports.copyFileSync = (source, destination, flags) => { /***/ }), -/* 770 */ +/* 771 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -86763,7 +86870,7 @@ exports.copyFileSync = (source, destination, flags) => { const fs = __webpack_require__(132); const path = __webpack_require__(4); const {promisify} = __webpack_require__(113); -const semver = __webpack_require__(771); +const semver = __webpack_require__(772); const useNativeRecursiveOption = semver.satisfies(process.version, '>=10.12.0'); @@ -86918,7 +87025,7 @@ module.exports.sync = (input, options) => { /***/ }), -/* 771 */ +/* 772 */ /***/ (function(module, exports) { exports = module.exports = SemVer @@ -88520,7 +88627,7 @@ function coerce (version, options) { /***/ }), -/* 772 */ +/* 773 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -88561,7 +88668,7 @@ module.exports = ProgressEmitter; /***/ }), -/* 773 */ +/* 774 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -88607,12 +88714,12 @@ exports.default = module.exports; /***/ }), -/* 774 */ +/* 775 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const pMap = __webpack_require__(775); +const pMap = __webpack_require__(776); const pFilter = async (iterable, filterer, options) => { const values = await pMap( @@ -88629,7 +88736,7 @@ module.exports.default = pFilter; /***/ }), -/* 775 */ +/* 776 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -88708,12 +88815,12 @@ module.exports.default = pMap; /***/ }), -/* 776 */ +/* 777 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const NestedError = __webpack_require__(768); +const NestedError = __webpack_require__(769); class CpyError extends NestedError { constructor(message, nested) { @@ -88727,7 +88834,7 @@ module.exports = CpyError; /***/ }), -/* 777 */ +/* 778 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -88735,10 +88842,10 @@ module.exports = CpyError; const fs = __webpack_require__(132); const arrayUnion = __webpack_require__(242); const merge2 = __webpack_require__(243); -const fastGlob = __webpack_require__(778); +const fastGlob = __webpack_require__(779); const dirGlob = __webpack_require__(326); -const gitignore = __webpack_require__(809); -const {FilterStream, UniqueStream} = __webpack_require__(810); +const gitignore = __webpack_require__(810); +const {FilterStream, UniqueStream} = __webpack_require__(811); const DEFAULT_FILTER = () => false; @@ -88915,17 +89022,17 @@ module.exports.gitignore = gitignore; /***/ }), -/* 778 */ +/* 779 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const taskManager = __webpack_require__(779); -const async_1 = __webpack_require__(795); -const stream_1 = __webpack_require__(805); -const sync_1 = __webpack_require__(806); -const settings_1 = __webpack_require__(808); -const utils = __webpack_require__(780); +const taskManager = __webpack_require__(780); +const async_1 = __webpack_require__(796); +const stream_1 = __webpack_require__(806); +const sync_1 = __webpack_require__(807); +const settings_1 = __webpack_require__(809); +const utils = __webpack_require__(781); async function FastGlob(source, options) { assertPatternsInput(source); const works = getWorks(source, async_1.default, options); @@ -88989,14 +89096,14 @@ module.exports = FastGlob; /***/ }), -/* 779 */ +/* 780 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.convertPatternGroupToTask = exports.convertPatternGroupsToTasks = exports.groupPatternsByBaseDirectory = exports.getNegativePatternsAsPositive = exports.getPositivePatterns = exports.convertPatternsToTasks = exports.generate = void 0; -const utils = __webpack_require__(780); +const utils = __webpack_require__(781); function generate(patterns, settings) { const positivePatterns = getPositivePatterns(patterns); const negativePatterns = getNegativePatternsAsPositive(patterns, settings.ignore); @@ -89076,31 +89183,31 @@ exports.convertPatternGroupToTask = convertPatternGroupToTask; /***/ }), -/* 780 */ +/* 781 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.string = exports.stream = exports.pattern = exports.path = exports.fs = exports.errno = exports.array = void 0; -const array = __webpack_require__(781); +const array = __webpack_require__(782); exports.array = array; -const errno = __webpack_require__(782); +const errno = __webpack_require__(783); exports.errno = errno; -const fs = __webpack_require__(783); +const fs = __webpack_require__(784); exports.fs = fs; -const path = __webpack_require__(784); +const path = __webpack_require__(785); exports.path = path; -const pattern = __webpack_require__(785); +const pattern = __webpack_require__(786); exports.pattern = pattern; -const stream = __webpack_require__(793); +const stream = __webpack_require__(794); exports.stream = stream; -const string = __webpack_require__(794); +const string = __webpack_require__(795); exports.string = string; /***/ }), -/* 781 */ +/* 782 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -89129,7 +89236,7 @@ exports.splitWhen = splitWhen; /***/ }), -/* 782 */ +/* 783 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -89143,7 +89250,7 @@ exports.isEnoentCodeError = isEnoentCodeError; /***/ }), -/* 783 */ +/* 784 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -89169,7 +89276,7 @@ exports.createDirentFromStats = createDirentFromStats; /***/ }), -/* 784 */ +/* 785 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -89209,7 +89316,7 @@ exports.removeLeadingDotSegment = removeLeadingDotSegment; /***/ }), -/* 785 */ +/* 786 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -89218,7 +89325,7 @@ Object.defineProperty(exports, "__esModule", { value: true }); exports.matchAny = exports.convertPatternsToRe = exports.makeRe = exports.getPatternParts = exports.expandBraceExpansion = exports.expandPatternsWithBraceExpansion = exports.isAffectDepthOfReadingPattern = exports.endsWithSlashGlobStar = exports.hasGlobStar = exports.getBaseDirectory = exports.isPatternRelatedToParentDirectory = exports.getPatternsOutsideCurrentDirectory = exports.getPatternsInsideCurrentDirectory = exports.getPositivePatterns = exports.getNegativePatterns = exports.isPositivePattern = exports.isNegativePattern = exports.convertToNegativePattern = exports.convertToPositivePattern = exports.isDynamicPattern = exports.isStaticPattern = void 0; const path = __webpack_require__(4); const globParent = __webpack_require__(265); -const micromatch = __webpack_require__(786); +const micromatch = __webpack_require__(787); const GLOBSTAR = '**'; const ESCAPE_SYMBOL = '\\'; const COMMON_GLOB_SYMBOLS_RE = /[*?]|^!/; @@ -89373,7 +89480,7 @@ exports.matchAny = matchAny; /***/ }), -/* 786 */ +/* 787 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -89381,8 +89488,8 @@ exports.matchAny = matchAny; const util = __webpack_require__(113); const braces = __webpack_require__(269); -const picomatch = __webpack_require__(787); -const utils = __webpack_require__(790); +const picomatch = __webpack_require__(788); +const utils = __webpack_require__(791); const isEmptyString = val => val === '' || val === './'; /** @@ -89847,27 +89954,27 @@ module.exports = micromatch; /***/ }), -/* 787 */ +/* 788 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -module.exports = __webpack_require__(788); +module.exports = __webpack_require__(789); /***/ }), -/* 788 */ +/* 789 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const path = __webpack_require__(4); -const scan = __webpack_require__(789); -const parse = __webpack_require__(792); -const utils = __webpack_require__(790); -const constants = __webpack_require__(791); +const scan = __webpack_require__(790); +const parse = __webpack_require__(793); +const utils = __webpack_require__(791); +const constants = __webpack_require__(792); const isObject = val => val && typeof val === 'object' && !Array.isArray(val); /** @@ -90206,13 +90313,13 @@ module.exports = picomatch; /***/ }), -/* 789 */ +/* 790 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const utils = __webpack_require__(790); +const utils = __webpack_require__(791); const { CHAR_ASTERISK, /* * */ CHAR_AT, /* @ */ @@ -90229,7 +90336,7 @@ const { CHAR_RIGHT_CURLY_BRACE, /* } */ CHAR_RIGHT_PARENTHESES, /* ) */ CHAR_RIGHT_SQUARE_BRACKET /* ] */ -} = __webpack_require__(791); +} = __webpack_require__(792); const isPathSeparator = code => { return code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH; @@ -90604,7 +90711,7 @@ module.exports = scan; /***/ }), -/* 790 */ +/* 791 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -90617,7 +90724,7 @@ const { REGEX_REMOVE_BACKSLASH, REGEX_SPECIAL_CHARS, REGEX_SPECIAL_CHARS_GLOBAL -} = __webpack_require__(791); +} = __webpack_require__(792); exports.isObject = val => val !== null && typeof val === 'object' && !Array.isArray(val); exports.hasRegexChars = str => REGEX_SPECIAL_CHARS.test(str); @@ -90675,7 +90782,7 @@ exports.wrapOutput = (input, state = {}, options = {}) => { /***/ }), -/* 791 */ +/* 792 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -90861,14 +90968,14 @@ module.exports = { /***/ }), -/* 792 */ +/* 793 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const constants = __webpack_require__(791); -const utils = __webpack_require__(790); +const constants = __webpack_require__(792); +const utils = __webpack_require__(791); /** * Constants @@ -91952,7 +92059,7 @@ module.exports = parse; /***/ }), -/* 793 */ +/* 794 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -91976,7 +92083,7 @@ function propagateCloseEventToSources(streams) { /***/ }), -/* 794 */ +/* 795 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -91994,14 +92101,14 @@ exports.isEmpty = isEmpty; /***/ }), -/* 795 */ +/* 796 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const stream_1 = __webpack_require__(796); -const provider_1 = __webpack_require__(798); +const stream_1 = __webpack_require__(797); +const provider_1 = __webpack_require__(799); class ProviderAsync extends provider_1.default { constructor() { super(...arguments); @@ -92029,7 +92136,7 @@ exports.default = ProviderAsync; /***/ }), -/* 796 */ +/* 797 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -92038,7 +92145,7 @@ Object.defineProperty(exports, "__esModule", { value: true }); const stream_1 = __webpack_require__(173); const fsStat = __webpack_require__(289); const fsWalk = __webpack_require__(294); -const reader_1 = __webpack_require__(797); +const reader_1 = __webpack_require__(798); class ReaderStream extends reader_1.default { constructor() { super(...arguments); @@ -92091,7 +92198,7 @@ exports.default = ReaderStream; /***/ }), -/* 797 */ +/* 798 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -92099,7 +92206,7 @@ exports.default = ReaderStream; Object.defineProperty(exports, "__esModule", { value: true }); const path = __webpack_require__(4); const fsStat = __webpack_require__(289); -const utils = __webpack_require__(780); +const utils = __webpack_require__(781); class Reader { constructor(_settings) { this._settings = _settings; @@ -92131,17 +92238,17 @@ exports.default = Reader; /***/ }), -/* 798 */ +/* 799 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const path = __webpack_require__(4); -const deep_1 = __webpack_require__(799); -const entry_1 = __webpack_require__(802); -const error_1 = __webpack_require__(803); -const entry_2 = __webpack_require__(804); +const deep_1 = __webpack_require__(800); +const entry_1 = __webpack_require__(803); +const error_1 = __webpack_require__(804); +const entry_2 = __webpack_require__(805); class Provider { constructor(_settings) { this._settings = _settings; @@ -92186,14 +92293,14 @@ exports.default = Provider; /***/ }), -/* 799 */ +/* 800 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const utils = __webpack_require__(780); -const partial_1 = __webpack_require__(800); +const utils = __webpack_require__(781); +const partial_1 = __webpack_require__(801); class DeepFilter { constructor(_settings, _micromatchOptions) { this._settings = _settings; @@ -92255,13 +92362,13 @@ exports.default = DeepFilter; /***/ }), -/* 800 */ +/* 801 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const matcher_1 = __webpack_require__(801); +const matcher_1 = __webpack_require__(802); class PartialMatcher extends matcher_1.default { match(filepath) { const parts = filepath.split('/'); @@ -92300,13 +92407,13 @@ exports.default = PartialMatcher; /***/ }), -/* 801 */ +/* 802 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const utils = __webpack_require__(780); +const utils = __webpack_require__(781); class Matcher { constructor(_patterns, _settings, _micromatchOptions) { this._patterns = _patterns; @@ -92357,13 +92464,13 @@ exports.default = Matcher; /***/ }), -/* 802 */ +/* 803 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const utils = __webpack_require__(780); +const utils = __webpack_require__(781); class EntryFilter { constructor(_settings, _micromatchOptions) { this._settings = _settings; @@ -92420,13 +92527,13 @@ exports.default = EntryFilter; /***/ }), -/* 803 */ +/* 804 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const utils = __webpack_require__(780); +const utils = __webpack_require__(781); class ErrorFilter { constructor(_settings) { this._settings = _settings; @@ -92442,13 +92549,13 @@ exports.default = ErrorFilter; /***/ }), -/* 804 */ +/* 805 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const utils = __webpack_require__(780); +const utils = __webpack_require__(781); class EntryTransformer { constructor(_settings) { this._settings = _settings; @@ -92475,15 +92582,15 @@ exports.default = EntryTransformer; /***/ }), -/* 805 */ +/* 806 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const stream_1 = __webpack_require__(173); -const stream_2 = __webpack_require__(796); -const provider_1 = __webpack_require__(798); +const stream_2 = __webpack_require__(797); +const provider_1 = __webpack_require__(799); class ProviderStream extends provider_1.default { constructor() { super(...arguments); @@ -92513,14 +92620,14 @@ exports.default = ProviderStream; /***/ }), -/* 806 */ +/* 807 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const sync_1 = __webpack_require__(807); -const provider_1 = __webpack_require__(798); +const sync_1 = __webpack_require__(808); +const provider_1 = __webpack_require__(799); class ProviderSync extends provider_1.default { constructor() { super(...arguments); @@ -92543,7 +92650,7 @@ exports.default = ProviderSync; /***/ }), -/* 807 */ +/* 808 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -92551,7 +92658,7 @@ exports.default = ProviderSync; Object.defineProperty(exports, "__esModule", { value: true }); const fsStat = __webpack_require__(289); const fsWalk = __webpack_require__(294); -const reader_1 = __webpack_require__(797); +const reader_1 = __webpack_require__(798); class ReaderSync extends reader_1.default { constructor() { super(...arguments); @@ -92593,7 +92700,7 @@ exports.default = ReaderSync; /***/ }), -/* 808 */ +/* 809 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -92657,7 +92764,7 @@ exports.default = Settings; /***/ }), -/* 809 */ +/* 810 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -92665,7 +92772,7 @@ exports.default = Settings; const {promisify} = __webpack_require__(113); const fs = __webpack_require__(132); const path = __webpack_require__(4); -const fastGlob = __webpack_require__(778); +const fastGlob = __webpack_require__(779); const gitIgnore = __webpack_require__(329); const slash = __webpack_require__(330); @@ -92784,7 +92891,7 @@ module.exports.sync = options => { /***/ }), -/* 810 */ +/* 811 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -92837,7 +92944,7 @@ module.exports = { /***/ }), -/* 811 */ +/* 812 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -92845,13 +92952,13 @@ __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "buildNonBazelProductionProjects", function() { return buildNonBazelProductionProjects; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getProductionProjects", function() { return getProductionProjects; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "buildProject", function() { return buildProject; }); -/* harmony import */ var cpy__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(565); +/* harmony import */ var cpy__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(566); /* harmony import */ var cpy__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(cpy__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var del__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(240); /* harmony import */ var del__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(del__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(4); /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_2__); -/* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(562); +/* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(563); /* harmony import */ var _utils_fs__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(231); /* harmony import */ var _utils_log__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(220); /* harmony import */ var _utils_package_json__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(343); diff --git a/packages/kbn-pm/src/commands/bootstrap.ts b/packages/kbn-pm/src/commands/bootstrap.ts index 12034a9f4a0949..e7b8cad7ebc161 100644 --- a/packages/kbn-pm/src/commands/bootstrap.ts +++ b/packages/kbn-pm/src/commands/bootstrap.ts @@ -23,6 +23,7 @@ import { runBazel, yarnIntegrityFileExists, } from '../utils/bazel'; +import { setupRemoteCache } from '../utils/bazel/setup_remote_cache'; export const BootstrapCommand: ICommand = { description: 'Install dependencies and crosslink projects', @@ -55,6 +56,9 @@ export const BootstrapCommand: ICommand = { // Install bazel machinery tools if needed await installBazelTools(rootPath); + // Setup remote cache settings in .bazelrc.cache if needed + await setupRemoteCache(rootPath); + // Bootstrap process for Bazel packages // Bazel is now managing dependencies so yarn install // will happen as part of this diff --git a/packages/kbn-pm/src/utils/bazel/setup_remote_cache.ts b/packages/kbn-pm/src/utils/bazel/setup_remote_cache.ts new file mode 100644 index 00000000000000..fb510cfa81ffd0 --- /dev/null +++ b/packages/kbn-pm/src/utils/bazel/setup_remote_cache.ts @@ -0,0 +1,92 @@ +/* + * 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. + */ +import dedent from 'dedent'; +import { existsSync, writeFileSync } from 'fs'; +import { resolve } from 'path'; +import { spawn } from '../child_process'; +import { log } from '../log'; + +async function isVaultAvailable() { + try { + await spawn('vault', ['--version'], { stdio: 'pipe' }); + + return true; + } catch { + return false; + } +} + +async function isElasticCommitter() { + try { + const { stdout: email } = await spawn('git', ['config', 'user.email'], { + stdio: 'pipe', + }); + + return email.trim().endsWith('@elastic.co'); + } catch { + return false; + } +} + +export async function setupRemoteCache(repoRootPath: string) { + // The remote cache is only for Elastic employees working locally (CI cache settings are handled elsewhere) + if (process.env.CI || !(await isElasticCommitter())) { + return; + } + + log.debug(`[bazel_tools] setting up remote cache settings if necessary`); + + const settingsPath = resolve(repoRootPath, '.bazelrc.cache'); + + if (existsSync(settingsPath)) { + log.debug(`[bazel_tools] remote cache settings already exist, skipping`); + return; + } + + if (!(await isVaultAvailable())) { + log.info('[bazel_tools] vault is not available, unable to setup remote cache settings.'); + log.info('[bazel_tools] building packages will work, but will be slower in many cases.'); + log.info('[bazel_tools] reach out to Operations if you need assistance with this.'); + return; + } + + let apiKey = ''; + + try { + const { stdout } = await spawn( + 'vault', + ['read', '-field=readonly-key', 'secret/kibana-issues/dev/bazel-remote-cache'], + { + stdio: 'pipe', + } + ); + apiKey = stdout.trim(); + } catch (ex: unknown) { + log.info( + '[bazel_tools] unable to read bazel remote cache key from vault, are you authenticated?' + ); + log.info('[bazel_tools] building packages will work, but will be slower in many cases.'); + log.info('[bazel_tools] reach out to Operations if you need assistance with this.'); + log.info(`[bazel_tools] ${ex}`); + + return; + } + + const contents = dedent` + # V1 - This file is automatically generated by 'yarn kbn bootstrap' + # To regenerate this file, delete it and run 'yarn kbn bootstrap' again. + build --bes_results_url=https://app.buildbuddy.io/invocation/ + build --bes_backend=grpcs://cloud.buildbuddy.io + build --remote_cache=grpcs://cloud.buildbuddy.io + build --remote_timeout=3600 + build --remote_header=${apiKey} + `; + + writeFileSync(settingsPath, contents); + log.info(`[bazel_tools] remote cache settings written to ${settingsPath}`); +} From a2c2adfab2e069d9d3b3eeb0e188d2c09c5b9bb4 Mon Sep 17 00:00:00 2001 From: Dave Snider Date: Tue, 18 Jan 2022 15:13:27 -0500 Subject: [PATCH 021/108] Fix major mobile issues with security overview (#122770) Makes mobile view for the security overview work. --- .../overview/components/sidebar/sidebar.tsx | 23 +++----------- .../public/overview/pages/overview.tsx | 31 +++++++------------ 2 files changed, 17 insertions(+), 37 deletions(-) diff --git a/x-pack/plugins/security_solution/public/overview/components/sidebar/sidebar.tsx b/x-pack/plugins/security_solution/public/overview/components/sidebar/sidebar.tsx index b8701f3ef1639d..f8a0e2e7c83b97 100644 --- a/x-pack/plugins/security_solution/public/overview/components/sidebar/sidebar.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/sidebar/sidebar.tsx @@ -7,7 +7,6 @@ import { EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui'; import React, { useMemo } from 'react'; -import styled from 'styled-components'; import { ENABLE_NEWS_FEED_SETTING, NEWS_FEED_URL_SETTING } from '../../../../common/constants'; import { Filters as RecentTimelinesFilters } from '../recent_timelines/filters'; @@ -20,10 +19,6 @@ import * as i18n from '../../pages/translations'; import { RecentCases } from '../recent_cases'; import { useGetUserCasesPermissions } from '../../../common/lib/kibana'; -const SidebarFlexGroup = styled(EuiFlexGroup)` - width: 305px; -`; - const SidebarSpacerComponent = () => ( @@ -31,8 +26,6 @@ const SidebarSpacerComponent = () => ( ); SidebarSpacerComponent.displayName = 'SidebarSpacerComponent'; -const Spacer = React.memo(SidebarSpacerComponent); - export const Sidebar = React.memo<{ recentTimelinesFilterBy: RecentTimelinesFilterMode; setRecentTimelinesFilterBy: (filterBy: RecentTimelinesFilterMode) => void; @@ -51,15 +44,11 @@ export const Sidebar = React.memo<{ const hasCasesReadPermissions = useGetUserCasesPermissions()?.read; return ( - + {hasCasesReadPermissions && ( - <> - - - - - - + + + )} @@ -67,15 +56,13 @@ export const Sidebar = React.memo<{ - - - + ); }); diff --git a/x-pack/plugins/security_solution/public/overview/pages/overview.tsx b/x-pack/plugins/security_solution/public/overview/pages/overview.tsx index 1df49fed073589..8de31fa8ebe8aa 100644 --- a/x-pack/plugins/security_solution/public/overview/pages/overview.tsx +++ b/x-pack/plugins/security_solution/public/overview/pages/overview.tsx @@ -5,9 +5,8 @@ * 2.0. */ -import { EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui'; +import { EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiShowFor } from '@elastic/eui'; import React, { useCallback, useState, useMemo } from 'react'; -import styled from 'styled-components'; import { AlertsByCategory } from '../components/alerts_by_category'; import { FiltersGlobal } from '../../common/components/filters_global'; @@ -37,14 +36,6 @@ import { RiskyHostLinks } from '../components/overview_risky_host_links'; import { useAlertsPrivileges } from '../../detections/containers/detection_engine/alerts/use_alerts_privileges'; import { useIsExperimentalFeatureEnabled } from '../../common/hooks/use_experimental_features'; -const SidebarFlexItem = styled(EuiFlexItem)` - margin-right: 24px; -`; - -const StyledSecuritySolutionPageWrapper = styled(SecuritySolutionPageWrapper)` - overflow-x: auto; -`; - const OverviewComponent = () => { const getGlobalFiltersQuerySelector = useMemo( () => inputsSelectors.globalFiltersQuerySelector(), @@ -91,20 +82,22 @@ const OverviewComponent = () => { - + {!dismissMessage && !metadataIndexExists && canAccessFleet && ( <> )} - - - - - - - + + + + + + + + + {hasIndexRead && hasKibanaREAD && ( <> @@ -180,7 +173,7 @@ const OverviewComponent = () => { - + ) : ( From 4b1e83df1ad64a9adfd9f9ce130e41d81416fbf0 Mon Sep 17 00:00:00 2001 From: Tim Sullivan Date: Tue, 18 Jan 2022 13:28:19 -0700 Subject: [PATCH 022/108] [Sharing/URLs] Wrap radio buttons in a fieldset and legend (#123011) Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../url_panel_content.test.tsx.snap | 64 +++++++++++-------- .../public/components/url_panel_content.tsx | 18 +++--- 2 files changed, 45 insertions(+), 37 deletions(-) diff --git a/src/plugins/share/public/components/__snapshots__/url_panel_content.test.tsx.snap b/src/plugins/share/public/components/__snapshots__/url_panel_content.test.tsx.snap index e883b550fde04f..0c80b72dc06b64 100644 --- a/src/plugins/share/public/components/__snapshots__/url_panel_content.test.tsx.snap +++ b/src/plugins/share/public/components/__snapshots__/url_panel_content.test.tsx.snap @@ -23,17 +23,19 @@ exports[`share url panel content render 1`] = ` } /> } - label={ - - } labelType="label" > , + } + } onChange={[Function]} options={ Array [ @@ -204,17 +206,19 @@ exports[`share url panel content should enable saved object export option when o fullWidth={false} hasChildLabel={true} hasEmptyLabelSpace={false} - label={ - - } labelType="label" > , + } + } onChange={[Function]} options={ Array [ @@ -385,17 +389,19 @@ exports[`share url panel content should hide short url section when allowShortUr fullWidth={false} hasChildLabel={true} hasEmptyLabelSpace={false} - label={ - - } labelType="label" > , + } + } onChange={[Function]} options={ Array [ @@ -521,17 +527,19 @@ exports[`should show url param extensions 1`] = ` fullWidth={false} hasChildLabel={true} hasEmptyLabelSpace={false} - label={ - - } labelType="label" > , + } + } onChange={[Function]} options={ Array [ diff --git a/src/plugins/share/public/components/url_panel_content.tsx b/src/plugins/share/public/components/url_panel_content.tsx index 899036fc7107fc..8670b84d5c48eb 100644 --- a/src/plugins/share/public/components/url_panel_content.tsx +++ b/src/plugins/share/public/components/url_panel_content.tsx @@ -451,19 +451,19 @@ export class UrlPanelContent extends Component { /> ) : undefined; return ( - - } - helpText={generateLinkAsHelp} - > + + ), + }} /> ); From 8c11be11547fb0a2c9136c98949a03473459a08f Mon Sep 17 00:00:00 2001 From: Ryland Herrick Date: Tue, 18 Jan 2022 14:46:45 -0600 Subject: [PATCH 023/108] [Timelines] Update fields metadata from beats 8.0 (#123014) * Move beats metadata script to timelines plugin This is the plugin that consumes the artifacts of the script, not security_solution. * Remove unused beats metadata file This file also exists in the timelines plugin, but only that one is used. * Update fields metadata from beats 8.0.0-rc1 This will serve as the data source for our metadata in kibana 8.0. * Update indexFields unit tests following ECS update 8.0 introduced some textual changes to field descriptions. * Revert "Move beats metadata script to timelines plugin" This reverts commit cbc8e9db1aded54d72aa4a00b8029025442dfb84. * Update script to modify the appropriate timelines file This is the one used by IndexFields. Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- x-pack/plugins/security_solution/package.json | 2 +- .../scripts/beat_docs/build.js | 4 +- .../server/utils/beat_schema/fields.ts | 44070 ------------- .../index_fields/index.test.ts | 18 +- .../server/utils/beat_schema/fields.ts | 54605 ++++++++++------ 5 files changed, 33913 insertions(+), 64786 deletions(-) delete mode 100644 x-pack/plugins/security_solution/server/utils/beat_schema/fields.ts diff --git a/x-pack/plugins/security_solution/package.json b/x-pack/plugins/security_solution/package.json index 821550f21919ac..a899f5948c7809 100644 --- a/x-pack/plugins/security_solution/package.json +++ b/x-pack/plugins/security_solution/package.json @@ -6,7 +6,7 @@ "license": "Elastic-License", "scripts": { "extract-mitre-attacks": "node scripts/extract_tactics_techniques_mitre.js && node ../../../scripts/eslint ./public/detections/mitre/mitre_tactics_techniques.ts --fix", - "build-beat-doc": "node scripts/beat_docs/build.js && node ../../../scripts/eslint ./server/utils/beat_schema/fields.ts --fix", + "build-beat-doc": "node scripts/beat_docs/build.js && node ../../../scripts/eslint ../timelines/server/utils/beat_schema/fields.ts --fix", "cypress": "../../../node_modules/.bin/cypress", "cypress:open": "yarn cypress open --config-file ./cypress/cypress.json", "cypress:open:ccs": "yarn cypress:open --config integrationFolder=./cypress/ccs_integration", diff --git a/x-pack/plugins/security_solution/scripts/beat_docs/build.js b/x-pack/plugins/security_solution/scripts/beat_docs/build.js index 554581e26d30f4..0179349df76a1d 100644 --- a/x-pack/plugins/security_solution/scripts/beat_docs/build.js +++ b/x-pack/plugins/security_solution/scripts/beat_docs/build.js @@ -25,8 +25,8 @@ const tar = require('tar'); const zlib = require('zlib'); const OUTPUT_DIRECTORY = resolve('scripts', 'beat_docs'); -const OUTPUT_SERVER_DIRECTORY = resolve('server', 'utils', 'beat_schema'); -const BEATS_VERSION = '7.14.0'; +const OUTPUT_SERVER_DIRECTORY = resolve('../timelines', 'server', 'utils', 'beat_schema'); +const BEATS_VERSION = '8.0.0-rc1'; const beats = [ { diff --git a/x-pack/plugins/security_solution/server/utils/beat_schema/fields.ts b/x-pack/plugins/security_solution/server/utils/beat_schema/fields.ts deleted file mode 100644 index b2f01d9ddb3660..00000000000000 --- a/x-pack/plugins/security_solution/server/utils/beat_schema/fields.ts +++ /dev/null @@ -1,44070 +0,0 @@ -/* - * 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 { BeatFields } from '../../../common/search_strategy/index_fields'; - -/* eslint-disable @typescript-eslint/naming-convention */ -export const fieldsBeat: BeatFields = { - _id: { - category: 'base', - description: 'Each document has an _id that uniquely identifies it', - example: 'Y-6TfmcB0WOhS6qyMv3s', - name: '_id', - type: 'keyword', - }, - _index: { - category: 'base', - description: - 'An index is like a ‘database’ in a relational database. It has a mapping which defines multiple types. An index is a logical namespace which maps to one or more primary shards and can have zero or more replica shards.', - example: 'auditbeat-8.0.0-2019.02.19-000001', - name: '_index', - type: 'keyword', - }, - '@timestamp': { - category: 'base', - description: - 'Date/time when the event originated. This is the date/time extracted from the event, typically representing when the event was generated by the source. If the event source has no original timestamp, this value is typically populated by the first time the event was received by the pipeline. Required field for all events.', - example: '2016-05-23T08:05:34.853Z', - name: '@timestamp', - type: 'date', - }, - labels: { - category: 'base', - description: - 'Custom key/value pairs. Can be used to add meta information to events. Should not contain nested objects. All values are stored as keyword. Example: `docker` and `k8s` labels.', - example: '{"application": "foo-bar", "env": "production"}', - name: 'labels', - type: 'object', - }, - message: { - category: 'base', - description: - 'For log events the message field contains the log message, optimized for viewing in a log viewer. For structured logs without an original message field, other fields can be concatenated to form a human-readable summary of the event. If multiple messages exist, they can be combined into one message.', - example: 'Hello World', - name: 'message', - type: 'text', - }, - tags: { - category: 'base', - description: 'List of keywords used to tag each event.', - example: '["production", "env2"]', - name: 'tags', - type: 'keyword', - }, - 'agent.build.original': { - category: 'agent', - description: - 'Extended build information for the agent. This field is intended to contain any build information that a data source may provide, no specific formatting is required.', - example: - 'metricbeat version 7.6.0 (amd64), libbeat 7.6.0 [6a23e8f8f30f5001ba344e4e54d8d9cb82cb107c built 2020-02-05 23:10:10 +0000 UTC]', - name: 'agent.build.original', - type: 'keyword', - }, - 'agent.ephemeral_id': { - category: 'agent', - description: - 'Ephemeral identifier of this agent (if one exists). This id normally changes across restarts, but `agent.id` does not.', - example: '8a4f500f', - name: 'agent.ephemeral_id', - type: 'keyword', - }, - 'agent.id': { - category: 'agent', - description: - 'Unique identifier of this agent (if one exists). Example: For Beats this would be beat.id.', - example: '8a4f500d', - name: 'agent.id', - type: 'keyword', - }, - 'agent.name': { - category: 'agent', - description: - 'Custom name of the agent. This is a name that can be given to an agent. This can be helpful if for example two Filebeat instances are running on the same host but a human readable separation is needed on which Filebeat instance data is coming from. If no name is given, the name is often left empty.', - example: 'foo', - name: 'agent.name', - type: 'keyword', - }, - 'agent.type': { - category: 'agent', - description: - 'Type of the agent. The agent type always stays the same and should be given by the agent used. In case of Filebeat the agent would always be Filebeat also if two Filebeat instances are run on the same machine.', - example: 'filebeat', - name: 'agent.type', - type: 'keyword', - }, - 'agent.version': { - category: 'agent', - description: 'Version of the agent.', - example: '6.0.0-rc2', - name: 'agent.version', - type: 'keyword', - }, - 'as.number': { - category: 'as', - description: - 'Unique number allocated to the autonomous system. The autonomous system number (ASN) uniquely identifies each network on the Internet.', - example: 15169, - name: 'as.number', - type: 'long', - }, - 'as.organization.name': { - category: 'as', - description: 'Organization name.', - example: 'Google LLC', - name: 'as.organization.name', - type: 'keyword', - }, - 'client.address': { - category: 'client', - description: - 'Some event client addresses are defined ambiguously. The event will sometimes list an IP, a domain or a unix socket. You should always store the raw address in the `.address` field. Then it should be duplicated to `.ip` or `.domain`, depending on which one it is.', - name: 'client.address', - type: 'keyword', - }, - 'client.as.number': { - category: 'client', - description: - 'Unique number allocated to the autonomous system. The autonomous system number (ASN) uniquely identifies each network on the Internet.', - example: 15169, - name: 'client.as.number', - type: 'long', - }, - 'client.as.organization.name': { - category: 'client', - description: 'Organization name.', - example: 'Google LLC', - name: 'client.as.organization.name', - type: 'keyword', - }, - 'client.bytes': { - category: 'client', - description: 'Bytes sent from the client to the server.', - example: 184, - name: 'client.bytes', - type: 'long', - format: 'bytes', - }, - 'client.domain': { - category: 'client', - description: 'Client domain.', - name: 'client.domain', - type: 'keyword', - }, - 'client.geo.city_name': { - category: 'client', - description: 'City name.', - example: 'Montreal', - name: 'client.geo.city_name', - type: 'keyword', - }, - 'client.geo.continent_code': { - category: 'client', - description: "Two-letter code representing continent's name.", - example: 'NA', - name: 'client.geo.continent_code', - type: 'keyword', - }, - 'client.geo.continent_name': { - category: 'client', - description: 'Name of the continent.', - example: 'North America', - name: 'client.geo.continent_name', - type: 'keyword', - }, - 'client.geo.country_iso_code': { - category: 'client', - description: 'Country ISO code.', - example: 'CA', - name: 'client.geo.country_iso_code', - type: 'keyword', - }, - 'client.geo.country_name': { - category: 'client', - description: 'Country name.', - example: 'Canada', - name: 'client.geo.country_name', - type: 'keyword', - }, - 'client.geo.location': { - category: 'client', - description: 'Longitude and latitude.', - example: '{ "lon": -73.614830, "lat": 45.505918 }', - name: 'client.geo.location', - type: 'geo_point', - }, - 'client.geo.name': { - category: 'client', - description: - 'User-defined description of a location, at the level of granularity they care about. Could be the name of their data centers, the floor number, if this describes a local physical entity, city names. Not typically used in automated geolocation.', - example: 'boston-dc', - name: 'client.geo.name', - type: 'keyword', - }, - 'client.geo.postal_code': { - category: 'client', - description: - 'Postal code associated with the location. Values appropriate for this field may also be known as a postcode or ZIP code and will vary widely from country to country.', - example: 94040, - name: 'client.geo.postal_code', - type: 'keyword', - }, - 'client.geo.region_iso_code': { - category: 'client', - description: 'Region ISO code.', - example: 'CA-QC', - name: 'client.geo.region_iso_code', - type: 'keyword', - }, - 'client.geo.region_name': { - category: 'client', - description: 'Region name.', - example: 'Quebec', - name: 'client.geo.region_name', - type: 'keyword', - }, - 'client.geo.timezone': { - category: 'client', - description: 'The time zone of the location, such as IANA time zone name.', - example: 'America/Argentina/Buenos_Aires', - name: 'client.geo.timezone', - type: 'keyword', - }, - 'client.ip': { - category: 'client', - description: 'IP address of the client (IPv4 or IPv6).', - name: 'client.ip', - type: 'ip', - }, - 'client.mac': { - category: 'client', - description: - 'MAC address of the client. The notation format from RFC 7042 is suggested: Each octet (that is, 8-bit byte) is represented by two [uppercase] hexadecimal digits giving the value of the octet as an unsigned integer. Successive octets are separated by a hyphen.', - example: '00-00-5E-00-53-23', - name: 'client.mac', - type: 'keyword', - }, - 'client.nat.ip': { - category: 'client', - description: - 'Translated IP of source based NAT sessions (e.g. internal client to internet). Typically connections traversing load balancers, firewalls, or routers.', - name: 'client.nat.ip', - type: 'ip', - }, - 'client.nat.port': { - category: 'client', - description: - 'Translated port of source based NAT sessions (e.g. internal client to internet). Typically connections traversing load balancers, firewalls, or routers.', - name: 'client.nat.port', - type: 'long', - format: 'string', - }, - 'client.packets': { - category: 'client', - description: 'Packets sent from the client to the server.', - example: 12, - name: 'client.packets', - type: 'long', - }, - 'client.port': { - category: 'client', - description: 'Port of the client.', - name: 'client.port', - type: 'long', - format: 'string', - }, - 'client.registered_domain': { - category: 'client', - description: - 'The highest registered client domain, stripped of the subdomain. For example, the registered domain for "foo.example.com" is "example.com". This value can be determined precisely with a list like the public suffix list (http://publicsuffix.org). Trying to approximate this by simply taking the last two labels will not work well for TLDs such as "co.uk".', - example: 'example.com', - name: 'client.registered_domain', - type: 'keyword', - }, - 'client.subdomain': { - category: 'client', - description: - 'The subdomain portion of a fully qualified domain name includes all of the names except the host name under the registered_domain. In a partially qualified domain, or if the the qualification level of the full name cannot be determined, subdomain contains all of the names below the registered domain. For example the subdomain portion of "www.east.mydomain.co.uk" is "east". If the domain has multiple levels of subdomain, such as "sub2.sub1.example.com", the subdomain field should contain "sub2.sub1", with no trailing period.', - example: 'east', - name: 'client.subdomain', - type: 'keyword', - }, - 'client.top_level_domain': { - category: 'client', - description: - 'The effective top level domain (eTLD), also known as the domain suffix, is the last part of the domain name. For example, the top level domain for example.com is "com". This value can be determined precisely with a list like the public suffix list (http://publicsuffix.org). Trying to approximate this by simply taking the last label will not work well for effective TLDs such as "co.uk".', - example: 'co.uk', - name: 'client.top_level_domain', - type: 'keyword', - }, - 'client.user.domain': { - category: 'client', - description: - 'Name of the directory the user is a member of. For example, an LDAP or Active Directory domain name.', - name: 'client.user.domain', - type: 'keyword', - }, - 'client.user.email': { - category: 'client', - description: 'User email address.', - name: 'client.user.email', - type: 'keyword', - }, - 'client.user.full_name': { - category: 'client', - description: "User's full name, if available.", - example: 'Albert Einstein', - name: 'client.user.full_name', - type: 'keyword', - }, - 'client.user.group.domain': { - category: 'client', - description: - 'Name of the directory the group is a member of. For example, an LDAP or Active Directory domain name.', - name: 'client.user.group.domain', - type: 'keyword', - }, - 'client.user.group.id': { - category: 'client', - description: 'Unique identifier for the group on the system/platform.', - name: 'client.user.group.id', - type: 'keyword', - }, - 'client.user.group.name': { - category: 'client', - description: 'Name of the group.', - name: 'client.user.group.name', - type: 'keyword', - }, - 'client.user.hash': { - category: 'client', - description: - 'Unique user hash to correlate information for a user in anonymized form. Useful if `user.id` or `user.name` contain confidential information and cannot be used.', - name: 'client.user.hash', - type: 'keyword', - }, - 'client.user.id': { - category: 'client', - description: 'Unique identifier of the user.', - name: 'client.user.id', - type: 'keyword', - }, - 'client.user.name': { - category: 'client', - description: 'Short name or login of the user.', - example: 'albert', - name: 'client.user.name', - type: 'keyword', - }, - 'client.user.roles': { - category: 'client', - description: 'Array of user roles at the time of the event.', - example: '["kibana_admin", "reporting_user"]', - name: 'client.user.roles', - type: 'keyword', - }, - 'cloud.account.id': { - category: 'cloud', - description: - 'The cloud account or organization id used to identify different entities in a multi-tenant environment. Examples: AWS account id, Google Cloud ORG Id, or other unique identifier.', - example: 666777888999, - name: 'cloud.account.id', - type: 'keyword', - }, - 'cloud.account.name': { - category: 'cloud', - description: - 'The cloud account name or alias used to identify different entities in a multi-tenant environment. Examples: AWS account name, Google Cloud ORG display name.', - example: 'elastic-dev', - name: 'cloud.account.name', - type: 'keyword', - }, - 'cloud.availability_zone': { - category: 'cloud', - description: 'Availability zone in which this host is running.', - example: 'us-east-1c', - name: 'cloud.availability_zone', - type: 'keyword', - }, - 'cloud.instance.id': { - category: 'cloud', - description: 'Instance ID of the host machine.', - example: 'i-1234567890abcdef0', - name: 'cloud.instance.id', - type: 'keyword', - }, - 'cloud.instance.name': { - category: 'cloud', - description: 'Instance name of the host machine.', - name: 'cloud.instance.name', - type: 'keyword', - }, - 'cloud.machine.type': { - category: 'cloud', - description: 'Machine type of the host machine.', - example: 't2.medium', - name: 'cloud.machine.type', - type: 'keyword', - }, - 'cloud.project.id': { - category: 'cloud', - description: - 'The cloud project identifier. Examples: Google Cloud Project id, Azure Project id.', - example: 'my-project', - name: 'cloud.project.id', - type: 'keyword', - }, - 'cloud.project.name': { - category: 'cloud', - description: 'The cloud project name. Examples: Google Cloud Project name, Azure Project name.', - example: 'my project', - name: 'cloud.project.name', - type: 'keyword', - }, - 'cloud.provider': { - category: 'cloud', - description: 'Name of the cloud provider. Example values are aws, azure, gcp, or digitalocean.', - example: 'aws', - name: 'cloud.provider', - type: 'keyword', - }, - 'cloud.region': { - category: 'cloud', - description: 'Region in which this host is running.', - example: 'us-east-1', - name: 'cloud.region', - type: 'keyword', - }, - 'cloud.service.name': { - category: 'cloud', - description: - 'The cloud service name is intended to distinguish services running on different platforms within a provider, eg AWS EC2 vs Lambda, GCP GCE vs App Engine, Azure VM vs App Server. Examples: app engine, app service, cloud run, fargate, lambda.', - example: 'lambda', - name: 'cloud.service.name', - type: 'keyword', - }, - 'code_signature.exists': { - category: 'code_signature', - description: 'Boolean to capture if a signature is present.', - example: 'true', - name: 'code_signature.exists', - type: 'boolean', - }, - 'code_signature.signing_id': { - category: 'code_signature', - description: - 'The identifier used to sign the process. This is used to identify the application manufactured by a software vendor. The field is relevant to Apple *OS only.', - example: 'com.apple.xpc.proxy', - name: 'code_signature.signing_id', - type: 'keyword', - }, - 'code_signature.status': { - category: 'code_signature', - description: - 'Additional information about the certificate status. This is useful for logging cryptographic errors with the certificate validity or trust status. Leave unpopulated if the validity or trust of the certificate was unchecked.', - example: 'ERROR_UNTRUSTED_ROOT', - name: 'code_signature.status', - type: 'keyword', - }, - 'code_signature.subject_name': { - category: 'code_signature', - description: 'Subject name of the code signer', - example: 'Microsoft Corporation', - name: 'code_signature.subject_name', - type: 'keyword', - }, - 'code_signature.team_id': { - category: 'code_signature', - description: - 'The team identifier used to sign the process. This is used to identify the team or vendor of a software product. The field is relevant to Apple *OS only.', - example: 'EQHXZ8M8AV', - name: 'code_signature.team_id', - type: 'keyword', - }, - 'code_signature.trusted': { - category: 'code_signature', - description: - 'Stores the trust status of the certificate chain. Validating the trust of the certificate chain may be complicated, and this field should only be populated by tools that actively check the status.', - example: 'true', - name: 'code_signature.trusted', - type: 'boolean', - }, - 'code_signature.valid': { - category: 'code_signature', - description: - 'Boolean to capture if the digital signature is verified against the binary content. Leave unpopulated if a certificate was unchecked.', - example: 'true', - name: 'code_signature.valid', - type: 'boolean', - }, - 'container.id': { - category: 'container', - description: 'Unique container id.', - name: 'container.id', - type: 'keyword', - }, - 'container.image.name': { - category: 'container', - description: 'Name of the image the container was built on.', - name: 'container.image.name', - type: 'keyword', - }, - 'container.image.tag': { - category: 'container', - description: 'Container image tags.', - name: 'container.image.tag', - type: 'keyword', - }, - 'container.labels': { - category: 'container', - description: 'Image labels.', - name: 'container.labels', - type: 'object', - }, - 'container.name': { - category: 'container', - description: 'Container name.', - name: 'container.name', - type: 'keyword', - }, - 'container.runtime': { - category: 'container', - description: 'Runtime managing this container.', - example: 'docker', - name: 'container.runtime', - type: 'keyword', - }, - 'data_stream.dataset': { - category: 'data_stream', - description: - 'The field can contain anything that makes sense to signify the source of the data. Examples include `nginx.access`, `prometheus`, `endpoint` etc. For data streams that otherwise fit, but that do not have dataset set we use the value "generic" for the dataset value. `event.dataset` should have the same value as `data_stream.dataset`. Beyond the Elasticsearch data stream naming criteria noted above, the `dataset` value has additional restrictions: * Must not contain `-` * No longer than 100 characters', - example: 'nginx.access', - name: 'data_stream.dataset', - type: 'constant_keyword', - }, - 'data_stream.namespace': { - category: 'data_stream', - description: - 'A user defined namespace. Namespaces are useful to allow grouping of data. Many users already organize their indices this way, and the data stream naming scheme now provides this best practice as a default. Many users will populate this field with `default`. If no value is used, it falls back to `default`. Beyond the Elasticsearch index naming criteria noted above, `namespace` value has the additional restrictions: * Must not contain `-` * No longer than 100 characters', - example: 'production', - name: 'data_stream.namespace', - type: 'constant_keyword', - }, - 'data_stream.type': { - category: 'data_stream', - description: - 'An overarching type for the data stream. Currently allowed values are "logs" and "metrics". We expect to also add "traces" and "synthetics" in the near future.', - example: 'logs', - name: 'data_stream.type', - type: 'constant_keyword', - }, - 'destination.address': { - category: 'destination', - description: - 'Some event destination addresses are defined ambiguously. The event will sometimes list an IP, a domain or a unix socket. You should always store the raw address in the `.address` field. Then it should be duplicated to `.ip` or `.domain`, depending on which one it is.', - name: 'destination.address', - type: 'keyword', - }, - 'destination.as.number': { - category: 'destination', - description: - 'Unique number allocated to the autonomous system. The autonomous system number (ASN) uniquely identifies each network on the Internet.', - example: 15169, - name: 'destination.as.number', - type: 'long', - }, - 'destination.as.organization.name': { - category: 'destination', - description: 'Organization name.', - example: 'Google LLC', - name: 'destination.as.organization.name', - type: 'keyword', - }, - 'destination.bytes': { - category: 'destination', - description: 'Bytes sent from the destination to the source.', - example: 184, - name: 'destination.bytes', - type: 'long', - format: 'bytes', - }, - 'destination.domain': { - category: 'destination', - description: 'Destination domain.', - name: 'destination.domain', - type: 'keyword', - }, - 'destination.geo.city_name': { - category: 'destination', - description: 'City name.', - example: 'Montreal', - name: 'destination.geo.city_name', - type: 'keyword', - }, - 'destination.geo.continent_code': { - category: 'destination', - description: "Two-letter code representing continent's name.", - example: 'NA', - name: 'destination.geo.continent_code', - type: 'keyword', - }, - 'destination.geo.continent_name': { - category: 'destination', - description: 'Name of the continent.', - example: 'North America', - name: 'destination.geo.continent_name', - type: 'keyword', - }, - 'destination.geo.country_iso_code': { - category: 'destination', - description: 'Country ISO code.', - example: 'CA', - name: 'destination.geo.country_iso_code', - type: 'keyword', - }, - 'destination.geo.country_name': { - category: 'destination', - description: 'Country name.', - example: 'Canada', - name: 'destination.geo.country_name', - type: 'keyword', - }, - 'destination.geo.location': { - category: 'destination', - description: 'Longitude and latitude.', - example: '{ "lon": -73.614830, "lat": 45.505918 }', - name: 'destination.geo.location', - type: 'geo_point', - }, - 'destination.geo.name': { - category: 'destination', - description: - 'User-defined description of a location, at the level of granularity they care about. Could be the name of their data centers, the floor number, if this describes a local physical entity, city names. Not typically used in automated geolocation.', - example: 'boston-dc', - name: 'destination.geo.name', - type: 'keyword', - }, - 'destination.geo.postal_code': { - category: 'destination', - description: - 'Postal code associated with the location. Values appropriate for this field may also be known as a postcode or ZIP code and will vary widely from country to country.', - example: 94040, - name: 'destination.geo.postal_code', - type: 'keyword', - }, - 'destination.geo.region_iso_code': { - category: 'destination', - description: 'Region ISO code.', - example: 'CA-QC', - name: 'destination.geo.region_iso_code', - type: 'keyword', - }, - 'destination.geo.region_name': { - category: 'destination', - description: 'Region name.', - example: 'Quebec', - name: 'destination.geo.region_name', - type: 'keyword', - }, - 'destination.geo.timezone': { - category: 'destination', - description: 'The time zone of the location, such as IANA time zone name.', - example: 'America/Argentina/Buenos_Aires', - name: 'destination.geo.timezone', - type: 'keyword', - }, - 'destination.ip': { - category: 'destination', - description: 'IP address of the destination (IPv4 or IPv6).', - name: 'destination.ip', - type: 'ip', - }, - 'destination.mac': { - category: 'destination', - description: - 'MAC address of the destination. The notation format from RFC 7042 is suggested: Each octet (that is, 8-bit byte) is represented by two [uppercase] hexadecimal digits giving the value of the octet as an unsigned integer. Successive octets are separated by a hyphen.', - example: '00-00-5E-00-53-23', - name: 'destination.mac', - type: 'keyword', - }, - 'destination.nat.ip': { - category: 'destination', - description: - 'Translated ip of destination based NAT sessions (e.g. internet to private DMZ) Typically used with load balancers, firewalls, or routers.', - name: 'destination.nat.ip', - type: 'ip', - }, - 'destination.nat.port': { - category: 'destination', - description: - 'Port the source session is translated to by NAT Device. Typically used with load balancers, firewalls, or routers.', - name: 'destination.nat.port', - type: 'long', - format: 'string', - }, - 'destination.packets': { - category: 'destination', - description: 'Packets sent from the destination to the source.', - example: 12, - name: 'destination.packets', - type: 'long', - }, - 'destination.port': { - category: 'destination', - description: 'Port of the destination.', - name: 'destination.port', - type: 'long', - format: 'string', - }, - 'destination.registered_domain': { - category: 'destination', - description: - 'The highest registered destination domain, stripped of the subdomain. For example, the registered domain for "foo.example.com" is "example.com". This value can be determined precisely with a list like the public suffix list (http://publicsuffix.org). Trying to approximate this by simply taking the last two labels will not work well for TLDs such as "co.uk".', - example: 'example.com', - name: 'destination.registered_domain', - type: 'keyword', - }, - 'destination.subdomain': { - category: 'destination', - description: - 'The subdomain portion of a fully qualified domain name includes all of the names except the host name under the registered_domain. In a partially qualified domain, or if the the qualification level of the full name cannot be determined, subdomain contains all of the names below the registered domain. For example the subdomain portion of "www.east.mydomain.co.uk" is "east". If the domain has multiple levels of subdomain, such as "sub2.sub1.example.com", the subdomain field should contain "sub2.sub1", with no trailing period.', - example: 'east', - name: 'destination.subdomain', - type: 'keyword', - }, - 'destination.top_level_domain': { - category: 'destination', - description: - 'The effective top level domain (eTLD), also known as the domain suffix, is the last part of the domain name. For example, the top level domain for example.com is "com". This value can be determined precisely with a list like the public suffix list (http://publicsuffix.org). Trying to approximate this by simply taking the last label will not work well for effective TLDs such as "co.uk".', - example: 'co.uk', - name: 'destination.top_level_domain', - type: 'keyword', - }, - 'destination.user.domain': { - category: 'destination', - description: - 'Name of the directory the user is a member of. For example, an LDAP or Active Directory domain name.', - name: 'destination.user.domain', - type: 'keyword', - }, - 'destination.user.email': { - category: 'destination', - description: 'User email address.', - name: 'destination.user.email', - type: 'keyword', - }, - 'destination.user.full_name': { - category: 'destination', - description: "User's full name, if available.", - example: 'Albert Einstein', - name: 'destination.user.full_name', - type: 'keyword', - }, - 'destination.user.group.domain': { - category: 'destination', - description: - 'Name of the directory the group is a member of. For example, an LDAP or Active Directory domain name.', - name: 'destination.user.group.domain', - type: 'keyword', - }, - 'destination.user.group.id': { - category: 'destination', - description: 'Unique identifier for the group on the system/platform.', - name: 'destination.user.group.id', - type: 'keyword', - }, - 'destination.user.group.name': { - category: 'destination', - description: 'Name of the group.', - name: 'destination.user.group.name', - type: 'keyword', - }, - 'destination.user.hash': { - category: 'destination', - description: - 'Unique user hash to correlate information for a user in anonymized form. Useful if `user.id` or `user.name` contain confidential information and cannot be used.', - name: 'destination.user.hash', - type: 'keyword', - }, - 'destination.user.id': { - category: 'destination', - description: 'Unique identifier of the user.', - name: 'destination.user.id', - type: 'keyword', - }, - 'destination.user.name': { - category: 'destination', - description: 'Short name or login of the user.', - example: 'albert', - name: 'destination.user.name', - type: 'keyword', - }, - 'destination.user.roles': { - category: 'destination', - description: 'Array of user roles at the time of the event.', - example: '["kibana_admin", "reporting_user"]', - name: 'destination.user.roles', - type: 'keyword', - }, - 'dll.code_signature.exists': { - category: 'dll', - description: 'Boolean to capture if a signature is present.', - example: 'true', - name: 'dll.code_signature.exists', - type: 'boolean', - }, - 'dll.code_signature.signing_id': { - category: 'dll', - description: - 'The identifier used to sign the process. This is used to identify the application manufactured by a software vendor. The field is relevant to Apple *OS only.', - example: 'com.apple.xpc.proxy', - name: 'dll.code_signature.signing_id', - type: 'keyword', - }, - 'dll.code_signature.status': { - category: 'dll', - description: - 'Additional information about the certificate status. This is useful for logging cryptographic errors with the certificate validity or trust status. Leave unpopulated if the validity or trust of the certificate was unchecked.', - example: 'ERROR_UNTRUSTED_ROOT', - name: 'dll.code_signature.status', - type: 'keyword', - }, - 'dll.code_signature.subject_name': { - category: 'dll', - description: 'Subject name of the code signer', - example: 'Microsoft Corporation', - name: 'dll.code_signature.subject_name', - type: 'keyword', - }, - 'dll.code_signature.team_id': { - category: 'dll', - description: - 'The team identifier used to sign the process. This is used to identify the team or vendor of a software product. The field is relevant to Apple *OS only.', - example: 'EQHXZ8M8AV', - name: 'dll.code_signature.team_id', - type: 'keyword', - }, - 'dll.code_signature.trusted': { - category: 'dll', - description: - 'Stores the trust status of the certificate chain. Validating the trust of the certificate chain may be complicated, and this field should only be populated by tools that actively check the status.', - example: 'true', - name: 'dll.code_signature.trusted', - type: 'boolean', - }, - 'dll.code_signature.valid': { - category: 'dll', - description: - 'Boolean to capture if the digital signature is verified against the binary content. Leave unpopulated if a certificate was unchecked.', - example: 'true', - name: 'dll.code_signature.valid', - type: 'boolean', - }, - 'dll.hash.md5': { - category: 'dll', - description: 'MD5 hash.', - name: 'dll.hash.md5', - type: 'keyword', - }, - 'dll.hash.sha1': { - category: 'dll', - description: 'SHA1 hash.', - name: 'dll.hash.sha1', - type: 'keyword', - }, - 'dll.hash.sha256': { - category: 'dll', - description: 'SHA256 hash.', - name: 'dll.hash.sha256', - type: 'keyword', - }, - 'dll.hash.sha512': { - category: 'dll', - description: 'SHA512 hash.', - name: 'dll.hash.sha512', - type: 'keyword', - }, - 'dll.hash.ssdeep': { - category: 'dll', - description: 'SSDEEP hash.', - name: 'dll.hash.ssdeep', - type: 'keyword', - }, - 'dll.name': { - category: 'dll', - description: 'Name of the library. This generally maps to the name of the file on disk.', - example: 'kernel32.dll', - name: 'dll.name', - type: 'keyword', - }, - 'dll.path': { - category: 'dll', - description: 'Full file path of the library.', - example: 'C:\\Windows\\System32\\kernel32.dll', - name: 'dll.path', - type: 'keyword', - }, - 'dll.pe.architecture': { - category: 'dll', - description: 'CPU architecture target for the file.', - example: 'x64', - name: 'dll.pe.architecture', - type: 'keyword', - }, - 'dll.pe.company': { - category: 'dll', - description: 'Internal company name of the file, provided at compile-time.', - example: 'Microsoft Corporation', - name: 'dll.pe.company', - type: 'keyword', - }, - 'dll.pe.description': { - category: 'dll', - description: 'Internal description of the file, provided at compile-time.', - example: 'Paint', - name: 'dll.pe.description', - type: 'keyword', - }, - 'dll.pe.file_version': { - category: 'dll', - description: 'Internal version of the file, provided at compile-time.', - example: '6.3.9600.17415', - name: 'dll.pe.file_version', - type: 'keyword', - }, - 'dll.pe.imphash': { - category: 'dll', - description: - 'A hash of the imports in a PE file. An imphash -- or import hash -- can be used to fingerprint binaries even after recompilation or other code-level transformations have occurred, which would change more traditional hash values. Learn more at https://www.fireeye.com/blog/threat-research/2014/01/tracking-malware-import-hashing.html.', - example: '0c6803c4e922103c4dca5963aad36ddf', - name: 'dll.pe.imphash', - type: 'keyword', - }, - 'dll.pe.original_file_name': { - category: 'dll', - description: 'Internal name of the file, provided at compile-time.', - example: 'MSPAINT.EXE', - name: 'dll.pe.original_file_name', - type: 'keyword', - }, - 'dll.pe.product': { - category: 'dll', - description: 'Internal product name of the file, provided at compile-time.', - example: 'Microsoft® Windows® Operating System', - name: 'dll.pe.product', - type: 'keyword', - }, - 'dns.answers': { - category: 'dns', - description: - 'An array containing an object for each answer section returned by the server. The main keys that should be present in these objects are defined by ECS. Records that have more information may contain more keys than what ECS defines. Not all DNS data sources give all details about DNS answers. At minimum, answer objects must contain the `data` key. If more information is available, map as much of it to ECS as possible, and add any additional fields to the answer objects as custom fields.', - name: 'dns.answers', - type: 'object', - }, - 'dns.answers.class': { - category: 'dns', - description: 'The class of DNS data contained in this resource record.', - example: 'IN', - name: 'dns.answers.class', - type: 'keyword', - }, - 'dns.answers.data': { - category: 'dns', - description: - 'The data describing the resource. The meaning of this data depends on the type and class of the resource record.', - example: '10.10.10.10', - name: 'dns.answers.data', - type: 'keyword', - }, - 'dns.answers.name': { - category: 'dns', - description: - "The domain name to which this resource record pertains. If a chain of CNAME is being resolved, each answer's `name` should be the one that corresponds with the answer's `data`. It should not simply be the original `question.name` repeated.", - example: 'www.example.com', - name: 'dns.answers.name', - type: 'keyword', - }, - 'dns.answers.ttl': { - category: 'dns', - description: - 'The time interval in seconds that this resource record may be cached before it should be discarded. Zero values mean that the data should not be cached.', - example: 180, - name: 'dns.answers.ttl', - type: 'long', - }, - 'dns.answers.type': { - category: 'dns', - description: 'The type of data contained in this resource record.', - example: 'CNAME', - name: 'dns.answers.type', - type: 'keyword', - }, - 'dns.header_flags': { - category: 'dns', - description: - 'Array of 2 letter DNS header flags. Expected values are: AA, TC, RD, RA, AD, CD, DO.', - example: '["RD", "RA"]', - name: 'dns.header_flags', - type: 'keyword', - }, - 'dns.id': { - category: 'dns', - description: - 'The DNS packet identifier assigned by the program that generated the query. The identifier is copied to the response.', - example: 62111, - name: 'dns.id', - type: 'keyword', - }, - 'dns.op_code': { - category: 'dns', - description: - 'The DNS operation code that specifies the kind of query in the message. This value is set by the originator of a query and copied into the response.', - example: 'QUERY', - name: 'dns.op_code', - type: 'keyword', - }, - 'dns.question.class': { - category: 'dns', - description: 'The class of records being queried.', - example: 'IN', - name: 'dns.question.class', - type: 'keyword', - }, - 'dns.question.name': { - category: 'dns', - description: - 'The name being queried. If the name field contains non-printable characters (below 32 or above 126), those characters should be represented as escaped base 10 integers (\\DDD). Back slashes and quotes should be escaped. Tabs, carriage returns, and line feeds should be converted to \\t, \\r, and \\n respectively.', - example: 'www.example.com', - name: 'dns.question.name', - type: 'keyword', - }, - 'dns.question.registered_domain': { - category: 'dns', - description: - 'The highest registered domain, stripped of the subdomain. For example, the registered domain for "foo.example.com" is "example.com". This value can be determined precisely with a list like the public suffix list (http://publicsuffix.org). Trying to approximate this by simply taking the last two labels will not work well for TLDs such as "co.uk".', - example: 'example.com', - name: 'dns.question.registered_domain', - type: 'keyword', - }, - 'dns.question.subdomain': { - category: 'dns', - description: - 'The subdomain is all of the labels under the registered_domain. If the domain has multiple levels of subdomain, such as "sub2.sub1.example.com", the subdomain field should contain "sub2.sub1", with no trailing period.', - example: 'www', - name: 'dns.question.subdomain', - type: 'keyword', - }, - 'dns.question.top_level_domain': { - category: 'dns', - description: - 'The effective top level domain (eTLD), also known as the domain suffix, is the last part of the domain name. For example, the top level domain for example.com is "com". This value can be determined precisely with a list like the public suffix list (http://publicsuffix.org). Trying to approximate this by simply taking the last label will not work well for effective TLDs such as "co.uk".', - example: 'co.uk', - name: 'dns.question.top_level_domain', - type: 'keyword', - }, - 'dns.question.type': { - category: 'dns', - description: 'The type of record being queried.', - example: 'AAAA', - name: 'dns.question.type', - type: 'keyword', - }, - 'dns.resolved_ip': { - category: 'dns', - description: - 'Array containing all IPs seen in `answers.data`. The `answers` array can be difficult to use, because of the variety of data formats it can contain. Extracting all IP addresses seen in there to `dns.resolved_ip` makes it possible to index them as IP addresses, and makes them easier to visualize and query for.', - example: '["10.10.10.10", "10.10.10.11"]', - name: 'dns.resolved_ip', - type: 'ip', - }, - 'dns.response_code': { - category: 'dns', - description: 'The DNS response code.', - example: 'NOERROR', - name: 'dns.response_code', - type: 'keyword', - }, - 'dns.type': { - category: 'dns', - description: - 'The type of DNS event captured, query or answer. If your source of DNS events only gives you DNS queries, you should only create dns events of type `dns.type:query`. If your source of DNS events gives you answers as well, you should create one event per query (optionally as soon as the query is seen). And a second event containing all query details as well as an array of answers.', - example: 'answer', - name: 'dns.type', - type: 'keyword', - }, - 'ecs.version': { - category: 'ecs', - description: - 'ECS version this event conforms to. `ecs.version` is a required field and must exist in all events. When querying across multiple indices -- which may conform to slightly different ECS versions -- this field lets integrations adjust to the schema version of the events.', - example: '1.0.0', - name: 'ecs.version', - type: 'keyword', - }, - 'error.code': { - category: 'error', - description: 'Error code describing the error.', - name: 'error.code', - type: 'keyword', - }, - 'error.id': { - category: 'error', - description: 'Unique identifier for the error.', - name: 'error.id', - type: 'keyword', - }, - 'error.message': { - category: 'error', - description: 'Error message.', - name: 'error.message', - type: 'text', - }, - 'error.stack_trace': { - category: 'error', - description: 'The stack trace of this error in plain text.', - name: 'error.stack_trace', - type: 'keyword', - }, - 'error.type': { - category: 'error', - description: 'The type of the error, for example the class name of the exception.', - example: 'java.lang.NullPointerException', - name: 'error.type', - type: 'keyword', - }, - 'event.action': { - category: 'event', - description: - 'The action captured by the event. This describes the information in the event. It is more specific than `event.category`. Examples are `group-add`, `process-started`, `file-created`. The value is normally defined by the implementer.', - example: 'user-password-change', - name: 'event.action', - type: 'keyword', - }, - 'event.category': { - category: 'event', - description: - 'This is one of four ECS Categorization Fields, and indicates the second level in the ECS category hierarchy. `event.category` represents the "big buckets" of ECS categories. For example, filtering on `event.category:process` yields all events relating to process activity. This field is closely related to `event.type`, which is used as a subcategory. This field is an array. This will allow proper categorization of some events that fall in multiple categories.', - example: 'authentication', - name: 'event.category', - type: 'keyword', - }, - 'event.code': { - category: 'event', - description: - 'Identification code for this event, if one exists. Some event sources use event codes to identify messages unambiguously, regardless of message language or wording adjustments over time. An example of this is the Windows Event ID.', - example: 4648, - name: 'event.code', - type: 'keyword', - }, - 'event.created': { - category: 'event', - description: - "event.created contains the date/time when the event was first read by an agent, or by your pipeline. This field is distinct from @timestamp in that @timestamp typically contain the time extracted from the original event. In most situations, these two timestamps will be slightly different. The difference can be used to calculate the delay between your source generating an event, and the time when your agent first processed it. This can be used to monitor your agent's or pipeline's ability to keep up with your event source. In case the two timestamps are identical, @timestamp should be used.", - example: '2016-05-23T08:05:34.857Z', - name: 'event.created', - type: 'date', - }, - 'event.dataset': { - category: 'event', - description: - "Name of the dataset. If an event source publishes more than one type of log or events (e.g. access log, error log), the dataset is used to specify which one the event comes from. It's recommended but not required to start the dataset name with the module name, followed by a dot, then the dataset name.", - example: 'apache.access', - name: 'event.dataset', - type: 'keyword', - }, - 'event.duration': { - category: 'event', - description: - 'Duration of the event in nanoseconds. If event.start and event.end are known this value should be the difference between the end and start time.', - name: 'event.duration', - type: 'long', - format: 'duration', - }, - 'event.end': { - category: 'event', - description: - 'event.end contains the date when the event ended or when the activity was last observed.', - name: 'event.end', - type: 'date', - }, - 'event.hash': { - category: 'event', - description: - 'Hash (perhaps logstash fingerprint) of raw field to be able to demonstrate log integrity.', - example: '123456789012345678901234567890ABCD', - name: 'event.hash', - type: 'keyword', - }, - 'event.id': { - category: 'event', - description: 'Unique ID to describe the event.', - example: '8a4f500d', - name: 'event.id', - type: 'keyword', - }, - 'event.ingested': { - category: 'event', - description: - "Timestamp when an event arrived in the central data store. This is different from `@timestamp`, which is when the event originally occurred. It's also different from `event.created`, which is meant to capture the first time an agent saw the event. In normal conditions, assuming no tampering, the timestamps should chronologically look like this: `@timestamp` < `event.created` < `event.ingested`.", - example: '2016-05-23T08:05:35.101Z', - name: 'event.ingested', - type: 'date', - }, - 'event.kind': { - category: 'event', - description: - 'This is one of four ECS Categorization Fields, and indicates the highest level in the ECS category hierarchy. `event.kind` gives high-level information about what type of information the event contains, without being specific to the contents of the event. For example, values of this field distinguish alert events from metric events. The value of this field can be used to inform how these kinds of events should be handled. They may warrant different retention, different access control, it may also help understand whether the data coming in at a regular interval or not.', - example: 'alert', - name: 'event.kind', - type: 'keyword', - }, - 'event.module': { - category: 'event', - description: - 'Name of the module this data is coming from. If your monitoring agent supports the concept of modules or plugins to process events of a given source (e.g. Apache logs), `event.module` should contain the name of this module.', - example: 'apache', - name: 'event.module', - type: 'keyword', - }, - 'event.original': { - category: 'event', - description: - 'Raw text message of entire event. Used to demonstrate log integrity. This field is not indexed and doc_values are disabled. It cannot be searched, but it can be retrieved from `_source`. If users wish to override this and index this field, consider using the wildcard data type.', - example: - 'Sep 19 08:26:10 host CEF:0|Security| threatmanager|1.0|100| worm successfully stopped|10|src=10.0.0.1 dst=2.1.2.2spt=1232', - name: 'event.original', - type: 'keyword', - }, - 'event.outcome': { - category: 'event', - description: - 'This is one of four ECS Categorization Fields, and indicates the lowest level in the ECS category hierarchy. `event.outcome` simply denotes whether the event represents a success or a failure from the perspective of the entity that produced the event. Note that when a single transaction is described in multiple events, each event may populate different values of `event.outcome`, according to their perspective. Also note that in the case of a compound event (a single event that contains multiple logical events), this field should be populated with the value that best captures the overall success or failure from the perspective of the event producer. Further note that not all events will have an associated outcome. For example, this field is generally not populated for metric events, events with `event.type:info`, or any events for which an outcome does not make logical sense.', - example: 'success', - name: 'event.outcome', - type: 'keyword', - }, - 'event.provider': { - category: 'event', - description: - 'Source of the event. Event transports such as Syslog or the Windows Event Log typically mention the source of an event. It can be the name of the software that generated the event (e.g. Sysmon, httpd), or of a subsystem of the operating system (kernel, Microsoft-Windows-Security-Auditing).', - example: 'kernel', - name: 'event.provider', - type: 'keyword', - }, - 'event.reason': { - category: 'event', - description: - 'Reason why this event happened, according to the source. This describes the why of a particular action or outcome captured in the event. Where `event.action` captures the action from the event, `event.reason` describes why that action was taken. For example, a web proxy with an `event.action` which denied the request may also populate `event.reason` with the reason why (e.g. `blocked site`).', - example: 'Terminated an unexpected process', - name: 'event.reason', - type: 'keyword', - }, - 'event.reference': { - category: 'event', - description: - 'Reference URL linking to additional information about this event. This URL links to a static definition of this event. Alert events, indicated by `event.kind:alert`, are a common use case for this field.', - example: 'https://system.example.com/event/#0001234', - name: 'event.reference', - type: 'keyword', - }, - 'event.risk_score': { - category: 'event', - description: - "Risk score or priority of the event (e.g. security solutions). Use your system's original value here.", - name: 'event.risk_score', - type: 'float', - }, - 'event.risk_score_norm': { - category: 'event', - description: - 'Normalized risk score or priority of the event, on a scale of 0 to 100. This is mainly useful if you use more than one system that assigns risk scores, and you want to see a normalized value across all systems.', - name: 'event.risk_score_norm', - type: 'float', - }, - 'event.sequence': { - category: 'event', - description: - 'Sequence number of the event. The sequence number is a value published by some event sources, to make the exact ordering of events unambiguous, regardless of the timestamp precision.', - name: 'event.sequence', - type: 'long', - format: 'string', - }, - 'event.severity': { - category: 'event', - description: - "The numeric severity of the event according to your event source. What the different severity values mean can be different between sources and use cases. It's up to the implementer to make sure severities are consistent across events from the same source. The Syslog severity belongs in `log.syslog.severity.code`. `event.severity` is meant to represent the severity according to the event source (e.g. firewall, IDS). If the event source does not publish its own severity, you may optionally copy the `log.syslog.severity.code` to `event.severity`.", - example: 7, - name: 'event.severity', - type: 'long', - format: 'string', - }, - 'event.start': { - category: 'event', - description: - 'event.start contains the date when the event started or when the activity was first observed.', - name: 'event.start', - type: 'date', - }, - 'event.timezone': { - category: 'event', - description: - 'This field should be populated when the event\'s timestamp does not include timezone information already (e.g. default Syslog timestamps). It\'s optional otherwise. Acceptable timezone formats are: a canonical ID (e.g. "Europe/Amsterdam"), abbreviated (e.g. "EST") or an HH:mm differential (e.g. "-05:00").', - name: 'event.timezone', - type: 'keyword', - }, - 'event.type': { - category: 'event', - description: - 'This is one of four ECS Categorization Fields, and indicates the third level in the ECS category hierarchy. `event.type` represents a categorization "sub-bucket" that, when used along with the `event.category` field values, enables filtering events down to a level appropriate for single visualization. This field is an array. This will allow proper categorization of some events that fall in multiple event types.', - name: 'event.type', - type: 'keyword', - }, - 'event.url': { - category: 'event', - description: - 'URL linking to an external system to continue investigation of this event. This URL links to another system where in-depth investigation of the specific occurrence of this event can take place. Alert events, indicated by `event.kind:alert`, are a common use case for this field.', - example: 'https://mysystem.example.com/alert/5271dedb-f5b0-4218-87f0-4ac4870a38fe', - name: 'event.url', - type: 'keyword', - }, - 'file.accessed': { - category: 'file', - description: - 'Last time the file was accessed. Note that not all filesystems keep track of access time.', - name: 'file.accessed', - type: 'date', - }, - 'file.attributes': { - category: 'file', - description: - "Array of file attributes. Attributes names will vary by platform. Here's a non-exhaustive list of values that are expected in this field: archive, compressed, directory, encrypted, execute, hidden, read, readonly, system, write.", - example: '["readonly", "system"]', - name: 'file.attributes', - type: 'keyword', - }, - 'file.code_signature.exists': { - category: 'file', - description: 'Boolean to capture if a signature is present.', - example: 'true', - name: 'file.code_signature.exists', - type: 'boolean', - }, - 'file.code_signature.signing_id': { - category: 'file', - description: - 'The identifier used to sign the process. This is used to identify the application manufactured by a software vendor. The field is relevant to Apple *OS only.', - example: 'com.apple.xpc.proxy', - name: 'file.code_signature.signing_id', - type: 'keyword', - }, - 'file.code_signature.status': { - category: 'file', - description: - 'Additional information about the certificate status. This is useful for logging cryptographic errors with the certificate validity or trust status. Leave unpopulated if the validity or trust of the certificate was unchecked.', - example: 'ERROR_UNTRUSTED_ROOT', - name: 'file.code_signature.status', - type: 'keyword', - }, - 'file.code_signature.subject_name': { - category: 'file', - description: 'Subject name of the code signer', - example: 'Microsoft Corporation', - name: 'file.code_signature.subject_name', - type: 'keyword', - }, - 'file.code_signature.team_id': { - category: 'file', - description: - 'The team identifier used to sign the process. This is used to identify the team or vendor of a software product. The field is relevant to Apple *OS only.', - example: 'EQHXZ8M8AV', - name: 'file.code_signature.team_id', - type: 'keyword', - }, - 'file.code_signature.trusted': { - category: 'file', - description: - 'Stores the trust status of the certificate chain. Validating the trust of the certificate chain may be complicated, and this field should only be populated by tools that actively check the status.', - example: 'true', - name: 'file.code_signature.trusted', - type: 'boolean', - }, - 'file.code_signature.valid': { - category: 'file', - description: - 'Boolean to capture if the digital signature is verified against the binary content. Leave unpopulated if a certificate was unchecked.', - example: 'true', - name: 'file.code_signature.valid', - type: 'boolean', - }, - 'file.created': { - category: 'file', - description: 'File creation time. Note that not all filesystems store the creation time.', - name: 'file.created', - type: 'date', - }, - 'file.ctime': { - category: 'file', - description: - 'Last time the file attributes or metadata changed. Note that changes to the file content will update `mtime`. This implies `ctime` will be adjusted at the same time, since `mtime` is an attribute of the file.', - name: 'file.ctime', - type: 'date', - }, - 'file.device': { - category: 'file', - description: 'Device that is the source of the file.', - example: 'sda', - name: 'file.device', - type: 'keyword', - }, - 'file.directory': { - category: 'file', - description: - 'Directory where the file is located. It should include the drive letter, when appropriate.', - example: '/home/alice', - name: 'file.directory', - type: 'keyword', - }, - 'file.drive_letter': { - category: 'file', - description: - 'Drive letter where the file is located. This field is only relevant on Windows. The value should be uppercase, and not include the colon.', - example: 'C', - name: 'file.drive_letter', - type: 'keyword', - }, - 'file.extension': { - category: 'file', - description: - 'File extension, excluding the leading dot. Note that when the file name has multiple extensions (example.tar.gz), only the last one should be captured ("gz", not "tar.gz").', - example: 'png', - name: 'file.extension', - type: 'keyword', - }, - 'file.gid': { - category: 'file', - description: 'Primary group ID (GID) of the file.', - example: '1001', - name: 'file.gid', - type: 'keyword', - }, - 'file.group': { - category: 'file', - description: 'Primary group name of the file.', - example: 'alice', - name: 'file.group', - type: 'keyword', - }, - 'file.hash.md5': { - category: 'file', - description: 'MD5 hash.', - name: 'file.hash.md5', - type: 'keyword', - }, - 'file.hash.sha1': { - category: 'file', - description: 'SHA1 hash.', - name: 'file.hash.sha1', - type: 'keyword', - }, - 'file.hash.sha256': { - category: 'file', - description: 'SHA256 hash.', - name: 'file.hash.sha256', - type: 'keyword', - }, - 'file.hash.sha512': { - category: 'file', - description: 'SHA512 hash.', - name: 'file.hash.sha512', - type: 'keyword', - }, - 'file.hash.ssdeep': { - category: 'file', - description: 'SSDEEP hash.', - name: 'file.hash.ssdeep', - type: 'keyword', - }, - 'file.inode': { - category: 'file', - description: 'Inode representing the file in the filesystem.', - example: '256383', - name: 'file.inode', - type: 'keyword', - }, - 'file.mime_type': { - category: 'file', - description: - 'MIME type should identify the format of the file or stream of bytes using https://www.iana.org/assignments/media-types/media-types.xhtml[IANA official types], where possible. When more than one type is applicable, the most specific type should be used.', - name: 'file.mime_type', - type: 'keyword', - }, - 'file.mode': { - category: 'file', - description: 'Mode of the file in octal representation.', - example: '0640', - name: 'file.mode', - type: 'keyword', - }, - 'file.mtime': { - category: 'file', - description: 'Last time the file content was modified.', - name: 'file.mtime', - type: 'date', - }, - 'file.name': { - category: 'file', - description: 'Name of the file including the extension, without the directory.', - example: 'example.png', - name: 'file.name', - type: 'keyword', - }, - 'file.owner': { - category: 'file', - description: "File owner's username.", - example: 'alice', - name: 'file.owner', - type: 'keyword', - }, - 'file.path': { - category: 'file', - description: - 'Full path to the file, including the file name. It should include the drive letter, when appropriate.', - example: '/home/alice/example.png', - name: 'file.path', - type: 'keyword', - }, - 'file.pe.architecture': { - category: 'file', - description: 'CPU architecture target for the file.', - example: 'x64', - name: 'file.pe.architecture', - type: 'keyword', - }, - 'file.pe.company': { - category: 'file', - description: 'Internal company name of the file, provided at compile-time.', - example: 'Microsoft Corporation', - name: 'file.pe.company', - type: 'keyword', - }, - 'file.pe.description': { - category: 'file', - description: 'Internal description of the file, provided at compile-time.', - example: 'Paint', - name: 'file.pe.description', - type: 'keyword', - }, - 'file.pe.file_version': { - category: 'file', - description: 'Internal version of the file, provided at compile-time.', - example: '6.3.9600.17415', - name: 'file.pe.file_version', - type: 'keyword', - }, - 'file.pe.imphash': { - category: 'file', - description: - 'A hash of the imports in a PE file. An imphash -- or import hash -- can be used to fingerprint binaries even after recompilation or other code-level transformations have occurred, which would change more traditional hash values. Learn more at https://www.fireeye.com/blog/threat-research/2014/01/tracking-malware-import-hashing.html.', - example: '0c6803c4e922103c4dca5963aad36ddf', - name: 'file.pe.imphash', - type: 'keyword', - }, - 'file.pe.original_file_name': { - category: 'file', - description: 'Internal name of the file, provided at compile-time.', - example: 'MSPAINT.EXE', - name: 'file.pe.original_file_name', - type: 'keyword', - }, - 'file.pe.product': { - category: 'file', - description: 'Internal product name of the file, provided at compile-time.', - example: 'Microsoft® Windows® Operating System', - name: 'file.pe.product', - type: 'keyword', - }, - 'file.size': { - category: 'file', - description: 'File size in bytes. Only relevant when `file.type` is "file".', - example: 16384, - name: 'file.size', - type: 'long', - }, - 'file.target_path': { - category: 'file', - description: 'Target path for symlinks.', - name: 'file.target_path', - type: 'keyword', - }, - 'file.type': { - category: 'file', - description: 'File type (file, dir, or symlink).', - example: 'file', - name: 'file.type', - type: 'keyword', - }, - 'file.uid': { - category: 'file', - description: 'The user ID (UID) or security identifier (SID) of the file owner.', - example: '1001', - name: 'file.uid', - type: 'keyword', - }, - 'file.x509.alternative_names': { - category: 'file', - description: - 'List of subject alternative names (SAN). Name types vary by certificate authority and certificate type but commonly contain IP addresses, DNS names (and wildcards), and email addresses.', - example: '*.elastic.co', - name: 'file.x509.alternative_names', - type: 'keyword', - }, - 'file.x509.issuer.common_name': { - category: 'file', - description: 'List of common name (CN) of issuing certificate authority.', - example: 'Example SHA2 High Assurance Server CA', - name: 'file.x509.issuer.common_name', - type: 'keyword', - }, - 'file.x509.issuer.country': { - category: 'file', - description: 'List of country (C) codes', - example: 'US', - name: 'file.x509.issuer.country', - type: 'keyword', - }, - 'file.x509.issuer.distinguished_name': { - category: 'file', - description: 'Distinguished name (DN) of issuing certificate authority.', - example: 'C=US, O=Example Inc, OU=www.example.com, CN=Example SHA2 High Assurance Server CA', - name: 'file.x509.issuer.distinguished_name', - type: 'keyword', - }, - 'file.x509.issuer.locality': { - category: 'file', - description: 'List of locality names (L)', - example: 'Mountain View', - name: 'file.x509.issuer.locality', - type: 'keyword', - }, - 'file.x509.issuer.organization': { - category: 'file', - description: 'List of organizations (O) of issuing certificate authority.', - example: 'Example Inc', - name: 'file.x509.issuer.organization', - type: 'keyword', - }, - 'file.x509.issuer.organizational_unit': { - category: 'file', - description: 'List of organizational units (OU) of issuing certificate authority.', - example: 'www.example.com', - name: 'file.x509.issuer.organizational_unit', - type: 'keyword', - }, - 'file.x509.issuer.state_or_province': { - category: 'file', - description: 'List of state or province names (ST, S, or P)', - example: 'California', - name: 'file.x509.issuer.state_or_province', - type: 'keyword', - }, - 'file.x509.not_after': { - category: 'file', - description: 'Time at which the certificate is no longer considered valid.', - example: '"2020-07-16T03:15:39.000Z"', - name: 'file.x509.not_after', - type: 'date', - }, - 'file.x509.not_before': { - category: 'file', - description: 'Time at which the certificate is first considered valid.', - example: '"2019-08-16T01:40:25.000Z"', - name: 'file.x509.not_before', - type: 'date', - }, - 'file.x509.public_key_algorithm': { - category: 'file', - description: 'Algorithm used to generate the public key.', - example: 'RSA', - name: 'file.x509.public_key_algorithm', - type: 'keyword', - }, - 'file.x509.public_key_curve': { - category: 'file', - description: - 'The curve used by the elliptic curve public key algorithm. This is algorithm specific.', - example: 'nistp521', - name: 'file.x509.public_key_curve', - type: 'keyword', - }, - 'file.x509.public_key_exponent': { - category: 'file', - description: 'Exponent used to derive the public key. This is algorithm specific.', - example: 65537, - name: 'file.x509.public_key_exponent', - type: 'long', - }, - 'file.x509.public_key_size': { - category: 'file', - description: 'The size of the public key space in bits.', - example: 2048, - name: 'file.x509.public_key_size', - type: 'long', - }, - 'file.x509.serial_number': { - category: 'file', - description: - 'Unique serial number issued by the certificate authority. For consistency, if this value is alphanumeric, it should be formatted without colons and uppercase characters.', - example: '55FBB9C7DEBF09809D12CCAA', - name: 'file.x509.serial_number', - type: 'keyword', - }, - 'file.x509.signature_algorithm': { - category: 'file', - description: - 'Identifier for certificate signature algorithm. We recommend using names found in Go Lang Crypto library. See https://github.com/golang/go/blob/go1.14/src/crypto/x509/x509.go#L337-L353.', - example: 'SHA256-RSA', - name: 'file.x509.signature_algorithm', - type: 'keyword', - }, - 'file.x509.subject.common_name': { - category: 'file', - description: 'List of common names (CN) of subject.', - example: 'shared.global.example.net', - name: 'file.x509.subject.common_name', - type: 'keyword', - }, - 'file.x509.subject.country': { - category: 'file', - description: 'List of country (C) code', - example: 'US', - name: 'file.x509.subject.country', - type: 'keyword', - }, - 'file.x509.subject.distinguished_name': { - category: 'file', - description: 'Distinguished name (DN) of the certificate subject entity.', - example: 'C=US, ST=California, L=San Francisco, O=Example, Inc., CN=shared.global.example.net', - name: 'file.x509.subject.distinguished_name', - type: 'keyword', - }, - 'file.x509.subject.locality': { - category: 'file', - description: 'List of locality names (L)', - example: 'San Francisco', - name: 'file.x509.subject.locality', - type: 'keyword', - }, - 'file.x509.subject.organization': { - category: 'file', - description: 'List of organizations (O) of subject.', - example: 'Example, Inc.', - name: 'file.x509.subject.organization', - type: 'keyword', - }, - 'file.x509.subject.organizational_unit': { - category: 'file', - description: 'List of organizational units (OU) of subject.', - name: 'file.x509.subject.organizational_unit', - type: 'keyword', - }, - 'file.x509.subject.state_or_province': { - category: 'file', - description: 'List of state or province names (ST, S, or P)', - example: 'California', - name: 'file.x509.subject.state_or_province', - type: 'keyword', - }, - 'file.x509.version_number': { - category: 'file', - description: 'Version of x509 format.', - example: 3, - name: 'file.x509.version_number', - type: 'keyword', - }, - 'geo.city_name': { - category: 'geo', - description: 'City name.', - example: 'Montreal', - name: 'geo.city_name', - type: 'keyword', - }, - 'geo.continent_code': { - category: 'geo', - description: "Two-letter code representing continent's name.", - example: 'NA', - name: 'geo.continent_code', - type: 'keyword', - }, - 'geo.continent_name': { - category: 'geo', - description: 'Name of the continent.', - example: 'North America', - name: 'geo.continent_name', - type: 'keyword', - }, - 'geo.country_iso_code': { - category: 'geo', - description: 'Country ISO code.', - example: 'CA', - name: 'geo.country_iso_code', - type: 'keyword', - }, - 'geo.country_name': { - category: 'geo', - description: 'Country name.', - example: 'Canada', - name: 'geo.country_name', - type: 'keyword', - }, - 'geo.location': { - category: 'geo', - description: 'Longitude and latitude.', - example: '{ "lon": -73.614830, "lat": 45.505918 }', - name: 'geo.location', - type: 'geo_point', - }, - 'geo.name': { - category: 'geo', - description: - 'User-defined description of a location, at the level of granularity they care about. Could be the name of their data centers, the floor number, if this describes a local physical entity, city names. Not typically used in automated geolocation.', - example: 'boston-dc', - name: 'geo.name', - type: 'keyword', - }, - 'geo.postal_code': { - category: 'geo', - description: - 'Postal code associated with the location. Values appropriate for this field may also be known as a postcode or ZIP code and will vary widely from country to country.', - example: 94040, - name: 'geo.postal_code', - type: 'keyword', - }, - 'geo.region_iso_code': { - category: 'geo', - description: 'Region ISO code.', - example: 'CA-QC', - name: 'geo.region_iso_code', - type: 'keyword', - }, - 'geo.region_name': { - category: 'geo', - description: 'Region name.', - example: 'Quebec', - name: 'geo.region_name', - type: 'keyword', - }, - 'geo.timezone': { - category: 'geo', - description: 'The time zone of the location, such as IANA time zone name.', - example: 'America/Argentina/Buenos_Aires', - name: 'geo.timezone', - type: 'keyword', - }, - 'group.domain': { - category: 'group', - description: - 'Name of the directory the group is a member of. For example, an LDAP or Active Directory domain name.', - name: 'group.domain', - type: 'keyword', - }, - 'group.id': { - category: 'group', - description: 'Unique identifier for the group on the system/platform.', - name: 'group.id', - type: 'keyword', - }, - 'group.name': { - category: 'group', - description: 'Name of the group.', - name: 'group.name', - type: 'keyword', - }, - 'hash.md5': { - category: 'hash', - description: 'MD5 hash.', - name: 'hash.md5', - type: 'keyword', - }, - 'hash.sha1': { - category: 'hash', - description: 'SHA1 hash.', - name: 'hash.sha1', - type: 'keyword', - }, - 'hash.sha256': { - category: 'hash', - description: 'SHA256 hash.', - name: 'hash.sha256', - type: 'keyword', - }, - 'hash.sha512': { - category: 'hash', - description: 'SHA512 hash.', - name: 'hash.sha512', - type: 'keyword', - }, - 'hash.ssdeep': { - category: 'hash', - description: 'SSDEEP hash.', - name: 'hash.ssdeep', - type: 'keyword', - }, - 'host.architecture': { - category: 'host', - description: 'Operating system architecture.', - example: 'x86_64', - name: 'host.architecture', - type: 'keyword', - }, - 'host.cpu.usage': { - category: 'host', - description: - 'Percent CPU used which is normalized by the number of CPU cores and it ranges from 0 to 1. Scaling factor: 1000. For example: For a two core host, this value should be the average of the two cores, between 0 and 1.', - name: 'host.cpu.usage', - type: 'scaled_float', - }, - 'host.disk.read.bytes': { - category: 'host', - description: - 'The total number of bytes (gauge) read successfully (aggregated from all disks) since the last metric collection.', - name: 'host.disk.read.bytes', - type: 'long', - }, - 'host.disk.write.bytes': { - category: 'host', - description: - 'The total number of bytes (gauge) written successfully (aggregated from all disks) since the last metric collection.', - name: 'host.disk.write.bytes', - type: 'long', - }, - 'host.domain': { - category: 'host', - description: - "Name of the domain of which the host is a member. For example, on Windows this could be the host's Active Directory domain or NetBIOS domain name. For Linux this could be the domain of the host's LDAP provider.", - example: 'CONTOSO', - name: 'host.domain', - type: 'keyword', - }, - 'host.geo.city_name': { - category: 'host', - description: 'City name.', - example: 'Montreal', - name: 'host.geo.city_name', - type: 'keyword', - }, - 'host.geo.continent_code': { - category: 'host', - description: "Two-letter code representing continent's name.", - example: 'NA', - name: 'host.geo.continent_code', - type: 'keyword', - }, - 'host.geo.continent_name': { - category: 'host', - description: 'Name of the continent.', - example: 'North America', - name: 'host.geo.continent_name', - type: 'keyword', - }, - 'host.geo.country_iso_code': { - category: 'host', - description: 'Country ISO code.', - example: 'CA', - name: 'host.geo.country_iso_code', - type: 'keyword', - }, - 'host.geo.country_name': { - category: 'host', - description: 'Country name.', - example: 'Canada', - name: 'host.geo.country_name', - type: 'keyword', - }, - 'host.geo.location': { - category: 'host', - description: 'Longitude and latitude.', - example: '{ "lon": -73.614830, "lat": 45.505918 }', - name: 'host.geo.location', - type: 'geo_point', - }, - 'host.geo.name': { - category: 'host', - description: - 'User-defined description of a location, at the level of granularity they care about. Could be the name of their data centers, the floor number, if this describes a local physical entity, city names. Not typically used in automated geolocation.', - example: 'boston-dc', - name: 'host.geo.name', - type: 'keyword', - }, - 'host.geo.postal_code': { - category: 'host', - description: - 'Postal code associated with the location. Values appropriate for this field may also be known as a postcode or ZIP code and will vary widely from country to country.', - example: 94040, - name: 'host.geo.postal_code', - type: 'keyword', - }, - 'host.geo.region_iso_code': { - category: 'host', - description: 'Region ISO code.', - example: 'CA-QC', - name: 'host.geo.region_iso_code', - type: 'keyword', - }, - 'host.geo.region_name': { - category: 'host', - description: 'Region name.', - example: 'Quebec', - name: 'host.geo.region_name', - type: 'keyword', - }, - 'host.geo.timezone': { - category: 'host', - description: 'The time zone of the location, such as IANA time zone name.', - example: 'America/Argentina/Buenos_Aires', - name: 'host.geo.timezone', - type: 'keyword', - }, - 'host.hostname': { - category: 'host', - description: - 'Hostname of the host. It normally contains what the `hostname` command returns on the host machine.', - name: 'host.hostname', - type: 'keyword', - }, - 'host.id': { - category: 'host', - description: - 'Unique host id. As hostname is not always unique, use values that are meaningful in your environment. Example: The current usage of `beat.name`.', - name: 'host.id', - type: 'keyword', - }, - 'host.ip': { - category: 'host', - description: 'Host ip addresses.', - name: 'host.ip', - type: 'ip', - }, - 'host.mac': { - category: 'host', - description: - 'Host MAC addresses. The notation format from RFC 7042 is suggested: Each octet (that is, 8-bit byte) is represented by two [uppercase] hexadecimal digits giving the value of the octet as an unsigned integer. Successive octets are separated by a hyphen.', - example: '["00-00-5E-00-53-23", "00-00-5E-00-53-24"]', - name: 'host.mac', - type: 'keyword', - }, - 'host.name': { - category: 'host', - description: - 'Name of the host. It can contain what `hostname` returns on Unix systems, the fully qualified domain name, or a name specified by the user. The sender decides which value to use.', - name: 'host.name', - type: 'keyword', - }, - 'host.network.egress.bytes': { - category: 'host', - description: - 'The number of bytes (gauge) sent out on all network interfaces by the host since the last metric collection.', - name: 'host.network.egress.bytes', - type: 'long', - }, - 'host.network.egress.packets': { - category: 'host', - description: - 'The number of packets (gauge) sent out on all network interfaces by the host since the last metric collection.', - name: 'host.network.egress.packets', - type: 'long', - }, - 'host.network.ingress.bytes': { - category: 'host', - description: - 'The number of bytes received (gauge) on all network interfaces by the host since the last metric collection.', - name: 'host.network.ingress.bytes', - type: 'long', - }, - 'host.network.ingress.packets': { - category: 'host', - description: - 'The number of packets (gauge) received on all network interfaces by the host since the last metric collection.', - name: 'host.network.ingress.packets', - type: 'long', - }, - 'host.os.family': { - category: 'host', - description: 'OS family (such as redhat, debian, freebsd, windows).', - example: 'debian', - name: 'host.os.family', - type: 'keyword', - }, - 'host.os.full': { - category: 'host', - description: 'Operating system name, including the version or code name.', - example: 'Mac OS Mojave', - name: 'host.os.full', - type: 'keyword', - }, - 'host.os.kernel': { - category: 'host', - description: 'Operating system kernel version as a raw string.', - example: '4.4.0-112-generic', - name: 'host.os.kernel', - type: 'keyword', - }, - 'host.os.name': { - category: 'host', - description: 'Operating system name, without the version.', - example: 'Mac OS X', - name: 'host.os.name', - type: 'keyword', - }, - 'host.os.platform': { - category: 'host', - description: 'Operating system platform (such centos, ubuntu, windows).', - example: 'darwin', - name: 'host.os.platform', - type: 'keyword', - }, - 'host.os.type': { - category: 'host', - description: - "Use the `os.type` field to categorize the operating system into one of the broad commercial families. One of these following values should be used (lowercase): linux, macos, unix, windows. If the OS you're dealing with is not in the list, the field should not be populated. Please let us know by opening an issue with ECS, to propose its addition.", - example: 'macos', - name: 'host.os.type', - type: 'keyword', - }, - 'host.os.version': { - category: 'host', - description: 'Operating system version as a raw string.', - example: '10.14.1', - name: 'host.os.version', - type: 'keyword', - }, - 'host.type': { - category: 'host', - description: - 'Type of host. For Cloud providers this can be the machine type like `t2.medium`. If vm, this could be the container, for example, or other information meaningful in your environment.', - name: 'host.type', - type: 'keyword', - }, - 'host.uptime': { - category: 'host', - description: 'Seconds the host has been up.', - example: 1325, - name: 'host.uptime', - type: 'long', - }, - 'host.user.domain': { - category: 'host', - description: - 'Name of the directory the user is a member of. For example, an LDAP or Active Directory domain name.', - name: 'host.user.domain', - type: 'keyword', - }, - 'host.user.email': { - category: 'host', - description: 'User email address.', - name: 'host.user.email', - type: 'keyword', - }, - 'host.user.full_name': { - category: 'host', - description: "User's full name, if available.", - example: 'Albert Einstein', - name: 'host.user.full_name', - type: 'keyword', - }, - 'host.user.group.domain': { - category: 'host', - description: - 'Name of the directory the group is a member of. For example, an LDAP or Active Directory domain name.', - name: 'host.user.group.domain', - type: 'keyword', - }, - 'host.user.group.id': { - category: 'host', - description: 'Unique identifier for the group on the system/platform.', - name: 'host.user.group.id', - type: 'keyword', - }, - 'host.user.group.name': { - category: 'host', - description: 'Name of the group.', - name: 'host.user.group.name', - type: 'keyword', - }, - 'host.user.hash': { - category: 'host', - description: - 'Unique user hash to correlate information for a user in anonymized form. Useful if `user.id` or `user.name` contain confidential information and cannot be used.', - name: 'host.user.hash', - type: 'keyword', - }, - 'host.user.id': { - category: 'host', - description: 'Unique identifier of the user.', - name: 'host.user.id', - type: 'keyword', - }, - 'host.user.name': { - category: 'host', - description: 'Short name or login of the user.', - example: 'albert', - name: 'host.user.name', - type: 'keyword', - }, - 'host.user.roles': { - category: 'host', - description: 'Array of user roles at the time of the event.', - example: '["kibana_admin", "reporting_user"]', - name: 'host.user.roles', - type: 'keyword', - }, - 'http.request.body.bytes': { - category: 'http', - description: 'Size in bytes of the request body.', - example: 887, - name: 'http.request.body.bytes', - type: 'long', - format: 'bytes', - }, - 'http.request.body.content': { - category: 'http', - description: 'The full HTTP request body.', - example: 'Hello world', - name: 'http.request.body.content', - type: 'keyword', - }, - 'http.request.bytes': { - category: 'http', - description: 'Total size in bytes of the request (body and headers).', - example: 1437, - name: 'http.request.bytes', - type: 'long', - format: 'bytes', - }, - 'http.request.id': { - category: 'http', - description: - 'A unique identifier for each HTTP request to correlate logs between clients and servers in transactions. The id may be contained in a non-standard HTTP header, such as `X-Request-ID` or `X-Correlation-ID`.', - example: '123e4567-e89b-12d3-a456-426614174000', - name: 'http.request.id', - type: 'keyword', - }, - 'http.request.method': { - category: 'http', - description: - 'HTTP request method. Prior to ECS 1.6.0 the following guidance was provided: "The field value must be normalized to lowercase for querying." As of ECS 1.6.0, the guidance is deprecated because the original case of the method may be useful in anomaly detection. Original case will be mandated in ECS 2.0.0', - example: 'GET, POST, PUT, PoST', - name: 'http.request.method', - type: 'keyword', - }, - 'http.request.mime_type': { - category: 'http', - description: - "Mime type of the body of the request. This value must only be populated based on the content of the request body, not on the `Content-Type` header. Comparing the mime type of a request with the request's Content-Type header can be helpful in detecting threats or misconfigured clients.", - example: 'image/gif', - name: 'http.request.mime_type', - type: 'keyword', - }, - 'http.request.referrer': { - category: 'http', - description: 'Referrer for this HTTP request.', - example: 'https://blog.example.com/', - name: 'http.request.referrer', - type: 'keyword', - }, - 'http.response.body.bytes': { - category: 'http', - description: 'Size in bytes of the response body.', - example: 887, - name: 'http.response.body.bytes', - type: 'long', - format: 'bytes', - }, - 'http.response.body.content': { - category: 'http', - description: 'The full HTTP response body.', - example: 'Hello world', - name: 'http.response.body.content', - type: 'keyword', - }, - 'http.response.bytes': { - category: 'http', - description: 'Total size in bytes of the response (body and headers).', - example: 1437, - name: 'http.response.bytes', - type: 'long', - format: 'bytes', - }, - 'http.response.mime_type': { - category: 'http', - description: - "Mime type of the body of the response. This value must only be populated based on the content of the response body, not on the `Content-Type` header. Comparing the mime type of a response with the response's Content-Type header can be helpful in detecting misconfigured servers.", - example: 'image/gif', - name: 'http.response.mime_type', - type: 'keyword', - }, - 'http.response.status_code': { - category: 'http', - description: 'HTTP response status code.', - example: 404, - name: 'http.response.status_code', - type: 'long', - format: 'string', - }, - 'http.version': { - category: 'http', - description: 'HTTP version.', - example: 1.1, - name: 'http.version', - type: 'keyword', - }, - 'interface.alias': { - category: 'interface', - description: - 'Interface alias as reported by the system, typically used in firewall implementations for e.g. inside, outside, or dmz logical interface naming.', - example: 'outside', - name: 'interface.alias', - type: 'keyword', - }, - 'interface.id': { - category: 'interface', - description: 'Interface ID as reported by an observer (typically SNMP interface ID).', - example: 10, - name: 'interface.id', - type: 'keyword', - }, - 'interface.name': { - category: 'interface', - description: 'Interface name as reported by the system.', - example: 'eth0', - name: 'interface.name', - type: 'keyword', - }, - 'log.file.path': { - category: 'log', - description: - "Full path to the log file this event came from, including the file name. It should include the drive letter, when appropriate. If the event wasn't read from a log file, do not populate this field.", - example: '/var/log/fun-times.log', - name: 'log.file.path', - type: 'keyword', - }, - 'log.level': { - category: 'log', - description: - "Original log level of the log event. If the source of the event provides a log level or textual severity, this is the one that goes in `log.level`. If your source doesn't specify one, you may put your event transport's severity here (e.g. Syslog severity). Some examples are `warn`, `err`, `i`, `informational`.", - example: 'error', - name: 'log.level', - type: 'keyword', - }, - 'log.logger': { - category: 'log', - description: - 'The name of the logger inside an application. This is usually the name of the class which initialized the logger, or can be a custom name.', - example: 'org.elasticsearch.bootstrap.Bootstrap', - name: 'log.logger', - type: 'keyword', - }, - 'log.origin.file.line': { - category: 'log', - description: - 'The line number of the file containing the source code which originated the log event.', - example: 42, - name: 'log.origin.file.line', - type: 'integer', - }, - 'log.origin.file.name': { - category: 'log', - description: - 'The name of the file containing the source code which originated the log event. Note that this field is not meant to capture the log file. The correct field to capture the log file is `log.file.path`.', - example: 'Bootstrap.java', - name: 'log.origin.file.name', - type: 'keyword', - }, - 'log.origin.function': { - category: 'log', - description: 'The name of the function or method which originated the log event.', - example: 'init', - name: 'log.origin.function', - type: 'keyword', - }, - 'log.original': { - category: 'log', - description: - "This is the original log message and contains the full log message before splitting it up in multiple parts. In contrast to the `message` field which can contain an extracted part of the log message, this field contains the original, full log message. It can have already some modifications applied like encoding or new lines removed to clean up the log message. This field is not indexed and doc_values are disabled so it can't be queried but the value can be retrieved from `_source`.", - example: 'Sep 19 08:26:10 localhost My log', - name: 'log.original', - type: 'keyword', - }, - 'log.syslog': { - category: 'log', - description: - 'The Syslog metadata of the event, if the event was transmitted via Syslog. Please see RFCs 5424 or 3164.', - name: 'log.syslog', - type: 'object', - }, - 'log.syslog.facility.code': { - category: 'log', - description: - 'The Syslog numeric facility of the log event, if available. According to RFCs 5424 and 3164, this value should be an integer between 0 and 23.', - example: 23, - name: 'log.syslog.facility.code', - type: 'long', - format: 'string', - }, - 'log.syslog.facility.name': { - category: 'log', - description: 'The Syslog text-based facility of the log event, if available.', - example: 'local7', - name: 'log.syslog.facility.name', - type: 'keyword', - }, - 'log.syslog.priority': { - category: 'log', - description: - 'Syslog numeric priority of the event, if available. According to RFCs 5424 and 3164, the priority is 8 * facility + severity. This number is therefore expected to contain a value between 0 and 191.', - example: 135, - name: 'log.syslog.priority', - type: 'long', - format: 'string', - }, - 'log.syslog.severity.code': { - category: 'log', - description: - "The Syslog numeric severity of the log event, if available. If the event source publishing via Syslog provides a different numeric severity value (e.g. firewall, IDS), your source's numeric severity should go to `event.severity`. If the event source does not specify a distinct severity, you can optionally copy the Syslog severity to `event.severity`.", - example: 3, - name: 'log.syslog.severity.code', - type: 'long', - }, - 'log.syslog.severity.name': { - category: 'log', - description: - "The Syslog numeric severity of the log event, if available. If the event source publishing via Syslog provides a different severity value (e.g. firewall, IDS), your source's text severity should go to `log.level`. If the event source does not specify a distinct severity, you can optionally copy the Syslog severity to `log.level`.", - example: 'Error', - name: 'log.syslog.severity.name', - type: 'keyword', - }, - 'network.application': { - category: 'network', - description: - 'A name given to an application level protocol. This can be arbitrarily assigned for things like microservices, but also apply to things like skype, icq, facebook, twitter. This would be used in situations where the vendor or service can be decoded such as from the source/dest IP owners, ports, or wire format. The field value must be normalized to lowercase for querying. See the documentation section "Implementing ECS".', - example: 'aim', - name: 'network.application', - type: 'keyword', - }, - 'network.bytes': { - category: 'network', - description: - 'Total bytes transferred in both directions. If `source.bytes` and `destination.bytes` are known, `network.bytes` is their sum.', - example: 368, - name: 'network.bytes', - type: 'long', - format: 'bytes', - }, - 'network.community_id': { - category: 'network', - description: - 'A hash of source and destination IPs and ports, as well as the protocol used in a communication. This is a tool-agnostic standard to identify flows. Learn more at https://github.com/corelight/community-id-spec.', - example: '1:hO+sN4H+MG5MY/8hIrXPqc4ZQz0=', - name: 'network.community_id', - type: 'keyword', - }, - 'network.direction': { - category: 'network', - description: - 'Direction of the network traffic. Recommended values are: * ingress * egress * inbound * outbound * internal * external * unknown When mapping events from a host-based monitoring context, populate this field from the host\'s point of view, using the values "ingress" or "egress". When mapping events from a network or perimeter-based monitoring context, populate this field from the point of view of the network perimeter, using the values "inbound", "outbound", "internal" or "external". Note that "internal" is not crossing perimeter boundaries, and is meant to describe communication between two hosts within the perimeter. Note also that "external" is meant to describe traffic between two hosts that are external to the perimeter. This could for example be useful for ISPs or VPN service providers.', - example: 'inbound', - name: 'network.direction', - type: 'keyword', - }, - 'network.forwarded_ip': { - category: 'network', - description: 'Host IP address when the source IP address is the proxy.', - example: '192.1.1.2', - name: 'network.forwarded_ip', - type: 'ip', - }, - 'network.iana_number': { - category: 'network', - description: - 'IANA Protocol Number (https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml). Standardized list of protocols. This aligns well with NetFlow and sFlow related logs which use the IANA Protocol Number.', - example: 6, - name: 'network.iana_number', - type: 'keyword', - }, - 'network.inner': { - category: 'network', - description: - 'Network.inner fields are added in addition to network.vlan fields to describe the innermost VLAN when q-in-q VLAN tagging is present. Allowed fields include vlan.id and vlan.name. Inner vlan fields are typically used when sending traffic with multiple 802.1q encapsulations to a network sensor (e.g. Zeek, Wireshark.)', - name: 'network.inner', - type: 'object', - }, - 'network.inner.vlan.id': { - category: 'network', - description: 'VLAN ID as reported by the observer.', - example: 10, - name: 'network.inner.vlan.id', - type: 'keyword', - }, - 'network.inner.vlan.name': { - category: 'network', - description: 'Optional VLAN name as reported by the observer.', - example: 'outside', - name: 'network.inner.vlan.name', - type: 'keyword', - }, - 'network.name': { - category: 'network', - description: 'Name given by operators to sections of their network.', - example: 'Guest Wifi', - name: 'network.name', - type: 'keyword', - }, - 'network.packets': { - category: 'network', - description: - 'Total packets transferred in both directions. If `source.packets` and `destination.packets` are known, `network.packets` is their sum.', - example: 24, - name: 'network.packets', - type: 'long', - }, - 'network.protocol': { - category: 'network', - description: - 'L7 Network protocol name. ex. http, lumberjack, transport protocol. The field value must be normalized to lowercase for querying. See the documentation section "Implementing ECS".', - example: 'http', - name: 'network.protocol', - type: 'keyword', - }, - 'network.transport': { - category: 'network', - description: - 'Same as network.iana_number, but instead using the Keyword name of the transport layer (udp, tcp, ipv6-icmp, etc.) The field value must be normalized to lowercase for querying. See the documentation section "Implementing ECS".', - example: 'tcp', - name: 'network.transport', - type: 'keyword', - }, - 'network.type': { - category: 'network', - description: - 'In the OSI Model this would be the Network Layer. ipv4, ipv6, ipsec, pim, etc The field value must be normalized to lowercase for querying. See the documentation section "Implementing ECS".', - example: 'ipv4', - name: 'network.type', - type: 'keyword', - }, - 'network.vlan.id': { - category: 'network', - description: 'VLAN ID as reported by the observer.', - example: 10, - name: 'network.vlan.id', - type: 'keyword', - }, - 'network.vlan.name': { - category: 'network', - description: 'Optional VLAN name as reported by the observer.', - example: 'outside', - name: 'network.vlan.name', - type: 'keyword', - }, - 'observer.egress': { - category: 'observer', - description: - 'Observer.egress holds information like interface number and name, vlan, and zone information to classify egress traffic. Single armed monitoring such as a network sensor on a span port should only use observer.ingress to categorize traffic.', - name: 'observer.egress', - type: 'object', - }, - 'observer.egress.interface.alias': { - category: 'observer', - description: - 'Interface alias as reported by the system, typically used in firewall implementations for e.g. inside, outside, or dmz logical interface naming.', - example: 'outside', - name: 'observer.egress.interface.alias', - type: 'keyword', - }, - 'observer.egress.interface.id': { - category: 'observer', - description: 'Interface ID as reported by an observer (typically SNMP interface ID).', - example: 10, - name: 'observer.egress.interface.id', - type: 'keyword', - }, - 'observer.egress.interface.name': { - category: 'observer', - description: 'Interface name as reported by the system.', - example: 'eth0', - name: 'observer.egress.interface.name', - type: 'keyword', - }, - 'observer.egress.vlan.id': { - category: 'observer', - description: 'VLAN ID as reported by the observer.', - example: 10, - name: 'observer.egress.vlan.id', - type: 'keyword', - }, - 'observer.egress.vlan.name': { - category: 'observer', - description: 'Optional VLAN name as reported by the observer.', - example: 'outside', - name: 'observer.egress.vlan.name', - type: 'keyword', - }, - 'observer.egress.zone': { - category: 'observer', - description: - 'Network zone of outbound traffic as reported by the observer to categorize the destination area of egress traffic, e.g. Internal, External, DMZ, HR, Legal, etc.', - example: 'Public_Internet', - name: 'observer.egress.zone', - type: 'keyword', - }, - 'observer.geo.city_name': { - category: 'observer', - description: 'City name.', - example: 'Montreal', - name: 'observer.geo.city_name', - type: 'keyword', - }, - 'observer.geo.continent_code': { - category: 'observer', - description: "Two-letter code representing continent's name.", - example: 'NA', - name: 'observer.geo.continent_code', - type: 'keyword', - }, - 'observer.geo.continent_name': { - category: 'observer', - description: 'Name of the continent.', - example: 'North America', - name: 'observer.geo.continent_name', - type: 'keyword', - }, - 'observer.geo.country_iso_code': { - category: 'observer', - description: 'Country ISO code.', - example: 'CA', - name: 'observer.geo.country_iso_code', - type: 'keyword', - }, - 'observer.geo.country_name': { - category: 'observer', - description: 'Country name.', - example: 'Canada', - name: 'observer.geo.country_name', - type: 'keyword', - }, - 'observer.geo.location': { - category: 'observer', - description: 'Longitude and latitude.', - example: '{ "lon": -73.614830, "lat": 45.505918 }', - name: 'observer.geo.location', - type: 'geo_point', - }, - 'observer.geo.name': { - category: 'observer', - description: - 'User-defined description of a location, at the level of granularity they care about. Could be the name of their data centers, the floor number, if this describes a local physical entity, city names. Not typically used in automated geolocation.', - example: 'boston-dc', - name: 'observer.geo.name', - type: 'keyword', - }, - 'observer.geo.postal_code': { - category: 'observer', - description: - 'Postal code associated with the location. Values appropriate for this field may also be known as a postcode or ZIP code and will vary widely from country to country.', - example: 94040, - name: 'observer.geo.postal_code', - type: 'keyword', - }, - 'observer.geo.region_iso_code': { - category: 'observer', - description: 'Region ISO code.', - example: 'CA-QC', - name: 'observer.geo.region_iso_code', - type: 'keyword', - }, - 'observer.geo.region_name': { - category: 'observer', - description: 'Region name.', - example: 'Quebec', - name: 'observer.geo.region_name', - type: 'keyword', - }, - 'observer.geo.timezone': { - category: 'observer', - description: 'The time zone of the location, such as IANA time zone name.', - example: 'America/Argentina/Buenos_Aires', - name: 'observer.geo.timezone', - type: 'keyword', - }, - 'observer.hostname': { - category: 'observer', - description: 'Hostname of the observer.', - name: 'observer.hostname', - type: 'keyword', - }, - 'observer.ingress': { - category: 'observer', - description: - 'Observer.ingress holds information like interface number and name, vlan, and zone information to classify ingress traffic. Single armed monitoring such as a network sensor on a span port should only use observer.ingress to categorize traffic.', - name: 'observer.ingress', - type: 'object', - }, - 'observer.ingress.interface.alias': { - category: 'observer', - description: - 'Interface alias as reported by the system, typically used in firewall implementations for e.g. inside, outside, or dmz logical interface naming.', - example: 'outside', - name: 'observer.ingress.interface.alias', - type: 'keyword', - }, - 'observer.ingress.interface.id': { - category: 'observer', - description: 'Interface ID as reported by an observer (typically SNMP interface ID).', - example: 10, - name: 'observer.ingress.interface.id', - type: 'keyword', - }, - 'observer.ingress.interface.name': { - category: 'observer', - description: 'Interface name as reported by the system.', - example: 'eth0', - name: 'observer.ingress.interface.name', - type: 'keyword', - }, - 'observer.ingress.vlan.id': { - category: 'observer', - description: 'VLAN ID as reported by the observer.', - example: 10, - name: 'observer.ingress.vlan.id', - type: 'keyword', - }, - 'observer.ingress.vlan.name': { - category: 'observer', - description: 'Optional VLAN name as reported by the observer.', - example: 'outside', - name: 'observer.ingress.vlan.name', - type: 'keyword', - }, - 'observer.ingress.zone': { - category: 'observer', - description: - 'Network zone of incoming traffic as reported by the observer to categorize the source area of ingress traffic. e.g. internal, External, DMZ, HR, Legal, etc.', - example: 'DMZ', - name: 'observer.ingress.zone', - type: 'keyword', - }, - 'observer.ip': { - category: 'observer', - description: 'IP addresses of the observer.', - name: 'observer.ip', - type: 'ip', - }, - 'observer.mac': { - category: 'observer', - description: - 'MAC addresses of the observer. The notation format from RFC 7042 is suggested: Each octet (that is, 8-bit byte) is represented by two [uppercase] hexadecimal digits giving the value of the octet as an unsigned integer. Successive octets are separated by a hyphen.', - example: '["00-00-5E-00-53-23", "00-00-5E-00-53-24"]', - name: 'observer.mac', - type: 'keyword', - }, - 'observer.name': { - category: 'observer', - description: - 'Custom name of the observer. This is a name that can be given to an observer. This can be helpful for example if multiple firewalls of the same model are used in an organization. If no custom name is needed, the field can be left empty.', - example: '1_proxySG', - name: 'observer.name', - type: 'keyword', - }, - 'observer.os.family': { - category: 'observer', - description: 'OS family (such as redhat, debian, freebsd, windows).', - example: 'debian', - name: 'observer.os.family', - type: 'keyword', - }, - 'observer.os.full': { - category: 'observer', - description: 'Operating system name, including the version or code name.', - example: 'Mac OS Mojave', - name: 'observer.os.full', - type: 'keyword', - }, - 'observer.os.kernel': { - category: 'observer', - description: 'Operating system kernel version as a raw string.', - example: '4.4.0-112-generic', - name: 'observer.os.kernel', - type: 'keyword', - }, - 'observer.os.name': { - category: 'observer', - description: 'Operating system name, without the version.', - example: 'Mac OS X', - name: 'observer.os.name', - type: 'keyword', - }, - 'observer.os.platform': { - category: 'observer', - description: 'Operating system platform (such centos, ubuntu, windows).', - example: 'darwin', - name: 'observer.os.platform', - type: 'keyword', - }, - 'observer.os.type': { - category: 'observer', - description: - "Use the `os.type` field to categorize the operating system into one of the broad commercial families. One of these following values should be used (lowercase): linux, macos, unix, windows. If the OS you're dealing with is not in the list, the field should not be populated. Please let us know by opening an issue with ECS, to propose its addition.", - example: 'macos', - name: 'observer.os.type', - type: 'keyword', - }, - 'observer.os.version': { - category: 'observer', - description: 'Operating system version as a raw string.', - example: '10.14.1', - name: 'observer.os.version', - type: 'keyword', - }, - 'observer.product': { - category: 'observer', - description: 'The product name of the observer.', - example: 's200', - name: 'observer.product', - type: 'keyword', - }, - 'observer.serial_number': { - category: 'observer', - description: 'Observer serial number.', - name: 'observer.serial_number', - type: 'keyword', - }, - 'observer.type': { - category: 'observer', - description: - 'The type of the observer the data is coming from. There is no predefined list of observer types. Some examples are `forwarder`, `firewall`, `ids`, `ips`, `proxy`, `poller`, `sensor`, `APM server`.', - example: 'firewall', - name: 'observer.type', - type: 'keyword', - }, - 'observer.vendor': { - category: 'observer', - description: 'Vendor name of the observer.', - example: 'Symantec', - name: 'observer.vendor', - type: 'keyword', - }, - 'observer.version': { - category: 'observer', - description: 'Observer version.', - name: 'observer.version', - type: 'keyword', - }, - 'orchestrator.api_version': { - category: 'orchestrator', - description: 'API version being used to carry out the action', - example: 'v1beta1', - name: 'orchestrator.api_version', - type: 'keyword', - }, - 'orchestrator.cluster.name': { - category: 'orchestrator', - description: 'Name of the cluster.', - name: 'orchestrator.cluster.name', - type: 'keyword', - }, - 'orchestrator.cluster.url': { - category: 'orchestrator', - description: 'URL of the API used to manage the cluster.', - name: 'orchestrator.cluster.url', - type: 'keyword', - }, - 'orchestrator.cluster.version': { - category: 'orchestrator', - description: 'The version of the cluster.', - name: 'orchestrator.cluster.version', - type: 'keyword', - }, - 'orchestrator.namespace': { - category: 'orchestrator', - description: 'Namespace in which the action is taking place.', - example: 'kube-system', - name: 'orchestrator.namespace', - type: 'keyword', - }, - 'orchestrator.organization': { - category: 'orchestrator', - description: 'Organization affected by the event (for multi-tenant orchestrator setups).', - example: 'elastic', - name: 'orchestrator.organization', - type: 'keyword', - }, - 'orchestrator.resource.name': { - category: 'orchestrator', - description: 'Name of the resource being acted upon.', - example: 'test-pod-cdcws', - name: 'orchestrator.resource.name', - type: 'keyword', - }, - 'orchestrator.resource.type': { - category: 'orchestrator', - description: 'Type of resource being acted upon.', - example: 'service', - name: 'orchestrator.resource.type', - type: 'keyword', - }, - 'orchestrator.type': { - category: 'orchestrator', - description: 'Orchestrator cluster type (e.g. kubernetes, nomad or cloudfoundry).', - example: 'kubernetes', - name: 'orchestrator.type', - type: 'keyword', - }, - 'organization.id': { - category: 'organization', - description: 'Unique identifier for the organization.', - name: 'organization.id', - type: 'keyword', - }, - 'organization.name': { - category: 'organization', - description: 'Organization name.', - name: 'organization.name', - type: 'keyword', - }, - 'os.family': { - category: 'os', - description: 'OS family (such as redhat, debian, freebsd, windows).', - example: 'debian', - name: 'os.family', - type: 'keyword', - }, - 'os.full': { - category: 'os', - description: 'Operating system name, including the version or code name.', - example: 'Mac OS Mojave', - name: 'os.full', - type: 'keyword', - }, - 'os.kernel': { - category: 'os', - description: 'Operating system kernel version as a raw string.', - example: '4.4.0-112-generic', - name: 'os.kernel', - type: 'keyword', - }, - 'os.name': { - category: 'os', - description: 'Operating system name, without the version.', - example: 'Mac OS X', - name: 'os.name', - type: 'keyword', - }, - 'os.platform': { - category: 'os', - description: 'Operating system platform (such centos, ubuntu, windows).', - example: 'darwin', - name: 'os.platform', - type: 'keyword', - }, - 'os.type': { - category: 'os', - description: - "Use the `os.type` field to categorize the operating system into one of the broad commercial families. One of these following values should be used (lowercase): linux, macos, unix, windows. If the OS you're dealing with is not in the list, the field should not be populated. Please let us know by opening an issue with ECS, to propose its addition.", - example: 'macos', - name: 'os.type', - type: 'keyword', - }, - 'os.version': { - category: 'os', - description: 'Operating system version as a raw string.', - example: '10.14.1', - name: 'os.version', - type: 'keyword', - }, - 'package.architecture': { - category: 'package', - description: 'Package architecture.', - example: 'x86_64', - name: 'package.architecture', - type: 'keyword', - }, - 'package.build_version': { - category: 'package', - description: - 'Additional information about the build version of the installed package. For example use the commit SHA of a non-released package.', - example: '36f4f7e89dd61b0988b12ee000b98966867710cd', - name: 'package.build_version', - type: 'keyword', - }, - 'package.checksum': { - category: 'package', - description: 'Checksum of the installed package for verification.', - example: '68b329da9893e34099c7d8ad5cb9c940', - name: 'package.checksum', - type: 'keyword', - }, - 'package.description': { - category: 'package', - description: 'Description of the package.', - example: 'Open source programming language to build simple/reliable/efficient software.', - name: 'package.description', - type: 'keyword', - }, - 'package.install_scope': { - category: 'package', - description: 'Indicating how the package was installed, e.g. user-local, global.', - example: 'global', - name: 'package.install_scope', - type: 'keyword', - }, - 'package.installed': { - category: 'package', - description: 'Time when package was installed.', - name: 'package.installed', - type: 'date', - }, - 'package.license': { - category: 'package', - description: - 'License under which the package was released. Use a short name, e.g. the license identifier from SPDX License List where possible (https://spdx.org/licenses/).', - example: 'Apache License 2.0', - name: 'package.license', - type: 'keyword', - }, - 'package.name': { - category: 'package', - description: 'Package name', - example: 'go', - name: 'package.name', - type: 'keyword', - }, - 'package.path': { - category: 'package', - description: 'Path where the package is installed.', - example: '/usr/local/Cellar/go/1.12.9/', - name: 'package.path', - type: 'keyword', - }, - 'package.reference': { - category: 'package', - description: 'Home page or reference URL of the software in this package, if available.', - example: 'https://golang.org', - name: 'package.reference', - type: 'keyword', - }, - 'package.size': { - category: 'package', - description: 'Package size in bytes.', - example: 62231, - name: 'package.size', - type: 'long', - format: 'string', - }, - 'package.type': { - category: 'package', - description: - 'Type of package. This should contain the package file type, rather than the package manager name. Examples: rpm, dpkg, brew, npm, gem, nupkg, jar.', - example: 'rpm', - name: 'package.type', - type: 'keyword', - }, - 'package.version': { - category: 'package', - description: 'Package version', - example: '1.12.9', - name: 'package.version', - type: 'keyword', - }, - 'pe.architecture': { - category: 'pe', - description: 'CPU architecture target for the file.', - example: 'x64', - name: 'pe.architecture', - type: 'keyword', - }, - 'pe.company': { - category: 'pe', - description: 'Internal company name of the file, provided at compile-time.', - example: 'Microsoft Corporation', - name: 'pe.company', - type: 'keyword', - }, - 'pe.description': { - category: 'pe', - description: 'Internal description of the file, provided at compile-time.', - example: 'Paint', - name: 'pe.description', - type: 'keyword', - }, - 'pe.file_version': { - category: 'pe', - description: 'Internal version of the file, provided at compile-time.', - example: '6.3.9600.17415', - name: 'pe.file_version', - type: 'keyword', - }, - 'pe.imphash': { - category: 'pe', - description: - 'A hash of the imports in a PE file. An imphash -- or import hash -- can be used to fingerprint binaries even after recompilation or other code-level transformations have occurred, which would change more traditional hash values. Learn more at https://www.fireeye.com/blog/threat-research/2014/01/tracking-malware-import-hashing.html.', - example: '0c6803c4e922103c4dca5963aad36ddf', - name: 'pe.imphash', - type: 'keyword', - }, - 'pe.original_file_name': { - category: 'pe', - description: 'Internal name of the file, provided at compile-time.', - example: 'MSPAINT.EXE', - name: 'pe.original_file_name', - type: 'keyword', - }, - 'pe.product': { - category: 'pe', - description: 'Internal product name of the file, provided at compile-time.', - example: 'Microsoft® Windows® Operating System', - name: 'pe.product', - type: 'keyword', - }, - 'process.args': { - category: 'process', - description: - 'Array of process arguments, starting with the absolute path to the executable. May be filtered to protect sensitive information.', - example: '["/usr/bin/ssh", "-l", "user", "10.0.0.16"]', - name: 'process.args', - type: 'keyword', - }, - 'process.args_count': { - category: 'process', - description: - 'Length of the process.args array. This field can be useful for querying or performing bucket analysis on how many arguments were provided to start a process. More arguments may be an indication of suspicious activity.', - example: 4, - name: 'process.args_count', - type: 'long', - }, - 'process.code_signature.exists': { - category: 'process', - description: 'Boolean to capture if a signature is present.', - example: 'true', - name: 'process.code_signature.exists', - type: 'boolean', - }, - 'process.code_signature.signing_id': { - category: 'process', - description: - 'The identifier used to sign the process. This is used to identify the application manufactured by a software vendor. The field is relevant to Apple *OS only.', - example: 'com.apple.xpc.proxy', - name: 'process.code_signature.signing_id', - type: 'keyword', - }, - 'process.code_signature.status': { - category: 'process', - description: - 'Additional information about the certificate status. This is useful for logging cryptographic errors with the certificate validity or trust status. Leave unpopulated if the validity or trust of the certificate was unchecked.', - example: 'ERROR_UNTRUSTED_ROOT', - name: 'process.code_signature.status', - type: 'keyword', - }, - 'process.code_signature.subject_name': { - category: 'process', - description: 'Subject name of the code signer', - example: 'Microsoft Corporation', - name: 'process.code_signature.subject_name', - type: 'keyword', - }, - 'process.code_signature.team_id': { - category: 'process', - description: - 'The team identifier used to sign the process. This is used to identify the team or vendor of a software product. The field is relevant to Apple *OS only.', - example: 'EQHXZ8M8AV', - name: 'process.code_signature.team_id', - type: 'keyword', - }, - 'process.code_signature.trusted': { - category: 'process', - description: - 'Stores the trust status of the certificate chain. Validating the trust of the certificate chain may be complicated, and this field should only be populated by tools that actively check the status.', - example: 'true', - name: 'process.code_signature.trusted', - type: 'boolean', - }, - 'process.code_signature.valid': { - category: 'process', - description: - 'Boolean to capture if the digital signature is verified against the binary content. Leave unpopulated if a certificate was unchecked.', - example: 'true', - name: 'process.code_signature.valid', - type: 'boolean', - }, - 'process.command_line': { - category: 'process', - description: - 'Full command line that started the process, including the absolute path to the executable, and all arguments. Some arguments may be filtered to protect sensitive information.', - example: '/usr/bin/ssh -l user 10.0.0.16', - name: 'process.command_line', - type: 'keyword', - }, - 'process.entity_id': { - category: 'process', - description: - 'Unique identifier for the process. The implementation of this is specified by the data source, but some examples of what could be used here are a process-generated UUID, Sysmon Process GUIDs, or a hash of some uniquely identifying components of a process. Constructing a globally unique identifier is a common practice to mitigate PID reuse as well as to identify a specific process over time, across multiple monitored hosts.', - example: 'c2c455d9f99375d', - name: 'process.entity_id', - type: 'keyword', - }, - 'process.executable': { - category: 'process', - description: 'Absolute path to the process executable.', - example: '/usr/bin/ssh', - name: 'process.executable', - type: 'keyword', - }, - 'process.exit_code': { - category: 'process', - description: - 'The exit code of the process, if this is a termination event. The field should be absent if there is no exit code for the event (e.g. process start).', - example: 137, - name: 'process.exit_code', - type: 'long', - }, - 'process.hash.md5': { - category: 'process', - description: 'MD5 hash.', - name: 'process.hash.md5', - type: 'keyword', - }, - 'process.hash.sha1': { - category: 'process', - description: 'SHA1 hash.', - name: 'process.hash.sha1', - type: 'keyword', - }, - 'process.hash.sha256': { - category: 'process', - description: 'SHA256 hash.', - name: 'process.hash.sha256', - type: 'keyword', - }, - 'process.hash.sha512': { - category: 'process', - description: 'SHA512 hash.', - name: 'process.hash.sha512', - type: 'keyword', - }, - 'process.hash.ssdeep': { - category: 'process', - description: 'SSDEEP hash.', - name: 'process.hash.ssdeep', - type: 'keyword', - }, - 'process.name': { - category: 'process', - description: 'Process name. Sometimes called program name or similar.', - example: 'ssh', - name: 'process.name', - type: 'keyword', - }, - 'process.parent.args': { - category: 'process', - description: - 'Array of process arguments, starting with the absolute path to the executable. May be filtered to protect sensitive information.', - example: '["/usr/bin/ssh", "-l", "user", "10.0.0.16"]', - name: 'process.parent.args', - type: 'keyword', - }, - 'process.parent.args_count': { - category: 'process', - description: - 'Length of the process.args array. This field can be useful for querying or performing bucket analysis on how many arguments were provided to start a process. More arguments may be an indication of suspicious activity.', - example: 4, - name: 'process.parent.args_count', - type: 'long', - }, - 'process.parent.code_signature.exists': { - category: 'process', - description: 'Boolean to capture if a signature is present.', - example: 'true', - name: 'process.parent.code_signature.exists', - type: 'boolean', - }, - 'process.parent.code_signature.signing_id': { - category: 'process', - description: - 'The identifier used to sign the process. This is used to identify the application manufactured by a software vendor. The field is relevant to Apple *OS only.', - example: 'com.apple.xpc.proxy', - name: 'process.parent.code_signature.signing_id', - type: 'keyword', - }, - 'process.parent.code_signature.status': { - category: 'process', - description: - 'Additional information about the certificate status. This is useful for logging cryptographic errors with the certificate validity or trust status. Leave unpopulated if the validity or trust of the certificate was unchecked.', - example: 'ERROR_UNTRUSTED_ROOT', - name: 'process.parent.code_signature.status', - type: 'keyword', - }, - 'process.parent.code_signature.subject_name': { - category: 'process', - description: 'Subject name of the code signer', - example: 'Microsoft Corporation', - name: 'process.parent.code_signature.subject_name', - type: 'keyword', - }, - 'process.parent.code_signature.team_id': { - category: 'process', - description: - 'The team identifier used to sign the process. This is used to identify the team or vendor of a software product. The field is relevant to Apple *OS only.', - example: 'EQHXZ8M8AV', - name: 'process.parent.code_signature.team_id', - type: 'keyword', - }, - 'process.parent.code_signature.trusted': { - category: 'process', - description: - 'Stores the trust status of the certificate chain. Validating the trust of the certificate chain may be complicated, and this field should only be populated by tools that actively check the status.', - example: 'true', - name: 'process.parent.code_signature.trusted', - type: 'boolean', - }, - 'process.parent.code_signature.valid': { - category: 'process', - description: - 'Boolean to capture if the digital signature is verified against the binary content. Leave unpopulated if a certificate was unchecked.', - example: 'true', - name: 'process.parent.code_signature.valid', - type: 'boolean', - }, - 'process.parent.command_line': { - category: 'process', - description: - 'Full command line that started the process, including the absolute path to the executable, and all arguments. Some arguments may be filtered to protect sensitive information.', - example: '/usr/bin/ssh -l user 10.0.0.16', - name: 'process.parent.command_line', - type: 'keyword', - }, - 'process.parent.entity_id': { - category: 'process', - description: - 'Unique identifier for the process. The implementation of this is specified by the data source, but some examples of what could be used here are a process-generated UUID, Sysmon Process GUIDs, or a hash of some uniquely identifying components of a process. Constructing a globally unique identifier is a common practice to mitigate PID reuse as well as to identify a specific process over time, across multiple monitored hosts.', - example: 'c2c455d9f99375d', - name: 'process.parent.entity_id', - type: 'keyword', - }, - 'process.parent.executable': { - category: 'process', - description: 'Absolute path to the process executable.', - example: '/usr/bin/ssh', - name: 'process.parent.executable', - type: 'keyword', - }, - 'process.parent.exit_code': { - category: 'process', - description: - 'The exit code of the process, if this is a termination event. The field should be absent if there is no exit code for the event (e.g. process start).', - example: 137, - name: 'process.parent.exit_code', - type: 'long', - }, - 'process.parent.hash.md5': { - category: 'process', - description: 'MD5 hash.', - name: 'process.parent.hash.md5', - type: 'keyword', - }, - 'process.parent.hash.sha1': { - category: 'process', - description: 'SHA1 hash.', - name: 'process.parent.hash.sha1', - type: 'keyword', - }, - 'process.parent.hash.sha256': { - category: 'process', - description: 'SHA256 hash.', - name: 'process.parent.hash.sha256', - type: 'keyword', - }, - 'process.parent.hash.sha512': { - category: 'process', - description: 'SHA512 hash.', - name: 'process.parent.hash.sha512', - type: 'keyword', - }, - 'process.parent.hash.ssdeep': { - category: 'process', - description: 'SSDEEP hash.', - name: 'process.parent.hash.ssdeep', - type: 'keyword', - }, - 'process.parent.name': { - category: 'process', - description: 'Process name. Sometimes called program name or similar.', - example: 'ssh', - name: 'process.parent.name', - type: 'keyword', - }, - 'process.parent.pe.architecture': { - category: 'process', - description: 'CPU architecture target for the file.', - example: 'x64', - name: 'process.parent.pe.architecture', - type: 'keyword', - }, - 'process.parent.pe.company': { - category: 'process', - description: 'Internal company name of the file, provided at compile-time.', - example: 'Microsoft Corporation', - name: 'process.parent.pe.company', - type: 'keyword', - }, - 'process.parent.pe.description': { - category: 'process', - description: 'Internal description of the file, provided at compile-time.', - example: 'Paint', - name: 'process.parent.pe.description', - type: 'keyword', - }, - 'process.parent.pe.file_version': { - category: 'process', - description: 'Internal version of the file, provided at compile-time.', - example: '6.3.9600.17415', - name: 'process.parent.pe.file_version', - type: 'keyword', - }, - 'process.parent.pe.imphash': { - category: 'process', - description: - 'A hash of the imports in a PE file. An imphash -- or import hash -- can be used to fingerprint binaries even after recompilation or other code-level transformations have occurred, which would change more traditional hash values. Learn more at https://www.fireeye.com/blog/threat-research/2014/01/tracking-malware-import-hashing.html.', - example: '0c6803c4e922103c4dca5963aad36ddf', - name: 'process.parent.pe.imphash', - type: 'keyword', - }, - 'process.parent.pe.original_file_name': { - category: 'process', - description: 'Internal name of the file, provided at compile-time.', - example: 'MSPAINT.EXE', - name: 'process.parent.pe.original_file_name', - type: 'keyword', - }, - 'process.parent.pe.product': { - category: 'process', - description: 'Internal product name of the file, provided at compile-time.', - example: 'Microsoft® Windows® Operating System', - name: 'process.parent.pe.product', - type: 'keyword', - }, - 'process.parent.pgid': { - category: 'process', - description: 'Identifier of the group of processes the process belongs to.', - name: 'process.parent.pgid', - type: 'long', - format: 'string', - }, - 'process.parent.pid': { - category: 'process', - description: 'Process id.', - example: 4242, - name: 'process.parent.pid', - type: 'long', - format: 'string', - }, - 'process.parent.ppid': { - category: 'process', - description: "Parent process' pid.", - example: 4241, - name: 'process.parent.ppid', - type: 'long', - format: 'string', - }, - 'process.parent.start': { - category: 'process', - description: 'The time the process started.', - example: '2016-05-23T08:05:34.853Z', - name: 'process.parent.start', - type: 'date', - }, - 'process.parent.thread.id': { - category: 'process', - description: 'Thread ID.', - example: 4242, - name: 'process.parent.thread.id', - type: 'long', - format: 'string', - }, - 'process.parent.thread.name': { - category: 'process', - description: 'Thread name.', - example: 'thread-0', - name: 'process.parent.thread.name', - type: 'keyword', - }, - 'process.parent.title': { - category: 'process', - description: - 'Process title. The proctitle, some times the same as process name. Can also be different: for example a browser setting its title to the web page currently opened.', - name: 'process.parent.title', - type: 'keyword', - }, - 'process.parent.uptime': { - category: 'process', - description: 'Seconds the process has been up.', - example: 1325, - name: 'process.parent.uptime', - type: 'long', - }, - 'process.parent.working_directory': { - category: 'process', - description: 'The working directory of the process.', - example: '/home/alice', - name: 'process.parent.working_directory', - type: 'keyword', - }, - 'process.pe.architecture': { - category: 'process', - description: 'CPU architecture target for the file.', - example: 'x64', - name: 'process.pe.architecture', - type: 'keyword', - }, - 'process.pe.company': { - category: 'process', - description: 'Internal company name of the file, provided at compile-time.', - example: 'Microsoft Corporation', - name: 'process.pe.company', - type: 'keyword', - }, - 'process.pe.description': { - category: 'process', - description: 'Internal description of the file, provided at compile-time.', - example: 'Paint', - name: 'process.pe.description', - type: 'keyword', - }, - 'process.pe.file_version': { - category: 'process', - description: 'Internal version of the file, provided at compile-time.', - example: '6.3.9600.17415', - name: 'process.pe.file_version', - type: 'keyword', - }, - 'process.pe.imphash': { - category: 'process', - description: - 'A hash of the imports in a PE file. An imphash -- or import hash -- can be used to fingerprint binaries even after recompilation or other code-level transformations have occurred, which would change more traditional hash values. Learn more at https://www.fireeye.com/blog/threat-research/2014/01/tracking-malware-import-hashing.html.', - example: '0c6803c4e922103c4dca5963aad36ddf', - name: 'process.pe.imphash', - type: 'keyword', - }, - 'process.pe.original_file_name': { - category: 'process', - description: 'Internal name of the file, provided at compile-time.', - example: 'MSPAINT.EXE', - name: 'process.pe.original_file_name', - type: 'keyword', - }, - 'process.pe.product': { - category: 'process', - description: 'Internal product name of the file, provided at compile-time.', - example: 'Microsoft® Windows® Operating System', - name: 'process.pe.product', - type: 'keyword', - }, - 'process.pgid': { - category: 'process', - description: 'Identifier of the group of processes the process belongs to.', - name: 'process.pgid', - type: 'long', - format: 'string', - }, - 'process.pid': { - category: 'process', - description: 'Process id.', - example: 4242, - name: 'process.pid', - type: 'long', - format: 'string', - }, - 'process.ppid': { - category: 'process', - description: "Parent process' pid.", - example: 4241, - name: 'process.ppid', - type: 'long', - format: 'string', - }, - 'process.start': { - category: 'process', - description: 'The time the process started.', - example: '2016-05-23T08:05:34.853Z', - name: 'process.start', - type: 'date', - }, - 'process.thread.id': { - category: 'process', - description: 'Thread ID.', - example: 4242, - name: 'process.thread.id', - type: 'long', - format: 'string', - }, - 'process.thread.name': { - category: 'process', - description: 'Thread name.', - example: 'thread-0', - name: 'process.thread.name', - type: 'keyword', - }, - 'process.title': { - category: 'process', - description: - 'Process title. The proctitle, some times the same as process name. Can also be different: for example a browser setting its title to the web page currently opened.', - name: 'process.title', - type: 'keyword', - }, - 'process.uptime': { - category: 'process', - description: 'Seconds the process has been up.', - example: 1325, - name: 'process.uptime', - type: 'long', - }, - 'process.working_directory': { - category: 'process', - description: 'The working directory of the process.', - example: '/home/alice', - name: 'process.working_directory', - type: 'keyword', - }, - 'registry.data.bytes': { - category: 'registry', - description: - 'Original bytes written with base64 encoding. For Windows registry operations, such as SetValueEx and RegQueryValueEx, this corresponds to the data pointed by `lp_data`. This is optional but provides better recoverability and should be populated for REG_BINARY encoded values.', - example: 'ZQBuAC0AVQBTAAAAZQBuAAAAAAA=', - name: 'registry.data.bytes', - type: 'keyword', - }, - 'registry.data.strings': { - category: 'registry', - description: - 'Content when writing string types. Populated as an array when writing string data to the registry. For single string registry types (REG_SZ, REG_EXPAND_SZ), this should be an array with one string. For sequences of string with REG_MULTI_SZ, this array will be variable length. For numeric data, such as REG_DWORD and REG_QWORD, this should be populated with the decimal representation (e.g `"1"`).', - example: '["C:\\rta\\red_ttp\\bin\\myapp.exe"]', - name: 'registry.data.strings', - type: 'keyword', - }, - 'registry.data.type': { - category: 'registry', - description: 'Standard registry type for encoding contents', - example: 'REG_SZ', - name: 'registry.data.type', - type: 'keyword', - }, - 'registry.hive': { - category: 'registry', - description: 'Abbreviated name for the hive.', - example: 'HKLM', - name: 'registry.hive', - type: 'keyword', - }, - 'registry.key': { - category: 'registry', - description: 'Hive-relative path of keys.', - example: - 'SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\winword.exe', - name: 'registry.key', - type: 'keyword', - }, - 'registry.path': { - category: 'registry', - description: 'Full path, including hive, key and value', - example: - 'HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\winword.exe\\Debugger', - name: 'registry.path', - type: 'keyword', - }, - 'registry.value': { - category: 'registry', - description: 'Name of the value written.', - example: 'Debugger', - name: 'registry.value', - type: 'keyword', - }, - 'related.hash': { - category: 'related', - description: - "All the hashes seen on your event. Populating this field, then using it to search for hashes can help in situations where you're unsure what the hash algorithm is (and therefore which key name to search).", - name: 'related.hash', - type: 'keyword', - }, - 'related.hosts': { - category: 'related', - description: - 'All hostnames or other host identifiers seen on your event. Example identifiers include FQDNs, domain names, workstation names, or aliases.', - name: 'related.hosts', - type: 'keyword', - }, - 'related.ip': { - category: 'related', - description: 'All of the IPs seen on your event.', - name: 'related.ip', - type: 'ip', - }, - 'related.user': { - category: 'related', - description: 'All the user names seen on your event.', - name: 'related.user', - type: 'keyword', - }, - 'rule.author': { - category: 'rule', - description: - 'Name, organization, or pseudonym of the author or authors who created the rule used to generate this event.', - example: '["Star-Lord"]', - name: 'rule.author', - type: 'keyword', - }, - 'rule.category': { - category: 'rule', - description: - 'A categorization value keyword used by the entity using the rule for detection of this event.', - example: 'Attempted Information Leak', - name: 'rule.category', - type: 'keyword', - }, - 'rule.description': { - category: 'rule', - description: 'The description of the rule generating the event.', - example: 'Block requests to public DNS over HTTPS / TLS protocols', - name: 'rule.description', - type: 'keyword', - }, - 'rule.id': { - category: 'rule', - description: - 'A rule ID that is unique within the scope of an agent, observer, or other entity using the rule for detection of this event.', - example: 101, - name: 'rule.id', - type: 'keyword', - }, - 'rule.license': { - category: 'rule', - description: - 'Name of the license under which the rule used to generate this event is made available.', - example: 'Apache 2.0', - name: 'rule.license', - type: 'keyword', - }, - 'rule.name': { - category: 'rule', - description: 'The name of the rule or signature generating the event.', - example: 'BLOCK_DNS_over_TLS', - name: 'rule.name', - type: 'keyword', - }, - 'rule.reference': { - category: 'rule', - description: - "Reference URL to additional information about the rule used to generate this event. The URL can point to the vendor's documentation about the rule. If that's not available, it can also be a link to a more general page describing this type of alert.", - example: 'https://en.wikipedia.org/wiki/DNS_over_TLS', - name: 'rule.reference', - type: 'keyword', - }, - 'rule.ruleset': { - category: 'rule', - description: - 'Name of the ruleset, policy, group, or parent category in which the rule used to generate this event is a member.', - example: 'Standard_Protocol_Filters', - name: 'rule.ruleset', - type: 'keyword', - }, - 'rule.uuid': { - category: 'rule', - description: - 'A rule ID that is unique within the scope of a set or group of agents, observers, or other entities using the rule for detection of this event.', - example: 1100110011, - name: 'rule.uuid', - type: 'keyword', - }, - 'rule.version': { - category: 'rule', - description: 'The version / revision of the rule being used for analysis.', - example: 1.1, - name: 'rule.version', - type: 'keyword', - }, - 'server.address': { - category: 'server', - description: - 'Some event server addresses are defined ambiguously. The event will sometimes list an IP, a domain or a unix socket. You should always store the raw address in the `.address` field. Then it should be duplicated to `.ip` or `.domain`, depending on which one it is.', - name: 'server.address', - type: 'keyword', - }, - 'server.as.number': { - category: 'server', - description: - 'Unique number allocated to the autonomous system. The autonomous system number (ASN) uniquely identifies each network on the Internet.', - example: 15169, - name: 'server.as.number', - type: 'long', - }, - 'server.as.organization.name': { - category: 'server', - description: 'Organization name.', - example: 'Google LLC', - name: 'server.as.organization.name', - type: 'keyword', - }, - 'server.bytes': { - category: 'server', - description: 'Bytes sent from the server to the client.', - example: 184, - name: 'server.bytes', - type: 'long', - format: 'bytes', - }, - 'server.domain': { - category: 'server', - description: 'Server domain.', - name: 'server.domain', - type: 'keyword', - }, - 'server.geo.city_name': { - category: 'server', - description: 'City name.', - example: 'Montreal', - name: 'server.geo.city_name', - type: 'keyword', - }, - 'server.geo.continent_code': { - category: 'server', - description: "Two-letter code representing continent's name.", - example: 'NA', - name: 'server.geo.continent_code', - type: 'keyword', - }, - 'server.geo.continent_name': { - category: 'server', - description: 'Name of the continent.', - example: 'North America', - name: 'server.geo.continent_name', - type: 'keyword', - }, - 'server.geo.country_iso_code': { - category: 'server', - description: 'Country ISO code.', - example: 'CA', - name: 'server.geo.country_iso_code', - type: 'keyword', - }, - 'server.geo.country_name': { - category: 'server', - description: 'Country name.', - example: 'Canada', - name: 'server.geo.country_name', - type: 'keyword', - }, - 'server.geo.location': { - category: 'server', - description: 'Longitude and latitude.', - example: '{ "lon": -73.614830, "lat": 45.505918 }', - name: 'server.geo.location', - type: 'geo_point', - }, - 'server.geo.name': { - category: 'server', - description: - 'User-defined description of a location, at the level of granularity they care about. Could be the name of their data centers, the floor number, if this describes a local physical entity, city names. Not typically used in automated geolocation.', - example: 'boston-dc', - name: 'server.geo.name', - type: 'keyword', - }, - 'server.geo.postal_code': { - category: 'server', - description: - 'Postal code associated with the location. Values appropriate for this field may also be known as a postcode or ZIP code and will vary widely from country to country.', - example: 94040, - name: 'server.geo.postal_code', - type: 'keyword', - }, - 'server.geo.region_iso_code': { - category: 'server', - description: 'Region ISO code.', - example: 'CA-QC', - name: 'server.geo.region_iso_code', - type: 'keyword', - }, - 'server.geo.region_name': { - category: 'server', - description: 'Region name.', - example: 'Quebec', - name: 'server.geo.region_name', - type: 'keyword', - }, - 'server.geo.timezone': { - category: 'server', - description: 'The time zone of the location, such as IANA time zone name.', - example: 'America/Argentina/Buenos_Aires', - name: 'server.geo.timezone', - type: 'keyword', - }, - 'server.ip': { - category: 'server', - description: 'IP address of the server (IPv4 or IPv6).', - name: 'server.ip', - type: 'ip', - }, - 'server.mac': { - category: 'server', - description: - 'MAC address of the server. The notation format from RFC 7042 is suggested: Each octet (that is, 8-bit byte) is represented by two [uppercase] hexadecimal digits giving the value of the octet as an unsigned integer. Successive octets are separated by a hyphen.', - example: '00-00-5E-00-53-23', - name: 'server.mac', - type: 'keyword', - }, - 'server.nat.ip': { - category: 'server', - description: - 'Translated ip of destination based NAT sessions (e.g. internet to private DMZ) Typically used with load balancers, firewalls, or routers.', - name: 'server.nat.ip', - type: 'ip', - }, - 'server.nat.port': { - category: 'server', - description: - 'Translated port of destination based NAT sessions (e.g. internet to private DMZ) Typically used with load balancers, firewalls, or routers.', - name: 'server.nat.port', - type: 'long', - format: 'string', - }, - 'server.packets': { - category: 'server', - description: 'Packets sent from the server to the client.', - example: 12, - name: 'server.packets', - type: 'long', - }, - 'server.port': { - category: 'server', - description: 'Port of the server.', - name: 'server.port', - type: 'long', - format: 'string', - }, - 'server.registered_domain': { - category: 'server', - description: - 'The highest registered server domain, stripped of the subdomain. For example, the registered domain for "foo.example.com" is "example.com". This value can be determined precisely with a list like the public suffix list (http://publicsuffix.org). Trying to approximate this by simply taking the last two labels will not work well for TLDs such as "co.uk".', - example: 'example.com', - name: 'server.registered_domain', - type: 'keyword', - }, - 'server.subdomain': { - category: 'server', - description: - 'The subdomain portion of a fully qualified domain name includes all of the names except the host name under the registered_domain. In a partially qualified domain, or if the the qualification level of the full name cannot be determined, subdomain contains all of the names below the registered domain. For example the subdomain portion of "www.east.mydomain.co.uk" is "east". If the domain has multiple levels of subdomain, such as "sub2.sub1.example.com", the subdomain field should contain "sub2.sub1", with no trailing period.', - example: 'east', - name: 'server.subdomain', - type: 'keyword', - }, - 'server.top_level_domain': { - category: 'server', - description: - 'The effective top level domain (eTLD), also known as the domain suffix, is the last part of the domain name. For example, the top level domain for example.com is "com". This value can be determined precisely with a list like the public suffix list (http://publicsuffix.org). Trying to approximate this by simply taking the last label will not work well for effective TLDs such as "co.uk".', - example: 'co.uk', - name: 'server.top_level_domain', - type: 'keyword', - }, - 'server.user.domain': { - category: 'server', - description: - 'Name of the directory the user is a member of. For example, an LDAP or Active Directory domain name.', - name: 'server.user.domain', - type: 'keyword', - }, - 'server.user.email': { - category: 'server', - description: 'User email address.', - name: 'server.user.email', - type: 'keyword', - }, - 'server.user.full_name': { - category: 'server', - description: "User's full name, if available.", - example: 'Albert Einstein', - name: 'server.user.full_name', - type: 'keyword', - }, - 'server.user.group.domain': { - category: 'server', - description: - 'Name of the directory the group is a member of. For example, an LDAP or Active Directory domain name.', - name: 'server.user.group.domain', - type: 'keyword', - }, - 'server.user.group.id': { - category: 'server', - description: 'Unique identifier for the group on the system/platform.', - name: 'server.user.group.id', - type: 'keyword', - }, - 'server.user.group.name': { - category: 'server', - description: 'Name of the group.', - name: 'server.user.group.name', - type: 'keyword', - }, - 'server.user.hash': { - category: 'server', - description: - 'Unique user hash to correlate information for a user in anonymized form. Useful if `user.id` or `user.name` contain confidential information and cannot be used.', - name: 'server.user.hash', - type: 'keyword', - }, - 'server.user.id': { - category: 'server', - description: 'Unique identifier of the user.', - name: 'server.user.id', - type: 'keyword', - }, - 'server.user.name': { - category: 'server', - description: 'Short name or login of the user.', - example: 'albert', - name: 'server.user.name', - type: 'keyword', - }, - 'server.user.roles': { - category: 'server', - description: 'Array of user roles at the time of the event.', - example: '["kibana_admin", "reporting_user"]', - name: 'server.user.roles', - type: 'keyword', - }, - 'service.ephemeral_id': { - category: 'service', - description: - 'Ephemeral identifier of this service (if one exists). This id normally changes across restarts, but `service.id` does not.', - example: '8a4f500f', - name: 'service.ephemeral_id', - type: 'keyword', - }, - 'service.id': { - category: 'service', - description: - 'Unique identifier of the running service. If the service is comprised of many nodes, the `service.id` should be the same for all nodes. This id should uniquely identify the service. This makes it possible to correlate logs and metrics for one specific service, no matter which particular node emitted the event. Note that if you need to see the events from one specific host of the service, you should filter on that `host.name` or `host.id` instead.', - example: 'd37e5ebfe0ae6c4972dbe9f0174a1637bb8247f6', - name: 'service.id', - type: 'keyword', - }, - 'service.name': { - category: 'service', - description: - 'Name of the service data is collected from. The name of the service is normally user given. This allows for distributed services that run on multiple hosts to correlate the related instances based on the name. In the case of Elasticsearch the `service.name` could contain the cluster name. For Beats the `service.name` is by default a copy of the `service.type` field if no name is specified.', - example: 'elasticsearch-metrics', - name: 'service.name', - type: 'keyword', - }, - 'service.node.name': { - category: 'service', - description: - "Name of a service node. This allows for two nodes of the same service running on the same host to be differentiated. Therefore, `service.node.name` should typically be unique across nodes of a given service. In the case of Elasticsearch, the `service.node.name` could contain the unique node name within the Elasticsearch cluster. In cases where the service doesn't have the concept of a node name, the host name or container name can be used to distinguish running instances that make up this service. If those do not provide uniqueness (e.g. multiple instances of the service running on the same host) - the node name can be manually set.", - example: 'instance-0000000016', - name: 'service.node.name', - type: 'keyword', - }, - 'service.state': { - category: 'service', - description: 'Current state of the service.', - name: 'service.state', - type: 'keyword', - }, - 'service.type': { - category: 'service', - description: - 'The type of the service data is collected from. The type can be used to group and correlate logs and metrics from one service type. Example: If logs or metrics are collected from Elasticsearch, `service.type` would be `elasticsearch`.', - example: 'elasticsearch', - name: 'service.type', - type: 'keyword', - }, - 'service.version': { - category: 'service', - description: - 'Version of the service the data was collected from. This allows to look at a data set only for a specific version of a service.', - example: '3.2.4', - name: 'service.version', - type: 'keyword', - }, - 'source.address': { - category: 'source', - description: - 'Some event source addresses are defined ambiguously. The event will sometimes list an IP, a domain or a unix socket. You should always store the raw address in the `.address` field. Then it should be duplicated to `.ip` or `.domain`, depending on which one it is.', - name: 'source.address', - type: 'keyword', - }, - 'source.as.number': { - category: 'source', - description: - 'Unique number allocated to the autonomous system. The autonomous system number (ASN) uniquely identifies each network on the Internet.', - example: 15169, - name: 'source.as.number', - type: 'long', - }, - 'source.as.organization.name': { - category: 'source', - description: 'Organization name.', - example: 'Google LLC', - name: 'source.as.organization.name', - type: 'keyword', - }, - 'source.bytes': { - category: 'source', - description: 'Bytes sent from the source to the destination.', - example: 184, - name: 'source.bytes', - type: 'long', - format: 'bytes', - }, - 'source.domain': { - category: 'source', - description: 'Source domain.', - name: 'source.domain', - type: 'keyword', - }, - 'source.geo.city_name': { - category: 'source', - description: 'City name.', - example: 'Montreal', - name: 'source.geo.city_name', - type: 'keyword', - }, - 'source.geo.continent_code': { - category: 'source', - description: "Two-letter code representing continent's name.", - example: 'NA', - name: 'source.geo.continent_code', - type: 'keyword', - }, - 'source.geo.continent_name': { - category: 'source', - description: 'Name of the continent.', - example: 'North America', - name: 'source.geo.continent_name', - type: 'keyword', - }, - 'source.geo.country_iso_code': { - category: 'source', - description: 'Country ISO code.', - example: 'CA', - name: 'source.geo.country_iso_code', - type: 'keyword', - }, - 'source.geo.country_name': { - category: 'source', - description: 'Country name.', - example: 'Canada', - name: 'source.geo.country_name', - type: 'keyword', - }, - 'source.geo.location': { - category: 'source', - description: 'Longitude and latitude.', - example: '{ "lon": -73.614830, "lat": 45.505918 }', - name: 'source.geo.location', - type: 'geo_point', - }, - 'source.geo.name': { - category: 'source', - description: - 'User-defined description of a location, at the level of granularity they care about. Could be the name of their data centers, the floor number, if this describes a local physical entity, city names. Not typically used in automated geolocation.', - example: 'boston-dc', - name: 'source.geo.name', - type: 'keyword', - }, - 'source.geo.postal_code': { - category: 'source', - description: - 'Postal code associated with the location. Values appropriate for this field may also be known as a postcode or ZIP code and will vary widely from country to country.', - example: 94040, - name: 'source.geo.postal_code', - type: 'keyword', - }, - 'source.geo.region_iso_code': { - category: 'source', - description: 'Region ISO code.', - example: 'CA-QC', - name: 'source.geo.region_iso_code', - type: 'keyword', - }, - 'source.geo.region_name': { - category: 'source', - description: 'Region name.', - example: 'Quebec', - name: 'source.geo.region_name', - type: 'keyword', - }, - 'source.geo.timezone': { - category: 'source', - description: 'The time zone of the location, such as IANA time zone name.', - example: 'America/Argentina/Buenos_Aires', - name: 'source.geo.timezone', - type: 'keyword', - }, - 'source.ip': { - category: 'source', - description: 'IP address of the source (IPv4 or IPv6).', - name: 'source.ip', - type: 'ip', - }, - 'source.mac': { - category: 'source', - description: - 'MAC address of the source. The notation format from RFC 7042 is suggested: Each octet (that is, 8-bit byte) is represented by two [uppercase] hexadecimal digits giving the value of the octet as an unsigned integer. Successive octets are separated by a hyphen.', - example: '00-00-5E-00-53-23', - name: 'source.mac', - type: 'keyword', - }, - 'source.nat.ip': { - category: 'source', - description: - 'Translated ip of source based NAT sessions (e.g. internal client to internet) Typically connections traversing load balancers, firewalls, or routers.', - name: 'source.nat.ip', - type: 'ip', - }, - 'source.nat.port': { - category: 'source', - description: - 'Translated port of source based NAT sessions. (e.g. internal client to internet) Typically used with load balancers, firewalls, or routers.', - name: 'source.nat.port', - type: 'long', - format: 'string', - }, - 'source.packets': { - category: 'source', - description: 'Packets sent from the source to the destination.', - example: 12, - name: 'source.packets', - type: 'long', - }, - 'source.port': { - category: 'source', - description: 'Port of the source.', - name: 'source.port', - type: 'long', - format: 'string', - }, - 'source.registered_domain': { - category: 'source', - description: - 'The highest registered source domain, stripped of the subdomain. For example, the registered domain for "foo.example.com" is "example.com". This value can be determined precisely with a list like the public suffix list (http://publicsuffix.org). Trying to approximate this by simply taking the last two labels will not work well for TLDs such as "co.uk".', - example: 'example.com', - name: 'source.registered_domain', - type: 'keyword', - }, - 'source.subdomain': { - category: 'source', - description: - 'The subdomain portion of a fully qualified domain name includes all of the names except the host name under the registered_domain. In a partially qualified domain, or if the the qualification level of the full name cannot be determined, subdomain contains all of the names below the registered domain. For example the subdomain portion of "www.east.mydomain.co.uk" is "east". If the domain has multiple levels of subdomain, such as "sub2.sub1.example.com", the subdomain field should contain "sub2.sub1", with no trailing period.', - example: 'east', - name: 'source.subdomain', - type: 'keyword', - }, - 'source.top_level_domain': { - category: 'source', - description: - 'The effective top level domain (eTLD), also known as the domain suffix, is the last part of the domain name. For example, the top level domain for example.com is "com". This value can be determined precisely with a list like the public suffix list (http://publicsuffix.org). Trying to approximate this by simply taking the last label will not work well for effective TLDs such as "co.uk".', - example: 'co.uk', - name: 'source.top_level_domain', - type: 'keyword', - }, - 'source.user.domain': { - category: 'source', - description: - 'Name of the directory the user is a member of. For example, an LDAP or Active Directory domain name.', - name: 'source.user.domain', - type: 'keyword', - }, - 'source.user.email': { - category: 'source', - description: 'User email address.', - name: 'source.user.email', - type: 'keyword', - }, - 'source.user.full_name': { - category: 'source', - description: "User's full name, if available.", - example: 'Albert Einstein', - name: 'source.user.full_name', - type: 'keyword', - }, - 'source.user.group.domain': { - category: 'source', - description: - 'Name of the directory the group is a member of. For example, an LDAP or Active Directory domain name.', - name: 'source.user.group.domain', - type: 'keyword', - }, - 'source.user.group.id': { - category: 'source', - description: 'Unique identifier for the group on the system/platform.', - name: 'source.user.group.id', - type: 'keyword', - }, - 'source.user.group.name': { - category: 'source', - description: 'Name of the group.', - name: 'source.user.group.name', - type: 'keyword', - }, - 'source.user.hash': { - category: 'source', - description: - 'Unique user hash to correlate information for a user in anonymized form. Useful if `user.id` or `user.name` contain confidential information and cannot be used.', - name: 'source.user.hash', - type: 'keyword', - }, - 'source.user.id': { - category: 'source', - description: 'Unique identifier of the user.', - name: 'source.user.id', - type: 'keyword', - }, - 'source.user.name': { - category: 'source', - description: 'Short name or login of the user.', - example: 'albert', - name: 'source.user.name', - type: 'keyword', - }, - 'source.user.roles': { - category: 'source', - description: 'Array of user roles at the time of the event.', - example: '["kibana_admin", "reporting_user"]', - name: 'source.user.roles', - type: 'keyword', - }, - 'threat.framework': { - category: 'threat', - description: - 'Name of the threat framework used to further categorize and classify the tactic and technique of the reported threat. Framework classification can be provided by detecting systems, evaluated at ingest time, or retrospectively tagged to events.', - example: 'MITRE ATT&CK', - name: 'threat.framework', - type: 'keyword', - }, - 'threat.tactic.id': { - category: 'threat', - description: - 'The id of tactic used by this threat. You can use a MITRE ATT&CK® tactic, for example. (ex. https://attack.mitre.org/tactics/TA0002/ )', - example: 'TA0002', - name: 'threat.tactic.id', - type: 'keyword', - }, - 'threat.tactic.name': { - category: 'threat', - description: - 'Name of the type of tactic used by this threat. You can use a MITRE ATT&CK® tactic, for example. (ex. https://attack.mitre.org/tactics/TA0002/)', - example: 'Execution', - name: 'threat.tactic.name', - type: 'keyword', - }, - 'threat.tactic.reference': { - category: 'threat', - description: - 'The reference url of tactic used by this threat. You can use a MITRE ATT&CK® tactic, for example. (ex. https://attack.mitre.org/tactics/TA0002/ )', - example: 'https://attack.mitre.org/tactics/TA0002/', - name: 'threat.tactic.reference', - type: 'keyword', - }, - 'threat.technique.id': { - category: 'threat', - description: - 'The id of technique used by this threat. You can use a MITRE ATT&CK® technique, for example. (ex. https://attack.mitre.org/techniques/T1059/)', - example: 'T1059', - name: 'threat.technique.id', - type: 'keyword', - }, - 'threat.technique.name': { - category: 'threat', - description: - 'The name of technique used by this threat. You can use a MITRE ATT&CK® technique, for example. (ex. https://attack.mitre.org/techniques/T1059/)', - example: 'Command and Scripting Interpreter', - name: 'threat.technique.name', - type: 'keyword', - }, - 'threat.technique.reference': { - category: 'threat', - description: - 'The reference url of technique used by this threat. You can use a MITRE ATT&CK® technique, for example. (ex. https://attack.mitre.org/techniques/T1059/)', - example: 'https://attack.mitre.org/techniques/T1059/', - name: 'threat.technique.reference', - type: 'keyword', - }, - 'threat.technique.subtechnique.id': { - category: 'threat', - description: - 'The full id of subtechnique used by this threat. You can use a MITRE ATT&CK® subtechnique, for example. (ex. https://attack.mitre.org/techniques/T1059/001/)', - example: 'T1059.001', - name: 'threat.technique.subtechnique.id', - type: 'keyword', - }, - 'threat.technique.subtechnique.name': { - category: 'threat', - description: - 'The name of subtechnique used by this threat. You can use a MITRE ATT&CK® subtechnique, for example. (ex. https://attack.mitre.org/techniques/T1059/001/)', - example: 'PowerShell', - name: 'threat.technique.subtechnique.name', - type: 'keyword', - }, - 'threat.technique.subtechnique.reference': { - category: 'threat', - description: - 'The reference url of subtechnique used by this threat. You can use a MITRE ATT&CK® subtechnique, for example. (ex. https://attack.mitre.org/techniques/T1059/001/)', - example: 'https://attack.mitre.org/techniques/T1059/001/', - name: 'threat.technique.subtechnique.reference', - type: 'keyword', - }, - 'tls.cipher': { - category: 'tls', - description: 'String indicating the cipher used during the current connection.', - example: 'TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256', - name: 'tls.cipher', - type: 'keyword', - }, - 'tls.client.certificate': { - category: 'tls', - description: - 'PEM-encoded stand-alone certificate offered by the client. This is usually mutually-exclusive of `client.certificate_chain` since this value also exists in that list.', - example: 'MII...', - name: 'tls.client.certificate', - type: 'keyword', - }, - 'tls.client.certificate_chain': { - category: 'tls', - description: - 'Array of PEM-encoded certificates that make up the certificate chain offered by the client. This is usually mutually-exclusive of `client.certificate` since that value should be the first certificate in the chain.', - example: '["MII...", "MII..."]', - name: 'tls.client.certificate_chain', - type: 'keyword', - }, - 'tls.client.hash.md5': { - category: 'tls', - description: - 'Certificate fingerprint using the MD5 digest of DER-encoded version of certificate offered by the client. For consistency with other hash values, this value should be formatted as an uppercase hash.', - example: '0F76C7F2C55BFD7D8E8B8F4BFBF0C9EC', - name: 'tls.client.hash.md5', - type: 'keyword', - }, - 'tls.client.hash.sha1': { - category: 'tls', - description: - 'Certificate fingerprint using the SHA1 digest of DER-encoded version of certificate offered by the client. For consistency with other hash values, this value should be formatted as an uppercase hash.', - example: '9E393D93138888D288266C2D915214D1D1CCEB2A', - name: 'tls.client.hash.sha1', - type: 'keyword', - }, - 'tls.client.hash.sha256': { - category: 'tls', - description: - 'Certificate fingerprint using the SHA256 digest of DER-encoded version of certificate offered by the client. For consistency with other hash values, this value should be formatted as an uppercase hash.', - example: '0687F666A054EF17A08E2F2162EAB4CBC0D265E1D7875BE74BF3C712CA92DAF0', - name: 'tls.client.hash.sha256', - type: 'keyword', - }, - 'tls.client.issuer': { - category: 'tls', - description: - 'Distinguished name of subject of the issuer of the x.509 certificate presented by the client.', - example: 'CN=Example Root CA, OU=Infrastructure Team, DC=example, DC=com', - name: 'tls.client.issuer', - type: 'keyword', - }, - 'tls.client.ja3': { - category: 'tls', - description: 'A hash that identifies clients based on how they perform an SSL/TLS handshake.', - example: 'd4e5b18d6b55c71272893221c96ba240', - name: 'tls.client.ja3', - type: 'keyword', - }, - 'tls.client.not_after': { - category: 'tls', - description: 'Date/Time indicating when client certificate is no longer considered valid.', - example: '2021-01-01T00:00:00.000Z', - name: 'tls.client.not_after', - type: 'date', - }, - 'tls.client.not_before': { - category: 'tls', - description: 'Date/Time indicating when client certificate is first considered valid.', - example: '1970-01-01T00:00:00.000Z', - name: 'tls.client.not_before', - type: 'date', - }, - 'tls.client.server_name': { - category: 'tls', - description: - 'Also called an SNI, this tells the server which hostname to which the client is attempting to connect to. When this value is available, it should get copied to `destination.domain`.', - example: 'www.elastic.co', - name: 'tls.client.server_name', - type: 'keyword', - }, - 'tls.client.subject': { - category: 'tls', - description: 'Distinguished name of subject of the x.509 certificate presented by the client.', - example: 'CN=myclient, OU=Documentation Team, DC=example, DC=com', - name: 'tls.client.subject', - type: 'keyword', - }, - 'tls.client.supported_ciphers': { - category: 'tls', - description: 'Array of ciphers offered by the client during the client hello.', - example: - '["TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", "..."]', - name: 'tls.client.supported_ciphers', - type: 'keyword', - }, - 'tls.client.x509.alternative_names': { - category: 'tls', - description: - 'List of subject alternative names (SAN). Name types vary by certificate authority and certificate type but commonly contain IP addresses, DNS names (and wildcards), and email addresses.', - example: '*.elastic.co', - name: 'tls.client.x509.alternative_names', - type: 'keyword', - }, - 'tls.client.x509.issuer.common_name': { - category: 'tls', - description: 'List of common name (CN) of issuing certificate authority.', - example: 'Example SHA2 High Assurance Server CA', - name: 'tls.client.x509.issuer.common_name', - type: 'keyword', - }, - 'tls.client.x509.issuer.country': { - category: 'tls', - description: 'List of country (C) codes', - example: 'US', - name: 'tls.client.x509.issuer.country', - type: 'keyword', - }, - 'tls.client.x509.issuer.distinguished_name': { - category: 'tls', - description: 'Distinguished name (DN) of issuing certificate authority.', - example: 'C=US, O=Example Inc, OU=www.example.com, CN=Example SHA2 High Assurance Server CA', - name: 'tls.client.x509.issuer.distinguished_name', - type: 'keyword', - }, - 'tls.client.x509.issuer.locality': { - category: 'tls', - description: 'List of locality names (L)', - example: 'Mountain View', - name: 'tls.client.x509.issuer.locality', - type: 'keyword', - }, - 'tls.client.x509.issuer.organization': { - category: 'tls', - description: 'List of organizations (O) of issuing certificate authority.', - example: 'Example Inc', - name: 'tls.client.x509.issuer.organization', - type: 'keyword', - }, - 'tls.client.x509.issuer.organizational_unit': { - category: 'tls', - description: 'List of organizational units (OU) of issuing certificate authority.', - example: 'www.example.com', - name: 'tls.client.x509.issuer.organizational_unit', - type: 'keyword', - }, - 'tls.client.x509.issuer.state_or_province': { - category: 'tls', - description: 'List of state or province names (ST, S, or P)', - example: 'California', - name: 'tls.client.x509.issuer.state_or_province', - type: 'keyword', - }, - 'tls.client.x509.not_after': { - category: 'tls', - description: 'Time at which the certificate is no longer considered valid.', - example: '"2020-07-16T03:15:39.000Z"', - name: 'tls.client.x509.not_after', - type: 'date', - }, - 'tls.client.x509.not_before': { - category: 'tls', - description: 'Time at which the certificate is first considered valid.', - example: '"2019-08-16T01:40:25.000Z"', - name: 'tls.client.x509.not_before', - type: 'date', - }, - 'tls.client.x509.public_key_algorithm': { - category: 'tls', - description: 'Algorithm used to generate the public key.', - example: 'RSA', - name: 'tls.client.x509.public_key_algorithm', - type: 'keyword', - }, - 'tls.client.x509.public_key_curve': { - category: 'tls', - description: - 'The curve used by the elliptic curve public key algorithm. This is algorithm specific.', - example: 'nistp521', - name: 'tls.client.x509.public_key_curve', - type: 'keyword', - }, - 'tls.client.x509.public_key_exponent': { - category: 'tls', - description: 'Exponent used to derive the public key. This is algorithm specific.', - example: 65537, - name: 'tls.client.x509.public_key_exponent', - type: 'long', - }, - 'tls.client.x509.public_key_size': { - category: 'tls', - description: 'The size of the public key space in bits.', - example: 2048, - name: 'tls.client.x509.public_key_size', - type: 'long', - }, - 'tls.client.x509.serial_number': { - category: 'tls', - description: - 'Unique serial number issued by the certificate authority. For consistency, if this value is alphanumeric, it should be formatted without colons and uppercase characters.', - example: '55FBB9C7DEBF09809D12CCAA', - name: 'tls.client.x509.serial_number', - type: 'keyword', - }, - 'tls.client.x509.signature_algorithm': { - category: 'tls', - description: - 'Identifier for certificate signature algorithm. We recommend using names found in Go Lang Crypto library. See https://github.com/golang/go/blob/go1.14/src/crypto/x509/x509.go#L337-L353.', - example: 'SHA256-RSA', - name: 'tls.client.x509.signature_algorithm', - type: 'keyword', - }, - 'tls.client.x509.subject.common_name': { - category: 'tls', - description: 'List of common names (CN) of subject.', - example: 'shared.global.example.net', - name: 'tls.client.x509.subject.common_name', - type: 'keyword', - }, - 'tls.client.x509.subject.country': { - category: 'tls', - description: 'List of country (C) code', - example: 'US', - name: 'tls.client.x509.subject.country', - type: 'keyword', - }, - 'tls.client.x509.subject.distinguished_name': { - category: 'tls', - description: 'Distinguished name (DN) of the certificate subject entity.', - example: 'C=US, ST=California, L=San Francisco, O=Example, Inc., CN=shared.global.example.net', - name: 'tls.client.x509.subject.distinguished_name', - type: 'keyword', - }, - 'tls.client.x509.subject.locality': { - category: 'tls', - description: 'List of locality names (L)', - example: 'San Francisco', - name: 'tls.client.x509.subject.locality', - type: 'keyword', - }, - 'tls.client.x509.subject.organization': { - category: 'tls', - description: 'List of organizations (O) of subject.', - example: 'Example, Inc.', - name: 'tls.client.x509.subject.organization', - type: 'keyword', - }, - 'tls.client.x509.subject.organizational_unit': { - category: 'tls', - description: 'List of organizational units (OU) of subject.', - name: 'tls.client.x509.subject.organizational_unit', - type: 'keyword', - }, - 'tls.client.x509.subject.state_or_province': { - category: 'tls', - description: 'List of state or province names (ST, S, or P)', - example: 'California', - name: 'tls.client.x509.subject.state_or_province', - type: 'keyword', - }, - 'tls.client.x509.version_number': { - category: 'tls', - description: 'Version of x509 format.', - example: 3, - name: 'tls.client.x509.version_number', - type: 'keyword', - }, - 'tls.curve': { - category: 'tls', - description: 'String indicating the curve used for the given cipher, when applicable.', - example: 'secp256r1', - name: 'tls.curve', - type: 'keyword', - }, - 'tls.established': { - category: 'tls', - description: - 'Boolean flag indicating if the TLS negotiation was successful and transitioned to an encrypted tunnel.', - name: 'tls.established', - type: 'boolean', - }, - 'tls.next_protocol': { - category: 'tls', - description: - 'String indicating the protocol being tunneled. Per the values in the IANA registry (https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids), this string should be lower case.', - example: 'http/1.1', - name: 'tls.next_protocol', - type: 'keyword', - }, - 'tls.resumed': { - category: 'tls', - description: - 'Boolean flag indicating if this TLS connection was resumed from an existing TLS negotiation.', - name: 'tls.resumed', - type: 'boolean', - }, - 'tls.server.certificate': { - category: 'tls', - description: - 'PEM-encoded stand-alone certificate offered by the server. This is usually mutually-exclusive of `server.certificate_chain` since this value also exists in that list.', - example: 'MII...', - name: 'tls.server.certificate', - type: 'keyword', - }, - 'tls.server.certificate_chain': { - category: 'tls', - description: - 'Array of PEM-encoded certificates that make up the certificate chain offered by the server. This is usually mutually-exclusive of `server.certificate` since that value should be the first certificate in the chain.', - example: '["MII...", "MII..."]', - name: 'tls.server.certificate_chain', - type: 'keyword', - }, - 'tls.server.hash.md5': { - category: 'tls', - description: - 'Certificate fingerprint using the MD5 digest of DER-encoded version of certificate offered by the server. For consistency with other hash values, this value should be formatted as an uppercase hash.', - example: '0F76C7F2C55BFD7D8E8B8F4BFBF0C9EC', - name: 'tls.server.hash.md5', - type: 'keyword', - }, - 'tls.server.hash.sha1': { - category: 'tls', - description: - 'Certificate fingerprint using the SHA1 digest of DER-encoded version of certificate offered by the server. For consistency with other hash values, this value should be formatted as an uppercase hash.', - example: '9E393D93138888D288266C2D915214D1D1CCEB2A', - name: 'tls.server.hash.sha1', - type: 'keyword', - }, - 'tls.server.hash.sha256': { - category: 'tls', - description: - 'Certificate fingerprint using the SHA256 digest of DER-encoded version of certificate offered by the server. For consistency with other hash values, this value should be formatted as an uppercase hash.', - example: '0687F666A054EF17A08E2F2162EAB4CBC0D265E1D7875BE74BF3C712CA92DAF0', - name: 'tls.server.hash.sha256', - type: 'keyword', - }, - 'tls.server.issuer': { - category: 'tls', - description: 'Subject of the issuer of the x.509 certificate presented by the server.', - example: 'CN=Example Root CA, OU=Infrastructure Team, DC=example, DC=com', - name: 'tls.server.issuer', - type: 'keyword', - }, - 'tls.server.ja3s': { - category: 'tls', - description: 'A hash that identifies servers based on how they perform an SSL/TLS handshake.', - example: '394441ab65754e2207b1e1b457b3641d', - name: 'tls.server.ja3s', - type: 'keyword', - }, - 'tls.server.not_after': { - category: 'tls', - description: 'Timestamp indicating when server certificate is no longer considered valid.', - example: '2021-01-01T00:00:00.000Z', - name: 'tls.server.not_after', - type: 'date', - }, - 'tls.server.not_before': { - category: 'tls', - description: 'Timestamp indicating when server certificate is first considered valid.', - example: '1970-01-01T00:00:00.000Z', - name: 'tls.server.not_before', - type: 'date', - }, - 'tls.server.subject': { - category: 'tls', - description: 'Subject of the x.509 certificate presented by the server.', - example: 'CN=www.example.com, OU=Infrastructure Team, DC=example, DC=com', - name: 'tls.server.subject', - type: 'keyword', - }, - 'tls.server.x509.alternative_names': { - category: 'tls', - description: - 'List of subject alternative names (SAN). Name types vary by certificate authority and certificate type but commonly contain IP addresses, DNS names (and wildcards), and email addresses.', - example: '*.elastic.co', - name: 'tls.server.x509.alternative_names', - type: 'keyword', - }, - 'tls.server.x509.issuer.common_name': { - category: 'tls', - description: 'List of common name (CN) of issuing certificate authority.', - example: 'Example SHA2 High Assurance Server CA', - name: 'tls.server.x509.issuer.common_name', - type: 'keyword', - }, - 'tls.server.x509.issuer.country': { - category: 'tls', - description: 'List of country (C) codes', - example: 'US', - name: 'tls.server.x509.issuer.country', - type: 'keyword', - }, - 'tls.server.x509.issuer.distinguished_name': { - category: 'tls', - description: 'Distinguished name (DN) of issuing certificate authority.', - example: 'C=US, O=Example Inc, OU=www.example.com, CN=Example SHA2 High Assurance Server CA', - name: 'tls.server.x509.issuer.distinguished_name', - type: 'keyword', - }, - 'tls.server.x509.issuer.locality': { - category: 'tls', - description: 'List of locality names (L)', - example: 'Mountain View', - name: 'tls.server.x509.issuer.locality', - type: 'keyword', - }, - 'tls.server.x509.issuer.organization': { - category: 'tls', - description: 'List of organizations (O) of issuing certificate authority.', - example: 'Example Inc', - name: 'tls.server.x509.issuer.organization', - type: 'keyword', - }, - 'tls.server.x509.issuer.organizational_unit': { - category: 'tls', - description: 'List of organizational units (OU) of issuing certificate authority.', - example: 'www.example.com', - name: 'tls.server.x509.issuer.organizational_unit', - type: 'keyword', - }, - 'tls.server.x509.issuer.state_or_province': { - category: 'tls', - description: 'List of state or province names (ST, S, or P)', - example: 'California', - name: 'tls.server.x509.issuer.state_or_province', - type: 'keyword', - }, - 'tls.server.x509.not_after': { - category: 'tls', - description: 'Time at which the certificate is no longer considered valid.', - example: '"2020-07-16T03:15:39.000Z"', - name: 'tls.server.x509.not_after', - type: 'date', - }, - 'tls.server.x509.not_before': { - category: 'tls', - description: 'Time at which the certificate is first considered valid.', - example: '"2019-08-16T01:40:25.000Z"', - name: 'tls.server.x509.not_before', - type: 'date', - }, - 'tls.server.x509.public_key_algorithm': { - category: 'tls', - description: 'Algorithm used to generate the public key.', - example: 'RSA', - name: 'tls.server.x509.public_key_algorithm', - type: 'keyword', - }, - 'tls.server.x509.public_key_curve': { - category: 'tls', - description: - 'The curve used by the elliptic curve public key algorithm. This is algorithm specific.', - example: 'nistp521', - name: 'tls.server.x509.public_key_curve', - type: 'keyword', - }, - 'tls.server.x509.public_key_exponent': { - category: 'tls', - description: 'Exponent used to derive the public key. This is algorithm specific.', - example: 65537, - name: 'tls.server.x509.public_key_exponent', - type: 'long', - }, - 'tls.server.x509.public_key_size': { - category: 'tls', - description: 'The size of the public key space in bits.', - example: 2048, - name: 'tls.server.x509.public_key_size', - type: 'long', - }, - 'tls.server.x509.serial_number': { - category: 'tls', - description: - 'Unique serial number issued by the certificate authority. For consistency, if this value is alphanumeric, it should be formatted without colons and uppercase characters.', - example: '55FBB9C7DEBF09809D12CCAA', - name: 'tls.server.x509.serial_number', - type: 'keyword', - }, - 'tls.server.x509.signature_algorithm': { - category: 'tls', - description: - 'Identifier for certificate signature algorithm. We recommend using names found in Go Lang Crypto library. See https://github.com/golang/go/blob/go1.14/src/crypto/x509/x509.go#L337-L353.', - example: 'SHA256-RSA', - name: 'tls.server.x509.signature_algorithm', - type: 'keyword', - }, - 'tls.server.x509.subject.common_name': { - category: 'tls', - description: 'List of common names (CN) of subject.', - example: 'shared.global.example.net', - name: 'tls.server.x509.subject.common_name', - type: 'keyword', - }, - 'tls.server.x509.subject.country': { - category: 'tls', - description: 'List of country (C) code', - example: 'US', - name: 'tls.server.x509.subject.country', - type: 'keyword', - }, - 'tls.server.x509.subject.distinguished_name': { - category: 'tls', - description: 'Distinguished name (DN) of the certificate subject entity.', - example: 'C=US, ST=California, L=San Francisco, O=Example, Inc., CN=shared.global.example.net', - name: 'tls.server.x509.subject.distinguished_name', - type: 'keyword', - }, - 'tls.server.x509.subject.locality': { - category: 'tls', - description: 'List of locality names (L)', - example: 'San Francisco', - name: 'tls.server.x509.subject.locality', - type: 'keyword', - }, - 'tls.server.x509.subject.organization': { - category: 'tls', - description: 'List of organizations (O) of subject.', - example: 'Example, Inc.', - name: 'tls.server.x509.subject.organization', - type: 'keyword', - }, - 'tls.server.x509.subject.organizational_unit': { - category: 'tls', - description: 'List of organizational units (OU) of subject.', - name: 'tls.server.x509.subject.organizational_unit', - type: 'keyword', - }, - 'tls.server.x509.subject.state_or_province': { - category: 'tls', - description: 'List of state or province names (ST, S, or P)', - example: 'California', - name: 'tls.server.x509.subject.state_or_province', - type: 'keyword', - }, - 'tls.server.x509.version_number': { - category: 'tls', - description: 'Version of x509 format.', - example: 3, - name: 'tls.server.x509.version_number', - type: 'keyword', - }, - 'tls.version': { - category: 'tls', - description: 'Numeric part of the version parsed from the original string.', - example: '1.2', - name: 'tls.version', - type: 'keyword', - }, - 'tls.version_protocol': { - category: 'tls', - description: 'Normalized lowercase protocol name parsed from original string.', - example: 'tls', - name: 'tls.version_protocol', - type: 'keyword', - }, - 'span.id': { - category: 'span', - description: - 'Unique identifier of the span within the scope of its trace. A span represents an operation within a transaction, such as a request to another service, or a database query.', - example: '3ff9a8981b7ccd5a', - name: 'span.id', - type: 'keyword', - }, - 'trace.id': { - category: 'trace', - description: - 'Unique identifier of the trace. A trace groups multiple events like transactions that belong together. For example, a user request handled by multiple inter-connected services.', - example: '4bf92f3577b34da6a3ce929d0e0e4736', - name: 'trace.id', - type: 'keyword', - }, - 'transaction.id': { - category: 'transaction', - description: - 'Unique identifier of the transaction within the scope of its trace. A transaction is the highest level of work measured within a service, such as a request to a server.', - example: '00f067aa0ba902b7', - name: 'transaction.id', - type: 'keyword', - }, - 'url.domain': { - category: 'url', - description: - 'Domain of the url, such as "www.elastic.co". In some cases a URL may refer to an IP and/or port directly, without a domain name. In this case, the IP address would go to the `domain` field. If the URL contains a literal IPv6 address enclosed by `[` and `]` (IETF RFC 2732), the `[` and `]` characters should also be captured in the `domain` field.', - example: 'www.elastic.co', - name: 'url.domain', - type: 'keyword', - }, - 'url.extension': { - category: 'url', - description: - 'The field contains the file extension from the original request url, excluding the leading dot. The file extension is only set if it exists, as not every url has a file extension. The leading period must not be included. For example, the value must be "png", not ".png". Note that when the file name has multiple extensions (example.tar.gz), only the last one should be captured ("gz", not "tar.gz").', - example: 'png', - name: 'url.extension', - type: 'keyword', - }, - 'url.fragment': { - category: 'url', - description: - 'Portion of the url after the `#`, such as "top". The `#` is not part of the fragment.', - name: 'url.fragment', - type: 'keyword', - }, - 'url.full': { - category: 'url', - description: - 'If full URLs are important to your use case, they should be stored in `url.full`, whether this field is reconstructed or present in the event source.', - example: 'https://www.elastic.co:443/search?q=elasticsearch#top', - name: 'url.full', - type: 'keyword', - }, - 'url.original': { - category: 'url', - description: - 'Unmodified original url as seen in the event source. Note that in network monitoring, the observed URL may be a full URL, whereas in access logs, the URL is often just represented as a path. This field is meant to represent the URL as it was observed, complete or not.', - example: 'https://www.elastic.co:443/search?q=elasticsearch#top or /search?q=elasticsearch', - name: 'url.original', - type: 'keyword', - }, - 'url.password': { - category: 'url', - description: 'Password of the request.', - name: 'url.password', - type: 'keyword', - }, - 'url.path': { - category: 'url', - description: 'Path of the request, such as "/search".', - name: 'url.path', - type: 'keyword', - }, - 'url.port': { - category: 'url', - description: 'Port of the request, such as 443.', - example: 443, - name: 'url.port', - type: 'long', - format: 'string', - }, - 'url.query': { - category: 'url', - description: - 'The query field describes the query string of the request, such as "q=elasticsearch". The `?` is excluded from the query string. If a URL contains no `?`, there is no query field. If there is a `?` but no query, the query field exists with an empty string. The `exists` query can be used to differentiate between the two cases.', - name: 'url.query', - type: 'keyword', - }, - 'url.registered_domain': { - category: 'url', - description: - 'The highest registered url domain, stripped of the subdomain. For example, the registered domain for "foo.example.com" is "example.com". This value can be determined precisely with a list like the public suffix list (http://publicsuffix.org). Trying to approximate this by simply taking the last two labels will not work well for TLDs such as "co.uk".', - example: 'example.com', - name: 'url.registered_domain', - type: 'keyword', - }, - 'url.scheme': { - category: 'url', - description: 'Scheme of the request, such as "https". Note: The `:` is not part of the scheme.', - example: 'https', - name: 'url.scheme', - type: 'keyword', - }, - 'url.subdomain': { - category: 'url', - description: - 'The subdomain portion of a fully qualified domain name includes all of the names except the host name under the registered_domain. In a partially qualified domain, or if the the qualification level of the full name cannot be determined, subdomain contains all of the names below the registered domain. For example the subdomain portion of "www.east.mydomain.co.uk" is "east". If the domain has multiple levels of subdomain, such as "sub2.sub1.example.com", the subdomain field should contain "sub2.sub1", with no trailing period.', - example: 'east', - name: 'url.subdomain', - type: 'keyword', - }, - 'url.top_level_domain': { - category: 'url', - description: - 'The effective top level domain (eTLD), also known as the domain suffix, is the last part of the domain name. For example, the top level domain for example.com is "com". This value can be determined precisely with a list like the public suffix list (http://publicsuffix.org). Trying to approximate this by simply taking the last label will not work well for effective TLDs such as "co.uk".', - example: 'co.uk', - name: 'url.top_level_domain', - type: 'keyword', - }, - 'url.username': { - category: 'url', - description: 'Username of the request.', - name: 'url.username', - type: 'keyword', - }, - 'user.changes.domain': { - category: 'user', - description: - 'Name of the directory the user is a member of. For example, an LDAP or Active Directory domain name.', - name: 'user.changes.domain', - type: 'keyword', - }, - 'user.changes.email': { - category: 'user', - description: 'User email address.', - name: 'user.changes.email', - type: 'keyword', - }, - 'user.changes.full_name': { - category: 'user', - description: "User's full name, if available.", - example: 'Albert Einstein', - name: 'user.changes.full_name', - type: 'keyword', - }, - 'user.changes.group.domain': { - category: 'user', - description: - 'Name of the directory the group is a member of. For example, an LDAP or Active Directory domain name.', - name: 'user.changes.group.domain', - type: 'keyword', - }, - 'user.changes.group.id': { - category: 'user', - description: 'Unique identifier for the group on the system/platform.', - name: 'user.changes.group.id', - type: 'keyword', - }, - 'user.changes.group.name': { - category: 'user', - description: 'Name of the group.', - name: 'user.changes.group.name', - type: 'keyword', - }, - 'user.changes.hash': { - category: 'user', - description: - 'Unique user hash to correlate information for a user in anonymized form. Useful if `user.id` or `user.name` contain confidential information and cannot be used.', - name: 'user.changes.hash', - type: 'keyword', - }, - 'user.changes.id': { - category: 'user', - description: 'Unique identifier of the user.', - name: 'user.changes.id', - type: 'keyword', - }, - 'user.changes.name': { - category: 'user', - description: 'Short name or login of the user.', - example: 'albert', - name: 'user.changes.name', - type: 'keyword', - }, - 'user.changes.roles': { - category: 'user', - description: 'Array of user roles at the time of the event.', - example: '["kibana_admin", "reporting_user"]', - name: 'user.changes.roles', - type: 'keyword', - }, - 'user.domain': { - category: 'user', - description: - 'Name of the directory the user is a member of. For example, an LDAP or Active Directory domain name.', - name: 'user.domain', - type: 'keyword', - }, - 'user.effective.domain': { - category: 'user', - description: - 'Name of the directory the user is a member of. For example, an LDAP or Active Directory domain name.', - name: 'user.effective.domain', - type: 'keyword', - }, - 'user.effective.email': { - category: 'user', - description: 'User email address.', - name: 'user.effective.email', - type: 'keyword', - }, - 'user.effective.full_name': { - category: 'user', - description: "User's full name, if available.", - example: 'Albert Einstein', - name: 'user.effective.full_name', - type: 'keyword', - }, - 'user.effective.group.domain': { - category: 'user', - description: - 'Name of the directory the group is a member of. For example, an LDAP or Active Directory domain name.', - name: 'user.effective.group.domain', - type: 'keyword', - }, - 'user.effective.group.id': { - category: 'user', - description: 'Unique identifier for the group on the system/platform.', - name: 'user.effective.group.id', - type: 'keyword', - }, - 'user.effective.group.name': { - category: 'user', - description: 'Name of the group.', - name: 'user.effective.group.name', - type: 'keyword', - }, - 'user.effective.hash': { - category: 'user', - description: - 'Unique user hash to correlate information for a user in anonymized form. Useful if `user.id` or `user.name` contain confidential information and cannot be used.', - name: 'user.effective.hash', - type: 'keyword', - }, - 'user.effective.id': { - category: 'user', - description: 'Unique identifier of the user.', - name: 'user.effective.id', - type: 'keyword', - }, - 'user.effective.name': { - category: 'user', - description: 'Short name or login of the user.', - example: 'albert', - name: 'user.effective.name', - type: 'keyword', - }, - 'user.effective.roles': { - category: 'user', - description: 'Array of user roles at the time of the event.', - example: '["kibana_admin", "reporting_user"]', - name: 'user.effective.roles', - type: 'keyword', - }, - 'user.email': { - category: 'user', - description: 'User email address.', - name: 'user.email', - type: 'keyword', - }, - 'user.full_name': { - category: 'user', - description: "User's full name, if available.", - example: 'Albert Einstein', - name: 'user.full_name', - type: 'keyword', - }, - 'user.group.domain': { - category: 'user', - description: - 'Name of the directory the group is a member of. For example, an LDAP or Active Directory domain name.', - name: 'user.group.domain', - type: 'keyword', - }, - 'user.group.id': { - category: 'user', - description: 'Unique identifier for the group on the system/platform.', - name: 'user.group.id', - type: 'keyword', - }, - 'user.group.name': { - category: 'user', - description: 'Name of the group.', - name: 'user.group.name', - type: 'keyword', - }, - 'user.hash': { - category: 'user', - description: - 'Unique user hash to correlate information for a user in anonymized form. Useful if `user.id` or `user.name` contain confidential information and cannot be used.', - name: 'user.hash', - type: 'keyword', - }, - 'user.id': { - category: 'user', - description: 'Unique identifier of the user.', - name: 'user.id', - type: 'keyword', - }, - 'user.name': { - category: 'user', - description: 'Short name or login of the user.', - example: 'albert', - name: 'user.name', - type: 'keyword', - }, - 'user.roles': { - category: 'user', - description: 'Array of user roles at the time of the event.', - example: '["kibana_admin", "reporting_user"]', - name: 'user.roles', - type: 'keyword', - }, - 'user.target.domain': { - category: 'user', - description: - 'Name of the directory the user is a member of. For example, an LDAP or Active Directory domain name.', - name: 'user.target.domain', - type: 'keyword', - }, - 'user.target.email': { - category: 'user', - description: 'User email address.', - name: 'user.target.email', - type: 'keyword', - }, - 'user.target.full_name': { - category: 'user', - description: "User's full name, if available.", - example: 'Albert Einstein', - name: 'user.target.full_name', - type: 'keyword', - }, - 'user.target.group.domain': { - category: 'user', - description: - 'Name of the directory the group is a member of. For example, an LDAP or Active Directory domain name.', - name: 'user.target.group.domain', - type: 'keyword', - }, - 'user.target.group.id': { - category: 'user', - description: 'Unique identifier for the group on the system/platform.', - name: 'user.target.group.id', - type: 'keyword', - }, - 'user.target.group.name': { - category: 'user', - description: 'Name of the group.', - name: 'user.target.group.name', - type: 'keyword', - }, - 'user.target.hash': { - category: 'user', - description: - 'Unique user hash to correlate information for a user in anonymized form. Useful if `user.id` or `user.name` contain confidential information and cannot be used.', - name: 'user.target.hash', - type: 'keyword', - }, - 'user.target.id': { - category: 'user', - description: 'Unique identifier of the user.', - name: 'user.target.id', - type: 'keyword', - }, - 'user.target.name': { - category: 'user', - description: 'Short name or login of the user.', - example: 'albert', - name: 'user.target.name', - type: 'keyword', - }, - 'user.target.roles': { - category: 'user', - description: 'Array of user roles at the time of the event.', - example: '["kibana_admin", "reporting_user"]', - name: 'user.target.roles', - type: 'keyword', - }, - 'user_agent.device.name': { - category: 'user_agent', - description: 'Name of the device.', - example: 'iPhone', - name: 'user_agent.device.name', - type: 'keyword', - }, - 'user_agent.name': { - category: 'user_agent', - description: 'Name of the user agent.', - example: 'Safari', - name: 'user_agent.name', - type: 'keyword', - }, - 'user_agent.original': { - category: 'user_agent', - description: 'Unparsed user_agent string.', - example: - 'Mozilla/5.0 (iPhone; CPU iPhone OS 12_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0 Mobile/15E148 Safari/604.1', - name: 'user_agent.original', - type: 'keyword', - }, - 'user_agent.os.family': { - category: 'user_agent', - description: 'OS family (such as redhat, debian, freebsd, windows).', - example: 'debian', - name: 'user_agent.os.family', - type: 'keyword', - }, - 'user_agent.os.full': { - category: 'user_agent', - description: 'Operating system name, including the version or code name.', - example: 'Mac OS Mojave', - name: 'user_agent.os.full', - type: 'keyword', - }, - 'user_agent.os.kernel': { - category: 'user_agent', - description: 'Operating system kernel version as a raw string.', - example: '4.4.0-112-generic', - name: 'user_agent.os.kernel', - type: 'keyword', - }, - 'user_agent.os.name': { - category: 'user_agent', - description: 'Operating system name, without the version.', - example: 'Mac OS X', - name: 'user_agent.os.name', - type: 'keyword', - }, - 'user_agent.os.platform': { - category: 'user_agent', - description: 'Operating system platform (such centos, ubuntu, windows).', - example: 'darwin', - name: 'user_agent.os.platform', - type: 'keyword', - }, - 'user_agent.os.type': { - category: 'user_agent', - description: - "Use the `os.type` field to categorize the operating system into one of the broad commercial families. One of these following values should be used (lowercase): linux, macos, unix, windows. If the OS you're dealing with is not in the list, the field should not be populated. Please let us know by opening an issue with ECS, to propose its addition.", - example: 'macos', - name: 'user_agent.os.type', - type: 'keyword', - }, - 'user_agent.os.version': { - category: 'user_agent', - description: 'Operating system version as a raw string.', - example: '10.14.1', - name: 'user_agent.os.version', - type: 'keyword', - }, - 'user_agent.version': { - category: 'user_agent', - description: 'Version of the user agent.', - example: 12, - name: 'user_agent.version', - type: 'keyword', - }, - 'vlan.id': { - category: 'vlan', - description: 'VLAN ID as reported by the observer.', - example: 10, - name: 'vlan.id', - type: 'keyword', - }, - 'vlan.name': { - category: 'vlan', - description: 'Optional VLAN name as reported by the observer.', - example: 'outside', - name: 'vlan.name', - type: 'keyword', - }, - 'vulnerability.category': { - category: 'vulnerability', - description: - 'The type of system or architecture that the vulnerability affects. These may be platform-specific (for example, Debian or SUSE) or general (for example, Database or Firewall). For example (https://qualysguard.qualys.com/qwebhelp/fo_portal/knowledgebase/vulnerability_categories.htm[Qualys vulnerability categories]) This field must be an array.', - example: '["Firewall"]', - name: 'vulnerability.category', - type: 'keyword', - }, - 'vulnerability.classification': { - category: 'vulnerability', - description: - 'The classification of the vulnerability scoring system. For example (https://www.first.org/cvss/)', - example: 'CVSS', - name: 'vulnerability.classification', - type: 'keyword', - }, - 'vulnerability.description': { - category: 'vulnerability', - description: - 'The description of the vulnerability that provides additional context of the vulnerability. For example (https://cve.mitre.org/about/faqs.html#cve_entry_descriptions_created[Common Vulnerabilities and Exposure CVE description])', - example: 'In macOS before 2.12.6, there is a vulnerability in the RPC...', - name: 'vulnerability.description', - type: 'keyword', - }, - 'vulnerability.enumeration': { - category: 'vulnerability', - description: - 'The type of identifier used for this vulnerability. For example (https://cve.mitre.org/about/)', - example: 'CVE', - name: 'vulnerability.enumeration', - type: 'keyword', - }, - 'vulnerability.id': { - category: 'vulnerability', - description: - 'The identification (ID) is the number portion of a vulnerability entry. It includes a unique identification number for the vulnerability. For example (https://cve.mitre.org/about/faqs.html#what_is_cve_id)[Common Vulnerabilities and Exposure CVE ID]', - example: 'CVE-2019-00001', - name: 'vulnerability.id', - type: 'keyword', - }, - 'vulnerability.reference': { - category: 'vulnerability', - description: - 'A resource that provides additional information, context, and mitigations for the identified vulnerability.', - example: 'https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-6111', - name: 'vulnerability.reference', - type: 'keyword', - }, - 'vulnerability.report_id': { - category: 'vulnerability', - description: 'The report or scan identification number.', - example: 20191018.0001, - name: 'vulnerability.report_id', - type: 'keyword', - }, - 'vulnerability.scanner.vendor': { - category: 'vulnerability', - description: 'The name of the vulnerability scanner vendor.', - example: 'Tenable', - name: 'vulnerability.scanner.vendor', - type: 'keyword', - }, - 'vulnerability.score.base': { - category: 'vulnerability', - description: - 'Scores can range from 0.0 to 10.0, with 10.0 being the most severe. Base scores cover an assessment for exploitability metrics (attack vector, complexity, privileges, and user interaction), impact metrics (confidentiality, integrity, and availability), and scope. For example (https://www.first.org/cvss/specification-document)', - example: 5.5, - name: 'vulnerability.score.base', - type: 'float', - }, - 'vulnerability.score.environmental': { - category: 'vulnerability', - description: - 'Scores can range from 0.0 to 10.0, with 10.0 being the most severe. Environmental scores cover an assessment for any modified Base metrics, confidentiality, integrity, and availability requirements. For example (https://www.first.org/cvss/specification-document)', - example: 5.5, - name: 'vulnerability.score.environmental', - type: 'float', - }, - 'vulnerability.score.temporal': { - category: 'vulnerability', - description: - 'Scores can range from 0.0 to 10.0, with 10.0 being the most severe. Temporal scores cover an assessment for code maturity, remediation level, and confidence. For example (https://www.first.org/cvss/specification-document)', - name: 'vulnerability.score.temporal', - type: 'float', - }, - 'vulnerability.score.version': { - category: 'vulnerability', - description: - 'The National Vulnerability Database (NVD) provides qualitative severity rankings of "Low", "Medium", and "High" for CVSS v2.0 base score ranges in addition to the severity ratings for CVSS v3.0 as they are defined in the CVSS v3.0 specification. CVSS is owned and managed by FIRST.Org, Inc. (FIRST), a US-based non-profit organization, whose mission is to help computer security incident response teams across the world. For example (https://nvd.nist.gov/vuln-metrics/cvss)', - example: 2, - name: 'vulnerability.score.version', - type: 'keyword', - }, - 'vulnerability.severity': { - category: 'vulnerability', - description: - 'The severity of the vulnerability can help with metrics and internal prioritization regarding remediation. For example (https://nvd.nist.gov/vuln-metrics/cvss)', - example: 'Critical', - name: 'vulnerability.severity', - type: 'keyword', - }, - 'x509.alternative_names': { - category: 'x509', - description: - 'List of subject alternative names (SAN). Name types vary by certificate authority and certificate type but commonly contain IP addresses, DNS names (and wildcards), and email addresses.', - example: '*.elastic.co', - name: 'x509.alternative_names', - type: 'keyword', - }, - 'x509.issuer.common_name': { - category: 'x509', - description: 'List of common name (CN) of issuing certificate authority.', - example: 'Example SHA2 High Assurance Server CA', - name: 'x509.issuer.common_name', - type: 'keyword', - }, - 'x509.issuer.country': { - category: 'x509', - description: 'List of country (C) codes', - example: 'US', - name: 'x509.issuer.country', - type: 'keyword', - }, - 'x509.issuer.distinguished_name': { - category: 'x509', - description: 'Distinguished name (DN) of issuing certificate authority.', - example: 'C=US, O=Example Inc, OU=www.example.com, CN=Example SHA2 High Assurance Server CA', - name: 'x509.issuer.distinguished_name', - type: 'keyword', - }, - 'x509.issuer.locality': { - category: 'x509', - description: 'List of locality names (L)', - example: 'Mountain View', - name: 'x509.issuer.locality', - type: 'keyword', - }, - 'x509.issuer.organization': { - category: 'x509', - description: 'List of organizations (O) of issuing certificate authority.', - example: 'Example Inc', - name: 'x509.issuer.organization', - type: 'keyword', - }, - 'x509.issuer.organizational_unit': { - category: 'x509', - description: 'List of organizational units (OU) of issuing certificate authority.', - example: 'www.example.com', - name: 'x509.issuer.organizational_unit', - type: 'keyword', - }, - 'x509.issuer.state_or_province': { - category: 'x509', - description: 'List of state or province names (ST, S, or P)', - example: 'California', - name: 'x509.issuer.state_or_province', - type: 'keyword', - }, - 'x509.not_after': { - category: 'x509', - description: 'Time at which the certificate is no longer considered valid.', - example: '"2020-07-16T03:15:39.000Z"', - name: 'x509.not_after', - type: 'date', - }, - 'x509.not_before': { - category: 'x509', - description: 'Time at which the certificate is first considered valid.', - example: '"2019-08-16T01:40:25.000Z"', - name: 'x509.not_before', - type: 'date', - }, - 'x509.public_key_algorithm': { - category: 'x509', - description: 'Algorithm used to generate the public key.', - example: 'RSA', - name: 'x509.public_key_algorithm', - type: 'keyword', - }, - 'x509.public_key_curve': { - category: 'x509', - description: - 'The curve used by the elliptic curve public key algorithm. This is algorithm specific.', - example: 'nistp521', - name: 'x509.public_key_curve', - type: 'keyword', - }, - 'x509.public_key_exponent': { - category: 'x509', - description: 'Exponent used to derive the public key. This is algorithm specific.', - example: 65537, - name: 'x509.public_key_exponent', - type: 'long', - }, - 'x509.public_key_size': { - category: 'x509', - description: 'The size of the public key space in bits.', - example: 2048, - name: 'x509.public_key_size', - type: 'long', - }, - 'x509.serial_number': { - category: 'x509', - description: - 'Unique serial number issued by the certificate authority. For consistency, if this value is alphanumeric, it should be formatted without colons and uppercase characters.', - example: '55FBB9C7DEBF09809D12CCAA', - name: 'x509.serial_number', - type: 'keyword', - }, - 'x509.signature_algorithm': { - category: 'x509', - description: - 'Identifier for certificate signature algorithm. We recommend using names found in Go Lang Crypto library. See https://github.com/golang/go/blob/go1.14/src/crypto/x509/x509.go#L337-L353.', - example: 'SHA256-RSA', - name: 'x509.signature_algorithm', - type: 'keyword', - }, - 'x509.subject.common_name': { - category: 'x509', - description: 'List of common names (CN) of subject.', - example: 'shared.global.example.net', - name: 'x509.subject.common_name', - type: 'keyword', - }, - 'x509.subject.country': { - category: 'x509', - description: 'List of country (C) code', - example: 'US', - name: 'x509.subject.country', - type: 'keyword', - }, - 'x509.subject.distinguished_name': { - category: 'x509', - description: 'Distinguished name (DN) of the certificate subject entity.', - example: 'C=US, ST=California, L=San Francisco, O=Example, Inc., CN=shared.global.example.net', - name: 'x509.subject.distinguished_name', - type: 'keyword', - }, - 'x509.subject.locality': { - category: 'x509', - description: 'List of locality names (L)', - example: 'San Francisco', - name: 'x509.subject.locality', - type: 'keyword', - }, - 'x509.subject.organization': { - category: 'x509', - description: 'List of organizations (O) of subject.', - example: 'Example, Inc.', - name: 'x509.subject.organization', - type: 'keyword', - }, - 'x509.subject.organizational_unit': { - category: 'x509', - description: 'List of organizational units (OU) of subject.', - name: 'x509.subject.organizational_unit', - type: 'keyword', - }, - 'x509.subject.state_or_province': { - category: 'x509', - description: 'List of state or province names (ST, S, or P)', - example: 'California', - name: 'x509.subject.state_or_province', - type: 'keyword', - }, - 'x509.version_number': { - category: 'x509', - description: 'Version of x509 format.', - example: 3, - name: 'x509.version_number', - type: 'keyword', - }, - 'agent.hostname': { - category: 'agent', - description: - 'Deprecated - use agent.name or agent.id to identify an agent. Hostname of the agent. ', - name: 'agent.hostname', - type: 'keyword', - }, - 'beat.timezone': { - category: 'beat', - name: 'beat.timezone', - type: 'alias', - }, - fields: { - category: 'base', - description: 'Contains user configurable fields. ', - name: 'fields', - type: 'object', - }, - 'beat.name': { - category: 'beat', - name: 'beat.name', - type: 'alias', - }, - 'beat.hostname': { - category: 'beat', - name: 'beat.hostname', - type: 'alias', - }, - 'timeseries.instance': { - category: 'timeseries', - description: 'Time series instance id', - name: 'timeseries.instance', - type: 'keyword', - }, - 'cloud.image.id': { - category: 'cloud', - description: 'Image ID for the cloud instance. ', - example: 'ami-abcd1234', - name: 'cloud.image.id', - }, - 'meta.cloud.provider': { - category: 'meta', - name: 'meta.cloud.provider', - type: 'alias', - }, - 'meta.cloud.instance_id': { - category: 'meta', - name: 'meta.cloud.instance_id', - type: 'alias', - }, - 'meta.cloud.instance_name': { - category: 'meta', - name: 'meta.cloud.instance_name', - type: 'alias', - }, - 'meta.cloud.machine_type': { - category: 'meta', - name: 'meta.cloud.machine_type', - type: 'alias', - }, - 'meta.cloud.availability_zone': { - category: 'meta', - name: 'meta.cloud.availability_zone', - type: 'alias', - }, - 'meta.cloud.project_id': { - category: 'meta', - name: 'meta.cloud.project_id', - type: 'alias', - }, - 'meta.cloud.region': { - category: 'meta', - name: 'meta.cloud.region', - type: 'alias', - }, - 'docker.container.id': { - category: 'docker', - name: 'docker.container.id', - type: 'alias', - }, - 'docker.container.image': { - category: 'docker', - name: 'docker.container.image', - type: 'alias', - }, - 'docker.container.name': { - category: 'docker', - name: 'docker.container.name', - type: 'alias', - }, - 'docker.container.labels': { - category: 'docker', - description: 'Image labels. ', - name: 'docker.container.labels', - type: 'object', - }, - 'host.containerized': { - category: 'host', - description: 'If the host is a container. ', - name: 'host.containerized', - type: 'boolean', - }, - 'host.os.build': { - category: 'host', - description: 'OS build information. ', - example: '18D109', - name: 'host.os.build', - type: 'keyword', - }, - 'host.os.codename': { - category: 'host', - description: 'OS codename, if any. ', - example: 'stretch', - name: 'host.os.codename', - type: 'keyword', - }, - 'kubernetes.pod.name': { - category: 'kubernetes', - description: 'Kubernetes pod name ', - name: 'kubernetes.pod.name', - type: 'keyword', - }, - 'kubernetes.pod.uid': { - category: 'kubernetes', - description: 'Kubernetes Pod UID ', - name: 'kubernetes.pod.uid', - type: 'keyword', - }, - 'kubernetes.pod.ip': { - category: 'kubernetes', - description: 'Kubernetes Pod IP ', - name: 'kubernetes.pod.ip', - type: 'ip', - }, - 'kubernetes.namespace': { - category: 'kubernetes', - description: 'Kubernetes namespace ', - name: 'kubernetes.namespace', - type: 'keyword', - }, - 'kubernetes.node.name': { - category: 'kubernetes', - description: 'Kubernetes node name ', - name: 'kubernetes.node.name', - type: 'keyword', - }, - 'kubernetes.node.hostname': { - category: 'kubernetes', - description: 'Kubernetes hostname as reported by the node’s kernel ', - name: 'kubernetes.node.hostname', - type: 'keyword', - }, - 'kubernetes.labels.*': { - category: 'kubernetes', - description: 'Kubernetes labels map ', - name: 'kubernetes.labels.*', - type: 'object', - }, - 'kubernetes.annotations.*': { - category: 'kubernetes', - description: 'Kubernetes annotations map ', - name: 'kubernetes.annotations.*', - type: 'object', - }, - 'kubernetes.selectors.*': { - category: 'kubernetes', - description: 'Kubernetes selectors map ', - name: 'kubernetes.selectors.*', - type: 'object', - }, - 'kubernetes.replicaset.name': { - category: 'kubernetes', - description: 'Kubernetes replicaset name ', - name: 'kubernetes.replicaset.name', - type: 'keyword', - }, - 'kubernetes.deployment.name': { - category: 'kubernetes', - description: 'Kubernetes deployment name ', - name: 'kubernetes.deployment.name', - type: 'keyword', - }, - 'kubernetes.statefulset.name': { - category: 'kubernetes', - description: 'Kubernetes statefulset name ', - name: 'kubernetes.statefulset.name', - type: 'keyword', - }, - 'kubernetes.container.name': { - category: 'kubernetes', - description: 'Kubernetes container name (different than the name from the runtime) ', - name: 'kubernetes.container.name', - type: 'keyword', - }, - 'kubernetes.container.image': { - category: 'kubernetes', - description: 'Kubernetes container image ', - name: 'kubernetes.container.image', - type: 'alias', - }, - 'process.exe': { - category: 'process', - name: 'process.exe', - type: 'alias', - }, - 'jolokia.agent.version': { - category: 'jolokia', - description: 'Version number of jolokia agent. ', - name: 'jolokia.agent.version', - type: 'keyword', - }, - 'jolokia.agent.id': { - category: 'jolokia', - description: - 'Each agent has a unique id which can be either provided during startup of the agent in form of a configuration parameter or being autodetected. If autodected, the id has several parts: The IP, the process id, hashcode of the agent and its type. ', - name: 'jolokia.agent.id', - type: 'keyword', - }, - 'jolokia.server.product': { - category: 'jolokia', - description: 'The container product if detected. ', - name: 'jolokia.server.product', - type: 'keyword', - }, - 'jolokia.server.version': { - category: 'jolokia', - description: "The container's version (if detected). ", - name: 'jolokia.server.version', - type: 'keyword', - }, - 'jolokia.server.vendor': { - category: 'jolokia', - description: 'The vendor of the container the agent is running in. ', - name: 'jolokia.server.vendor', - type: 'keyword', - }, - 'jolokia.url': { - category: 'jolokia', - description: 'The URL how this agent can be contacted. ', - name: 'jolokia.url', - type: 'keyword', - }, - 'jolokia.secured': { - category: 'jolokia', - description: 'Whether the agent was configured for authentication or not. ', - name: 'jolokia.secured', - type: 'boolean', - }, - 'file.setuid': { - category: 'file', - description: 'Set if the file has the `setuid` bit set. Omitted otherwise.', - example: 'true', - name: 'file.setuid', - type: 'boolean', - }, - 'file.setgid': { - category: 'file', - description: 'Set if the file has the `setgid` bit set. Omitted otherwise.', - example: 'true', - name: 'file.setgid', - type: 'boolean', - }, - 'file.origin': { - category: 'file', - description: - 'An array of strings describing a possible external origin for this file. For example, the URL it was downloaded from. Only supported in macOS, via the kMDItemWhereFroms attribute. Omitted if origin information is not available. ', - name: 'file.origin', - type: 'keyword', - }, - 'file.selinux.user': { - category: 'file', - description: 'The owner of the object.', - name: 'file.selinux.user', - type: 'keyword', - }, - 'file.selinux.role': { - category: 'file', - description: "The object's SELinux role.", - name: 'file.selinux.role', - type: 'keyword', - }, - 'file.selinux.domain': { - category: 'file', - description: "The object's SELinux domain or type.", - name: 'file.selinux.domain', - type: 'keyword', - }, - 'file.selinux.level': { - category: 'file', - description: "The object's SELinux level.", - example: 's0', - name: 'file.selinux.level', - type: 'keyword', - }, - 'user.audit.id': { - category: 'user', - description: 'Audit user ID.', - name: 'user.audit.id', - type: 'keyword', - }, - 'user.audit.name': { - category: 'user', - description: 'Audit user name.', - name: 'user.audit.name', - type: 'keyword', - }, - 'user.filesystem.id': { - category: 'user', - description: 'Filesystem user ID.', - name: 'user.filesystem.id', - type: 'keyword', - }, - 'user.filesystem.name': { - category: 'user', - description: 'Filesystem user name.', - name: 'user.filesystem.name', - type: 'keyword', - }, - 'user.filesystem.group.id': { - category: 'user', - description: 'Filesystem group ID.', - name: 'user.filesystem.group.id', - type: 'keyword', - }, - 'user.filesystem.group.name': { - category: 'user', - description: 'Filesystem group name.', - name: 'user.filesystem.group.name', - type: 'keyword', - }, - 'user.saved.id': { - category: 'user', - description: 'Saved user ID.', - name: 'user.saved.id', - type: 'keyword', - }, - 'user.saved.name': { - category: 'user', - description: 'Saved user name.', - name: 'user.saved.name', - type: 'keyword', - }, - 'user.saved.group.id': { - category: 'user', - description: 'Saved group ID.', - name: 'user.saved.group.id', - type: 'keyword', - }, - 'user.saved.group.name': { - category: 'user', - description: 'Saved group name.', - name: 'user.saved.group.name', - type: 'keyword', - }, - 'user.auid': { - category: 'user', - name: 'user.auid', - type: 'alias', - }, - 'user.uid': { - category: 'user', - name: 'user.uid', - type: 'alias', - }, - 'user.fsuid': { - category: 'user', - name: 'user.fsuid', - type: 'alias', - }, - 'user.suid': { - category: 'user', - name: 'user.suid', - type: 'alias', - }, - 'user.gid': { - category: 'user', - name: 'user.gid', - type: 'alias', - }, - 'user.sgid': { - category: 'user', - name: 'user.sgid', - type: 'alias', - }, - 'user.fsgid': { - category: 'user', - name: 'user.fsgid', - type: 'alias', - }, - 'user.name_map.auid': { - category: 'user', - name: 'user.name_map.auid', - type: 'alias', - }, - 'user.name_map.uid': { - category: 'user', - name: 'user.name_map.uid', - type: 'alias', - }, - 'user.name_map.fsuid': { - category: 'user', - name: 'user.name_map.fsuid', - type: 'alias', - }, - 'user.name_map.suid': { - category: 'user', - name: 'user.name_map.suid', - type: 'alias', - }, - 'user.name_map.gid': { - category: 'user', - name: 'user.name_map.gid', - type: 'alias', - }, - 'user.name_map.sgid': { - category: 'user', - name: 'user.name_map.sgid', - type: 'alias', - }, - 'user.name_map.fsgid': { - category: 'user', - name: 'user.name_map.fsgid', - type: 'alias', - }, - 'user.selinux.user': { - category: 'user', - description: 'account submitted for authentication', - name: 'user.selinux.user', - type: 'keyword', - }, - 'user.selinux.role': { - category: 'user', - description: "user's SELinux role", - name: 'user.selinux.role', - type: 'keyword', - }, - 'user.selinux.domain': { - category: 'user', - description: "The actor's SELinux domain or type.", - name: 'user.selinux.domain', - type: 'keyword', - }, - 'user.selinux.level': { - category: 'user', - description: "The actor's SELinux level.", - example: 's0', - name: 'user.selinux.level', - type: 'keyword', - }, - 'user.selinux.category': { - category: 'user', - description: "The actor's SELinux category or compartments.", - name: 'user.selinux.category', - type: 'keyword', - }, - 'process.cwd': { - category: 'process', - description: 'The current working directory.', - name: 'process.cwd', - type: 'alias', - }, - 'source.path': { - category: 'source', - description: 'This is the path associated with a unix socket.', - name: 'source.path', - type: 'keyword', - }, - 'destination.path': { - category: 'destination', - description: 'This is the path associated with a unix socket.', - name: 'destination.path', - type: 'keyword', - }, - 'auditd.message_type': { - category: 'auditd', - description: 'The audit message type (e.g. syscall or apparmor_denied). ', - example: 'syscall', - name: 'auditd.message_type', - type: 'keyword', - }, - 'auditd.sequence': { - category: 'auditd', - description: - 'The sequence number of the event as assigned by the kernel. Sequence numbers are stored as a uint32 in the kernel and can rollover. ', - name: 'auditd.sequence', - type: 'long', - }, - 'auditd.session': { - category: 'auditd', - description: - 'The session ID assigned to a login. All events related to a login session will have the same value. ', - name: 'auditd.session', - type: 'keyword', - }, - 'auditd.result': { - category: 'auditd', - description: 'The result of the audited operation (success/fail).', - example: 'success or fail', - name: 'auditd.result', - type: 'keyword', - }, - 'auditd.summary.actor.primary': { - category: 'auditd', - description: - "The primary identity of the actor. This is the actor's original login ID. It will not change even if the user changes to another account. ", - name: 'auditd.summary.actor.primary', - type: 'keyword', - }, - 'auditd.summary.actor.secondary': { - category: 'auditd', - description: - 'The secondary identity of the actor. This is typically the same as the primary, except for when the user has used `su`.', - name: 'auditd.summary.actor.secondary', - type: 'keyword', - }, - 'auditd.summary.object.type': { - category: 'auditd', - description: 'A description of the what the "thing" is (e.g. file, socket, user-session). ', - name: 'auditd.summary.object.type', - type: 'keyword', - }, - 'auditd.summary.object.primary': { - category: 'auditd', - description: '', - name: 'auditd.summary.object.primary', - type: 'keyword', - }, - 'auditd.summary.object.secondary': { - category: 'auditd', - description: '', - name: 'auditd.summary.object.secondary', - type: 'keyword', - }, - 'auditd.summary.how': { - category: 'auditd', - description: - 'This describes how the action was performed. Usually this is the exe or command that was being executed that triggered the event. ', - name: 'auditd.summary.how', - type: 'keyword', - }, - 'auditd.paths.inode': { - category: 'auditd', - description: 'inode number', - name: 'auditd.paths.inode', - type: 'keyword', - }, - 'auditd.paths.dev': { - category: 'auditd', - description: 'device name as found in /dev', - name: 'auditd.paths.dev', - type: 'keyword', - }, - 'auditd.paths.obj_user': { - category: 'auditd', - description: '', - name: 'auditd.paths.obj_user', - type: 'keyword', - }, - 'auditd.paths.obj_role': { - category: 'auditd', - description: '', - name: 'auditd.paths.obj_role', - type: 'keyword', - }, - 'auditd.paths.obj_domain': { - category: 'auditd', - description: '', - name: 'auditd.paths.obj_domain', - type: 'keyword', - }, - 'auditd.paths.obj_level': { - category: 'auditd', - description: '', - name: 'auditd.paths.obj_level', - type: 'keyword', - }, - 'auditd.paths.objtype': { - category: 'auditd', - description: '', - name: 'auditd.paths.objtype', - type: 'keyword', - }, - 'auditd.paths.ouid': { - category: 'auditd', - description: 'file owner user ID', - name: 'auditd.paths.ouid', - type: 'keyword', - }, - 'auditd.paths.rdev': { - category: 'auditd', - description: 'the device identifier (special files only)', - name: 'auditd.paths.rdev', - type: 'keyword', - }, - 'auditd.paths.nametype': { - category: 'auditd', - description: 'kind of file operation being referenced', - name: 'auditd.paths.nametype', - type: 'keyword', - }, - 'auditd.paths.ogid': { - category: 'auditd', - description: 'file owner group ID', - name: 'auditd.paths.ogid', - type: 'keyword', - }, - 'auditd.paths.item': { - category: 'auditd', - description: 'which item is being recorded', - name: 'auditd.paths.item', - type: 'keyword', - }, - 'auditd.paths.mode': { - category: 'auditd', - description: 'mode flags on a file', - name: 'auditd.paths.mode', - type: 'keyword', - }, - 'auditd.paths.name': { - category: 'auditd', - description: 'file name in avcs', - name: 'auditd.paths.name', - type: 'keyword', - }, - 'auditd.data.action': { - category: 'auditd', - description: 'netfilter packet disposition', - name: 'auditd.data.action', - type: 'keyword', - }, - 'auditd.data.minor': { - category: 'auditd', - description: 'device minor number', - name: 'auditd.data.minor', - type: 'keyword', - }, - 'auditd.data.acct': { - category: 'auditd', - description: "a user's account name", - name: 'auditd.data.acct', - type: 'keyword', - }, - 'auditd.data.addr': { - category: 'auditd', - description: 'the remote address that the user is connecting from', - name: 'auditd.data.addr', - type: 'keyword', - }, - 'auditd.data.cipher': { - category: 'auditd', - description: 'name of crypto cipher selected', - name: 'auditd.data.cipher', - type: 'keyword', - }, - 'auditd.data.id': { - category: 'auditd', - description: 'during account changes', - name: 'auditd.data.id', - type: 'keyword', - }, - 'auditd.data.entries': { - category: 'auditd', - description: 'number of entries in the netfilter table', - name: 'auditd.data.entries', - type: 'keyword', - }, - 'auditd.data.kind': { - category: 'auditd', - description: 'server or client in crypto operation', - name: 'auditd.data.kind', - type: 'keyword', - }, - 'auditd.data.ksize': { - category: 'auditd', - description: 'key size for crypto operation', - name: 'auditd.data.ksize', - type: 'keyword', - }, - 'auditd.data.spid': { - category: 'auditd', - description: 'sent process ID', - name: 'auditd.data.spid', - type: 'keyword', - }, - 'auditd.data.arch': { - category: 'auditd', - description: 'the elf architecture flags', - name: 'auditd.data.arch', - type: 'keyword', - }, - 'auditd.data.argc': { - category: 'auditd', - description: 'the number of arguments to an execve syscall', - name: 'auditd.data.argc', - type: 'keyword', - }, - 'auditd.data.major': { - category: 'auditd', - description: 'device major number', - name: 'auditd.data.major', - type: 'keyword', - }, - 'auditd.data.unit': { - category: 'auditd', - description: 'systemd unit', - name: 'auditd.data.unit', - type: 'keyword', - }, - 'auditd.data.table': { - category: 'auditd', - description: 'netfilter table name', - name: 'auditd.data.table', - type: 'keyword', - }, - 'auditd.data.terminal': { - category: 'auditd', - description: 'terminal name the user is running programs on', - name: 'auditd.data.terminal', - type: 'keyword', - }, - 'auditd.data.grantors': { - category: 'auditd', - description: 'pam modules approving the action', - name: 'auditd.data.grantors', - type: 'keyword', - }, - 'auditd.data.direction': { - category: 'auditd', - description: 'direction of crypto operation', - name: 'auditd.data.direction', - type: 'keyword', - }, - 'auditd.data.op': { - category: 'auditd', - description: 'the operation being performed that is audited', - name: 'auditd.data.op', - type: 'keyword', - }, - 'auditd.data.tty': { - category: 'auditd', - description: 'tty udevice the user is running programs on', - name: 'auditd.data.tty', - type: 'keyword', - }, - 'auditd.data.syscall': { - category: 'auditd', - description: 'syscall number in effect when the event occurred', - name: 'auditd.data.syscall', - type: 'keyword', - }, - 'auditd.data.data': { - category: 'auditd', - description: 'TTY text', - name: 'auditd.data.data', - type: 'keyword', - }, - 'auditd.data.family': { - category: 'auditd', - description: 'netfilter protocol', - name: 'auditd.data.family', - type: 'keyword', - }, - 'auditd.data.mac': { - category: 'auditd', - description: 'crypto MAC algorithm selected', - name: 'auditd.data.mac', - type: 'keyword', - }, - 'auditd.data.pfs': { - category: 'auditd', - description: 'perfect forward secrecy method', - name: 'auditd.data.pfs', - type: 'keyword', - }, - 'auditd.data.items': { - category: 'auditd', - description: 'the number of path records in the event', - name: 'auditd.data.items', - type: 'keyword', - }, - 'auditd.data.a0': { - category: 'auditd', - description: '', - name: 'auditd.data.a0', - type: 'keyword', - }, - 'auditd.data.a1': { - category: 'auditd', - description: '', - name: 'auditd.data.a1', - type: 'keyword', - }, - 'auditd.data.a2': { - category: 'auditd', - description: '', - name: 'auditd.data.a2', - type: 'keyword', - }, - 'auditd.data.a3': { - category: 'auditd', - description: '', - name: 'auditd.data.a3', - type: 'keyword', - }, - 'auditd.data.hostname': { - category: 'auditd', - description: 'the hostname that the user is connecting from', - name: 'auditd.data.hostname', - type: 'keyword', - }, - 'auditd.data.lport': { - category: 'auditd', - description: 'local network port', - name: 'auditd.data.lport', - type: 'keyword', - }, - 'auditd.data.rport': { - category: 'auditd', - description: 'remote port number', - name: 'auditd.data.rport', - type: 'keyword', - }, - 'auditd.data.exit': { - category: 'auditd', - description: 'syscall exit code', - name: 'auditd.data.exit', - type: 'keyword', - }, - 'auditd.data.fp': { - category: 'auditd', - description: 'crypto key finger print', - name: 'auditd.data.fp', - type: 'keyword', - }, - 'auditd.data.laddr': { - category: 'auditd', - description: 'local network address', - name: 'auditd.data.laddr', - type: 'keyword', - }, - 'auditd.data.sport': { - category: 'auditd', - description: 'local port number', - name: 'auditd.data.sport', - type: 'keyword', - }, - 'auditd.data.capability': { - category: 'auditd', - description: 'posix capabilities', - name: 'auditd.data.capability', - type: 'keyword', - }, - 'auditd.data.nargs': { - category: 'auditd', - description: 'the number of arguments to a socket call', - name: 'auditd.data.nargs', - type: 'keyword', - }, - 'auditd.data.new-enabled': { - category: 'auditd', - description: 'new TTY audit enabled setting', - name: 'auditd.data.new-enabled', - type: 'keyword', - }, - 'auditd.data.audit_backlog_limit': { - category: 'auditd', - description: "audit system's backlog queue size", - name: 'auditd.data.audit_backlog_limit', - type: 'keyword', - }, - 'auditd.data.dir': { - category: 'auditd', - description: 'directory name', - name: 'auditd.data.dir', - type: 'keyword', - }, - 'auditd.data.cap_pe': { - category: 'auditd', - description: 'process effective capability map', - name: 'auditd.data.cap_pe', - type: 'keyword', - }, - 'auditd.data.model': { - category: 'auditd', - description: 'security model being used for virt', - name: 'auditd.data.model', - type: 'keyword', - }, - 'auditd.data.new_pp': { - category: 'auditd', - description: 'new process permitted capability map', - name: 'auditd.data.new_pp', - type: 'keyword', - }, - 'auditd.data.old-enabled': { - category: 'auditd', - description: 'present TTY audit enabled setting', - name: 'auditd.data.old-enabled', - type: 'keyword', - }, - 'auditd.data.oauid': { - category: 'auditd', - description: "object's login user ID", - name: 'auditd.data.oauid', - type: 'keyword', - }, - 'auditd.data.old': { - category: 'auditd', - description: 'old value', - name: 'auditd.data.old', - type: 'keyword', - }, - 'auditd.data.banners': { - category: 'auditd', - description: 'banners used on printed page', - name: 'auditd.data.banners', - type: 'keyword', - }, - 'auditd.data.feature': { - category: 'auditd', - description: 'kernel feature being changed', - name: 'auditd.data.feature', - type: 'keyword', - }, - 'auditd.data.vm-ctx': { - category: 'auditd', - description: "the vm's context string", - name: 'auditd.data.vm-ctx', - type: 'keyword', - }, - 'auditd.data.opid': { - category: 'auditd', - description: "object's process ID", - name: 'auditd.data.opid', - type: 'keyword', - }, - 'auditd.data.seperms': { - category: 'auditd', - description: 'SELinux permissions being used', - name: 'auditd.data.seperms', - type: 'keyword', - }, - 'auditd.data.seresult': { - category: 'auditd', - description: 'SELinux AVC decision granted/denied', - name: 'auditd.data.seresult', - type: 'keyword', - }, - 'auditd.data.new-rng': { - category: 'auditd', - description: 'device name of rng being added from a vm', - name: 'auditd.data.new-rng', - type: 'keyword', - }, - 'auditd.data.old-net': { - category: 'auditd', - description: 'present MAC address assigned to vm', - name: 'auditd.data.old-net', - type: 'keyword', - }, - 'auditd.data.sigev_signo': { - category: 'auditd', - description: 'signal number', - name: 'auditd.data.sigev_signo', - type: 'keyword', - }, - 'auditd.data.ino': { - category: 'auditd', - description: 'inode number', - name: 'auditd.data.ino', - type: 'keyword', - }, - 'auditd.data.old_enforcing': { - category: 'auditd', - description: 'old MAC enforcement status', - name: 'auditd.data.old_enforcing', - type: 'keyword', - }, - 'auditd.data.old-vcpu': { - category: 'auditd', - description: 'present number of CPU cores', - name: 'auditd.data.old-vcpu', - type: 'keyword', - }, - 'auditd.data.range': { - category: 'auditd', - description: "user's SE Linux range", - name: 'auditd.data.range', - type: 'keyword', - }, - 'auditd.data.res': { - category: 'auditd', - description: 'result of the audited operation(success/fail)', - name: 'auditd.data.res', - type: 'keyword', - }, - 'auditd.data.added': { - category: 'auditd', - description: 'number of new files detected', - name: 'auditd.data.added', - type: 'keyword', - }, - 'auditd.data.fam': { - category: 'auditd', - description: 'socket address family', - name: 'auditd.data.fam', - type: 'keyword', - }, - 'auditd.data.nlnk-pid': { - category: 'auditd', - description: 'pid of netlink packet sender', - name: 'auditd.data.nlnk-pid', - type: 'keyword', - }, - 'auditd.data.subj': { - category: 'auditd', - description: "lspp subject's context string", - name: 'auditd.data.subj', - type: 'keyword', - }, - 'auditd.data.a[0-3]': { - category: 'auditd', - description: 'the arguments to a syscall', - name: 'auditd.data.a[0-3]', - type: 'keyword', - }, - 'auditd.data.cgroup': { - category: 'auditd', - description: 'path to cgroup in sysfs', - name: 'auditd.data.cgroup', - type: 'keyword', - }, - 'auditd.data.kernel': { - category: 'auditd', - description: "kernel's version number", - name: 'auditd.data.kernel', - type: 'keyword', - }, - 'auditd.data.ocomm': { - category: 'auditd', - description: "object's command line name", - name: 'auditd.data.ocomm', - type: 'keyword', - }, - 'auditd.data.new-net': { - category: 'auditd', - description: 'MAC address being assigned to vm', - name: 'auditd.data.new-net', - type: 'keyword', - }, - 'auditd.data.permissive': { - category: 'auditd', - description: 'SELinux is in permissive mode', - name: 'auditd.data.permissive', - type: 'keyword', - }, - 'auditd.data.class': { - category: 'auditd', - description: 'resource class assigned to vm', - name: 'auditd.data.class', - type: 'keyword', - }, - 'auditd.data.compat': { - category: 'auditd', - description: 'is_compat_task result', - name: 'auditd.data.compat', - type: 'keyword', - }, - 'auditd.data.fi': { - category: 'auditd', - description: 'file assigned inherited capability map', - name: 'auditd.data.fi', - type: 'keyword', - }, - 'auditd.data.changed': { - category: 'auditd', - description: 'number of changed files', - name: 'auditd.data.changed', - type: 'keyword', - }, - 'auditd.data.msg': { - category: 'auditd', - description: 'the payload of the audit record', - name: 'auditd.data.msg', - type: 'keyword', - }, - 'auditd.data.dport': { - category: 'auditd', - description: 'remote port number', - name: 'auditd.data.dport', - type: 'keyword', - }, - 'auditd.data.new-seuser': { - category: 'auditd', - description: 'new SELinux user', - name: 'auditd.data.new-seuser', - type: 'keyword', - }, - 'auditd.data.invalid_context': { - category: 'auditd', - description: 'SELinux context', - name: 'auditd.data.invalid_context', - type: 'keyword', - }, - 'auditd.data.dmac': { - category: 'auditd', - description: 'remote MAC address', - name: 'auditd.data.dmac', - type: 'keyword', - }, - 'auditd.data.ipx-net': { - category: 'auditd', - description: 'IPX network number', - name: 'auditd.data.ipx-net', - type: 'keyword', - }, - 'auditd.data.iuid': { - category: 'auditd', - description: "ipc object's user ID", - name: 'auditd.data.iuid', - type: 'keyword', - }, - 'auditd.data.macproto': { - category: 'auditd', - description: 'ethernet packet type ID field', - name: 'auditd.data.macproto', - type: 'keyword', - }, - 'auditd.data.obj': { - category: 'auditd', - description: 'lspp object context string', - name: 'auditd.data.obj', - type: 'keyword', - }, - 'auditd.data.ipid': { - category: 'auditd', - description: 'IP datagram fragment identifier', - name: 'auditd.data.ipid', - type: 'keyword', - }, - 'auditd.data.new-fs': { - category: 'auditd', - description: 'file system being added to vm', - name: 'auditd.data.new-fs', - type: 'keyword', - }, - 'auditd.data.vm-pid': { - category: 'auditd', - description: "vm's process ID", - name: 'auditd.data.vm-pid', - type: 'keyword', - }, - 'auditd.data.cap_pi': { - category: 'auditd', - description: 'process inherited capability map', - name: 'auditd.data.cap_pi', - type: 'keyword', - }, - 'auditd.data.old-auid': { - category: 'auditd', - description: 'previous auid value', - name: 'auditd.data.old-auid', - type: 'keyword', - }, - 'auditd.data.oses': { - category: 'auditd', - description: "object's session ID", - name: 'auditd.data.oses', - type: 'keyword', - }, - 'auditd.data.fd': { - category: 'auditd', - description: 'file descriptor number', - name: 'auditd.data.fd', - type: 'keyword', - }, - 'auditd.data.igid': { - category: 'auditd', - description: "ipc object's group ID", - name: 'auditd.data.igid', - type: 'keyword', - }, - 'auditd.data.new-disk': { - category: 'auditd', - description: 'disk being added to vm', - name: 'auditd.data.new-disk', - type: 'keyword', - }, - 'auditd.data.parent': { - category: 'auditd', - description: 'the inode number of the parent file', - name: 'auditd.data.parent', - type: 'keyword', - }, - 'auditd.data.len': { - category: 'auditd', - description: 'length', - name: 'auditd.data.len', - type: 'keyword', - }, - 'auditd.data.oflag': { - category: 'auditd', - description: 'open syscall flags', - name: 'auditd.data.oflag', - type: 'keyword', - }, - 'auditd.data.uuid': { - category: 'auditd', - description: 'a UUID', - name: 'auditd.data.uuid', - type: 'keyword', - }, - 'auditd.data.code': { - category: 'auditd', - description: 'seccomp action code', - name: 'auditd.data.code', - type: 'keyword', - }, - 'auditd.data.nlnk-grp': { - category: 'auditd', - description: 'netlink group number', - name: 'auditd.data.nlnk-grp', - type: 'keyword', - }, - 'auditd.data.cap_fp': { - category: 'auditd', - description: 'file permitted capability map', - name: 'auditd.data.cap_fp', - type: 'keyword', - }, - 'auditd.data.new-mem': { - category: 'auditd', - description: 'new amount of memory in KB', - name: 'auditd.data.new-mem', - type: 'keyword', - }, - 'auditd.data.seperm': { - category: 'auditd', - description: 'SELinux permission being decided on', - name: 'auditd.data.seperm', - type: 'keyword', - }, - 'auditd.data.enforcing': { - category: 'auditd', - description: 'new MAC enforcement status', - name: 'auditd.data.enforcing', - type: 'keyword', - }, - 'auditd.data.new-chardev': { - category: 'auditd', - description: 'new character device being assigned to vm', - name: 'auditd.data.new-chardev', - type: 'keyword', - }, - 'auditd.data.old-rng': { - category: 'auditd', - description: 'device name of rng being removed from a vm', - name: 'auditd.data.old-rng', - type: 'keyword', - }, - 'auditd.data.outif': { - category: 'auditd', - description: 'out interface number', - name: 'auditd.data.outif', - type: 'keyword', - }, - 'auditd.data.cmd': { - category: 'auditd', - description: 'command being executed', - name: 'auditd.data.cmd', - type: 'keyword', - }, - 'auditd.data.hook': { - category: 'auditd', - description: 'netfilter hook that packet came from', - name: 'auditd.data.hook', - type: 'keyword', - }, - 'auditd.data.new-level': { - category: 'auditd', - description: 'new run level', - name: 'auditd.data.new-level', - type: 'keyword', - }, - 'auditd.data.sauid': { - category: 'auditd', - description: 'sent login user ID', - name: 'auditd.data.sauid', - type: 'keyword', - }, - 'auditd.data.sig': { - category: 'auditd', - description: 'signal number', - name: 'auditd.data.sig', - type: 'keyword', - }, - 'auditd.data.audit_backlog_wait_time': { - category: 'auditd', - description: "audit system's backlog wait time", - name: 'auditd.data.audit_backlog_wait_time', - type: 'keyword', - }, - 'auditd.data.printer': { - category: 'auditd', - description: 'printer name', - name: 'auditd.data.printer', - type: 'keyword', - }, - 'auditd.data.old-mem': { - category: 'auditd', - description: 'present amount of memory in KB', - name: 'auditd.data.old-mem', - type: 'keyword', - }, - 'auditd.data.perm': { - category: 'auditd', - description: 'the file permission being used', - name: 'auditd.data.perm', - type: 'keyword', - }, - 'auditd.data.old_pi': { - category: 'auditd', - description: 'old process inherited capability map', - name: 'auditd.data.old_pi', - type: 'keyword', - }, - 'auditd.data.state': { - category: 'auditd', - description: 'audit daemon configuration resulting state', - name: 'auditd.data.state', - type: 'keyword', - }, - 'auditd.data.format': { - category: 'auditd', - description: "audit log's format", - name: 'auditd.data.format', - type: 'keyword', - }, - 'auditd.data.new_gid': { - category: 'auditd', - description: 'new group ID being assigned', - name: 'auditd.data.new_gid', - type: 'keyword', - }, - 'auditd.data.tcontext': { - category: 'auditd', - description: "the target's or object's context string", - name: 'auditd.data.tcontext', - type: 'keyword', - }, - 'auditd.data.maj': { - category: 'auditd', - description: 'device major number', - name: 'auditd.data.maj', - type: 'keyword', - }, - 'auditd.data.watch': { - category: 'auditd', - description: 'file name in a watch record', - name: 'auditd.data.watch', - type: 'keyword', - }, - 'auditd.data.device': { - category: 'auditd', - description: 'device name', - name: 'auditd.data.device', - type: 'keyword', - }, - 'auditd.data.grp': { - category: 'auditd', - description: 'group name', - name: 'auditd.data.grp', - type: 'keyword', - }, - 'auditd.data.bool': { - category: 'auditd', - description: 'name of SELinux boolean', - name: 'auditd.data.bool', - type: 'keyword', - }, - 'auditd.data.icmp_type': { - category: 'auditd', - description: 'type of icmp message', - name: 'auditd.data.icmp_type', - type: 'keyword', - }, - 'auditd.data.new_lock': { - category: 'auditd', - description: 'new value of feature lock', - name: 'auditd.data.new_lock', - type: 'keyword', - }, - 'auditd.data.old_prom': { - category: 'auditd', - description: 'network promiscuity flag', - name: 'auditd.data.old_prom', - type: 'keyword', - }, - 'auditd.data.acl': { - category: 'auditd', - description: 'access mode of resource assigned to vm', - name: 'auditd.data.acl', - type: 'keyword', - }, - 'auditd.data.ip': { - category: 'auditd', - description: 'network address of a printer', - name: 'auditd.data.ip', - type: 'keyword', - }, - 'auditd.data.new_pi': { - category: 'auditd', - description: 'new process inherited capability map', - name: 'auditd.data.new_pi', - type: 'keyword', - }, - 'auditd.data.default-context': { - category: 'auditd', - description: 'default MAC context', - name: 'auditd.data.default-context', - type: 'keyword', - }, - 'auditd.data.inode_gid': { - category: 'auditd', - description: "group ID of the inode's owner", - name: 'auditd.data.inode_gid', - type: 'keyword', - }, - 'auditd.data.new-log_passwd': { - category: 'auditd', - description: 'new value for TTY password logging', - name: 'auditd.data.new-log_passwd', - type: 'keyword', - }, - 'auditd.data.new_pe': { - category: 'auditd', - description: 'new process effective capability map', - name: 'auditd.data.new_pe', - type: 'keyword', - }, - 'auditd.data.selected-context': { - category: 'auditd', - description: 'new MAC context assigned to session', - name: 'auditd.data.selected-context', - type: 'keyword', - }, - 'auditd.data.cap_fver': { - category: 'auditd', - description: 'file system capabilities version number', - name: 'auditd.data.cap_fver', - type: 'keyword', - }, - 'auditd.data.file': { - category: 'auditd', - description: 'file name', - name: 'auditd.data.file', - type: 'keyword', - }, - 'auditd.data.net': { - category: 'auditd', - description: 'network MAC address', - name: 'auditd.data.net', - type: 'keyword', - }, - 'auditd.data.virt': { - category: 'auditd', - description: 'kind of virtualization being referenced', - name: 'auditd.data.virt', - type: 'keyword', - }, - 'auditd.data.cap_pp': { - category: 'auditd', - description: 'process permitted capability map', - name: 'auditd.data.cap_pp', - type: 'keyword', - }, - 'auditd.data.old-range': { - category: 'auditd', - description: 'present SELinux range', - name: 'auditd.data.old-range', - type: 'keyword', - }, - 'auditd.data.resrc': { - category: 'auditd', - description: 'resource being assigned', - name: 'auditd.data.resrc', - type: 'keyword', - }, - 'auditd.data.new-range': { - category: 'auditd', - description: 'new SELinux range', - name: 'auditd.data.new-range', - type: 'keyword', - }, - 'auditd.data.obj_gid': { - category: 'auditd', - description: 'group ID of object', - name: 'auditd.data.obj_gid', - type: 'keyword', - }, - 'auditd.data.proto': { - category: 'auditd', - description: 'network protocol', - name: 'auditd.data.proto', - type: 'keyword', - }, - 'auditd.data.old-disk': { - category: 'auditd', - description: 'disk being removed from vm', - name: 'auditd.data.old-disk', - type: 'keyword', - }, - 'auditd.data.audit_failure': { - category: 'auditd', - description: "audit system's failure mode", - name: 'auditd.data.audit_failure', - type: 'keyword', - }, - 'auditd.data.inif': { - category: 'auditd', - description: 'in interface number', - name: 'auditd.data.inif', - type: 'keyword', - }, - 'auditd.data.vm': { - category: 'auditd', - description: 'virtual machine name', - name: 'auditd.data.vm', - type: 'keyword', - }, - 'auditd.data.flags': { - category: 'auditd', - description: 'mmap syscall flags', - name: 'auditd.data.flags', - type: 'keyword', - }, - 'auditd.data.nlnk-fam': { - category: 'auditd', - description: 'netlink protocol number', - name: 'auditd.data.nlnk-fam', - type: 'keyword', - }, - 'auditd.data.old-fs': { - category: 'auditd', - description: 'file system being removed from vm', - name: 'auditd.data.old-fs', - type: 'keyword', - }, - 'auditd.data.old-ses': { - category: 'auditd', - description: 'previous ses value', - name: 'auditd.data.old-ses', - type: 'keyword', - }, - 'auditd.data.seqno': { - category: 'auditd', - description: 'sequence number', - name: 'auditd.data.seqno', - type: 'keyword', - }, - 'auditd.data.fver': { - category: 'auditd', - description: 'file system capabilities version number', - name: 'auditd.data.fver', - type: 'keyword', - }, - 'auditd.data.qbytes': { - category: 'auditd', - description: 'ipc objects quantity of bytes', - name: 'auditd.data.qbytes', - type: 'keyword', - }, - 'auditd.data.seuser': { - category: 'auditd', - description: "user's SE Linux user acct", - name: 'auditd.data.seuser', - type: 'keyword', - }, - 'auditd.data.cap_fe': { - category: 'auditd', - description: 'file assigned effective capability map', - name: 'auditd.data.cap_fe', - type: 'keyword', - }, - 'auditd.data.new-vcpu': { - category: 'auditd', - description: 'new number of CPU cores', - name: 'auditd.data.new-vcpu', - type: 'keyword', - }, - 'auditd.data.old-level': { - category: 'auditd', - description: 'old run level', - name: 'auditd.data.old-level', - type: 'keyword', - }, - 'auditd.data.old_pp': { - category: 'auditd', - description: 'old process permitted capability map', - name: 'auditd.data.old_pp', - type: 'keyword', - }, - 'auditd.data.daddr': { - category: 'auditd', - description: 'remote IP address', - name: 'auditd.data.daddr', - type: 'keyword', - }, - 'auditd.data.old-role': { - category: 'auditd', - description: 'present SELinux role', - name: 'auditd.data.old-role', - type: 'keyword', - }, - 'auditd.data.ioctlcmd': { - category: 'auditd', - description: 'The request argument to the ioctl syscall', - name: 'auditd.data.ioctlcmd', - type: 'keyword', - }, - 'auditd.data.smac': { - category: 'auditd', - description: 'local MAC address', - name: 'auditd.data.smac', - type: 'keyword', - }, - 'auditd.data.apparmor': { - category: 'auditd', - description: 'apparmor event information', - name: 'auditd.data.apparmor', - type: 'keyword', - }, - 'auditd.data.fe': { - category: 'auditd', - description: 'file assigned effective capability map', - name: 'auditd.data.fe', - type: 'keyword', - }, - 'auditd.data.perm_mask': { - category: 'auditd', - description: 'file permission mask that triggered a watch event', - name: 'auditd.data.perm_mask', - type: 'keyword', - }, - 'auditd.data.ses': { - category: 'auditd', - description: 'login session ID', - name: 'auditd.data.ses', - type: 'keyword', - }, - 'auditd.data.cap_fi': { - category: 'auditd', - description: 'file inherited capability map', - name: 'auditd.data.cap_fi', - type: 'keyword', - }, - 'auditd.data.obj_uid': { - category: 'auditd', - description: 'user ID of object', - name: 'auditd.data.obj_uid', - type: 'keyword', - }, - 'auditd.data.reason': { - category: 'auditd', - description: 'text string denoting a reason for the action', - name: 'auditd.data.reason', - type: 'keyword', - }, - 'auditd.data.list': { - category: 'auditd', - description: "the audit system's filter list number", - name: 'auditd.data.list', - type: 'keyword', - }, - 'auditd.data.old_lock': { - category: 'auditd', - description: 'present value of feature lock', - name: 'auditd.data.old_lock', - type: 'keyword', - }, - 'auditd.data.bus': { - category: 'auditd', - description: 'name of subsystem bus a vm resource belongs to', - name: 'auditd.data.bus', - type: 'keyword', - }, - 'auditd.data.old_pe': { - category: 'auditd', - description: 'old process effective capability map', - name: 'auditd.data.old_pe', - type: 'keyword', - }, - 'auditd.data.new-role': { - category: 'auditd', - description: 'new SELinux role', - name: 'auditd.data.new-role', - type: 'keyword', - }, - 'auditd.data.prom': { - category: 'auditd', - description: 'network promiscuity flag', - name: 'auditd.data.prom', - type: 'keyword', - }, - 'auditd.data.uri': { - category: 'auditd', - description: 'URI pointing to a printer', - name: 'auditd.data.uri', - type: 'keyword', - }, - 'auditd.data.audit_enabled': { - category: 'auditd', - description: "audit systems's enable/disable status", - name: 'auditd.data.audit_enabled', - type: 'keyword', - }, - 'auditd.data.old-log_passwd': { - category: 'auditd', - description: 'present value for TTY password logging', - name: 'auditd.data.old-log_passwd', - type: 'keyword', - }, - 'auditd.data.old-seuser': { - category: 'auditd', - description: 'present SELinux user', - name: 'auditd.data.old-seuser', - type: 'keyword', - }, - 'auditd.data.per': { - category: 'auditd', - description: 'linux personality', - name: 'auditd.data.per', - type: 'keyword', - }, - 'auditd.data.scontext': { - category: 'auditd', - description: "the subject's context string", - name: 'auditd.data.scontext', - type: 'keyword', - }, - 'auditd.data.tclass': { - category: 'auditd', - description: "target's object classification", - name: 'auditd.data.tclass', - type: 'keyword', - }, - 'auditd.data.ver': { - category: 'auditd', - description: "audit daemon's version number", - name: 'auditd.data.ver', - type: 'keyword', - }, - 'auditd.data.new': { - category: 'auditd', - description: 'value being set in feature', - name: 'auditd.data.new', - type: 'keyword', - }, - 'auditd.data.val': { - category: 'auditd', - description: 'generic value associated with the operation', - name: 'auditd.data.val', - type: 'keyword', - }, - 'auditd.data.img-ctx': { - category: 'auditd', - description: "the vm's disk image context string", - name: 'auditd.data.img-ctx', - type: 'keyword', - }, - 'auditd.data.old-chardev': { - category: 'auditd', - description: 'present character device assigned to vm', - name: 'auditd.data.old-chardev', - type: 'keyword', - }, - 'auditd.data.old_val': { - category: 'auditd', - description: 'current value of SELinux boolean', - name: 'auditd.data.old_val', - type: 'keyword', - }, - 'auditd.data.success': { - category: 'auditd', - description: 'whether the syscall was successful or not', - name: 'auditd.data.success', - type: 'keyword', - }, - 'auditd.data.inode_uid': { - category: 'auditd', - description: "user ID of the inode's owner", - name: 'auditd.data.inode_uid', - type: 'keyword', - }, - 'auditd.data.removed': { - category: 'auditd', - description: 'number of deleted files', - name: 'auditd.data.removed', - type: 'keyword', - }, - 'auditd.data.socket.port': { - category: 'auditd', - description: 'The port number.', - name: 'auditd.data.socket.port', - type: 'keyword', - }, - 'auditd.data.socket.saddr': { - category: 'auditd', - description: 'The raw socket address structure.', - name: 'auditd.data.socket.saddr', - type: 'keyword', - }, - 'auditd.data.socket.addr': { - category: 'auditd', - description: 'The remote address.', - name: 'auditd.data.socket.addr', - type: 'keyword', - }, - 'auditd.data.socket.family': { - category: 'auditd', - description: 'The socket family (unix, ipv4, ipv6, netlink).', - example: 'unix', - name: 'auditd.data.socket.family', - type: 'keyword', - }, - 'auditd.data.socket.path': { - category: 'auditd', - description: 'This is the path associated with a unix socket.', - name: 'auditd.data.socket.path', - type: 'keyword', - }, - 'auditd.messages': { - category: 'auditd', - description: - 'An ordered list of the raw messages received from the kernel that were used to construct this document. This field is present if an error occurred processing the data or if `include_raw_message` is set in the config. ', - name: 'auditd.messages', - type: 'alias', - }, - 'auditd.warnings': { - category: 'auditd', - description: - 'The warnings generated by the Beat during the construction of the event. These are disabled by default and are used for development and debug purposes only. ', - name: 'auditd.warnings', - type: 'alias', - }, - 'geoip.continent_name': { - category: 'geoip', - description: 'The name of the continent. ', - name: 'geoip.continent_name', - type: 'keyword', - }, - 'geoip.city_name': { - category: 'geoip', - description: 'The name of the city. ', - name: 'geoip.city_name', - type: 'keyword', - }, - 'geoip.region_name': { - category: 'geoip', - description: 'The name of the region. ', - name: 'geoip.region_name', - type: 'keyword', - }, - 'geoip.country_iso_code': { - category: 'geoip', - description: 'Country ISO code. ', - name: 'geoip.country_iso_code', - type: 'keyword', - }, - 'geoip.location': { - category: 'geoip', - description: 'The longitude and latitude. ', - name: 'geoip.location', - type: 'geo_point', - }, - 'hash.blake2b_256': { - category: 'hash', - description: 'BLAKE2b-256 hash of the file.', - name: 'hash.blake2b_256', - type: 'keyword', - }, - 'hash.blake2b_384': { - category: 'hash', - description: 'BLAKE2b-384 hash of the file.', - name: 'hash.blake2b_384', - type: 'keyword', - }, - 'hash.blake2b_512': { - category: 'hash', - description: 'BLAKE2b-512 hash of the file.', - name: 'hash.blake2b_512', - type: 'keyword', - }, - 'hash.sha224': { - category: 'hash', - description: 'SHA224 hash of the file.', - name: 'hash.sha224', - type: 'keyword', - }, - 'hash.sha384': { - category: 'hash', - description: 'SHA384 hash of the file.', - name: 'hash.sha384', - type: 'keyword', - }, - 'hash.sha3_224': { - category: 'hash', - description: 'SHA3_224 hash of the file.', - name: 'hash.sha3_224', - type: 'keyword', - }, - 'hash.sha3_256': { - category: 'hash', - description: 'SHA3_256 hash of the file.', - name: 'hash.sha3_256', - type: 'keyword', - }, - 'hash.sha3_384': { - category: 'hash', - description: 'SHA3_384 hash of the file.', - name: 'hash.sha3_384', - type: 'keyword', - }, - 'hash.sha3_512': { - category: 'hash', - description: 'SHA3_512 hash of the file.', - name: 'hash.sha3_512', - type: 'keyword', - }, - 'hash.sha512_224': { - category: 'hash', - description: 'SHA512/224 hash of the file.', - name: 'hash.sha512_224', - type: 'keyword', - }, - 'hash.sha512_256': { - category: 'hash', - description: 'SHA512/256 hash of the file.', - name: 'hash.sha512_256', - type: 'keyword', - }, - 'hash.xxh64': { - category: 'hash', - description: 'XX64 hash of the file.', - name: 'hash.xxh64', - type: 'keyword', - }, - 'event.origin': { - category: 'event', - description: - 'Origin of the event. This can be a file path (e.g. `/var/log/log.1`), or the name of the system component that supplied the data (e.g. `netlink`). ', - name: 'event.origin', - type: 'keyword', - }, - 'user.entity_id': { - category: 'user', - description: - 'ID uniquely identifying the user on a host. It is computed as a SHA-256 hash of the host ID, user ID, and user name. ', - name: 'user.entity_id', - type: 'keyword', - }, - 'user.terminal': { - category: 'user', - description: 'Terminal of the user. ', - name: 'user.terminal', - type: 'keyword', - }, - 'process.hash.blake2b_256': { - category: 'process', - description: 'BLAKE2b-256 hash of the executable.', - name: 'process.hash.blake2b_256', - type: 'keyword', - }, - 'process.hash.blake2b_384': { - category: 'process', - description: 'BLAKE2b-384 hash of the executable.', - name: 'process.hash.blake2b_384', - type: 'keyword', - }, - 'process.hash.blake2b_512': { - category: 'process', - description: 'BLAKE2b-512 hash of the executable.', - name: 'process.hash.blake2b_512', - type: 'keyword', - }, - 'process.hash.sha224': { - category: 'process', - description: 'SHA224 hash of the executable.', - name: 'process.hash.sha224', - type: 'keyword', - }, - 'process.hash.sha384': { - category: 'process', - description: 'SHA384 hash of the executable.', - name: 'process.hash.sha384', - type: 'keyword', - }, - 'process.hash.sha3_224': { - category: 'process', - description: 'SHA3_224 hash of the executable.', - name: 'process.hash.sha3_224', - type: 'keyword', - }, - 'process.hash.sha3_256': { - category: 'process', - description: 'SHA3_256 hash of the executable.', - name: 'process.hash.sha3_256', - type: 'keyword', - }, - 'process.hash.sha3_384': { - category: 'process', - description: 'SHA3_384 hash of the executable.', - name: 'process.hash.sha3_384', - type: 'keyword', - }, - 'process.hash.sha3_512': { - category: 'process', - description: 'SHA3_512 hash of the executable.', - name: 'process.hash.sha3_512', - type: 'keyword', - }, - 'process.hash.sha512_224': { - category: 'process', - description: 'SHA512/224 hash of the executable.', - name: 'process.hash.sha512_224', - type: 'keyword', - }, - 'process.hash.sha512_256': { - category: 'process', - description: 'SHA512/256 hash of the executable.', - name: 'process.hash.sha512_256', - type: 'keyword', - }, - 'process.hash.xxh64': { - category: 'process', - description: 'XX64 hash of the executable.', - name: 'process.hash.xxh64', - type: 'keyword', - }, - 'socket.entity_id': { - category: 'socket', - description: - 'ID uniquely identifying the socket. It is computed as a SHA-256 hash of the host ID, socket inode, local IP, local port, remote IP, and remote port. ', - name: 'socket.entity_id', - type: 'keyword', - }, - 'system.audit.host.uptime': { - category: 'system', - description: 'Uptime in nanoseconds. ', - name: 'system.audit.host.uptime', - type: 'long', - format: 'duration', - }, - 'system.audit.host.boottime': { - category: 'system', - description: 'Boot time. ', - name: 'system.audit.host.boottime', - type: 'date', - }, - 'system.audit.host.containerized': { - category: 'system', - description: 'Set if host is a container. ', - name: 'system.audit.host.containerized', - type: 'boolean', - }, - 'system.audit.host.timezone.name': { - category: 'system', - description: 'Name of the timezone of the host, e.g. BST. ', - name: 'system.audit.host.timezone.name', - type: 'keyword', - }, - 'system.audit.host.timezone.offset.sec': { - category: 'system', - description: 'Timezone offset in seconds. ', - name: 'system.audit.host.timezone.offset.sec', - type: 'long', - }, - 'system.audit.host.hostname': { - category: 'system', - description: 'Hostname. ', - name: 'system.audit.host.hostname', - type: 'keyword', - }, - 'system.audit.host.id': { - category: 'system', - description: 'Host ID. ', - name: 'system.audit.host.id', - type: 'keyword', - }, - 'system.audit.host.architecture': { - category: 'system', - description: 'Host architecture (e.g. x86_64). ', - name: 'system.audit.host.architecture', - type: 'keyword', - }, - 'system.audit.host.mac': { - category: 'system', - description: 'MAC addresses. ', - name: 'system.audit.host.mac', - type: 'keyword', - }, - 'system.audit.host.ip': { - category: 'system', - description: 'IP addresses. ', - name: 'system.audit.host.ip', - type: 'ip', - }, - 'system.audit.host.os.codename': { - category: 'system', - description: 'OS codename, if any (e.g. stretch). ', - name: 'system.audit.host.os.codename', - type: 'keyword', - }, - 'system.audit.host.os.platform': { - category: 'system', - description: 'OS platform (e.g. centos, ubuntu, windows). ', - name: 'system.audit.host.os.platform', - type: 'keyword', - }, - 'system.audit.host.os.name': { - category: 'system', - description: 'OS name (e.g. Mac OS X). ', - name: 'system.audit.host.os.name', - type: 'keyword', - }, - 'system.audit.host.os.family': { - category: 'system', - description: 'OS family (e.g. redhat, debian, freebsd, windows). ', - name: 'system.audit.host.os.family', - type: 'keyword', - }, - 'system.audit.host.os.version': { - category: 'system', - description: 'OS version. ', - name: 'system.audit.host.os.version', - type: 'keyword', - }, - 'system.audit.host.os.kernel': { - category: 'system', - description: "The operating system's kernel version. ", - name: 'system.audit.host.os.kernel', - type: 'keyword', - }, - 'system.audit.host.os.type': { - category: 'system', - description: 'OS type (see ECS os.type). ', - name: 'system.audit.host.os.type', - type: 'keyword', - }, - 'system.audit.package.entity_id': { - category: 'system', - description: - 'ID uniquely identifying the package. It is computed as a SHA-256 hash of the host ID, package name, and package version. ', - name: 'system.audit.package.entity_id', - type: 'keyword', - }, - 'system.audit.package.name': { - category: 'system', - description: 'Package name. ', - name: 'system.audit.package.name', - type: 'keyword', - }, - 'system.audit.package.version': { - category: 'system', - description: 'Package version. ', - name: 'system.audit.package.version', - type: 'keyword', - }, - 'system.audit.package.release': { - category: 'system', - description: 'Package release. ', - name: 'system.audit.package.release', - type: 'keyword', - }, - 'system.audit.package.arch': { - category: 'system', - description: 'Package architecture. ', - name: 'system.audit.package.arch', - type: 'keyword', - }, - 'system.audit.package.license': { - category: 'system', - description: 'Package license. ', - name: 'system.audit.package.license', - type: 'keyword', - }, - 'system.audit.package.installtime': { - category: 'system', - description: 'Package install time. ', - name: 'system.audit.package.installtime', - type: 'date', - }, - 'system.audit.package.size': { - category: 'system', - description: 'Package size. ', - name: 'system.audit.package.size', - type: 'long', - }, - 'system.audit.package.summary': { - category: 'system', - description: 'Package summary. ', - name: 'system.audit.package.summary', - }, - 'system.audit.package.url': { - category: 'system', - description: 'Package URL. ', - name: 'system.audit.package.url', - type: 'keyword', - }, - 'system.audit.user.name': { - category: 'system', - description: 'User name. ', - name: 'system.audit.user.name', - type: 'keyword', - }, - 'system.audit.user.uid': { - category: 'system', - description: 'User ID. ', - name: 'system.audit.user.uid', - type: 'keyword', - }, - 'system.audit.user.gid': { - category: 'system', - description: 'Group ID. ', - name: 'system.audit.user.gid', - type: 'keyword', - }, - 'system.audit.user.dir': { - category: 'system', - description: "User's home directory. ", - name: 'system.audit.user.dir', - type: 'keyword', - }, - 'system.audit.user.shell': { - category: 'system', - description: 'Program to run at login. ', - name: 'system.audit.user.shell', - type: 'keyword', - }, - 'system.audit.user.user_information': { - category: 'system', - description: 'General user information. On Linux, this is the gecos field. ', - name: 'system.audit.user.user_information', - type: 'keyword', - }, - 'system.audit.user.group.name': { - category: 'system', - description: 'Group name. ', - name: 'system.audit.user.group.name', - type: 'keyword', - }, - 'system.audit.user.group.gid': { - category: 'system', - description: 'Group ID. ', - name: 'system.audit.user.group.gid', - type: 'integer', - }, - 'system.audit.user.password.type': { - category: 'system', - description: - "A user's password type. Possible values are `shadow_password` (the password hash is in the shadow file), `password_disabled`, `no_password` (this is dangerous as anyone can log in), and `crypt_password` (when the password field in /etc/passwd seems to contain an encrypted password). ", - name: 'system.audit.user.password.type', - type: 'keyword', - }, - 'system.audit.user.password.last_changed': { - category: 'system', - description: "The day the user's password was last changed. ", - name: 'system.audit.user.password.last_changed', - type: 'date', - }, - 'log.source.address': { - category: 'log', - description: 'Source address from which the log event was read / sent from. ', - name: 'log.source.address', - type: 'keyword', - }, - 'log.offset': { - category: 'log', - description: 'The file offset the reported line starts at. ', - name: 'log.offset', - type: 'long', - }, - stream: { - category: 'base', - description: "Log stream when reading container logs, can be 'stdout' or 'stderr' ", - name: 'stream', - type: 'keyword', - }, - 'input.type': { - category: 'input', - description: - 'The input type from which the event was generated. This field is set to the value specified for the `type` option in the input section of the Filebeat config file. ', - name: 'input.type', - }, - 'syslog.facility': { - category: 'syslog', - description: 'The facility extracted from the priority. ', - name: 'syslog.facility', - type: 'long', - }, - 'syslog.priority': { - category: 'syslog', - description: 'The priority of the syslog event. ', - name: 'syslog.priority', - type: 'long', - }, - 'syslog.severity_label': { - category: 'syslog', - description: 'The human readable severity. ', - name: 'syslog.severity_label', - type: 'keyword', - }, - 'syslog.facility_label': { - category: 'syslog', - description: 'The human readable facility. ', - name: 'syslog.facility_label', - type: 'keyword', - }, - 'process.program': { - category: 'process', - description: 'The name of the program. ', - name: 'process.program', - type: 'keyword', - }, - 'log.flags': { - category: 'log', - description: 'This field contains the flags of the event. ', - name: 'log.flags', - }, - 'http.response.content_length': { - category: 'http', - name: 'http.response.content_length', - type: 'alias', - }, - 'user_agent.os.full_name': { - category: 'user_agent', - name: 'user_agent.os.full_name', - type: 'keyword', - }, - 'fileset.name': { - category: 'fileset', - description: 'The Filebeat fileset that generated this event. ', - name: 'fileset.name', - type: 'keyword', - }, - 'fileset.module': { - category: 'fileset', - name: 'fileset.module', - type: 'alias', - }, - read_timestamp: { - category: 'base', - name: 'read_timestamp', - type: 'alias', - }, - 'docker.attrs': { - category: 'docker', - description: - "docker.attrs contains labels and environment variables written by docker's JSON File logging driver. These fields are only available when they are configured in the logging driver options. ", - name: 'docker.attrs', - type: 'object', - }, - 'icmp.code': { - category: 'icmp', - description: 'ICMP code. ', - name: 'icmp.code', - type: 'keyword', - }, - 'icmp.type': { - category: 'icmp', - description: 'ICMP type. ', - name: 'icmp.type', - type: 'keyword', - }, - 'igmp.type': { - category: 'igmp', - description: 'IGMP type. ', - name: 'igmp.type', - type: 'keyword', - }, - 'azure.eventhub': { - category: 'azure', - description: 'Name of the eventhub. ', - name: 'azure.eventhub', - type: 'keyword', - }, - 'azure.offset': { - category: 'azure', - description: 'The offset. ', - name: 'azure.offset', - type: 'long', - }, - 'azure.enqueued_time': { - category: 'azure', - description: 'The enqueued time. ', - name: 'azure.enqueued_time', - type: 'date', - }, - 'azure.partition_id': { - category: 'azure', - description: 'The partition id. ', - name: 'azure.partition_id', - type: 'long', - }, - 'azure.consumer_group': { - category: 'azure', - description: 'The consumer group. ', - name: 'azure.consumer_group', - type: 'keyword', - }, - 'azure.sequence_number': { - category: 'azure', - description: 'The sequence number. ', - name: 'azure.sequence_number', - type: 'long', - }, - 'kafka.topic': { - category: 'kafka', - description: 'Kafka topic ', - name: 'kafka.topic', - type: 'keyword', - }, - 'kafka.partition': { - category: 'kafka', - description: 'Kafka partition number ', - name: 'kafka.partition', - type: 'long', - }, - 'kafka.offset': { - category: 'kafka', - description: 'Kafka offset of this message ', - name: 'kafka.offset', - type: 'long', - }, - 'kafka.key': { - category: 'kafka', - description: 'Kafka key, corresponding to the Kafka value stored in the message ', - name: 'kafka.key', - type: 'keyword', - }, - 'kafka.block_timestamp': { - category: 'kafka', - description: 'Kafka outer (compressed) block timestamp ', - name: 'kafka.block_timestamp', - type: 'date', - }, - 'kafka.headers': { - category: 'kafka', - description: - 'An array of Kafka header strings for this message, in the form ": ". ', - name: 'kafka.headers', - type: 'array', - }, - 'apache2.access.remote_ip': { - category: 'apache2', - name: 'apache2.access.remote_ip', - type: 'alias', - }, - 'apache2.access.ssl.protocol': { - category: 'apache2', - name: 'apache2.access.ssl.protocol', - type: 'alias', - }, - 'apache2.access.ssl.cipher': { - category: 'apache2', - name: 'apache2.access.ssl.cipher', - type: 'alias', - }, - 'apache2.access.body_sent.bytes': { - category: 'apache2', - name: 'apache2.access.body_sent.bytes', - type: 'alias', - }, - 'apache2.access.user_name': { - category: 'apache2', - name: 'apache2.access.user_name', - type: 'alias', - }, - 'apache2.access.method': { - category: 'apache2', - name: 'apache2.access.method', - type: 'alias', - }, - 'apache2.access.url': { - category: 'apache2', - name: 'apache2.access.url', - type: 'alias', - }, - 'apache2.access.http_version': { - category: 'apache2', - name: 'apache2.access.http_version', - type: 'alias', - }, - 'apache2.access.response_code': { - category: 'apache2', - name: 'apache2.access.response_code', - type: 'alias', - }, - 'apache2.access.referrer': { - category: 'apache2', - name: 'apache2.access.referrer', - type: 'alias', - }, - 'apache2.access.agent': { - category: 'apache2', - name: 'apache2.access.agent', - type: 'alias', - }, - 'apache2.access.user_agent.device': { - category: 'apache2', - name: 'apache2.access.user_agent.device', - type: 'alias', - }, - 'apache2.access.user_agent.name': { - category: 'apache2', - name: 'apache2.access.user_agent.name', - type: 'alias', - }, - 'apache2.access.user_agent.os': { - category: 'apache2', - name: 'apache2.access.user_agent.os', - type: 'alias', - }, - 'apache2.access.user_agent.os_name': { - category: 'apache2', - name: 'apache2.access.user_agent.os_name', - type: 'alias', - }, - 'apache2.access.user_agent.original': { - category: 'apache2', - name: 'apache2.access.user_agent.original', - type: 'alias', - }, - 'apache2.access.geoip.continent_name': { - category: 'apache2', - name: 'apache2.access.geoip.continent_name', - type: 'alias', - }, - 'apache2.access.geoip.country_iso_code': { - category: 'apache2', - name: 'apache2.access.geoip.country_iso_code', - type: 'alias', - }, - 'apache2.access.geoip.location': { - category: 'apache2', - name: 'apache2.access.geoip.location', - type: 'alias', - }, - 'apache2.access.geoip.region_name': { - category: 'apache2', - name: 'apache2.access.geoip.region_name', - type: 'alias', - }, - 'apache2.access.geoip.city_name': { - category: 'apache2', - name: 'apache2.access.geoip.city_name', - type: 'alias', - }, - 'apache2.access.geoip.region_iso_code': { - category: 'apache2', - name: 'apache2.access.geoip.region_iso_code', - type: 'alias', - }, - 'apache2.error.level': { - category: 'apache2', - name: 'apache2.error.level', - type: 'alias', - }, - 'apache2.error.message': { - category: 'apache2', - name: 'apache2.error.message', - type: 'alias', - }, - 'apache2.error.pid': { - category: 'apache2', - name: 'apache2.error.pid', - type: 'alias', - }, - 'apache2.error.tid': { - category: 'apache2', - name: 'apache2.error.tid', - type: 'alias', - }, - 'apache2.error.module': { - category: 'apache2', - name: 'apache2.error.module', - type: 'alias', - }, - 'apache.access.ssl.protocol': { - category: 'apache', - description: 'SSL protocol version. ', - name: 'apache.access.ssl.protocol', - type: 'keyword', - }, - 'apache.access.ssl.cipher': { - category: 'apache', - description: 'SSL cipher name. ', - name: 'apache.access.ssl.cipher', - type: 'keyword', - }, - 'apache.error.module': { - category: 'apache', - description: 'The module producing the logged message. ', - name: 'apache.error.module', - type: 'keyword', - }, - 'user.audit.group.id': { - category: 'user', - description: 'Unique identifier for the group on the system/platform. ', - name: 'user.audit.group.id', - type: 'keyword', - }, - 'user.audit.group.name': { - category: 'user', - description: 'Name of the group. ', - name: 'user.audit.group.name', - type: 'keyword', - }, - 'user.owner.id': { - category: 'user', - description: 'One or multiple unique identifiers of the user. ', - name: 'user.owner.id', - type: 'keyword', - }, - 'user.owner.name': { - category: 'user', - description: 'Short name or login of the user. ', - example: 'albert', - name: 'user.owner.name', - type: 'keyword', - }, - 'user.owner.group.id': { - category: 'user', - description: 'Unique identifier for the group on the system/platform. ', - name: 'user.owner.group.id', - type: 'keyword', - }, - 'user.owner.group.name': { - category: 'user', - description: 'Name of the group. ', - name: 'user.owner.group.name', - type: 'keyword', - }, - 'auditd.log.old_auid': { - category: 'auditd', - description: - 'For login events this is the old audit ID used for the user prior to this login. ', - name: 'auditd.log.old_auid', - }, - 'auditd.log.new_auid': { - category: 'auditd', - description: - 'For login events this is the new audit ID. The audit ID can be used to trace future events to the user even if their identity changes (like becoming root). ', - name: 'auditd.log.new_auid', - }, - 'auditd.log.old_ses': { - category: 'auditd', - description: - 'For login events this is the old session ID used for the user prior to this login. ', - name: 'auditd.log.old_ses', - }, - 'auditd.log.new_ses': { - category: 'auditd', - description: - 'For login events this is the new session ID. It can be used to tie a user to future events by session ID. ', - name: 'auditd.log.new_ses', - }, - 'auditd.log.sequence': { - category: 'auditd', - description: 'The audit event sequence number. ', - name: 'auditd.log.sequence', - type: 'long', - }, - 'auditd.log.items': { - category: 'auditd', - description: 'The number of items in an event. ', - name: 'auditd.log.items', - }, - 'auditd.log.item': { - category: 'auditd', - description: - 'The item field indicates which item out of the total number of items. This number is zero-based; a value of 0 means it is the first item. ', - name: 'auditd.log.item', - }, - 'auditd.log.tty': { - category: 'auditd', - name: 'auditd.log.tty', - type: 'keyword', - }, - 'auditd.log.a0': { - category: 'auditd', - description: 'The first argument to the system call. ', - name: 'auditd.log.a0', - }, - 'auditd.log.addr': { - category: 'auditd', - name: 'auditd.log.addr', - type: 'ip', - }, - 'auditd.log.rport': { - category: 'auditd', - name: 'auditd.log.rport', - type: 'long', - }, - 'auditd.log.laddr': { - category: 'auditd', - name: 'auditd.log.laddr', - type: 'ip', - }, - 'auditd.log.lport': { - category: 'auditd', - name: 'auditd.log.lport', - type: 'long', - }, - 'auditd.log.acct': { - category: 'auditd', - name: 'auditd.log.acct', - type: 'alias', - }, - 'auditd.log.pid': { - category: 'auditd', - name: 'auditd.log.pid', - type: 'alias', - }, - 'auditd.log.ppid': { - category: 'auditd', - name: 'auditd.log.ppid', - type: 'alias', - }, - 'auditd.log.res': { - category: 'auditd', - name: 'auditd.log.res', - type: 'alias', - }, - 'auditd.log.record_type': { - category: 'auditd', - name: 'auditd.log.record_type', - type: 'alias', - }, - 'auditd.log.geoip.continent_name': { - category: 'auditd', - name: 'auditd.log.geoip.continent_name', - type: 'alias', - }, - 'auditd.log.geoip.country_iso_code': { - category: 'auditd', - name: 'auditd.log.geoip.country_iso_code', - type: 'alias', - }, - 'auditd.log.geoip.location': { - category: 'auditd', - name: 'auditd.log.geoip.location', - type: 'alias', - }, - 'auditd.log.geoip.region_name': { - category: 'auditd', - name: 'auditd.log.geoip.region_name', - type: 'alias', - }, - 'auditd.log.geoip.city_name': { - category: 'auditd', - name: 'auditd.log.geoip.city_name', - type: 'alias', - }, - 'auditd.log.geoip.region_iso_code': { - category: 'auditd', - name: 'auditd.log.geoip.region_iso_code', - type: 'alias', - }, - 'auditd.log.arch': { - category: 'auditd', - name: 'auditd.log.arch', - type: 'alias', - }, - 'auditd.log.gid': { - category: 'auditd', - name: 'auditd.log.gid', - type: 'alias', - }, - 'auditd.log.uid': { - category: 'auditd', - name: 'auditd.log.uid', - type: 'alias', - }, - 'auditd.log.agid': { - category: 'auditd', - name: 'auditd.log.agid', - type: 'alias', - }, - 'auditd.log.auid': { - category: 'auditd', - name: 'auditd.log.auid', - type: 'alias', - }, - 'auditd.log.fsgid': { - category: 'auditd', - name: 'auditd.log.fsgid', - type: 'alias', - }, - 'auditd.log.fsuid': { - category: 'auditd', - name: 'auditd.log.fsuid', - type: 'alias', - }, - 'auditd.log.egid': { - category: 'auditd', - name: 'auditd.log.egid', - type: 'alias', - }, - 'auditd.log.euid': { - category: 'auditd', - name: 'auditd.log.euid', - type: 'alias', - }, - 'auditd.log.sgid': { - category: 'auditd', - name: 'auditd.log.sgid', - type: 'alias', - }, - 'auditd.log.suid': { - category: 'auditd', - name: 'auditd.log.suid', - type: 'alias', - }, - 'auditd.log.ogid': { - category: 'auditd', - name: 'auditd.log.ogid', - type: 'alias', - }, - 'auditd.log.ouid': { - category: 'auditd', - name: 'auditd.log.ouid', - type: 'alias', - }, - 'auditd.log.comm': { - category: 'auditd', - name: 'auditd.log.comm', - type: 'alias', - }, - 'auditd.log.exe': { - category: 'auditd', - name: 'auditd.log.exe', - type: 'alias', - }, - 'auditd.log.terminal': { - category: 'auditd', - name: 'auditd.log.terminal', - type: 'alias', - }, - 'auditd.log.msg': { - category: 'auditd', - name: 'auditd.log.msg', - type: 'alias', - }, - 'auditd.log.src': { - category: 'auditd', - name: 'auditd.log.src', - type: 'alias', - }, - 'auditd.log.dst': { - category: 'auditd', - name: 'auditd.log.dst', - type: 'alias', - }, - 'elasticsearch.component': { - category: 'elasticsearch', - description: 'Elasticsearch component from where the log event originated', - example: 'o.e.c.m.MetaDataCreateIndexService', - name: 'elasticsearch.component', - type: 'keyword', - }, - 'elasticsearch.cluster.uuid': { - category: 'elasticsearch', - description: 'UUID of the cluster', - example: 'GmvrbHlNTiSVYiPf8kxg9g', - name: 'elasticsearch.cluster.uuid', - type: 'keyword', - }, - 'elasticsearch.cluster.name': { - category: 'elasticsearch', - description: 'Name of the cluster', - example: 'docker-cluster', - name: 'elasticsearch.cluster.name', - type: 'keyword', - }, - 'elasticsearch.node.id': { - category: 'elasticsearch', - description: 'ID of the node', - example: 'DSiWcTyeThWtUXLB9J0BMw', - name: 'elasticsearch.node.id', - type: 'keyword', - }, - 'elasticsearch.node.name': { - category: 'elasticsearch', - description: 'Name of the node', - example: 'vWNJsZ3', - name: 'elasticsearch.node.name', - type: 'keyword', - }, - 'elasticsearch.index.name': { - category: 'elasticsearch', - description: 'Index name', - example: 'filebeat-test-input', - name: 'elasticsearch.index.name', - type: 'keyword', - }, - 'elasticsearch.index.id': { - category: 'elasticsearch', - description: 'Index id', - example: 'aOGgDwbURfCV57AScqbCgw', - name: 'elasticsearch.index.id', - type: 'keyword', - }, - 'elasticsearch.shard.id': { - category: 'elasticsearch', - description: 'Id of the shard', - example: '0', - name: 'elasticsearch.shard.id', - type: 'keyword', - }, - 'elasticsearch.audit.layer': { - category: 'elasticsearch', - description: 'The layer from which this event originated: rest, transport or ip_filter', - example: 'rest', - name: 'elasticsearch.audit.layer', - type: 'keyword', - }, - 'elasticsearch.audit.event_type': { - category: 'elasticsearch', - description: - 'The type of event that occurred: anonymous_access_denied, authentication_failed, access_denied, access_granted, connection_granted, connection_denied, tampered_request, run_as_granted, run_as_denied', - example: 'access_granted', - name: 'elasticsearch.audit.event_type', - type: 'keyword', - }, - 'elasticsearch.audit.origin.type': { - category: 'elasticsearch', - description: - 'Where the request originated: rest (request originated from a REST API request), transport (request was received on the transport channel), local_node (the local node issued the request)', - example: 'local_node', - name: 'elasticsearch.audit.origin.type', - type: 'keyword', - }, - 'elasticsearch.audit.realm': { - category: 'elasticsearch', - description: 'The authentication realm the authentication was validated against', - name: 'elasticsearch.audit.realm', - type: 'keyword', - }, - 'elasticsearch.audit.user.realm': { - category: 'elasticsearch', - description: "The user's authentication realm, if authenticated", - name: 'elasticsearch.audit.user.realm', - type: 'keyword', - }, - 'elasticsearch.audit.user.roles': { - category: 'elasticsearch', - description: 'Roles to which the principal belongs', - example: '["kibana_admin","beats_admin"]', - name: 'elasticsearch.audit.user.roles', - type: 'keyword', - }, - 'elasticsearch.audit.user.run_as.name': { - category: 'elasticsearch', - name: 'elasticsearch.audit.user.run_as.name', - type: 'keyword', - }, - 'elasticsearch.audit.user.run_as.realm': { - category: 'elasticsearch', - name: 'elasticsearch.audit.user.run_as.realm', - type: 'keyword', - }, - 'elasticsearch.audit.component': { - category: 'elasticsearch', - name: 'elasticsearch.audit.component', - type: 'keyword', - }, - 'elasticsearch.audit.action': { - category: 'elasticsearch', - description: 'The name of the action that was executed', - example: 'cluster:monitor/main', - name: 'elasticsearch.audit.action', - type: 'keyword', - }, - 'elasticsearch.audit.url.params': { - category: 'elasticsearch', - description: 'REST URI parameters', - example: '{username=jacknich2}', - name: 'elasticsearch.audit.url.params', - }, - 'elasticsearch.audit.indices': { - category: 'elasticsearch', - description: 'Indices accessed by action', - example: '["foo-2019.01.04","foo-2019.01.03","foo-2019.01.06"]', - name: 'elasticsearch.audit.indices', - type: 'keyword', - }, - 'elasticsearch.audit.request.id': { - category: 'elasticsearch', - description: 'Unique ID of request', - example: 'WzL_kb6VSvOhAq0twPvHOQ', - name: 'elasticsearch.audit.request.id', - type: 'keyword', - }, - 'elasticsearch.audit.request.name': { - category: 'elasticsearch', - description: 'The type of request that was executed', - example: 'ClearScrollRequest', - name: 'elasticsearch.audit.request.name', - type: 'keyword', - }, - 'elasticsearch.audit.request_body': { - category: 'elasticsearch', - name: 'elasticsearch.audit.request_body', - type: 'alias', - }, - 'elasticsearch.audit.origin_address': { - category: 'elasticsearch', - name: 'elasticsearch.audit.origin_address', - type: 'alias', - }, - 'elasticsearch.audit.uri': { - category: 'elasticsearch', - name: 'elasticsearch.audit.uri', - type: 'alias', - }, - 'elasticsearch.audit.principal': { - category: 'elasticsearch', - name: 'elasticsearch.audit.principal', - type: 'alias', - }, - 'elasticsearch.audit.message': { - category: 'elasticsearch', - name: 'elasticsearch.audit.message', - type: 'text', - }, - 'elasticsearch.audit.invalidate.apikeys.owned_by_authenticated_user': { - category: 'elasticsearch', - name: 'elasticsearch.audit.invalidate.apikeys.owned_by_authenticated_user', - type: 'boolean', - }, - 'elasticsearch.deprecation': { - category: 'elasticsearch', - description: '', - name: 'elasticsearch.deprecation', - type: 'group', - }, - 'elasticsearch.gc.phase.name': { - category: 'elasticsearch', - description: 'Name of the GC collection phase. ', - name: 'elasticsearch.gc.phase.name', - type: 'keyword', - }, - 'elasticsearch.gc.phase.duration_sec': { - category: 'elasticsearch', - description: 'Collection phase duration according to the Java virtual machine. ', - name: 'elasticsearch.gc.phase.duration_sec', - type: 'float', - }, - 'elasticsearch.gc.phase.scrub_symbol_table_time_sec': { - category: 'elasticsearch', - description: 'Pause time in seconds cleaning up symbol tables. ', - name: 'elasticsearch.gc.phase.scrub_symbol_table_time_sec', - type: 'float', - }, - 'elasticsearch.gc.phase.scrub_string_table_time_sec': { - category: 'elasticsearch', - description: 'Pause time in seconds cleaning up string tables. ', - name: 'elasticsearch.gc.phase.scrub_string_table_time_sec', - type: 'float', - }, - 'elasticsearch.gc.phase.weak_refs_processing_time_sec': { - category: 'elasticsearch', - description: 'Time spent processing weak references in seconds. ', - name: 'elasticsearch.gc.phase.weak_refs_processing_time_sec', - type: 'float', - }, - 'elasticsearch.gc.phase.parallel_rescan_time_sec': { - category: 'elasticsearch', - description: 'Time spent in seconds marking live objects while application is stopped. ', - name: 'elasticsearch.gc.phase.parallel_rescan_time_sec', - type: 'float', - }, - 'elasticsearch.gc.phase.class_unload_time_sec': { - category: 'elasticsearch', - description: 'Time spent unloading unused classes in seconds. ', - name: 'elasticsearch.gc.phase.class_unload_time_sec', - type: 'float', - }, - 'elasticsearch.gc.phase.cpu_time.user_sec': { - category: 'elasticsearch', - description: 'CPU time spent outside the kernel. ', - name: 'elasticsearch.gc.phase.cpu_time.user_sec', - type: 'float', - }, - 'elasticsearch.gc.phase.cpu_time.sys_sec': { - category: 'elasticsearch', - description: 'CPU time spent inside the kernel. ', - name: 'elasticsearch.gc.phase.cpu_time.sys_sec', - type: 'float', - }, - 'elasticsearch.gc.phase.cpu_time.real_sec': { - category: 'elasticsearch', - description: 'Total elapsed CPU time spent to complete the collection from start to finish. ', - name: 'elasticsearch.gc.phase.cpu_time.real_sec', - type: 'float', - }, - 'elasticsearch.gc.jvm_runtime_sec': { - category: 'elasticsearch', - description: 'The time from JVM start up in seconds, as a floating point number. ', - name: 'elasticsearch.gc.jvm_runtime_sec', - type: 'float', - }, - 'elasticsearch.gc.threads_total_stop_time_sec': { - category: 'elasticsearch', - description: 'Garbage collection threads total stop time seconds. ', - name: 'elasticsearch.gc.threads_total_stop_time_sec', - type: 'float', - }, - 'elasticsearch.gc.stopping_threads_time_sec': { - category: 'elasticsearch', - description: 'Time took to stop threads seconds. ', - name: 'elasticsearch.gc.stopping_threads_time_sec', - type: 'float', - }, - 'elasticsearch.gc.tags': { - category: 'elasticsearch', - description: 'GC logging tags. ', - name: 'elasticsearch.gc.tags', - type: 'keyword', - }, - 'elasticsearch.gc.heap.size_kb': { - category: 'elasticsearch', - description: 'Total heap size in kilobytes. ', - name: 'elasticsearch.gc.heap.size_kb', - type: 'integer', - }, - 'elasticsearch.gc.heap.used_kb': { - category: 'elasticsearch', - description: 'Used heap in kilobytes. ', - name: 'elasticsearch.gc.heap.used_kb', - type: 'integer', - }, - 'elasticsearch.gc.old_gen.size_kb': { - category: 'elasticsearch', - description: 'Total size of old generation in kilobytes. ', - name: 'elasticsearch.gc.old_gen.size_kb', - type: 'integer', - }, - 'elasticsearch.gc.old_gen.used_kb': { - category: 'elasticsearch', - description: 'Old generation occupancy in kilobytes. ', - name: 'elasticsearch.gc.old_gen.used_kb', - type: 'integer', - }, - 'elasticsearch.gc.young_gen.size_kb': { - category: 'elasticsearch', - description: 'Total size of young generation in kilobytes. ', - name: 'elasticsearch.gc.young_gen.size_kb', - type: 'integer', - }, - 'elasticsearch.gc.young_gen.used_kb': { - category: 'elasticsearch', - description: 'Young generation occupancy in kilobytes. ', - name: 'elasticsearch.gc.young_gen.used_kb', - type: 'integer', - }, - 'elasticsearch.server.stacktrace': { - category: 'elasticsearch', - name: 'elasticsearch.server.stacktrace', - }, - 'elasticsearch.server.gc.young.one': { - category: 'elasticsearch', - description: '', - example: '', - name: 'elasticsearch.server.gc.young.one', - type: 'long', - }, - 'elasticsearch.server.gc.young.two': { - category: 'elasticsearch', - description: '', - example: '', - name: 'elasticsearch.server.gc.young.two', - type: 'long', - }, - 'elasticsearch.server.gc.overhead_seq': { - category: 'elasticsearch', - description: 'Sequence number', - example: 3449992, - name: 'elasticsearch.server.gc.overhead_seq', - type: 'long', - }, - 'elasticsearch.server.gc.collection_duration.ms': { - category: 'elasticsearch', - description: 'Time spent in GC, in milliseconds', - example: 1600, - name: 'elasticsearch.server.gc.collection_duration.ms', - type: 'float', - }, - 'elasticsearch.server.gc.observation_duration.ms': { - category: 'elasticsearch', - description: 'Total time over which collection was observed, in milliseconds', - example: 1800, - name: 'elasticsearch.server.gc.observation_duration.ms', - type: 'float', - }, - 'elasticsearch.slowlog.logger': { - category: 'elasticsearch', - description: 'Logger name', - example: 'index.search.slowlog.fetch', - name: 'elasticsearch.slowlog.logger', - type: 'keyword', - }, - 'elasticsearch.slowlog.took': { - category: 'elasticsearch', - description: 'Time it took to execute the query', - example: '300ms', - name: 'elasticsearch.slowlog.took', - type: 'keyword', - }, - 'elasticsearch.slowlog.types': { - category: 'elasticsearch', - description: 'Types', - example: '', - name: 'elasticsearch.slowlog.types', - type: 'keyword', - }, - 'elasticsearch.slowlog.stats': { - category: 'elasticsearch', - description: 'Stats groups', - example: 'group1', - name: 'elasticsearch.slowlog.stats', - type: 'keyword', - }, - 'elasticsearch.slowlog.search_type': { - category: 'elasticsearch', - description: 'Search type', - example: 'QUERY_THEN_FETCH', - name: 'elasticsearch.slowlog.search_type', - type: 'keyword', - }, - 'elasticsearch.slowlog.source_query': { - category: 'elasticsearch', - description: 'Slow query', - example: '{"query":{"match_all":{"boost":1.0}}}', - name: 'elasticsearch.slowlog.source_query', - type: 'keyword', - }, - 'elasticsearch.slowlog.extra_source': { - category: 'elasticsearch', - description: 'Extra source information', - example: '', - name: 'elasticsearch.slowlog.extra_source', - type: 'keyword', - }, - 'elasticsearch.slowlog.total_hits': { - category: 'elasticsearch', - description: 'Total hits', - example: 42, - name: 'elasticsearch.slowlog.total_hits', - type: 'keyword', - }, - 'elasticsearch.slowlog.total_shards': { - category: 'elasticsearch', - description: 'Total queried shards', - example: 22, - name: 'elasticsearch.slowlog.total_shards', - type: 'keyword', - }, - 'elasticsearch.slowlog.routing': { - category: 'elasticsearch', - description: 'Routing', - example: 's01HZ2QBk9jw4gtgaFtn', - name: 'elasticsearch.slowlog.routing', - type: 'keyword', - }, - 'elasticsearch.slowlog.id': { - category: 'elasticsearch', - description: 'Id', - example: '', - name: 'elasticsearch.slowlog.id', - type: 'keyword', - }, - 'elasticsearch.slowlog.type': { - category: 'elasticsearch', - description: 'Type', - example: 'doc', - name: 'elasticsearch.slowlog.type', - type: 'keyword', - }, - 'elasticsearch.slowlog.source': { - category: 'elasticsearch', - description: 'Source of document that was indexed', - name: 'elasticsearch.slowlog.source', - type: 'keyword', - }, - 'haproxy.frontend_name': { - category: 'haproxy', - description: 'Name of the frontend (or listener) which received and processed the connection.', - name: 'haproxy.frontend_name', - }, - 'haproxy.backend_name': { - category: 'haproxy', - description: - 'Name of the backend (or listener) which was selected to manage the connection to the server.', - name: 'haproxy.backend_name', - }, - 'haproxy.server_name': { - category: 'haproxy', - description: 'Name of the last server to which the connection was sent.', - name: 'haproxy.server_name', - }, - 'haproxy.total_waiting_time_ms': { - category: 'haproxy', - description: 'Total time in milliseconds spent waiting in the various queues', - name: 'haproxy.total_waiting_time_ms', - type: 'long', - }, - 'haproxy.connection_wait_time_ms': { - category: 'haproxy', - description: - 'Total time in milliseconds spent waiting for the connection to establish to the final server', - name: 'haproxy.connection_wait_time_ms', - type: 'long', - }, - 'haproxy.bytes_read': { - category: 'haproxy', - description: 'Total number of bytes transmitted to the client when the log is emitted.', - name: 'haproxy.bytes_read', - type: 'long', - }, - 'haproxy.time_queue': { - category: 'haproxy', - description: 'Total time in milliseconds spent waiting in the various queues.', - name: 'haproxy.time_queue', - type: 'long', - }, - 'haproxy.time_backend_connect': { - category: 'haproxy', - description: - 'Total time in milliseconds spent waiting for the connection to establish to the final server, including retries.', - name: 'haproxy.time_backend_connect', - type: 'long', - }, - 'haproxy.server_queue': { - category: 'haproxy', - description: - 'Total number of requests which were processed before this one in the server queue.', - name: 'haproxy.server_queue', - type: 'long', - }, - 'haproxy.backend_queue': { - category: 'haproxy', - description: - "Total number of requests which were processed before this one in the backend's global queue.", - name: 'haproxy.backend_queue', - type: 'long', - }, - 'haproxy.bind_name': { - category: 'haproxy', - description: 'Name of the listening address which received the connection.', - name: 'haproxy.bind_name', - }, - 'haproxy.error_message': { - category: 'haproxy', - description: 'Error message logged by HAProxy in case of error.', - name: 'haproxy.error_message', - type: 'text', - }, - 'haproxy.source': { - category: 'haproxy', - description: 'The HAProxy source of the log', - name: 'haproxy.source', - type: 'keyword', - }, - 'haproxy.termination_state': { - category: 'haproxy', - description: 'Condition the session was in when the session ended.', - name: 'haproxy.termination_state', - }, - 'haproxy.mode': { - category: 'haproxy', - description: 'mode that the frontend is operating (TCP or HTTP)', - name: 'haproxy.mode', - type: 'keyword', - }, - 'haproxy.connections.active': { - category: 'haproxy', - description: - 'Total number of concurrent connections on the process when the session was logged.', - name: 'haproxy.connections.active', - type: 'long', - }, - 'haproxy.connections.frontend': { - category: 'haproxy', - description: - 'Total number of concurrent connections on the frontend when the session was logged.', - name: 'haproxy.connections.frontend', - type: 'long', - }, - 'haproxy.connections.backend': { - category: 'haproxy', - description: - 'Total number of concurrent connections handled by the backend when the session was logged.', - name: 'haproxy.connections.backend', - type: 'long', - }, - 'haproxy.connections.server': { - category: 'haproxy', - description: - 'Total number of concurrent connections still active on the server when the session was logged.', - name: 'haproxy.connections.server', - type: 'long', - }, - 'haproxy.connections.retries': { - category: 'haproxy', - description: - 'Number of connection retries experienced by this session when trying to connect to the server.', - name: 'haproxy.connections.retries', - type: 'long', - }, - 'haproxy.client.ip': { - category: 'haproxy', - name: 'haproxy.client.ip', - type: 'alias', - }, - 'haproxy.client.port': { - category: 'haproxy', - name: 'haproxy.client.port', - type: 'alias', - }, - 'haproxy.process_name': { - category: 'haproxy', - name: 'haproxy.process_name', - type: 'alias', - }, - 'haproxy.pid': { - category: 'haproxy', - name: 'haproxy.pid', - type: 'alias', - }, - 'haproxy.destination.port': { - category: 'haproxy', - name: 'haproxy.destination.port', - type: 'alias', - }, - 'haproxy.destination.ip': { - category: 'haproxy', - name: 'haproxy.destination.ip', - type: 'alias', - }, - 'haproxy.geoip.continent_name': { - category: 'haproxy', - name: 'haproxy.geoip.continent_name', - type: 'alias', - }, - 'haproxy.geoip.country_iso_code': { - category: 'haproxy', - name: 'haproxy.geoip.country_iso_code', - type: 'alias', - }, - 'haproxy.geoip.location': { - category: 'haproxy', - name: 'haproxy.geoip.location', - type: 'alias', - }, - 'haproxy.geoip.region_name': { - category: 'haproxy', - name: 'haproxy.geoip.region_name', - type: 'alias', - }, - 'haproxy.geoip.city_name': { - category: 'haproxy', - name: 'haproxy.geoip.city_name', - type: 'alias', - }, - 'haproxy.geoip.region_iso_code': { - category: 'haproxy', - name: 'haproxy.geoip.region_iso_code', - type: 'alias', - }, - 'haproxy.http.response.captured_cookie': { - category: 'haproxy', - description: - 'Optional "name=value" entry indicating that the client had this cookie in the response. ', - name: 'haproxy.http.response.captured_cookie', - }, - 'haproxy.http.response.captured_headers': { - category: 'haproxy', - description: - 'List of headers captured in the response due to the presence of the "capture response header" statement in the frontend. ', - name: 'haproxy.http.response.captured_headers', - type: 'keyword', - }, - 'haproxy.http.response.status_code': { - category: 'haproxy', - name: 'haproxy.http.response.status_code', - type: 'alias', - }, - 'haproxy.http.request.captured_cookie': { - category: 'haproxy', - description: - 'Optional "name=value" entry indicating that the server has returned a cookie with its request. ', - name: 'haproxy.http.request.captured_cookie', - }, - 'haproxy.http.request.captured_headers': { - category: 'haproxy', - description: - 'List of headers captured in the request due to the presence of the "capture request header" statement in the frontend. ', - name: 'haproxy.http.request.captured_headers', - type: 'keyword', - }, - 'haproxy.http.request.raw_request_line': { - category: 'haproxy', - description: - 'Complete HTTP request line, including the method, request and HTTP version string.', - name: 'haproxy.http.request.raw_request_line', - type: 'keyword', - }, - 'haproxy.http.request.time_wait_without_data_ms': { - category: 'haproxy', - description: - 'Total time in milliseconds spent waiting for the server to send a full HTTP response, not counting data.', - name: 'haproxy.http.request.time_wait_without_data_ms', - type: 'long', - }, - 'haproxy.http.request.time_wait_ms': { - category: 'haproxy', - description: - 'Total time in milliseconds spent waiting for a full HTTP request from the client (not counting body) after the first byte was received.', - name: 'haproxy.http.request.time_wait_ms', - type: 'long', - }, - 'haproxy.tcp.connection_waiting_time_ms': { - category: 'haproxy', - description: 'Total time in milliseconds elapsed between the accept and the last close', - name: 'haproxy.tcp.connection_waiting_time_ms', - type: 'long', - }, - 'icinga.debug.facility': { - category: 'icinga', - description: 'Specifies what component of Icinga logged the message. ', - name: 'icinga.debug.facility', - type: 'keyword', - }, - 'icinga.debug.severity': { - category: 'icinga', - name: 'icinga.debug.severity', - type: 'alias', - }, - 'icinga.debug.message': { - category: 'icinga', - name: 'icinga.debug.message', - type: 'alias', - }, - 'icinga.main.facility': { - category: 'icinga', - description: 'Specifies what component of Icinga logged the message. ', - name: 'icinga.main.facility', - type: 'keyword', - }, - 'icinga.main.severity': { - category: 'icinga', - name: 'icinga.main.severity', - type: 'alias', - }, - 'icinga.main.message': { - category: 'icinga', - name: 'icinga.main.message', - type: 'alias', - }, - 'icinga.startup.facility': { - category: 'icinga', - description: 'Specifies what component of Icinga logged the message. ', - name: 'icinga.startup.facility', - type: 'keyword', - }, - 'icinga.startup.severity': { - category: 'icinga', - name: 'icinga.startup.severity', - type: 'alias', - }, - 'icinga.startup.message': { - category: 'icinga', - name: 'icinga.startup.message', - type: 'alias', - }, - 'iis.access.sub_status': { - category: 'iis', - description: 'The HTTP substatus code. ', - name: 'iis.access.sub_status', - type: 'long', - }, - 'iis.access.win32_status': { - category: 'iis', - description: 'The Windows status code. ', - name: 'iis.access.win32_status', - type: 'long', - }, - 'iis.access.site_name': { - category: 'iis', - description: 'The site name and instance number. ', - name: 'iis.access.site_name', - type: 'keyword', - }, - 'iis.access.server_name': { - category: 'iis', - description: 'The name of the server on which the log file entry was generated. ', - name: 'iis.access.server_name', - type: 'keyword', - }, - 'iis.access.cookie': { - category: 'iis', - description: 'The content of the cookie sent or received, if any. ', - name: 'iis.access.cookie', - type: 'keyword', - }, - 'iis.access.body_received.bytes': { - category: 'iis', - name: 'iis.access.body_received.bytes', - type: 'alias', - }, - 'iis.access.body_sent.bytes': { - category: 'iis', - name: 'iis.access.body_sent.bytes', - type: 'alias', - }, - 'iis.access.server_ip': { - category: 'iis', - name: 'iis.access.server_ip', - type: 'alias', - }, - 'iis.access.method': { - category: 'iis', - name: 'iis.access.method', - type: 'alias', - }, - 'iis.access.url': { - category: 'iis', - name: 'iis.access.url', - type: 'alias', - }, - 'iis.access.query_string': { - category: 'iis', - name: 'iis.access.query_string', - type: 'alias', - }, - 'iis.access.port': { - category: 'iis', - name: 'iis.access.port', - type: 'alias', - }, - 'iis.access.user_name': { - category: 'iis', - name: 'iis.access.user_name', - type: 'alias', - }, - 'iis.access.remote_ip': { - category: 'iis', - name: 'iis.access.remote_ip', - type: 'alias', - }, - 'iis.access.referrer': { - category: 'iis', - name: 'iis.access.referrer', - type: 'alias', - }, - 'iis.access.response_code': { - category: 'iis', - name: 'iis.access.response_code', - type: 'alias', - }, - 'iis.access.http_version': { - category: 'iis', - name: 'iis.access.http_version', - type: 'alias', - }, - 'iis.access.hostname': { - category: 'iis', - name: 'iis.access.hostname', - type: 'alias', - }, - 'iis.access.user_agent.device': { - category: 'iis', - name: 'iis.access.user_agent.device', - type: 'alias', - }, - 'iis.access.user_agent.name': { - category: 'iis', - name: 'iis.access.user_agent.name', - type: 'alias', - }, - 'iis.access.user_agent.os': { - category: 'iis', - name: 'iis.access.user_agent.os', - type: 'alias', - }, - 'iis.access.user_agent.os_name': { - category: 'iis', - name: 'iis.access.user_agent.os_name', - type: 'alias', - }, - 'iis.access.user_agent.original': { - category: 'iis', - name: 'iis.access.user_agent.original', - type: 'alias', - }, - 'iis.access.geoip.continent_name': { - category: 'iis', - name: 'iis.access.geoip.continent_name', - type: 'alias', - }, - 'iis.access.geoip.country_iso_code': { - category: 'iis', - name: 'iis.access.geoip.country_iso_code', - type: 'alias', - }, - 'iis.access.geoip.location': { - category: 'iis', - name: 'iis.access.geoip.location', - type: 'alias', - }, - 'iis.access.geoip.region_name': { - category: 'iis', - name: 'iis.access.geoip.region_name', - type: 'alias', - }, - 'iis.access.geoip.city_name': { - category: 'iis', - name: 'iis.access.geoip.city_name', - type: 'alias', - }, - 'iis.access.geoip.region_iso_code': { - category: 'iis', - name: 'iis.access.geoip.region_iso_code', - type: 'alias', - }, - 'iis.error.reason_phrase': { - category: 'iis', - description: 'The HTTP reason phrase. ', - name: 'iis.error.reason_phrase', - type: 'keyword', - }, - 'iis.error.queue_name': { - category: 'iis', - description: 'The IIS application pool name. ', - name: 'iis.error.queue_name', - type: 'keyword', - }, - 'iis.error.remote_ip': { - category: 'iis', - name: 'iis.error.remote_ip', - type: 'alias', - }, - 'iis.error.remote_port': { - category: 'iis', - name: 'iis.error.remote_port', - type: 'alias', - }, - 'iis.error.server_ip': { - category: 'iis', - name: 'iis.error.server_ip', - type: 'alias', - }, - 'iis.error.server_port': { - category: 'iis', - name: 'iis.error.server_port', - type: 'alias', - }, - 'iis.error.http_version': { - category: 'iis', - name: 'iis.error.http_version', - type: 'alias', - }, - 'iis.error.method': { - category: 'iis', - name: 'iis.error.method', - type: 'alias', - }, - 'iis.error.url': { - category: 'iis', - name: 'iis.error.url', - type: 'alias', - }, - 'iis.error.response_code': { - category: 'iis', - name: 'iis.error.response_code', - type: 'alias', - }, - 'iis.error.geoip.continent_name': { - category: 'iis', - name: 'iis.error.geoip.continent_name', - type: 'alias', - }, - 'iis.error.geoip.country_iso_code': { - category: 'iis', - name: 'iis.error.geoip.country_iso_code', - type: 'alias', - }, - 'iis.error.geoip.location': { - category: 'iis', - name: 'iis.error.geoip.location', - type: 'alias', - }, - 'iis.error.geoip.region_name': { - category: 'iis', - name: 'iis.error.geoip.region_name', - type: 'alias', - }, - 'iis.error.geoip.city_name': { - category: 'iis', - name: 'iis.error.geoip.city_name', - type: 'alias', - }, - 'iis.error.geoip.region_iso_code': { - category: 'iis', - name: 'iis.error.geoip.region_iso_code', - type: 'alias', - }, - 'kafka.log.level': { - category: 'kafka', - name: 'kafka.log.level', - type: 'alias', - }, - 'kafka.log.message': { - category: 'kafka', - name: 'kafka.log.message', - type: 'alias', - }, - 'kafka.log.component': { - category: 'kafka', - description: 'Component the log is coming from. ', - name: 'kafka.log.component', - type: 'keyword', - }, - 'kafka.log.class': { - category: 'kafka', - description: 'Java class the log is coming from. ', - name: 'kafka.log.class', - type: 'keyword', - }, - 'kafka.log.thread': { - category: 'kafka', - description: 'Thread name the log is coming from. ', - name: 'kafka.log.thread', - type: 'keyword', - }, - 'kafka.log.trace.class': { - category: 'kafka', - description: 'Java class the trace is coming from. ', - name: 'kafka.log.trace.class', - type: 'keyword', - }, - 'kafka.log.trace.message': { - category: 'kafka', - description: 'Message part of the trace. ', - name: 'kafka.log.trace.message', - type: 'text', - }, - 'kibana.session_id': { - category: 'kibana', - description: - 'The ID of the user session associated with this event. Each login attempt results in a unique session id.', - example: '123e4567-e89b-12d3-a456-426614174000', - name: 'kibana.session_id', - type: 'keyword', - }, - 'kibana.space_id': { - category: 'kibana', - description: 'The id of the space associated with this event.', - example: 'default', - name: 'kibana.space_id', - type: 'keyword', - }, - 'kibana.saved_object.type': { - category: 'kibana', - description: 'The type of the saved object associated with this event.', - example: 'dashboard', - name: 'kibana.saved_object.type', - type: 'keyword', - }, - 'kibana.saved_object.id': { - category: 'kibana', - description: 'The id of the saved object associated with this event.', - example: '6295bdd0-0a0e-11e7-825f-6748cda7d858', - name: 'kibana.saved_object.id', - type: 'keyword', - }, - 'kibana.add_to_spaces': { - category: 'kibana', - description: 'The set of space ids that a saved object was shared to.', - example: "['default', 'marketing']", - name: 'kibana.add_to_spaces', - type: 'keyword', - }, - 'kibana.delete_from_spaces': { - category: 'kibana', - description: 'The set of space ids that a saved object was removed from.', - example: "['default', 'marketing']", - name: 'kibana.delete_from_spaces', - type: 'keyword', - }, - 'kibana.authentication_provider': { - category: 'kibana', - description: 'The authentication provider associated with a login event.', - example: 'basic1', - name: 'kibana.authentication_provider', - type: 'keyword', - }, - 'kibana.authentication_type': { - category: 'kibana', - description: 'The authentication provider type associated with a login event.', - example: 'basic', - name: 'kibana.authentication_type', - type: 'keyword', - }, - 'kibana.authentication_realm': { - category: 'kibana', - description: 'The Elasticsearch authentication realm name which fulfilled a login event.', - example: 'native', - name: 'kibana.authentication_realm', - type: 'keyword', - }, - 'kibana.lookup_realm': { - category: 'kibana', - description: 'The Elasticsearch lookup realm which fulfilled a login event.', - example: 'native', - name: 'kibana.lookup_realm', - type: 'keyword', - }, - 'kibana.log.tags': { - category: 'kibana', - description: 'Kibana logging tags. ', - name: 'kibana.log.tags', - type: 'keyword', - }, - 'kibana.log.state': { - category: 'kibana', - description: 'Current state of Kibana. ', - name: 'kibana.log.state', - type: 'keyword', - }, - 'kibana.log.meta': { - category: 'kibana', - name: 'kibana.log.meta', - type: 'object', - }, - 'kibana.log.kibana.log.meta.req.headers.referer': { - category: 'kibana', - name: 'kibana.log.kibana.log.meta.req.headers.referer', - type: 'alias', - }, - 'kibana.log.kibana.log.meta.req.referer': { - category: 'kibana', - name: 'kibana.log.kibana.log.meta.req.referer', - type: 'alias', - }, - 'kibana.log.kibana.log.meta.req.headers.user-agent': { - category: 'kibana', - name: 'kibana.log.kibana.log.meta.req.headers.user-agent', - type: 'alias', - }, - 'kibana.log.kibana.log.meta.req.remoteAddress': { - category: 'kibana', - name: 'kibana.log.kibana.log.meta.req.remoteAddress', - type: 'alias', - }, - 'kibana.log.kibana.log.meta.req.url': { - category: 'kibana', - name: 'kibana.log.kibana.log.meta.req.url', - type: 'alias', - }, - 'kibana.log.kibana.log.meta.statusCode': { - category: 'kibana', - name: 'kibana.log.kibana.log.meta.statusCode', - type: 'alias', - }, - 'kibana.log.kibana.log.meta.method': { - category: 'kibana', - name: 'kibana.log.kibana.log.meta.method', - type: 'alias', - }, - 'logstash.log.module': { - category: 'logstash', - description: 'The module or class where the event originate. ', - name: 'logstash.log.module', - type: 'keyword', - }, - 'logstash.log.thread': { - category: 'logstash', - description: 'Information about the running thread where the log originate. ', - name: 'logstash.log.thread', - type: 'keyword', - }, - 'logstash.log.log_event': { - category: 'logstash', - description: 'key and value debugging information. ', - name: 'logstash.log.log_event', - type: 'object', - }, - 'logstash.log.log_event.action': { - category: 'logstash', - name: 'logstash.log.log_event.action', - type: 'keyword', - }, - 'logstash.log.pipeline_id': { - category: 'logstash', - description: 'The ID of the pipeline. ', - example: 'main', - name: 'logstash.log.pipeline_id', - type: 'keyword', - }, - 'logstash.log.message': { - category: 'logstash', - name: 'logstash.log.message', - type: 'alias', - }, - 'logstash.log.level': { - category: 'logstash', - name: 'logstash.log.level', - type: 'alias', - }, - 'logstash.slowlog.module': { - category: 'logstash', - description: 'The module or class where the event originate. ', - name: 'logstash.slowlog.module', - type: 'keyword', - }, - 'logstash.slowlog.thread': { - category: 'logstash', - description: 'Information about the running thread where the log originate. ', - name: 'logstash.slowlog.thread', - type: 'keyword', - }, - 'logstash.slowlog.event': { - category: 'logstash', - description: 'Raw dump of the original event ', - name: 'logstash.slowlog.event', - type: 'keyword', - }, - 'logstash.slowlog.plugin_name': { - category: 'logstash', - description: 'Name of the plugin ', - name: 'logstash.slowlog.plugin_name', - type: 'keyword', - }, - 'logstash.slowlog.plugin_type': { - category: 'logstash', - description: 'Type of the plugin: Inputs, Filters, Outputs or Codecs. ', - name: 'logstash.slowlog.plugin_type', - type: 'keyword', - }, - 'logstash.slowlog.took_in_millis': { - category: 'logstash', - description: 'Execution time for the plugin in milliseconds. ', - name: 'logstash.slowlog.took_in_millis', - type: 'long', - }, - 'logstash.slowlog.plugin_params': { - category: 'logstash', - description: 'String value of the plugin configuration ', - name: 'logstash.slowlog.plugin_params', - type: 'keyword', - }, - 'logstash.slowlog.plugin_params_object': { - category: 'logstash', - description: 'key -> value of the configuration used by the plugin. ', - name: 'logstash.slowlog.plugin_params_object', - type: 'object', - }, - 'logstash.slowlog.level': { - category: 'logstash', - name: 'logstash.slowlog.level', - type: 'alias', - }, - 'logstash.slowlog.took_in_nanos': { - category: 'logstash', - name: 'logstash.slowlog.took_in_nanos', - type: 'alias', - }, - 'mongodb.log.component': { - category: 'mongodb', - description: 'Functional categorization of message ', - example: 'COMMAND', - name: 'mongodb.log.component', - type: 'keyword', - }, - 'mongodb.log.context': { - category: 'mongodb', - description: 'Context of message ', - example: 'initandlisten', - name: 'mongodb.log.context', - type: 'keyword', - }, - 'mongodb.log.severity': { - category: 'mongodb', - name: 'mongodb.log.severity', - type: 'alias', - }, - 'mongodb.log.message': { - category: 'mongodb', - name: 'mongodb.log.message', - type: 'alias', - }, - 'mongodb.log.id': { - category: 'mongodb', - description: 'Integer representing the unique identifier of the log statement ', - example: 4615611, - name: 'mongodb.log.id', - type: 'long', - }, - 'mysql.thread_id': { - category: 'mysql', - description: 'The connection or thread ID for the query. ', - name: 'mysql.thread_id', - type: 'long', - }, - 'mysql.error.thread_id': { - category: 'mysql', - name: 'mysql.error.thread_id', - type: 'alias', - }, - 'mysql.error.level': { - category: 'mysql', - name: 'mysql.error.level', - type: 'alias', - }, - 'mysql.error.message': { - category: 'mysql', - name: 'mysql.error.message', - type: 'alias', - }, - 'mysql.slowlog.lock_time.sec': { - category: 'mysql', - description: - 'The amount of time the query waited for the lock to be available. The value is in seconds, as a floating point number. ', - name: 'mysql.slowlog.lock_time.sec', - type: 'float', - }, - 'mysql.slowlog.rows_sent': { - category: 'mysql', - description: 'The number of rows returned by the query. ', - name: 'mysql.slowlog.rows_sent', - type: 'long', - }, - 'mysql.slowlog.rows_examined': { - category: 'mysql', - description: 'The number of rows scanned by the query. ', - name: 'mysql.slowlog.rows_examined', - type: 'long', - }, - 'mysql.slowlog.rows_affected': { - category: 'mysql', - description: 'The number of rows modified by the query. ', - name: 'mysql.slowlog.rows_affected', - type: 'long', - }, - 'mysql.slowlog.bytes_sent': { - category: 'mysql', - description: 'The number of bytes sent to client. ', - name: 'mysql.slowlog.bytes_sent', - type: 'long', - format: 'bytes', - }, - 'mysql.slowlog.bytes_received': { - category: 'mysql', - description: 'The number of bytes received from client. ', - name: 'mysql.slowlog.bytes_received', - type: 'long', - format: 'bytes', - }, - 'mysql.slowlog.query': { - category: 'mysql', - description: 'The slow query. ', - name: 'mysql.slowlog.query', - }, - 'mysql.slowlog.id': { - category: 'mysql', - name: 'mysql.slowlog.id', - type: 'alias', - }, - 'mysql.slowlog.schema': { - category: 'mysql', - description: 'The schema where the slow query was executed. ', - name: 'mysql.slowlog.schema', - type: 'keyword', - }, - 'mysql.slowlog.current_user': { - category: 'mysql', - description: - 'Current authenticated user, used to determine access privileges. Can differ from the value for user. ', - name: 'mysql.slowlog.current_user', - type: 'keyword', - }, - 'mysql.slowlog.last_errno': { - category: 'mysql', - description: 'Last SQL error seen. ', - name: 'mysql.slowlog.last_errno', - type: 'keyword', - }, - 'mysql.slowlog.killed': { - category: 'mysql', - description: 'Code of the reason if the query was killed. ', - name: 'mysql.slowlog.killed', - type: 'keyword', - }, - 'mysql.slowlog.query_cache_hit': { - category: 'mysql', - description: 'Whether the query cache was hit. ', - name: 'mysql.slowlog.query_cache_hit', - type: 'boolean', - }, - 'mysql.slowlog.tmp_table': { - category: 'mysql', - description: 'Whether a temporary table was used to resolve the query. ', - name: 'mysql.slowlog.tmp_table', - type: 'boolean', - }, - 'mysql.slowlog.tmp_table_on_disk': { - category: 'mysql', - description: 'Whether the query needed temporary tables on disk. ', - name: 'mysql.slowlog.tmp_table_on_disk', - type: 'boolean', - }, - 'mysql.slowlog.tmp_tables': { - category: 'mysql', - description: 'Number of temporary tables created for this query ', - name: 'mysql.slowlog.tmp_tables', - type: 'long', - }, - 'mysql.slowlog.tmp_disk_tables': { - category: 'mysql', - description: 'Number of temporary tables created on disk for this query. ', - name: 'mysql.slowlog.tmp_disk_tables', - type: 'long', - }, - 'mysql.slowlog.tmp_table_sizes': { - category: 'mysql', - description: 'Size of temporary tables created for this query.', - name: 'mysql.slowlog.tmp_table_sizes', - type: 'long', - format: 'bytes', - }, - 'mysql.slowlog.filesort': { - category: 'mysql', - description: 'Whether filesort optimization was used. ', - name: 'mysql.slowlog.filesort', - type: 'boolean', - }, - 'mysql.slowlog.filesort_on_disk': { - category: 'mysql', - description: 'Whether filesort optimization was used and it needed temporary tables on disk. ', - name: 'mysql.slowlog.filesort_on_disk', - type: 'boolean', - }, - 'mysql.slowlog.priority_queue': { - category: 'mysql', - description: 'Whether a priority queue was used for filesort. ', - name: 'mysql.slowlog.priority_queue', - type: 'boolean', - }, - 'mysql.slowlog.full_scan': { - category: 'mysql', - description: 'Whether a full table scan was needed for the slow query. ', - name: 'mysql.slowlog.full_scan', - type: 'boolean', - }, - 'mysql.slowlog.full_join': { - category: 'mysql', - description: - 'Whether a full join was needed for the slow query (no indexes were used for joins). ', - name: 'mysql.slowlog.full_join', - type: 'boolean', - }, - 'mysql.slowlog.merge_passes': { - category: 'mysql', - description: 'Number of merge passes executed for the query. ', - name: 'mysql.slowlog.merge_passes', - type: 'long', - }, - 'mysql.slowlog.sort_merge_passes': { - category: 'mysql', - description: 'Number of merge passes that the sort algorithm has had to do. ', - name: 'mysql.slowlog.sort_merge_passes', - type: 'long', - }, - 'mysql.slowlog.sort_range_count': { - category: 'mysql', - description: 'Number of sorts that were done using ranges. ', - name: 'mysql.slowlog.sort_range_count', - type: 'long', - }, - 'mysql.slowlog.sort_rows': { - category: 'mysql', - description: 'Number of sorted rows. ', - name: 'mysql.slowlog.sort_rows', - type: 'long', - }, - 'mysql.slowlog.sort_scan_count': { - category: 'mysql', - description: 'Number of sorts that were done by scanning the table. ', - name: 'mysql.slowlog.sort_scan_count', - type: 'long', - }, - 'mysql.slowlog.log_slow_rate_type': { - category: 'mysql', - description: - 'Type of slow log rate limit, it can be `session` if the rate limit is applied per session, or `query` if it applies per query. ', - name: 'mysql.slowlog.log_slow_rate_type', - type: 'keyword', - }, - 'mysql.slowlog.log_slow_rate_limit': { - category: 'mysql', - description: - 'Slow log rate limit, a value of 100 means that one in a hundred queries or sessions are being logged. ', - name: 'mysql.slowlog.log_slow_rate_limit', - type: 'keyword', - }, - 'mysql.slowlog.read_first': { - category: 'mysql', - description: 'The number of times the first entry in an index was read. ', - name: 'mysql.slowlog.read_first', - type: 'long', - }, - 'mysql.slowlog.read_last': { - category: 'mysql', - description: 'The number of times the last key in an index was read. ', - name: 'mysql.slowlog.read_last', - type: 'long', - }, - 'mysql.slowlog.read_key': { - category: 'mysql', - description: 'The number of requests to read a row based on a key. ', - name: 'mysql.slowlog.read_key', - type: 'long', - }, - 'mysql.slowlog.read_next': { - category: 'mysql', - description: 'The number of requests to read the next row in key order. ', - name: 'mysql.slowlog.read_next', - type: 'long', - }, - 'mysql.slowlog.read_prev': { - category: 'mysql', - description: 'The number of requests to read the previous row in key order. ', - name: 'mysql.slowlog.read_prev', - type: 'long', - }, - 'mysql.slowlog.read_rnd': { - category: 'mysql', - description: 'The number of requests to read a row based on a fixed position. ', - name: 'mysql.slowlog.read_rnd', - type: 'long', - }, - 'mysql.slowlog.read_rnd_next': { - category: 'mysql', - description: 'The number of requests to read the next row in the data file. ', - name: 'mysql.slowlog.read_rnd_next', - type: 'long', - }, - 'mysql.slowlog.innodb.trx_id': { - category: 'mysql', - description: 'Transaction ID ', - name: 'mysql.slowlog.innodb.trx_id', - type: 'keyword', - }, - 'mysql.slowlog.innodb.io_r_ops': { - category: 'mysql', - description: 'Number of page read operations. ', - name: 'mysql.slowlog.innodb.io_r_ops', - type: 'long', - }, - 'mysql.slowlog.innodb.io_r_bytes': { - category: 'mysql', - description: 'Bytes read during page read operations. ', - name: 'mysql.slowlog.innodb.io_r_bytes', - type: 'long', - format: 'bytes', - }, - 'mysql.slowlog.innodb.io_r_wait.sec': { - category: 'mysql', - description: 'How long it took to read all needed data from storage. ', - name: 'mysql.slowlog.innodb.io_r_wait.sec', - type: 'long', - }, - 'mysql.slowlog.innodb.rec_lock_wait.sec': { - category: 'mysql', - description: 'How long the query waited for locks. ', - name: 'mysql.slowlog.innodb.rec_lock_wait.sec', - type: 'long', - }, - 'mysql.slowlog.innodb.queue_wait.sec': { - category: 'mysql', - description: - 'How long the query waited to enter the InnoDB queue and to be executed once in the queue. ', - name: 'mysql.slowlog.innodb.queue_wait.sec', - type: 'long', - }, - 'mysql.slowlog.innodb.pages_distinct': { - category: 'mysql', - description: 'Approximated count of pages accessed to execute the query. ', - name: 'mysql.slowlog.innodb.pages_distinct', - type: 'long', - }, - 'mysql.slowlog.user': { - category: 'mysql', - name: 'mysql.slowlog.user', - type: 'alias', - }, - 'mysql.slowlog.host': { - category: 'mysql', - name: 'mysql.slowlog.host', - type: 'alias', - }, - 'mysql.slowlog.ip': { - category: 'mysql', - name: 'mysql.slowlog.ip', - type: 'alias', - }, - 'nats.log.client.id': { - category: 'nats', - description: 'The id of the client ', - name: 'nats.log.client.id', - type: 'integer', - }, - 'nats.log.msg.bytes': { - category: 'nats', - description: 'Size of the payload in bytes ', - name: 'nats.log.msg.bytes', - type: 'long', - format: 'bytes', - }, - 'nats.log.msg.type': { - category: 'nats', - description: 'The protocol message type ', - name: 'nats.log.msg.type', - type: 'keyword', - }, - 'nats.log.msg.subject': { - category: 'nats', - description: 'Subject name this message was received on ', - name: 'nats.log.msg.subject', - type: 'keyword', - }, - 'nats.log.msg.sid': { - category: 'nats', - description: 'The unique alphanumeric subscription ID of the subject ', - name: 'nats.log.msg.sid', - type: 'integer', - }, - 'nats.log.msg.reply_to': { - category: 'nats', - description: 'The inbox subject on which the publisher is listening for responses ', - name: 'nats.log.msg.reply_to', - type: 'keyword', - }, - 'nats.log.msg.max_messages': { - category: 'nats', - description: 'An optional number of messages to wait for before automatically unsubscribing ', - name: 'nats.log.msg.max_messages', - type: 'integer', - }, - 'nats.log.msg.error.message': { - category: 'nats', - description: 'Details about the error occurred ', - name: 'nats.log.msg.error.message', - type: 'text', - }, - 'nats.log.msg.queue_group': { - category: 'nats', - description: 'The queue group which subscriber will join ', - name: 'nats.log.msg.queue_group', - type: 'text', - }, - 'nginx.access.remote_ip_list': { - category: 'nginx', - description: - 'An array of remote IP addresses. It is a list because it is common to include, besides the client IP address, IP addresses from headers like `X-Forwarded-For`. Real source IP is restored to `source.ip`. ', - name: 'nginx.access.remote_ip_list', - type: 'array', - }, - 'nginx.access.body_sent.bytes': { - category: 'nginx', - name: 'nginx.access.body_sent.bytes', - type: 'alias', - }, - 'nginx.access.user_name': { - category: 'nginx', - name: 'nginx.access.user_name', - type: 'alias', - }, - 'nginx.access.method': { - category: 'nginx', - name: 'nginx.access.method', - type: 'alias', - }, - 'nginx.access.url': { - category: 'nginx', - name: 'nginx.access.url', - type: 'alias', - }, - 'nginx.access.http_version': { - category: 'nginx', - name: 'nginx.access.http_version', - type: 'alias', - }, - 'nginx.access.response_code': { - category: 'nginx', - name: 'nginx.access.response_code', - type: 'alias', - }, - 'nginx.access.referrer': { - category: 'nginx', - name: 'nginx.access.referrer', - type: 'alias', - }, - 'nginx.access.agent': { - category: 'nginx', - name: 'nginx.access.agent', - type: 'alias', - }, - 'nginx.access.user_agent.device': { - category: 'nginx', - name: 'nginx.access.user_agent.device', - type: 'alias', - }, - 'nginx.access.user_agent.name': { - category: 'nginx', - name: 'nginx.access.user_agent.name', - type: 'alias', - }, - 'nginx.access.user_agent.os': { - category: 'nginx', - name: 'nginx.access.user_agent.os', - type: 'alias', - }, - 'nginx.access.user_agent.os_name': { - category: 'nginx', - name: 'nginx.access.user_agent.os_name', - type: 'alias', - }, - 'nginx.access.user_agent.original': { - category: 'nginx', - name: 'nginx.access.user_agent.original', - type: 'alias', - }, - 'nginx.access.geoip.continent_name': { - category: 'nginx', - name: 'nginx.access.geoip.continent_name', - type: 'alias', - }, - 'nginx.access.geoip.country_iso_code': { - category: 'nginx', - name: 'nginx.access.geoip.country_iso_code', - type: 'alias', - }, - 'nginx.access.geoip.location': { - category: 'nginx', - name: 'nginx.access.geoip.location', - type: 'alias', - }, - 'nginx.access.geoip.region_name': { - category: 'nginx', - name: 'nginx.access.geoip.region_name', - type: 'alias', - }, - 'nginx.access.geoip.city_name': { - category: 'nginx', - name: 'nginx.access.geoip.city_name', - type: 'alias', - }, - 'nginx.access.geoip.region_iso_code': { - category: 'nginx', - name: 'nginx.access.geoip.region_iso_code', - type: 'alias', - }, - 'nginx.error.connection_id': { - category: 'nginx', - description: 'Connection identifier. ', - name: 'nginx.error.connection_id', - type: 'long', - }, - 'nginx.error.level': { - category: 'nginx', - name: 'nginx.error.level', - type: 'alias', - }, - 'nginx.error.pid': { - category: 'nginx', - name: 'nginx.error.pid', - type: 'alias', - }, - 'nginx.error.tid': { - category: 'nginx', - name: 'nginx.error.tid', - type: 'alias', - }, - 'nginx.error.message': { - category: 'nginx', - name: 'nginx.error.message', - type: 'alias', - }, - 'nginx.ingress_controller.remote_ip_list': { - category: 'nginx', - description: - 'An array of remote IP addresses. It is a list because it is common to include, besides the client IP address, IP addresses from headers like `X-Forwarded-For`. Real source IP is restored to `source.ip`. ', - name: 'nginx.ingress_controller.remote_ip_list', - type: 'array', - }, - 'nginx.ingress_controller.upstream_address_list': { - category: 'nginx', - description: - 'An array of the upstream addresses. It is a list because it is common that several upstream servers were contacted during request processing. ', - name: 'nginx.ingress_controller.upstream_address_list', - type: 'keyword', - }, - 'nginx.ingress_controller.upstream.response.length_list': { - category: 'nginx', - description: - 'An array of upstream response lengths. It is a list because it is common that several upstream servers were contacted during request processing. ', - name: 'nginx.ingress_controller.upstream.response.length_list', - type: 'keyword', - }, - 'nginx.ingress_controller.upstream.response.time_list': { - category: 'nginx', - description: - 'An array of upstream response durations. It is a list because it is common that several upstream servers were contacted during request processing. ', - name: 'nginx.ingress_controller.upstream.response.time_list', - type: 'keyword', - }, - 'nginx.ingress_controller.upstream.response.status_code_list': { - category: 'nginx', - description: - 'An array of upstream response status codes. It is a list because it is common that several upstream servers were contacted during request processing. ', - name: 'nginx.ingress_controller.upstream.response.status_code_list', - type: 'keyword', - }, - 'nginx.ingress_controller.http.request.length': { - category: 'nginx', - description: 'The request length (including request line, header, and request body) ', - name: 'nginx.ingress_controller.http.request.length', - type: 'long', - format: 'bytes', - }, - 'nginx.ingress_controller.http.request.time': { - category: 'nginx', - description: 'Time elapsed since the first bytes were read from the client ', - name: 'nginx.ingress_controller.http.request.time', - type: 'double', - format: 'duration', - }, - 'nginx.ingress_controller.upstream.name': { - category: 'nginx', - description: 'The name of the upstream. ', - name: 'nginx.ingress_controller.upstream.name', - type: 'keyword', - }, - 'nginx.ingress_controller.upstream.alternative_name': { - category: 'nginx', - description: 'The name of the alternative upstream. ', - name: 'nginx.ingress_controller.upstream.alternative_name', - type: 'keyword', - }, - 'nginx.ingress_controller.upstream.response.length': { - category: 'nginx', - description: - 'The length of the response obtained from the upstream server. If several servers were contacted during request process, the summary of the multiple response lengths is stored. ', - name: 'nginx.ingress_controller.upstream.response.length', - type: 'long', - format: 'bytes', - }, - 'nginx.ingress_controller.upstream.response.time': { - category: 'nginx', - description: - 'The time spent on receiving the response from the upstream as seconds with millisecond resolution. If several servers were contacted during request process, the summary of the multiple response times is stored. ', - name: 'nginx.ingress_controller.upstream.response.time', - type: 'double', - format: 'duration', - }, - 'nginx.ingress_controller.upstream.response.status_code': { - category: 'nginx', - description: - 'The status code of the response obtained from the upstream server. If several servers were contacted during request process, only the status code of the response from the last one is stored in this field. ', - name: 'nginx.ingress_controller.upstream.response.status_code', - type: 'long', - }, - 'nginx.ingress_controller.upstream.ip': { - category: 'nginx', - description: - 'The IP address of the upstream server. If several servers were contacted during request process, only the last one is stored in this field. ', - name: 'nginx.ingress_controller.upstream.ip', - type: 'ip', - }, - 'nginx.ingress_controller.upstream.port': { - category: 'nginx', - description: - 'The port of the upstream server. If several servers were contacted during request process, only the last one is stored in this field. ', - name: 'nginx.ingress_controller.upstream.port', - type: 'long', - }, - 'nginx.ingress_controller.http.request.id': { - category: 'nginx', - description: 'The randomly generated ID of the request ', - name: 'nginx.ingress_controller.http.request.id', - type: 'keyword', - }, - 'nginx.ingress_controller.body_sent.bytes': { - category: 'nginx', - name: 'nginx.ingress_controller.body_sent.bytes', - type: 'alias', - }, - 'nginx.ingress_controller.user_name': { - category: 'nginx', - name: 'nginx.ingress_controller.user_name', - type: 'alias', - }, - 'nginx.ingress_controller.method': { - category: 'nginx', - name: 'nginx.ingress_controller.method', - type: 'alias', - }, - 'nginx.ingress_controller.url': { - category: 'nginx', - name: 'nginx.ingress_controller.url', - type: 'alias', - }, - 'nginx.ingress_controller.http_version': { - category: 'nginx', - name: 'nginx.ingress_controller.http_version', - type: 'alias', - }, - 'nginx.ingress_controller.response_code': { - category: 'nginx', - name: 'nginx.ingress_controller.response_code', - type: 'alias', - }, - 'nginx.ingress_controller.referrer': { - category: 'nginx', - name: 'nginx.ingress_controller.referrer', - type: 'alias', - }, - 'nginx.ingress_controller.agent': { - category: 'nginx', - name: 'nginx.ingress_controller.agent', - type: 'alias', - }, - 'nginx.ingress_controller.user_agent.device': { - category: 'nginx', - name: 'nginx.ingress_controller.user_agent.device', - type: 'alias', - }, - 'nginx.ingress_controller.user_agent.name': { - category: 'nginx', - name: 'nginx.ingress_controller.user_agent.name', - type: 'alias', - }, - 'nginx.ingress_controller.user_agent.os': { - category: 'nginx', - name: 'nginx.ingress_controller.user_agent.os', - type: 'alias', - }, - 'nginx.ingress_controller.user_agent.os_name': { - category: 'nginx', - name: 'nginx.ingress_controller.user_agent.os_name', - type: 'alias', - }, - 'nginx.ingress_controller.user_agent.original': { - category: 'nginx', - name: 'nginx.ingress_controller.user_agent.original', - type: 'alias', - }, - 'nginx.ingress_controller.geoip.continent_name': { - category: 'nginx', - name: 'nginx.ingress_controller.geoip.continent_name', - type: 'alias', - }, - 'nginx.ingress_controller.geoip.country_iso_code': { - category: 'nginx', - name: 'nginx.ingress_controller.geoip.country_iso_code', - type: 'alias', - }, - 'nginx.ingress_controller.geoip.location': { - category: 'nginx', - name: 'nginx.ingress_controller.geoip.location', - type: 'alias', - }, - 'nginx.ingress_controller.geoip.region_name': { - category: 'nginx', - name: 'nginx.ingress_controller.geoip.region_name', - type: 'alias', - }, - 'nginx.ingress_controller.geoip.city_name': { - category: 'nginx', - name: 'nginx.ingress_controller.geoip.city_name', - type: 'alias', - }, - 'nginx.ingress_controller.geoip.region_iso_code': { - category: 'nginx', - name: 'nginx.ingress_controller.geoip.region_iso_code', - type: 'alias', - }, - 'osquery.result.name': { - category: 'osquery', - description: 'The name of the query that generated this event. ', - name: 'osquery.result.name', - type: 'keyword', - }, - 'osquery.result.action': { - category: 'osquery', - description: - 'For incremental data, marks whether the entry was added or removed. It can be one of "added", "removed", or "snapshot". ', - name: 'osquery.result.action', - type: 'keyword', - }, - 'osquery.result.host_identifier': { - category: 'osquery', - description: - 'The identifier for the host on which the osquery agent is running. Normally the hostname. ', - name: 'osquery.result.host_identifier', - type: 'keyword', - }, - 'osquery.result.unix_time': { - category: 'osquery', - description: - 'Unix timestamp of the event, in seconds since the epoch. Used for computing the `@timestamp` column. ', - name: 'osquery.result.unix_time', - type: 'long', - }, - 'osquery.result.calendar_time': { - category: 'osquery', - description: 'String representation of the collection time, as formatted by osquery. ', - name: 'osquery.result.calendar_time', - type: 'keyword', - }, - 'pensando.dfw.action': { - category: 'pensando', - description: 'Action on the flow. ', - name: 'pensando.dfw.action', - type: 'keyword', - }, - 'pensando.dfw.app_id': { - category: 'pensando', - description: 'Application ID ', - name: 'pensando.dfw.app_id', - type: 'integer', - }, - 'pensando.dfw.destination_address': { - category: 'pensando', - description: 'Address of destination. ', - name: 'pensando.dfw.destination_address', - type: 'keyword', - }, - 'pensando.dfw.destination_port': { - category: 'pensando', - description: 'Port of destination. ', - name: 'pensando.dfw.destination_port', - type: 'integer', - }, - 'pensando.dfw.direction': { - category: 'pensando', - description: 'Direction of the flow ', - name: 'pensando.dfw.direction', - type: 'keyword', - }, - 'pensando.dfw.protocol': { - category: 'pensando', - description: 'Protocol of the flow ', - name: 'pensando.dfw.protocol', - type: 'keyword', - }, - 'pensando.dfw.rule_id': { - category: 'pensando', - description: 'Rule ID that was matched. ', - name: 'pensando.dfw.rule_id', - type: 'keyword', - }, - 'pensando.dfw.session_id': { - category: 'pensando', - description: 'Session ID of the flow ', - name: 'pensando.dfw.session_id', - type: 'integer', - }, - 'pensando.dfw.session_state': { - category: 'pensando', - description: 'Session state of the flow. ', - name: 'pensando.dfw.session_state', - type: 'keyword', - }, - 'pensando.dfw.source_address': { - category: 'pensando', - description: 'Source address of the flow. ', - name: 'pensando.dfw.source_address', - type: 'keyword', - }, - 'pensando.dfw.source_port': { - category: 'pensando', - description: 'Source port of the flow. ', - name: 'pensando.dfw.source_port', - type: 'integer', - }, - 'pensando.dfw.timestamp': { - category: 'pensando', - description: 'Timestamp of the log. ', - name: 'pensando.dfw.timestamp', - type: 'date', - }, - 'postgresql.log.timestamp': { - category: 'postgresql', - description: 'The timestamp from the log line. ', - name: 'postgresql.log.timestamp', - }, - 'postgresql.log.core_id': { - category: 'postgresql', - description: - 'Core id. (deprecated, there is no core_id in PostgreSQL logs, this is actually session_line_number). ', - name: 'postgresql.log.core_id', - type: 'alias', - }, - 'postgresql.log.client_addr': { - category: 'postgresql', - description: 'Host where the connection originated from. ', - example: '127.0.0.1', - name: 'postgresql.log.client_addr', - }, - 'postgresql.log.client_port': { - category: 'postgresql', - description: 'Port where the connection originated from. ', - example: '59700', - name: 'postgresql.log.client_port', - }, - 'postgresql.log.session_id': { - category: 'postgresql', - description: 'PostgreSQL session. ', - example: '5ff1dd98.22', - name: 'postgresql.log.session_id', - }, - 'postgresql.log.session_line_number': { - category: 'postgresql', - description: 'Line number inside a session. (%l in `log_line_prefix`). ', - name: 'postgresql.log.session_line_number', - type: 'long', - }, - 'postgresql.log.database': { - category: 'postgresql', - description: 'Name of database. ', - example: 'postgres', - name: 'postgresql.log.database', - }, - 'postgresql.log.query': { - category: 'postgresql', - description: - 'Query statement. In the case of CSV parse, look at command_tag to get more context. ', - example: 'SELECT * FROM users;', - name: 'postgresql.log.query', - }, - 'postgresql.log.query_step': { - category: 'postgresql', - description: - 'Statement step when using extended query protocol (one of statement, parse, bind or execute). ', - example: 'parse', - name: 'postgresql.log.query_step', - }, - 'postgresql.log.query_name': { - category: 'postgresql', - description: - 'Name given to a query when using extended query protocol. If it is "", or not present, this field is ignored. ', - example: 'pdo_stmt_00000001', - name: 'postgresql.log.query_name', - }, - 'postgresql.log.command_tag': { - category: 'postgresql', - description: - "Type of session's current command. The complete list can be found at: src/include/tcop/cmdtaglist.h ", - example: 'SELECT', - name: 'postgresql.log.command_tag', - }, - 'postgresql.log.session_start_time': { - category: 'postgresql', - description: 'Time when this session started. ', - name: 'postgresql.log.session_start_time', - type: 'date', - }, - 'postgresql.log.virtual_transaction_id': { - category: 'postgresql', - description: 'Backend local transaction id. ', - name: 'postgresql.log.virtual_transaction_id', - }, - 'postgresql.log.transaction_id': { - category: 'postgresql', - description: 'The id of current transaction. ', - name: 'postgresql.log.transaction_id', - type: 'long', - }, - 'postgresql.log.sql_state_code': { - category: 'postgresql', - description: - 'State code returned by Postgres (if any). See also https://www.postgresql.org/docs/current/errcodes-appendix.html ', - name: 'postgresql.log.sql_state_code', - type: 'keyword', - }, - 'postgresql.log.detail': { - category: 'postgresql', - description: - "More information about the message, parameters in case of a parametrized query. e.g. 'Role \\\"user\\\" does not exist.', 'parameters: $1 = 42', etc. ", - name: 'postgresql.log.detail', - }, - 'postgresql.log.hint': { - category: 'postgresql', - description: 'A possible solution to solve an error. ', - name: 'postgresql.log.hint', - }, - 'postgresql.log.internal_query': { - category: 'postgresql', - description: 'Internal query that led to the error (if any). ', - name: 'postgresql.log.internal_query', - }, - 'postgresql.log.internal_query_pos': { - category: 'postgresql', - description: 'Character count of the internal query (if any). ', - name: 'postgresql.log.internal_query_pos', - type: 'long', - }, - 'postgresql.log.context': { - category: 'postgresql', - description: 'Error context. ', - name: 'postgresql.log.context', - }, - 'postgresql.log.query_pos': { - category: 'postgresql', - description: 'Character count of the error position (if any). ', - name: 'postgresql.log.query_pos', - type: 'long', - }, - 'postgresql.log.location': { - category: 'postgresql', - description: - 'Location of the error in the PostgreSQL source code (if log_error_verbosity is set to verbose). ', - name: 'postgresql.log.location', - }, - 'postgresql.log.application_name': { - category: 'postgresql', - description: 'Name of the application of this event. It is defined by the client. ', - name: 'postgresql.log.application_name', - }, - 'postgresql.log.backend_type': { - category: 'postgresql', - description: - 'Type of backend of this event. Possible types are autovacuum launcher, autovacuum worker, logical replication launcher, logical replication worker, parallel worker, background writer, client backend, checkpointer, startup, walreceiver, walsender and walwriter. In addition, background workers registered by extensions may have additional types. ', - example: 'client backend', - name: 'postgresql.log.backend_type', - }, - 'postgresql.log.error.code': { - category: 'postgresql', - description: - 'Error code returned by Postgres (if any). Deprecated: errors can have letters. Use sql_state_code instead. ', - name: 'postgresql.log.error.code', - type: 'alias', - }, - 'postgresql.log.timezone': { - category: 'postgresql', - name: 'postgresql.log.timezone', - type: 'alias', - }, - 'postgresql.log.user': { - category: 'postgresql', - name: 'postgresql.log.user', - type: 'alias', - }, - 'postgresql.log.level': { - category: 'postgresql', - description: - 'Valid values are DEBUG5, DEBUG4, DEBUG3, DEBUG2, DEBUG1, INFO, NOTICE, WARNING, ERROR, LOG, FATAL, and PANIC. ', - example: 'LOG', - name: 'postgresql.log.level', - type: 'alias', - }, - 'postgresql.log.message': { - category: 'postgresql', - name: 'postgresql.log.message', - type: 'alias', - }, - 'redis.log.role': { - category: 'redis', - description: - 'The role of the Redis instance. Can be one of `master`, `slave`, `child` (for RDF/AOF writing child), or `sentinel`. ', - name: 'redis.log.role', - type: 'keyword', - }, - 'redis.log.pid': { - category: 'redis', - name: 'redis.log.pid', - type: 'alias', - }, - 'redis.log.level': { - category: 'redis', - name: 'redis.log.level', - type: 'alias', - }, - 'redis.log.message': { - category: 'redis', - name: 'redis.log.message', - type: 'alias', - }, - 'redis.slowlog.cmd': { - category: 'redis', - description: 'The command executed. ', - name: 'redis.slowlog.cmd', - type: 'keyword', - }, - 'redis.slowlog.duration.us': { - category: 'redis', - description: 'How long it took to execute the command in microseconds. ', - name: 'redis.slowlog.duration.us', - type: 'long', - }, - 'redis.slowlog.id': { - category: 'redis', - description: 'The ID of the query. ', - name: 'redis.slowlog.id', - type: 'long', - }, - 'redis.slowlog.key': { - category: 'redis', - description: 'The key on which the command was executed. ', - name: 'redis.slowlog.key', - type: 'keyword', - }, - 'redis.slowlog.args': { - category: 'redis', - description: 'The arguments with which the command was called. ', - name: 'redis.slowlog.args', - type: 'keyword', - }, - 'santa.action': { - category: 'santa', - description: 'Action', - example: 'EXEC', - name: 'santa.action', - type: 'keyword', - }, - 'santa.decision': { - category: 'santa', - description: 'Decision that santad took.', - example: 'ALLOW', - name: 'santa.decision', - type: 'keyword', - }, - 'santa.reason': { - category: 'santa', - description: 'Reason for the decsision.', - example: 'CERT', - name: 'santa.reason', - type: 'keyword', - }, - 'santa.mode': { - category: 'santa', - description: 'Operating mode of Santa.', - example: 'M', - name: 'santa.mode', - type: 'keyword', - }, - 'santa.disk.volume': { - category: 'santa', - description: 'The volume name.', - name: 'santa.disk.volume', - }, - 'santa.disk.bus': { - category: 'santa', - description: 'The disk bus protocol.', - name: 'santa.disk.bus', - }, - 'santa.disk.serial': { - category: 'santa', - description: 'The disk serial number.', - name: 'santa.disk.serial', - }, - 'santa.disk.bsdname': { - category: 'santa', - description: 'The disk BSD name.', - example: 'disk1s3', - name: 'santa.disk.bsdname', - }, - 'santa.disk.model': { - category: 'santa', - description: 'The disk model.', - example: 'APPLE SSD SM0512L', - name: 'santa.disk.model', - }, - 'santa.disk.fs': { - category: 'santa', - description: 'The disk volume kind (filesystem type).', - example: 'apfs', - name: 'santa.disk.fs', - }, - 'santa.disk.mount': { - category: 'santa', - description: 'The disk volume path.', - name: 'santa.disk.mount', - }, - 'santa.certificate.common_name': { - category: 'santa', - description: 'Common name from code signing certificate.', - name: 'santa.certificate.common_name', - type: 'keyword', - }, - 'santa.certificate.sha256': { - category: 'santa', - description: 'SHA256 hash of code signing certificate.', - name: 'santa.certificate.sha256', - type: 'keyword', - }, - 'system.auth.timestamp': { - category: 'system', - name: 'system.auth.timestamp', - type: 'alias', - }, - 'system.auth.hostname': { - category: 'system', - name: 'system.auth.hostname', - type: 'alias', - }, - 'system.auth.program': { - category: 'system', - name: 'system.auth.program', - type: 'alias', - }, - 'system.auth.pid': { - category: 'system', - name: 'system.auth.pid', - type: 'alias', - }, - 'system.auth.message': { - category: 'system', - name: 'system.auth.message', - type: 'alias', - }, - 'system.auth.user': { - category: 'system', - name: 'system.auth.user', - type: 'alias', - }, - 'system.auth.ssh.method': { - category: 'system', - description: 'The SSH authentication method. Can be one of "password" or "publickey". ', - name: 'system.auth.ssh.method', - }, - 'system.auth.ssh.signature': { - category: 'system', - description: 'The signature of the client public key. ', - name: 'system.auth.ssh.signature', - }, - 'system.auth.ssh.dropped_ip': { - category: 'system', - description: 'The client IP from SSH connections that are open and immediately dropped. ', - name: 'system.auth.ssh.dropped_ip', - type: 'ip', - }, - 'system.auth.ssh.event': { - category: 'system', - description: 'The SSH event as found in the logs (Accepted, Invalid, Failed, etc.) ', - example: 'Accepted', - name: 'system.auth.ssh.event', - }, - 'system.auth.ssh.ip': { - category: 'system', - name: 'system.auth.ssh.ip', - type: 'alias', - }, - 'system.auth.ssh.port': { - category: 'system', - name: 'system.auth.ssh.port', - type: 'alias', - }, - 'system.auth.ssh.geoip.continent_name': { - category: 'system', - name: 'system.auth.ssh.geoip.continent_name', - type: 'alias', - }, - 'system.auth.ssh.geoip.country_iso_code': { - category: 'system', - name: 'system.auth.ssh.geoip.country_iso_code', - type: 'alias', - }, - 'system.auth.ssh.geoip.location': { - category: 'system', - name: 'system.auth.ssh.geoip.location', - type: 'alias', - }, - 'system.auth.ssh.geoip.region_name': { - category: 'system', - name: 'system.auth.ssh.geoip.region_name', - type: 'alias', - }, - 'system.auth.ssh.geoip.city_name': { - category: 'system', - name: 'system.auth.ssh.geoip.city_name', - type: 'alias', - }, - 'system.auth.ssh.geoip.region_iso_code': { - category: 'system', - name: 'system.auth.ssh.geoip.region_iso_code', - type: 'alias', - }, - 'system.auth.sudo.error': { - category: 'system', - description: 'The error message in case the sudo command failed. ', - example: 'user NOT in sudoers', - name: 'system.auth.sudo.error', - }, - 'system.auth.sudo.tty': { - category: 'system', - description: 'The TTY where the sudo command is executed. ', - name: 'system.auth.sudo.tty', - }, - 'system.auth.sudo.pwd': { - category: 'system', - description: 'The current directory where the sudo command is executed. ', - name: 'system.auth.sudo.pwd', - }, - 'system.auth.sudo.user': { - category: 'system', - description: 'The target user to which the sudo command is switching. ', - example: 'root', - name: 'system.auth.sudo.user', - }, - 'system.auth.sudo.command': { - category: 'system', - description: 'The command executed via sudo. ', - name: 'system.auth.sudo.command', - }, - 'system.auth.useradd.home': { - category: 'system', - description: 'The home folder for the new user.', - name: 'system.auth.useradd.home', - }, - 'system.auth.useradd.shell': { - category: 'system', - description: 'The default shell for the new user.', - name: 'system.auth.useradd.shell', - }, - 'system.auth.useradd.name': { - category: 'system', - name: 'system.auth.useradd.name', - type: 'alias', - }, - 'system.auth.useradd.uid': { - category: 'system', - name: 'system.auth.useradd.uid', - type: 'alias', - }, - 'system.auth.useradd.gid': { - category: 'system', - name: 'system.auth.useradd.gid', - type: 'alias', - }, - 'system.auth.groupadd.name': { - category: 'system', - name: 'system.auth.groupadd.name', - type: 'alias', - }, - 'system.auth.groupadd.gid': { - category: 'system', - name: 'system.auth.groupadd.gid', - type: 'alias', - }, - 'system.syslog.timestamp': { - category: 'system', - name: 'system.syslog.timestamp', - type: 'alias', - }, - 'system.syslog.hostname': { - category: 'system', - name: 'system.syslog.hostname', - type: 'alias', - }, - 'system.syslog.program': { - category: 'system', - name: 'system.syslog.program', - type: 'alias', - }, - 'system.syslog.pid': { - category: 'system', - name: 'system.syslog.pid', - type: 'alias', - }, - 'system.syslog.message': { - category: 'system', - name: 'system.syslog.message', - type: 'alias', - }, - 'traefik.access.user_identifier': { - category: 'traefik', - description: 'Is the RFC 1413 identity of the client ', - name: 'traefik.access.user_identifier', - type: 'keyword', - }, - 'traefik.access.request_count': { - category: 'traefik', - description: 'The number of requests ', - name: 'traefik.access.request_count', - type: 'long', - }, - 'traefik.access.frontend_name': { - category: 'traefik', - description: 'The name of the frontend used ', - name: 'traefik.access.frontend_name', - type: 'keyword', - }, - 'traefik.access.backend_url': { - category: 'traefik', - description: 'The url of the backend where request is forwarded', - name: 'traefik.access.backend_url', - type: 'keyword', - }, - 'traefik.access.body_sent.bytes': { - category: 'traefik', - name: 'traefik.access.body_sent.bytes', - type: 'alias', - }, - 'traefik.access.remote_ip': { - category: 'traefik', - name: 'traefik.access.remote_ip', - type: 'alias', - }, - 'traefik.access.user_name': { - category: 'traefik', - name: 'traefik.access.user_name', - type: 'alias', - }, - 'traefik.access.method': { - category: 'traefik', - name: 'traefik.access.method', - type: 'alias', - }, - 'traefik.access.url': { - category: 'traefik', - name: 'traefik.access.url', - type: 'alias', - }, - 'traefik.access.http_version': { - category: 'traefik', - name: 'traefik.access.http_version', - type: 'alias', - }, - 'traefik.access.response_code': { - category: 'traefik', - name: 'traefik.access.response_code', - type: 'alias', - }, - 'traefik.access.referrer': { - category: 'traefik', - name: 'traefik.access.referrer', - type: 'alias', - }, - 'traefik.access.agent': { - category: 'traefik', - name: 'traefik.access.agent', - type: 'alias', - }, - 'traefik.access.user_agent.device': { - category: 'traefik', - name: 'traefik.access.user_agent.device', - type: 'alias', - }, - 'traefik.access.user_agent.name': { - category: 'traefik', - name: 'traefik.access.user_agent.name', - type: 'alias', - }, - 'traefik.access.user_agent.os': { - category: 'traefik', - name: 'traefik.access.user_agent.os', - type: 'alias', - }, - 'traefik.access.user_agent.os_name': { - category: 'traefik', - name: 'traefik.access.user_agent.os_name', - type: 'alias', - }, - 'traefik.access.user_agent.original': { - category: 'traefik', - name: 'traefik.access.user_agent.original', - type: 'alias', - }, - 'traefik.access.geoip.continent_name': { - category: 'traefik', - name: 'traefik.access.geoip.continent_name', - type: 'alias', - }, - 'traefik.access.geoip.country_iso_code': { - category: 'traefik', - name: 'traefik.access.geoip.country_iso_code', - type: 'alias', - }, - 'traefik.access.geoip.location': { - category: 'traefik', - name: 'traefik.access.geoip.location', - type: 'alias', - }, - 'traefik.access.geoip.region_name': { - category: 'traefik', - name: 'traefik.access.geoip.region_name', - type: 'alias', - }, - 'traefik.access.geoip.city_name': { - category: 'traefik', - name: 'traefik.access.geoip.city_name', - type: 'alias', - }, - 'traefik.access.geoip.region_iso_code': { - category: 'traefik', - name: 'traefik.access.geoip.region_iso_code', - type: 'alias', - }, - 'activemq.caller': { - category: 'activemq', - description: 'Name of the caller issuing the logging request (class or resource). ', - name: 'activemq.caller', - type: 'keyword', - }, - 'activemq.thread': { - category: 'activemq', - description: 'Thread that generated the logging event. ', - name: 'activemq.thread', - type: 'keyword', - }, - 'activemq.user': { - category: 'activemq', - description: 'User that generated the logging event. ', - name: 'activemq.user', - type: 'keyword', - }, - 'activemq.audit': { - category: 'activemq', - description: 'Fields from ActiveMQ audit logs. ', - name: 'activemq.audit', - type: 'group', - }, - 'activemq.log.stack_trace': { - category: 'activemq', - name: 'activemq.log.stack_trace', - type: 'keyword', - }, - 'aws.cloudtrail.event_version': { - category: 'aws', - description: 'The CloudTrail version of the log event format. ', - name: 'aws.cloudtrail.event_version', - type: 'keyword', - }, - 'aws.cloudtrail.user_identity.type': { - category: 'aws', - description: 'The type of the identity ', - name: 'aws.cloudtrail.user_identity.type', - type: 'keyword', - }, - 'aws.cloudtrail.user_identity.arn': { - category: 'aws', - description: 'The Amazon Resource Name (ARN) of the principal that made the call.', - name: 'aws.cloudtrail.user_identity.arn', - type: 'keyword', - }, - 'aws.cloudtrail.user_identity.access_key_id': { - category: 'aws', - description: 'The access key ID that was used to sign the request.', - name: 'aws.cloudtrail.user_identity.access_key_id', - type: 'keyword', - }, - 'aws.cloudtrail.user_identity.session_context.mfa_authenticated': { - category: 'aws', - description: - 'The value is true if the root user or IAM user whose credentials were used for the request also was authenticated with an MFA device; otherwise, false.', - name: 'aws.cloudtrail.user_identity.session_context.mfa_authenticated', - type: 'keyword', - }, - 'aws.cloudtrail.user_identity.session_context.creation_date': { - category: 'aws', - description: 'The date and time when the temporary security credentials were issued.', - name: 'aws.cloudtrail.user_identity.session_context.creation_date', - type: 'date', - }, - 'aws.cloudtrail.user_identity.session_context.session_issuer.type': { - category: 'aws', - description: - 'The source of the temporary security credentials, such as Root, IAMUser, or Role.', - name: 'aws.cloudtrail.user_identity.session_context.session_issuer.type', - type: 'keyword', - }, - 'aws.cloudtrail.user_identity.session_context.session_issuer.principal_id': { - category: 'aws', - description: 'The internal ID of the entity that was used to get credentials.', - name: 'aws.cloudtrail.user_identity.session_context.session_issuer.principal_id', - type: 'keyword', - }, - 'aws.cloudtrail.user_identity.session_context.session_issuer.arn': { - category: 'aws', - description: - 'The ARN of the source (account, IAM user, or role) that was used to get temporary security credentials.', - name: 'aws.cloudtrail.user_identity.session_context.session_issuer.arn', - type: 'keyword', - }, - 'aws.cloudtrail.user_identity.session_context.session_issuer.account_id': { - category: 'aws', - description: 'The account that owns the entity that was used to get credentials.', - name: 'aws.cloudtrail.user_identity.session_context.session_issuer.account_id', - type: 'keyword', - }, - 'aws.cloudtrail.user_identity.invoked_by': { - category: 'aws', - description: - 'The name of the AWS service that made the request, such as Amazon EC2 Auto Scaling or AWS Elastic Beanstalk.', - name: 'aws.cloudtrail.user_identity.invoked_by', - type: 'keyword', - }, - 'aws.cloudtrail.error_code': { - category: 'aws', - description: 'The AWS service error if the request returns an error.', - name: 'aws.cloudtrail.error_code', - type: 'keyword', - }, - 'aws.cloudtrail.error_message': { - category: 'aws', - description: 'If the request returns an error, the description of the error.', - name: 'aws.cloudtrail.error_message', - type: 'keyword', - }, - 'aws.cloudtrail.request_parameters': { - category: 'aws', - description: 'The parameters, if any, that were sent with the request.', - name: 'aws.cloudtrail.request_parameters', - type: 'keyword', - }, - 'aws.cloudtrail.response_elements': { - category: 'aws', - description: - 'The response element for actions that make changes (create, update, or delete actions).', - name: 'aws.cloudtrail.response_elements', - type: 'keyword', - }, - 'aws.cloudtrail.additional_eventdata': { - category: 'aws', - description: 'Additional data about the event that was not part of the request or response.', - name: 'aws.cloudtrail.additional_eventdata', - type: 'keyword', - }, - 'aws.cloudtrail.request_id': { - category: 'aws', - description: - 'The value that identifies the request. The service being called generates this value.', - name: 'aws.cloudtrail.request_id', - type: 'keyword', - }, - 'aws.cloudtrail.event_type': { - category: 'aws', - description: 'Identifies the type of event that generated the event record.', - name: 'aws.cloudtrail.event_type', - type: 'keyword', - }, - 'aws.cloudtrail.api_version': { - category: 'aws', - description: 'Identifies the API version associated with the AwsApiCall eventType value.', - name: 'aws.cloudtrail.api_version', - type: 'keyword', - }, - 'aws.cloudtrail.management_event': { - category: 'aws', - description: 'A Boolean value that identifies whether the event is a management event.', - name: 'aws.cloudtrail.management_event', - type: 'keyword', - }, - 'aws.cloudtrail.read_only': { - category: 'aws', - description: 'Identifies whether this operation is a read-only operation.', - name: 'aws.cloudtrail.read_only', - type: 'keyword', - }, - 'aws.cloudtrail.resources.arn': { - category: 'aws', - description: 'Resource ARNs', - name: 'aws.cloudtrail.resources.arn', - type: 'keyword', - }, - 'aws.cloudtrail.resources.account_id': { - category: 'aws', - description: 'Account ID of the resource owner', - name: 'aws.cloudtrail.resources.account_id', - type: 'keyword', - }, - 'aws.cloudtrail.resources.type': { - category: 'aws', - description: 'Resource type identifier in the format: AWS::aws-service-name::data-type-name', - name: 'aws.cloudtrail.resources.type', - type: 'keyword', - }, - 'aws.cloudtrail.recipient_account_id': { - category: 'aws', - description: 'Represents the account ID that received this event.', - name: 'aws.cloudtrail.recipient_account_id', - type: 'keyword', - }, - 'aws.cloudtrail.service_event_details': { - category: 'aws', - description: 'Identifies the service event, including what triggered the event and the result.', - name: 'aws.cloudtrail.service_event_details', - type: 'keyword', - }, - 'aws.cloudtrail.shared_event_id': { - category: 'aws', - description: - 'GUID generated by CloudTrail to uniquely identify CloudTrail events from the same AWS action that is sent to different AWS accounts.', - name: 'aws.cloudtrail.shared_event_id', - type: 'keyword', - }, - 'aws.cloudtrail.vpc_endpoint_id': { - category: 'aws', - description: - 'Identifies the VPC endpoint in which requests were made from a VPC to another AWS service, such as Amazon S3.', - name: 'aws.cloudtrail.vpc_endpoint_id', - type: 'keyword', - }, - 'aws.cloudtrail.event_category': { - category: 'aws', - description: - 'Shows the event category that is used in LookupEvents calls. - For management events, the value is management. - For data events, the value is data. - For Insights events, the value is insight.', - name: 'aws.cloudtrail.event_category', - type: 'keyword', - }, - 'aws.cloudtrail.console_login.additional_eventdata.mobile_version': { - category: 'aws', - description: 'Identifies whether ConsoleLogin was from mobile version', - name: 'aws.cloudtrail.console_login.additional_eventdata.mobile_version', - type: 'boolean', - }, - 'aws.cloudtrail.console_login.additional_eventdata.login_to': { - category: 'aws', - description: 'URL for ConsoleLogin', - name: 'aws.cloudtrail.console_login.additional_eventdata.login_to', - type: 'keyword', - }, - 'aws.cloudtrail.console_login.additional_eventdata.mfa_used': { - category: 'aws', - description: 'Identifies whether multi factor authentication was used during ConsoleLogin', - name: 'aws.cloudtrail.console_login.additional_eventdata.mfa_used', - type: 'boolean', - }, - 'aws.cloudtrail.flattened.additional_eventdata': { - category: 'aws', - description: 'Additional data about the event that was not part of the request or response. ', - name: 'aws.cloudtrail.flattened.additional_eventdata', - type: 'flattened', - }, - 'aws.cloudtrail.flattened.request_parameters': { - category: 'aws', - description: 'The parameters, if any, that were sent with the request.', - name: 'aws.cloudtrail.flattened.request_parameters', - type: 'flattened', - }, - 'aws.cloudtrail.flattened.response_elements': { - category: 'aws', - description: - 'The response element for actions that make changes (create, update, or delete actions).', - name: 'aws.cloudtrail.flattened.response_elements', - type: 'flattened', - }, - 'aws.cloudtrail.flattened.service_event_details': { - category: 'aws', - description: 'Identifies the service event, including what triggered the event and the result.', - name: 'aws.cloudtrail.flattened.service_event_details', - type: 'flattened', - }, - 'aws.cloudtrail.digest.log_files': { - category: 'aws', - description: 'A list of Logfiles contained in the digest.', - name: 'aws.cloudtrail.digest.log_files', - type: 'nested', - }, - 'aws.cloudtrail.digest.start_time': { - category: 'aws', - description: - 'The starting UTC time range that the digest file covers, taking as a reference the time in which log files have been delivered by CloudTrail.', - name: 'aws.cloudtrail.digest.start_time', - type: 'date', - }, - 'aws.cloudtrail.digest.end_time': { - category: 'aws', - description: - 'The ending UTC time range that the digest file covers, taking as a reference the time in which log files have been delivered by CloudTrail.', - name: 'aws.cloudtrail.digest.end_time', - type: 'date', - }, - 'aws.cloudtrail.digest.s3_bucket': { - category: 'aws', - description: - 'The name of the Amazon S3 bucket to which the current digest file has been delivered.', - name: 'aws.cloudtrail.digest.s3_bucket', - type: 'keyword', - }, - 'aws.cloudtrail.digest.s3_object': { - category: 'aws', - description: - 'The Amazon S3 object key (that is, the Amazon S3 bucket location) of the current digest file.', - name: 'aws.cloudtrail.digest.s3_object', - type: 'keyword', - }, - 'aws.cloudtrail.digest.newest_event_time': { - category: 'aws', - description: - 'The UTC time of the most recent event among all of the events in the log files in the digest.', - name: 'aws.cloudtrail.digest.newest_event_time', - type: 'date', - }, - 'aws.cloudtrail.digest.oldest_event_time': { - category: 'aws', - description: - 'The UTC time of the oldest event among all of the events in the log files in the digest.', - name: 'aws.cloudtrail.digest.oldest_event_time', - type: 'date', - }, - 'aws.cloudtrail.digest.previous_s3_bucket': { - category: 'aws', - description: 'The Amazon S3 bucket to which the previous digest file was delivered.', - name: 'aws.cloudtrail.digest.previous_s3_bucket', - type: 'keyword', - }, - 'aws.cloudtrail.digest.previous_hash_algorithm': { - category: 'aws', - description: 'The name of the hash algorithm that was used to hash the previous digest file.', - name: 'aws.cloudtrail.digest.previous_hash_algorithm', - type: 'keyword', - }, - 'aws.cloudtrail.digest.public_key_fingerprint': { - category: 'aws', - description: - 'The hexadecimal encoded fingerprint of the public key that matches the private key used to sign this digest file.', - name: 'aws.cloudtrail.digest.public_key_fingerprint', - type: 'keyword', - }, - 'aws.cloudtrail.digest.signature_algorithm': { - category: 'aws', - description: 'The algorithm used to sign the digest file.', - name: 'aws.cloudtrail.digest.signature_algorithm', - type: 'keyword', - }, - 'aws.cloudtrail.insight_details': { - category: 'aws', - description: - 'Shows information about the underlying triggers of an Insights event, such as event source, user agent, statistics, API name, and whether the event is the start or end of the Insights event.', - name: 'aws.cloudtrail.insight_details', - type: 'flattened', - }, - 'aws.cloudwatch.message': { - category: 'aws', - description: 'CloudWatch log message. ', - name: 'aws.cloudwatch.message', - type: 'text', - }, - 'aws.ec2.ip_address': { - category: 'aws', - description: 'The internet address of the requester. ', - name: 'aws.ec2.ip_address', - type: 'keyword', - }, - 'aws.elb.name': { - category: 'aws', - description: 'The name of the load balancer. ', - name: 'aws.elb.name', - type: 'keyword', - }, - 'aws.elb.type': { - category: 'aws', - description: 'The type of the load balancer for v2 Load Balancers. ', - name: 'aws.elb.type', - type: 'keyword', - }, - 'aws.elb.target_group.arn': { - category: 'aws', - description: 'The ARN of the target group handling the request. ', - name: 'aws.elb.target_group.arn', - type: 'keyword', - }, - 'aws.elb.listener': { - category: 'aws', - description: 'The ELB listener that received the connection. ', - name: 'aws.elb.listener', - type: 'keyword', - }, - 'aws.elb.protocol': { - category: 'aws', - description: 'The protocol of the load balancer (http or tcp). ', - name: 'aws.elb.protocol', - type: 'keyword', - }, - 'aws.elb.request_processing_time.sec': { - category: 'aws', - description: - 'The total time in seconds since the connection or request is received until it is sent to a registered backend. ', - name: 'aws.elb.request_processing_time.sec', - type: 'float', - }, - 'aws.elb.backend_processing_time.sec': { - category: 'aws', - description: - 'The total time in seconds since the connection is sent to the backend till the backend starts responding. ', - name: 'aws.elb.backend_processing_time.sec', - type: 'float', - }, - 'aws.elb.response_processing_time.sec': { - category: 'aws', - description: - 'The total time in seconds since the response is received from the backend till it is sent to the client. ', - name: 'aws.elb.response_processing_time.sec', - type: 'float', - }, - 'aws.elb.connection_time.ms': { - category: 'aws', - description: - 'The total time of the connection in milliseconds, since it is opened till it is closed. ', - name: 'aws.elb.connection_time.ms', - type: 'long', - }, - 'aws.elb.tls_handshake_time.ms': { - category: 'aws', - description: - 'The total time for the TLS handshake to complete in milliseconds once the connection has been established. ', - name: 'aws.elb.tls_handshake_time.ms', - type: 'long', - }, - 'aws.elb.backend.ip': { - category: 'aws', - description: 'The IP address of the backend processing this connection. ', - name: 'aws.elb.backend.ip', - type: 'keyword', - }, - 'aws.elb.backend.port': { - category: 'aws', - description: 'The port in the backend processing this connection. ', - name: 'aws.elb.backend.port', - type: 'keyword', - }, - 'aws.elb.backend.http.response.status_code': { - category: 'aws', - description: - 'The status code from the backend (status code sent to the client from ELB is stored in `http.response.status_code` ', - name: 'aws.elb.backend.http.response.status_code', - type: 'keyword', - }, - 'aws.elb.ssl_cipher': { - category: 'aws', - description: 'The SSL cipher used in TLS/SSL connections. ', - name: 'aws.elb.ssl_cipher', - type: 'keyword', - }, - 'aws.elb.ssl_protocol': { - category: 'aws', - description: 'The SSL protocol used in TLS/SSL connections. ', - name: 'aws.elb.ssl_protocol', - type: 'keyword', - }, - 'aws.elb.chosen_cert.arn': { - category: 'aws', - description: - 'The ARN of the chosen certificate presented to the client in TLS/SSL connections. ', - name: 'aws.elb.chosen_cert.arn', - type: 'keyword', - }, - 'aws.elb.chosen_cert.serial': { - category: 'aws', - description: - 'The serial number of the chosen certificate presented to the client in TLS/SSL connections. ', - name: 'aws.elb.chosen_cert.serial', - type: 'keyword', - }, - 'aws.elb.incoming_tls_alert': { - category: 'aws', - description: - 'The integer value of TLS alerts received by the load balancer from the client, if present. ', - name: 'aws.elb.incoming_tls_alert', - type: 'keyword', - }, - 'aws.elb.tls_named_group': { - category: 'aws', - description: 'The TLS named group. ', - name: 'aws.elb.tls_named_group', - type: 'keyword', - }, - 'aws.elb.trace_id': { - category: 'aws', - description: 'The contents of the `X-Amzn-Trace-Id` header. ', - name: 'aws.elb.trace_id', - type: 'keyword', - }, - 'aws.elb.matched_rule_priority': { - category: 'aws', - description: 'The priority value of the rule that matched the request, if a rule matched. ', - name: 'aws.elb.matched_rule_priority', - type: 'keyword', - }, - 'aws.elb.action_executed': { - category: 'aws', - description: - 'The action executed when processing the request (forward, fixed-response, authenticate...). It can contain several values. ', - name: 'aws.elb.action_executed', - type: 'keyword', - }, - 'aws.elb.redirect_url': { - category: 'aws', - description: 'The URL used if a redirection action was executed. ', - name: 'aws.elb.redirect_url', - type: 'keyword', - }, - 'aws.elb.error.reason': { - category: 'aws', - description: 'The error reason if the executed action failed. ', - name: 'aws.elb.error.reason', - type: 'keyword', - }, - 'aws.elb.target_port': { - category: 'aws', - description: 'List of IP addresses and ports for the targets that processed this request. ', - name: 'aws.elb.target_port', - type: 'keyword', - }, - 'aws.elb.target_status_code': { - category: 'aws', - description: 'List of status codes from the responses of the targets. ', - name: 'aws.elb.target_status_code', - type: 'keyword', - }, - 'aws.elb.classification': { - category: 'aws', - description: 'The classification for desync mitigation. ', - name: 'aws.elb.classification', - type: 'keyword', - }, - 'aws.elb.classification_reason': { - category: 'aws', - description: 'The classification reason code. ', - name: 'aws.elb.classification_reason', - type: 'keyword', - }, - 'aws.s3access.bucket_owner': { - category: 'aws', - description: 'The canonical user ID of the owner of the source bucket. ', - name: 'aws.s3access.bucket_owner', - type: 'keyword', - }, - 'aws.s3access.bucket': { - category: 'aws', - description: 'The name of the bucket that the request was processed against. ', - name: 'aws.s3access.bucket', - type: 'keyword', - }, - 'aws.s3access.remote_ip': { - category: 'aws', - description: 'The apparent internet address of the requester. ', - name: 'aws.s3access.remote_ip', - type: 'ip', - }, - 'aws.s3access.requester': { - category: 'aws', - description: 'The canonical user ID of the requester, or a - for unauthenticated requests. ', - name: 'aws.s3access.requester', - type: 'keyword', - }, - 'aws.s3access.request_id': { - category: 'aws', - description: 'A string generated by Amazon S3 to uniquely identify each request. ', - name: 'aws.s3access.request_id', - type: 'keyword', - }, - 'aws.s3access.operation': { - category: 'aws', - description: - 'The operation listed here is declared as SOAP.operation, REST.HTTP_method.resource_type, WEBSITE.HTTP_method.resource_type, or BATCH.DELETE.OBJECT. ', - name: 'aws.s3access.operation', - type: 'keyword', - }, - 'aws.s3access.key': { - category: 'aws', - description: - 'The "key" part of the request, URL encoded, or "-" if the operation does not take a key parameter. ', - name: 'aws.s3access.key', - type: 'keyword', - }, - 'aws.s3access.request_uri': { - category: 'aws', - description: 'The Request-URI part of the HTTP request message. ', - name: 'aws.s3access.request_uri', - type: 'keyword', - }, - 'aws.s3access.http_status': { - category: 'aws', - description: 'The numeric HTTP status code of the response. ', - name: 'aws.s3access.http_status', - type: 'long', - }, - 'aws.s3access.error_code': { - category: 'aws', - description: 'The Amazon S3 Error Code, or "-" if no error occurred. ', - name: 'aws.s3access.error_code', - type: 'keyword', - }, - 'aws.s3access.bytes_sent': { - category: 'aws', - description: - 'The number of response bytes sent, excluding HTTP protocol overhead, or "-" if zero. ', - name: 'aws.s3access.bytes_sent', - type: 'long', - }, - 'aws.s3access.object_size': { - category: 'aws', - description: 'The total size of the object in question. ', - name: 'aws.s3access.object_size', - type: 'long', - }, - 'aws.s3access.total_time': { - category: 'aws', - description: - "The number of milliseconds the request was in flight from the server's perspective. ", - name: 'aws.s3access.total_time', - type: 'long', - }, - 'aws.s3access.turn_around_time': { - category: 'aws', - description: 'The number of milliseconds that Amazon S3 spent processing your request. ', - name: 'aws.s3access.turn_around_time', - type: 'long', - }, - 'aws.s3access.referrer': { - category: 'aws', - description: 'The value of the HTTP Referrer header, if present. ', - name: 'aws.s3access.referrer', - type: 'keyword', - }, - 'aws.s3access.user_agent': { - category: 'aws', - description: 'The value of the HTTP User-Agent header. ', - name: 'aws.s3access.user_agent', - type: 'keyword', - }, - 'aws.s3access.version_id': { - category: 'aws', - description: - 'The version ID in the request, or "-" if the operation does not take a versionId parameter. ', - name: 'aws.s3access.version_id', - type: 'keyword', - }, - 'aws.s3access.host_id': { - category: 'aws', - description: 'The x-amz-id-2 or Amazon S3 extended request ID. ', - name: 'aws.s3access.host_id', - type: 'keyword', - }, - 'aws.s3access.signature_version': { - category: 'aws', - description: - 'The signature version, SigV2 or SigV4, that was used to authenticate the request or a - for unauthenticated requests. ', - name: 'aws.s3access.signature_version', - type: 'keyword', - }, - 'aws.s3access.cipher_suite': { - category: 'aws', - description: - 'The Secure Sockets Layer (SSL) cipher that was negotiated for HTTPS request or a - for HTTP. ', - name: 'aws.s3access.cipher_suite', - type: 'keyword', - }, - 'aws.s3access.authentication_type': { - category: 'aws', - description: - 'The type of request authentication used, AuthHeader for authentication headers, QueryString for query string (pre-signed URL) or a - for unauthenticated requests. ', - name: 'aws.s3access.authentication_type', - type: 'keyword', - }, - 'aws.s3access.host_header': { - category: 'aws', - description: 'The endpoint used to connect to Amazon S3. ', - name: 'aws.s3access.host_header', - type: 'keyword', - }, - 'aws.s3access.tls_version': { - category: 'aws', - description: 'The Transport Layer Security (TLS) version negotiated by the client. ', - name: 'aws.s3access.tls_version', - type: 'keyword', - }, - 'aws.vpcflow.version': { - category: 'aws', - description: - 'The VPC Flow Logs version. If you use the default format, the version is 2. If you specify a custom format, the version is 3. ', - name: 'aws.vpcflow.version', - type: 'keyword', - }, - 'aws.vpcflow.account_id': { - category: 'aws', - description: 'The AWS account ID for the flow log. ', - name: 'aws.vpcflow.account_id', - type: 'keyword', - }, - 'aws.vpcflow.interface_id': { - category: 'aws', - description: 'The ID of the network interface for which the traffic is recorded. ', - name: 'aws.vpcflow.interface_id', - type: 'keyword', - }, - 'aws.vpcflow.action': { - category: 'aws', - description: 'The action that is associated with the traffic, ACCEPT or REJECT. ', - name: 'aws.vpcflow.action', - type: 'keyword', - }, - 'aws.vpcflow.log_status': { - category: 'aws', - description: 'The logging status of the flow log, OK, NODATA or SKIPDATA. ', - name: 'aws.vpcflow.log_status', - type: 'keyword', - }, - 'aws.vpcflow.instance_id': { - category: 'aws', - description: - "The ID of the instance that's associated with network interface for which the traffic is recorded, if the instance is owned by you. ", - name: 'aws.vpcflow.instance_id', - type: 'keyword', - }, - 'aws.vpcflow.pkt_srcaddr': { - category: 'aws', - description: 'The packet-level (original) source IP address of the traffic. ', - name: 'aws.vpcflow.pkt_srcaddr', - type: 'ip', - }, - 'aws.vpcflow.pkt_dstaddr': { - category: 'aws', - description: 'The packet-level (original) destination IP address for the traffic. ', - name: 'aws.vpcflow.pkt_dstaddr', - type: 'ip', - }, - 'aws.vpcflow.vpc_id': { - category: 'aws', - description: - 'The ID of the VPC that contains the network interface for which the traffic is recorded. ', - name: 'aws.vpcflow.vpc_id', - type: 'keyword', - }, - 'aws.vpcflow.subnet_id': { - category: 'aws', - description: - 'The ID of the subnet that contains the network interface for which the traffic is recorded. ', - name: 'aws.vpcflow.subnet_id', - type: 'keyword', - }, - 'aws.vpcflow.tcp_flags': { - category: 'aws', - description: 'The bitmask value for the following TCP flags: 2=SYN,18=SYN-ACK,1=FIN,4=RST ', - name: 'aws.vpcflow.tcp_flags', - type: 'keyword', - }, - 'aws.vpcflow.tcp_flags_array': { - category: 'aws', - description: "List of TCP flags: 'fin, syn, rst, psh, ack, urg' ", - name: 'aws.vpcflow.tcp_flags_array', - type: 'keyword', - }, - 'aws.vpcflow.type': { - category: 'aws', - description: 'The type of traffic: IPv4, IPv6, or EFA. ', - name: 'aws.vpcflow.type', - type: 'keyword', - }, - 'awsfargate.log': { - category: 'awsfargate', - description: 'Fields for Amazon Fargate container logs. ', - name: 'awsfargate.log', - type: 'group', - }, - 'azure.subscription_id': { - category: 'azure', - description: 'Azure subscription ID ', - name: 'azure.subscription_id', - type: 'keyword', - }, - 'azure.correlation_id': { - category: 'azure', - description: 'Correlation ID ', - name: 'azure.correlation_id', - type: 'keyword', - }, - 'azure.tenant_id': { - category: 'azure', - description: 'tenant ID ', - name: 'azure.tenant_id', - type: 'keyword', - }, - 'azure.resource.id': { - category: 'azure', - description: 'Resource ID ', - name: 'azure.resource.id', - type: 'keyword', - }, - 'azure.resource.group': { - category: 'azure', - description: 'Resource group ', - name: 'azure.resource.group', - type: 'keyword', - }, - 'azure.resource.provider': { - category: 'azure', - description: 'Resource type/namespace ', - name: 'azure.resource.provider', - type: 'keyword', - }, - 'azure.resource.namespace': { - category: 'azure', - description: 'Resource type/namespace ', - name: 'azure.resource.namespace', - type: 'keyword', - }, - 'azure.resource.name': { - category: 'azure', - description: 'Name ', - name: 'azure.resource.name', - type: 'keyword', - }, - 'azure.resource.authorization_rule': { - category: 'azure', - description: 'Authorization rule ', - name: 'azure.resource.authorization_rule', - type: 'keyword', - }, - 'azure.activitylogs.identity.claims_initiated_by_user.name': { - category: 'azure', - description: 'Name ', - name: 'azure.activitylogs.identity.claims_initiated_by_user.name', - type: 'keyword', - }, - 'azure.activitylogs.identity.claims_initiated_by_user.givenname': { - category: 'azure', - description: 'Givenname ', - name: 'azure.activitylogs.identity.claims_initiated_by_user.givenname', - type: 'keyword', - }, - 'azure.activitylogs.identity.claims_initiated_by_user.surname': { - category: 'azure', - description: 'Surname ', - name: 'azure.activitylogs.identity.claims_initiated_by_user.surname', - type: 'keyword', - }, - 'azure.activitylogs.identity.claims_initiated_by_user.fullname': { - category: 'azure', - description: 'Fullname ', - name: 'azure.activitylogs.identity.claims_initiated_by_user.fullname', - type: 'keyword', - }, - 'azure.activitylogs.identity.claims_initiated_by_user.schema': { - category: 'azure', - description: 'Schema ', - name: 'azure.activitylogs.identity.claims_initiated_by_user.schema', - type: 'keyword', - }, - 'azure.activitylogs.identity.claims.*': { - category: 'azure', - description: 'Claims ', - name: 'azure.activitylogs.identity.claims.*', - type: 'object', - }, - 'azure.activitylogs.identity.authorization.scope': { - category: 'azure', - description: 'Scope ', - name: 'azure.activitylogs.identity.authorization.scope', - type: 'keyword', - }, - 'azure.activitylogs.identity.authorization.action': { - category: 'azure', - description: 'Action ', - name: 'azure.activitylogs.identity.authorization.action', - type: 'keyword', - }, - 'azure.activitylogs.identity.authorization.evidence.role_assignment_scope': { - category: 'azure', - description: 'Role assignment scope ', - name: 'azure.activitylogs.identity.authorization.evidence.role_assignment_scope', - type: 'keyword', - }, - 'azure.activitylogs.identity.authorization.evidence.role_definition_id': { - category: 'azure', - description: 'Role definition ID ', - name: 'azure.activitylogs.identity.authorization.evidence.role_definition_id', - type: 'keyword', - }, - 'azure.activitylogs.identity.authorization.evidence.role': { - category: 'azure', - description: 'Role ', - name: 'azure.activitylogs.identity.authorization.evidence.role', - type: 'keyword', - }, - 'azure.activitylogs.identity.authorization.evidence.role_assignment_id': { - category: 'azure', - description: 'Role assignment ID ', - name: 'azure.activitylogs.identity.authorization.evidence.role_assignment_id', - type: 'keyword', - }, - 'azure.activitylogs.identity.authorization.evidence.principal_id': { - category: 'azure', - description: 'Principal ID ', - name: 'azure.activitylogs.identity.authorization.evidence.principal_id', - type: 'keyword', - }, - 'azure.activitylogs.identity.authorization.evidence.principal_type': { - category: 'azure', - description: 'Principal type ', - name: 'azure.activitylogs.identity.authorization.evidence.principal_type', - type: 'keyword', - }, - 'azure.activitylogs.operation_name': { - category: 'azure', - description: 'Operation name ', - name: 'azure.activitylogs.operation_name', - type: 'keyword', - }, - 'azure.activitylogs.result_type': { - category: 'azure', - description: 'Result type ', - name: 'azure.activitylogs.result_type', - type: 'keyword', - }, - 'azure.activitylogs.result_signature': { - category: 'azure', - description: 'Result signature ', - name: 'azure.activitylogs.result_signature', - type: 'keyword', - }, - 'azure.activitylogs.category': { - category: 'azure', - description: 'Category ', - name: 'azure.activitylogs.category', - type: 'keyword', - }, - 'azure.activitylogs.event_category': { - category: 'azure', - description: 'Event Category ', - name: 'azure.activitylogs.event_category', - type: 'keyword', - }, - 'azure.activitylogs.properties': { - category: 'azure', - description: 'Properties ', - name: 'azure.activitylogs.properties', - type: 'flattened', - }, - 'azure.auditlogs.category': { - category: 'azure', - description: 'The category of the operation. Currently, Audit is the only supported value. ', - name: 'azure.auditlogs.category', - type: 'keyword', - }, - 'azure.auditlogs.operation_name': { - category: 'azure', - description: 'The operation name ', - name: 'azure.auditlogs.operation_name', - type: 'keyword', - }, - 'azure.auditlogs.operation_version': { - category: 'azure', - description: 'The operation version ', - name: 'azure.auditlogs.operation_version', - type: 'keyword', - }, - 'azure.auditlogs.identity': { - category: 'azure', - description: 'Identity ', - name: 'azure.auditlogs.identity', - type: 'keyword', - }, - 'azure.auditlogs.tenant_id': { - category: 'azure', - description: 'Tenant ID ', - name: 'azure.auditlogs.tenant_id', - type: 'keyword', - }, - 'azure.auditlogs.result_signature': { - category: 'azure', - description: 'Result signature ', - name: 'azure.auditlogs.result_signature', - type: 'keyword', - }, - 'azure.auditlogs.properties.result': { - category: 'azure', - description: 'Log result ', - name: 'azure.auditlogs.properties.result', - type: 'keyword', - }, - 'azure.auditlogs.properties.activity_display_name': { - category: 'azure', - description: 'Activity display name ', - name: 'azure.auditlogs.properties.activity_display_name', - type: 'keyword', - }, - 'azure.auditlogs.properties.result_reason': { - category: 'azure', - description: 'Reason for the log result ', - name: 'azure.auditlogs.properties.result_reason', - type: 'keyword', - }, - 'azure.auditlogs.properties.correlation_id': { - category: 'azure', - description: 'Correlation ID ', - name: 'azure.auditlogs.properties.correlation_id', - type: 'keyword', - }, - 'azure.auditlogs.properties.logged_by_service': { - category: 'azure', - description: 'Logged by service ', - name: 'azure.auditlogs.properties.logged_by_service', - type: 'keyword', - }, - 'azure.auditlogs.properties.operation_type': { - category: 'azure', - description: 'Operation type ', - name: 'azure.auditlogs.properties.operation_type', - type: 'keyword', - }, - 'azure.auditlogs.properties.id': { - category: 'azure', - description: 'ID ', - name: 'azure.auditlogs.properties.id', - type: 'keyword', - }, - 'azure.auditlogs.properties.activity_datetime': { - category: 'azure', - description: 'Activity timestamp ', - name: 'azure.auditlogs.properties.activity_datetime', - type: 'date', - }, - 'azure.auditlogs.properties.category': { - category: 'azure', - description: 'category ', - name: 'azure.auditlogs.properties.category', - type: 'keyword', - }, - 'azure.auditlogs.properties.target_resources.*.display_name': { - category: 'azure', - description: 'Display name ', - name: 'azure.auditlogs.properties.target_resources.*.display_name', - type: 'keyword', - }, - 'azure.auditlogs.properties.target_resources.*.id': { - category: 'azure', - description: 'ID ', - name: 'azure.auditlogs.properties.target_resources.*.id', - type: 'keyword', - }, - 'azure.auditlogs.properties.target_resources.*.type': { - category: 'azure', - description: 'Type ', - name: 'azure.auditlogs.properties.target_resources.*.type', - type: 'keyword', - }, - 'azure.auditlogs.properties.target_resources.*.ip_address': { - category: 'azure', - description: 'ip Address ', - name: 'azure.auditlogs.properties.target_resources.*.ip_address', - type: 'keyword', - }, - 'azure.auditlogs.properties.target_resources.*.user_principal_name': { - category: 'azure', - description: 'User principal name ', - name: 'azure.auditlogs.properties.target_resources.*.user_principal_name', - type: 'keyword', - }, - 'azure.auditlogs.properties.target_resources.*.modified_properties.*.new_value': { - category: 'azure', - description: 'New value ', - name: 'azure.auditlogs.properties.target_resources.*.modified_properties.*.new_value', - type: 'keyword', - }, - 'azure.auditlogs.properties.target_resources.*.modified_properties.*.display_name': { - category: 'azure', - description: 'Display value ', - name: 'azure.auditlogs.properties.target_resources.*.modified_properties.*.display_name', - type: 'keyword', - }, - 'azure.auditlogs.properties.target_resources.*.modified_properties.*.old_value': { - category: 'azure', - description: 'Old value ', - name: 'azure.auditlogs.properties.target_resources.*.modified_properties.*.old_value', - type: 'keyword', - }, - 'azure.auditlogs.properties.initiated_by.app.servicePrincipalName': { - category: 'azure', - description: 'Service principal name ', - name: 'azure.auditlogs.properties.initiated_by.app.servicePrincipalName', - type: 'keyword', - }, - 'azure.auditlogs.properties.initiated_by.app.displayName': { - category: 'azure', - description: 'Display name ', - name: 'azure.auditlogs.properties.initiated_by.app.displayName', - type: 'keyword', - }, - 'azure.auditlogs.properties.initiated_by.app.appId': { - category: 'azure', - description: 'App ID ', - name: 'azure.auditlogs.properties.initiated_by.app.appId', - type: 'keyword', - }, - 'azure.auditlogs.properties.initiated_by.app.servicePrincipalId': { - category: 'azure', - description: 'Service principal ID ', - name: 'azure.auditlogs.properties.initiated_by.app.servicePrincipalId', - type: 'keyword', - }, - 'azure.auditlogs.properties.initiated_by.user.userPrincipalName': { - category: 'azure', - description: 'User principal name ', - name: 'azure.auditlogs.properties.initiated_by.user.userPrincipalName', - type: 'keyword', - }, - 'azure.auditlogs.properties.initiated_by.user.displayName': { - category: 'azure', - description: 'Display name ', - name: 'azure.auditlogs.properties.initiated_by.user.displayName', - type: 'keyword', - }, - 'azure.auditlogs.properties.initiated_by.user.id': { - category: 'azure', - description: 'ID ', - name: 'azure.auditlogs.properties.initiated_by.user.id', - type: 'keyword', - }, - 'azure.auditlogs.properties.initiated_by.user.ipAddress': { - category: 'azure', - description: 'ip Address ', - name: 'azure.auditlogs.properties.initiated_by.user.ipAddress', - type: 'keyword', - }, - 'azure.platformlogs.operation_name': { - category: 'azure', - description: 'Operation name ', - name: 'azure.platformlogs.operation_name', - type: 'keyword', - }, - 'azure.platformlogs.result_type': { - category: 'azure', - description: 'Result type ', - name: 'azure.platformlogs.result_type', - type: 'keyword', - }, - 'azure.platformlogs.result_signature': { - category: 'azure', - description: 'Result signature ', - name: 'azure.platformlogs.result_signature', - type: 'keyword', - }, - 'azure.platformlogs.category': { - category: 'azure', - description: 'Category ', - name: 'azure.platformlogs.category', - type: 'keyword', - }, - 'azure.platformlogs.event_category': { - category: 'azure', - description: 'Event Category ', - name: 'azure.platformlogs.event_category', - type: 'keyword', - }, - 'azure.platformlogs.status': { - category: 'azure', - description: 'Status ', - name: 'azure.platformlogs.status', - type: 'keyword', - }, - 'azure.platformlogs.ccpNamespace': { - category: 'azure', - description: 'ccpNamespace ', - name: 'azure.platformlogs.ccpNamespace', - type: 'keyword', - }, - 'azure.platformlogs.Cloud': { - category: 'azure', - description: 'Cloud ', - name: 'azure.platformlogs.Cloud', - type: 'keyword', - }, - 'azure.platformlogs.Environment': { - category: 'azure', - description: 'Environment ', - name: 'azure.platformlogs.Environment', - type: 'keyword', - }, - 'azure.platformlogs.EventTimeString': { - category: 'azure', - description: 'EventTimeString ', - name: 'azure.platformlogs.EventTimeString', - type: 'keyword', - }, - 'azure.platformlogs.Caller': { - category: 'azure', - description: 'Caller ', - name: 'azure.platformlogs.Caller', - type: 'keyword', - }, - 'azure.platformlogs.ScaleUnit': { - category: 'azure', - description: 'ScaleUnit ', - name: 'azure.platformlogs.ScaleUnit', - type: 'keyword', - }, - 'azure.platformlogs.ActivityId': { - category: 'azure', - description: 'ActivityId ', - name: 'azure.platformlogs.ActivityId', - type: 'keyword', - }, - 'azure.platformlogs.properties': { - category: 'azure', - description: 'Event inner properties ', - name: 'azure.platformlogs.properties', - type: 'flattened', - }, - 'azure.signinlogs.operation_name': { - category: 'azure', - description: 'The operation name ', - name: 'azure.signinlogs.operation_name', - type: 'keyword', - }, - 'azure.signinlogs.operation_version': { - category: 'azure', - description: 'The operation version ', - name: 'azure.signinlogs.operation_version', - type: 'keyword', - }, - 'azure.signinlogs.tenant_id': { - category: 'azure', - description: 'Tenant ID ', - name: 'azure.signinlogs.tenant_id', - type: 'keyword', - }, - 'azure.signinlogs.result_signature': { - category: 'azure', - description: 'Result signature ', - name: 'azure.signinlogs.result_signature', - type: 'keyword', - }, - 'azure.signinlogs.result_description': { - category: 'azure', - description: 'Result description ', - name: 'azure.signinlogs.result_description', - type: 'keyword', - }, - 'azure.signinlogs.result_type': { - category: 'azure', - description: 'Result type ', - name: 'azure.signinlogs.result_type', - type: 'keyword', - }, - 'azure.signinlogs.identity': { - category: 'azure', - description: 'Identity ', - name: 'azure.signinlogs.identity', - type: 'keyword', - }, - 'azure.signinlogs.category': { - category: 'azure', - description: 'Category ', - name: 'azure.signinlogs.category', - type: 'keyword', - }, - 'azure.signinlogs.properties.id': { - category: 'azure', - description: 'ID ', - name: 'azure.signinlogs.properties.id', - type: 'keyword', - }, - 'azure.signinlogs.properties.created_at': { - category: 'azure', - description: 'Created date time ', - name: 'azure.signinlogs.properties.created_at', - type: 'date', - }, - 'azure.signinlogs.properties.user_display_name': { - category: 'azure', - description: 'User display name ', - name: 'azure.signinlogs.properties.user_display_name', - type: 'keyword', - }, - 'azure.signinlogs.properties.correlation_id': { - category: 'azure', - description: 'Correlation ID ', - name: 'azure.signinlogs.properties.correlation_id', - type: 'keyword', - }, - 'azure.signinlogs.properties.user_principal_name': { - category: 'azure', - description: 'User principal name ', - name: 'azure.signinlogs.properties.user_principal_name', - type: 'keyword', - }, - 'azure.signinlogs.properties.user_id': { - category: 'azure', - description: 'User ID ', - name: 'azure.signinlogs.properties.user_id', - type: 'keyword', - }, - 'azure.signinlogs.properties.app_id': { - category: 'azure', - description: 'App ID ', - name: 'azure.signinlogs.properties.app_id', - type: 'keyword', - }, - 'azure.signinlogs.properties.app_display_name': { - category: 'azure', - description: 'App display name ', - name: 'azure.signinlogs.properties.app_display_name', - type: 'keyword', - }, - 'azure.signinlogs.properties.ip_address': { - category: 'azure', - description: 'Ip address ', - name: 'azure.signinlogs.properties.ip_address', - type: 'keyword', - }, - 'azure.signinlogs.properties.client_app_used': { - category: 'azure', - description: 'Client app used ', - name: 'azure.signinlogs.properties.client_app_used', - type: 'keyword', - }, - 'azure.signinlogs.properties.conditional_access_status': { - category: 'azure', - description: 'Conditional access status ', - name: 'azure.signinlogs.properties.conditional_access_status', - type: 'keyword', - }, - 'azure.signinlogs.properties.original_request_id': { - category: 'azure', - description: 'Original request ID ', - name: 'azure.signinlogs.properties.original_request_id', - type: 'keyword', - }, - 'azure.signinlogs.properties.is_interactive': { - category: 'azure', - description: 'Is interactive ', - name: 'azure.signinlogs.properties.is_interactive', - type: 'keyword', - }, - 'azure.signinlogs.properties.token_issuer_name': { - category: 'azure', - description: 'Token issuer name ', - name: 'azure.signinlogs.properties.token_issuer_name', - type: 'keyword', - }, - 'azure.signinlogs.properties.token_issuer_type': { - category: 'azure', - description: 'Token issuer type ', - name: 'azure.signinlogs.properties.token_issuer_type', - type: 'keyword', - }, - 'azure.signinlogs.properties.processing_time_ms': { - category: 'azure', - description: 'Processing time in milliseconds ', - name: 'azure.signinlogs.properties.processing_time_ms', - type: 'float', - }, - 'azure.signinlogs.properties.risk_detail': { - category: 'azure', - description: 'Risk detail ', - name: 'azure.signinlogs.properties.risk_detail', - type: 'keyword', - }, - 'azure.signinlogs.properties.risk_level_aggregated': { - category: 'azure', - description: 'Risk level aggregated ', - name: 'azure.signinlogs.properties.risk_level_aggregated', - type: 'keyword', - }, - 'azure.signinlogs.properties.risk_level_during_signin': { - category: 'azure', - description: 'Risk level during signIn ', - name: 'azure.signinlogs.properties.risk_level_during_signin', - type: 'keyword', - }, - 'azure.signinlogs.properties.risk_state': { - category: 'azure', - description: 'Risk state ', - name: 'azure.signinlogs.properties.risk_state', - type: 'keyword', - }, - 'azure.signinlogs.properties.resource_display_name': { - category: 'azure', - description: 'Resource display name ', - name: 'azure.signinlogs.properties.resource_display_name', - type: 'keyword', - }, - 'azure.signinlogs.properties.status.error_code': { - category: 'azure', - description: 'Error code ', - name: 'azure.signinlogs.properties.status.error_code', - type: 'keyword', - }, - 'azure.signinlogs.properties.device_detail.device_id': { - category: 'azure', - description: 'Device ID ', - name: 'azure.signinlogs.properties.device_detail.device_id', - type: 'keyword', - }, - 'azure.signinlogs.properties.device_detail.operating_system': { - category: 'azure', - description: 'Operating system ', - name: 'azure.signinlogs.properties.device_detail.operating_system', - type: 'keyword', - }, - 'azure.signinlogs.properties.device_detail.browser': { - category: 'azure', - description: 'Browser ', - name: 'azure.signinlogs.properties.device_detail.browser', - type: 'keyword', - }, - 'azure.signinlogs.properties.device_detail.display_name': { - category: 'azure', - description: 'Display name ', - name: 'azure.signinlogs.properties.device_detail.display_name', - type: 'keyword', - }, - 'azure.signinlogs.properties.device_detail.trust_type': { - category: 'azure', - description: 'Trust type ', - name: 'azure.signinlogs.properties.device_detail.trust_type', - type: 'keyword', - }, - 'azure.signinlogs.properties.service_principal_id': { - category: 'azure', - description: 'Status ', - name: 'azure.signinlogs.properties.service_principal_id', - type: 'keyword', - }, - 'network.interface.name': { - category: 'network', - description: 'Name of the network interface where the traffic has been observed. ', - name: 'network.interface.name', - type: 'keyword', - }, - 'rsa.internal.msg': { - category: 'rsa', - description: 'This key is used to capture the raw message that comes into the Log Decoder', - name: 'rsa.internal.msg', - type: 'keyword', - }, - 'rsa.internal.messageid': { - category: 'rsa', - name: 'rsa.internal.messageid', - type: 'keyword', - }, - 'rsa.internal.event_desc': { - category: 'rsa', - name: 'rsa.internal.event_desc', - type: 'keyword', - }, - 'rsa.internal.message': { - category: 'rsa', - description: 'This key captures the contents of instant messages', - name: 'rsa.internal.message', - type: 'keyword', - }, - 'rsa.internal.time': { - category: 'rsa', - description: - 'This is the time at which a session hits a NetWitness Decoder. This key should never be used to parse Meta data from a session (Logs/Packets) Directly, this is a Reserved key in NetWitness.', - name: 'rsa.internal.time', - type: 'date', - }, - 'rsa.internal.level': { - category: 'rsa', - description: 'Deprecated key defined only in table map.', - name: 'rsa.internal.level', - type: 'long', - }, - 'rsa.internal.msg_id': { - category: 'rsa', - description: - 'This is the Message ID1 value that identifies the exact log parser definition which parses a particular log session. This key should never be used to parse Meta data from a session (Logs/Packets) Directly, this is a Reserved key in NetWitness', - name: 'rsa.internal.msg_id', - type: 'keyword', - }, - 'rsa.internal.msg_vid': { - category: 'rsa', - description: - 'This is the Message ID2 value that identifies the exact log parser definition which parses a particular log session. This key should never be used to parse Meta data from a session (Logs/Packets) Directly, this is a Reserved key in NetWitness', - name: 'rsa.internal.msg_vid', - type: 'keyword', - }, - 'rsa.internal.data': { - category: 'rsa', - description: 'Deprecated key defined only in table map.', - name: 'rsa.internal.data', - type: 'keyword', - }, - 'rsa.internal.obj_server': { - category: 'rsa', - description: 'Deprecated key defined only in table map.', - name: 'rsa.internal.obj_server', - type: 'keyword', - }, - 'rsa.internal.obj_val': { - category: 'rsa', - description: 'Deprecated key defined only in table map.', - name: 'rsa.internal.obj_val', - type: 'keyword', - }, - 'rsa.internal.resource': { - category: 'rsa', - description: 'Deprecated key defined only in table map.', - name: 'rsa.internal.resource', - type: 'keyword', - }, - 'rsa.internal.obj_id': { - category: 'rsa', - description: 'Deprecated key defined only in table map.', - name: 'rsa.internal.obj_id', - type: 'keyword', - }, - 'rsa.internal.statement': { - category: 'rsa', - description: 'Deprecated key defined only in table map.', - name: 'rsa.internal.statement', - type: 'keyword', - }, - 'rsa.internal.audit_class': { - category: 'rsa', - description: 'Deprecated key defined only in table map.', - name: 'rsa.internal.audit_class', - type: 'keyword', - }, - 'rsa.internal.entry': { - category: 'rsa', - description: 'Deprecated key defined only in table map.', - name: 'rsa.internal.entry', - type: 'keyword', - }, - 'rsa.internal.hcode': { - category: 'rsa', - description: 'Deprecated key defined only in table map.', - name: 'rsa.internal.hcode', - type: 'keyword', - }, - 'rsa.internal.inode': { - category: 'rsa', - description: 'Deprecated key defined only in table map.', - name: 'rsa.internal.inode', - type: 'long', - }, - 'rsa.internal.resource_class': { - category: 'rsa', - description: 'Deprecated key defined only in table map.', - name: 'rsa.internal.resource_class', - type: 'keyword', - }, - 'rsa.internal.dead': { - category: 'rsa', - description: 'Deprecated key defined only in table map.', - name: 'rsa.internal.dead', - type: 'long', - }, - 'rsa.internal.feed_desc': { - category: 'rsa', - description: - 'This is used to capture the description of the feed. This key should never be used to parse Meta data from a session (Logs/Packets) Directly, this is a Reserved key in NetWitness', - name: 'rsa.internal.feed_desc', - type: 'keyword', - }, - 'rsa.internal.feed_name': { - category: 'rsa', - description: - 'This is used to capture the name of the feed. This key should never be used to parse Meta data from a session (Logs/Packets) Directly, this is a Reserved key in NetWitness', - name: 'rsa.internal.feed_name', - type: 'keyword', - }, - 'rsa.internal.cid': { - category: 'rsa', - description: - 'This is the unique identifier used to identify a NetWitness Concentrator. This key should never be used to parse Meta data from a session (Logs/Packets) Directly, this is a Reserved key in NetWitness', - name: 'rsa.internal.cid', - type: 'keyword', - }, - 'rsa.internal.device_class': { - category: 'rsa', - description: - 'This is the Classification of the Log Event Source under a predefined fixed set of Event Source Classifications. This key should never be used to parse Meta data from a session (Logs/Packets) Directly, this is a Reserved key in NetWitness', - name: 'rsa.internal.device_class', - type: 'keyword', - }, - 'rsa.internal.device_group': { - category: 'rsa', - description: - 'This key should never be used to parse Meta data from a session (Logs/Packets) Directly, this is a Reserved key in NetWitness', - name: 'rsa.internal.device_group', - type: 'keyword', - }, - 'rsa.internal.device_host': { - category: 'rsa', - description: - 'This is the Hostname of the log Event Source sending the logs to NetWitness. This key should never be used to parse Meta data from a session (Logs/Packets) Directly, this is a Reserved key in NetWitness', - name: 'rsa.internal.device_host', - type: 'keyword', - }, - 'rsa.internal.device_ip': { - category: 'rsa', - description: - 'This is the IPv4 address of the Log Event Source sending the logs to NetWitness. This key should never be used to parse Meta data from a session (Logs/Packets) Directly, this is a Reserved key in NetWitness', - name: 'rsa.internal.device_ip', - type: 'ip', - }, - 'rsa.internal.device_ipv6': { - category: 'rsa', - description: - 'This is the IPv6 address of the Log Event Source sending the logs to NetWitness. This key should never be used to parse Meta data from a session (Logs/Packets) Directly, this is a Reserved key in NetWitness', - name: 'rsa.internal.device_ipv6', - type: 'ip', - }, - 'rsa.internal.device_type': { - category: 'rsa', - description: - 'This is the name of the log parser which parsed a given session. This key should never be used to parse Meta data from a session (Logs/Packets) Directly, this is a Reserved key in NetWitness', - name: 'rsa.internal.device_type', - type: 'keyword', - }, - 'rsa.internal.device_type_id': { - category: 'rsa', - description: 'Deprecated key defined only in table map.', - name: 'rsa.internal.device_type_id', - type: 'long', - }, - 'rsa.internal.did': { - category: 'rsa', - description: - 'This is the unique identifier used to identify a NetWitness Decoder. This key should never be used to parse Meta data from a session (Logs/Packets) Directly, this is a Reserved key in NetWitness', - name: 'rsa.internal.did', - type: 'keyword', - }, - 'rsa.internal.entropy_req': { - category: 'rsa', - description: - 'This key is only used by the Entropy Parser, the Meta Type can be either UInt16 or Float32 based on the configuration', - name: 'rsa.internal.entropy_req', - type: 'long', - }, - 'rsa.internal.entropy_res': { - category: 'rsa', - description: - 'This key is only used by the Entropy Parser, the Meta Type can be either UInt16 or Float32 based on the configuration', - name: 'rsa.internal.entropy_res', - type: 'long', - }, - 'rsa.internal.event_name': { - category: 'rsa', - description: 'Deprecated key defined only in table map.', - name: 'rsa.internal.event_name', - type: 'keyword', - }, - 'rsa.internal.feed_category': { - category: 'rsa', - description: - 'This is used to capture the category of the feed. This key should never be used to parse Meta data from a session (Logs/Packets) Directly, this is a Reserved key in NetWitness', - name: 'rsa.internal.feed_category', - type: 'keyword', - }, - 'rsa.internal.forward_ip': { - category: 'rsa', - description: - 'This key should be used to capture the IPV4 address of a relay system which forwarded the events from the original system to NetWitness.', - name: 'rsa.internal.forward_ip', - type: 'ip', - }, - 'rsa.internal.forward_ipv6': { - category: 'rsa', - description: - 'This key is used to capture the IPV6 address of a relay system which forwarded the events from the original system to NetWitness. This key should never be used to parse Meta data from a session (Logs/Packets) Directly, this is a Reserved key in NetWitness', - name: 'rsa.internal.forward_ipv6', - type: 'ip', - }, - 'rsa.internal.header_id': { - category: 'rsa', - description: - 'This is the Header ID value that identifies the exact log parser header definition that parses a particular log session. This key should never be used to parse Meta data from a session (Logs/Packets) Directly, this is a Reserved key in NetWitness', - name: 'rsa.internal.header_id', - type: 'keyword', - }, - 'rsa.internal.lc_cid': { - category: 'rsa', - description: - 'This is a unique Identifier of a Log Collector. This key should never be used to parse Meta data from a session (Logs/Packets) Directly, this is a Reserved key in NetWitness', - name: 'rsa.internal.lc_cid', - type: 'keyword', - }, - 'rsa.internal.lc_ctime': { - category: 'rsa', - description: - 'This is the time at which a log is collected in a NetWitness Log Collector. This key should never be used to parse Meta data from a session (Logs/Packets) Directly, this is a Reserved key in NetWitness', - name: 'rsa.internal.lc_ctime', - type: 'date', - }, - 'rsa.internal.mcb_req': { - category: 'rsa', - description: - 'This key is only used by the Entropy Parser, the most common byte request is simply which byte for each side (0 thru 255) was seen the most', - name: 'rsa.internal.mcb_req', - type: 'long', - }, - 'rsa.internal.mcb_res': { - category: 'rsa', - description: - 'This key is only used by the Entropy Parser, the most common byte response is simply which byte for each side (0 thru 255) was seen the most', - name: 'rsa.internal.mcb_res', - type: 'long', - }, - 'rsa.internal.mcbc_req': { - category: 'rsa', - description: - 'This key is only used by the Entropy Parser, the most common byte count is the number of times the most common byte (above) was seen in the session streams', - name: 'rsa.internal.mcbc_req', - type: 'long', - }, - 'rsa.internal.mcbc_res': { - category: 'rsa', - description: - 'This key is only used by the Entropy Parser, the most common byte count is the number of times the most common byte (above) was seen in the session streams', - name: 'rsa.internal.mcbc_res', - type: 'long', - }, - 'rsa.internal.medium': { - category: 'rsa', - description: - 'This key is used to identify if it’s a log/packet session or Layer 2 Encapsulation Type. This key should never be used to parse Meta data from a session (Logs/Packets) Directly, this is a Reserved key in NetWitness. 32 = log, 33 = correlation session, < 32 is packet session', - name: 'rsa.internal.medium', - type: 'long', - }, - 'rsa.internal.node_name': { - category: 'rsa', - description: 'Deprecated key defined only in table map.', - name: 'rsa.internal.node_name', - type: 'keyword', - }, - 'rsa.internal.nwe_callback_id': { - category: 'rsa', - description: 'This key denotes that event is endpoint related', - name: 'rsa.internal.nwe_callback_id', - type: 'keyword', - }, - 'rsa.internal.parse_error': { - category: 'rsa', - description: - 'This is a special key that stores any Meta key validation error found while parsing a log session. This key should never be used to parse Meta data from a session (Logs/Packets) Directly, this is a Reserved key in NetWitness', - name: 'rsa.internal.parse_error', - type: 'keyword', - }, - 'rsa.internal.payload_req': { - category: 'rsa', - description: - 'This key is only used by the Entropy Parser, the payload size metrics are the payload sizes of each session side at the time of parsing. However, in order to keep', - name: 'rsa.internal.payload_req', - type: 'long', - }, - 'rsa.internal.payload_res': { - category: 'rsa', - description: - 'This key is only used by the Entropy Parser, the payload size metrics are the payload sizes of each session side at the time of parsing. However, in order to keep', - name: 'rsa.internal.payload_res', - type: 'long', - }, - 'rsa.internal.process_vid_dst': { - category: 'rsa', - description: - 'Endpoint generates and uses a unique virtual ID to identify any similar group of process. This ID represents the target process.', - name: 'rsa.internal.process_vid_dst', - type: 'keyword', - }, - 'rsa.internal.process_vid_src': { - category: 'rsa', - description: - 'Endpoint generates and uses a unique virtual ID to identify any similar group of process. This ID represents the source process.', - name: 'rsa.internal.process_vid_src', - type: 'keyword', - }, - 'rsa.internal.rid': { - category: 'rsa', - description: - 'This is a special ID of the Remote Session created by NetWitness Decoder. This key should never be used to parse Meta data from a session (Logs/Packets) Directly, this is a Reserved key in NetWitness', - name: 'rsa.internal.rid', - type: 'long', - }, - 'rsa.internal.session_split': { - category: 'rsa', - description: - 'This key should never be used to parse Meta data from a session (Logs/Packets) Directly, this is a Reserved key in NetWitness', - name: 'rsa.internal.session_split', - type: 'keyword', - }, - 'rsa.internal.site': { - category: 'rsa', - description: 'Deprecated key defined only in table map.', - name: 'rsa.internal.site', - type: 'keyword', - }, - 'rsa.internal.size': { - category: 'rsa', - description: - 'This is the size of the session as seen by the NetWitness Decoder. This key should never be used to parse Meta data from a session (Logs/Packets) Directly, this is a Reserved key in NetWitness', - name: 'rsa.internal.size', - type: 'long', - }, - 'rsa.internal.sourcefile': { - category: 'rsa', - description: - 'This is the name of the log file or PCAPs that can be imported into NetWitness. This key should never be used to parse Meta data from a session (Logs/Packets) Directly, this is a Reserved key in NetWitness', - name: 'rsa.internal.sourcefile', - type: 'keyword', - }, - 'rsa.internal.ubc_req': { - category: 'rsa', - description: - 'This key is only used by the Entropy Parser, Unique byte count is the number of unique bytes seen in each stream. 256 would mean all byte values of 0 thru 255 were seen at least once', - name: 'rsa.internal.ubc_req', - type: 'long', - }, - 'rsa.internal.ubc_res': { - category: 'rsa', - description: - 'This key is only used by the Entropy Parser, Unique byte count is the number of unique bytes seen in each stream. 256 would mean all byte values of 0 thru 255 were seen at least once', - name: 'rsa.internal.ubc_res', - type: 'long', - }, - 'rsa.internal.word': { - category: 'rsa', - description: - 'This is used by the Word Parsing technology to capture the first 5 character of every word in an unparsed log', - name: 'rsa.internal.word', - type: 'keyword', - }, - 'rsa.time.event_time': { - category: 'rsa', - description: - 'This key is used to capture the time mentioned in a raw session that represents the actual time an event occured in a standard normalized form', - name: 'rsa.time.event_time', - type: 'date', - }, - 'rsa.time.duration_time': { - category: 'rsa', - description: 'This key is used to capture the normalized duration/lifetime in seconds.', - name: 'rsa.time.duration_time', - type: 'double', - }, - 'rsa.time.event_time_str': { - category: 'rsa', - description: - 'This key is used to capture the incomplete time mentioned in a session as a string', - name: 'rsa.time.event_time_str', - type: 'keyword', - }, - 'rsa.time.starttime': { - category: 'rsa', - description: - 'This key is used to capture the Start time mentioned in a session in a standard form', - name: 'rsa.time.starttime', - type: 'date', - }, - 'rsa.time.month': { - category: 'rsa', - name: 'rsa.time.month', - type: 'keyword', - }, - 'rsa.time.day': { - category: 'rsa', - name: 'rsa.time.day', - type: 'keyword', - }, - 'rsa.time.endtime': { - category: 'rsa', - description: - 'This key is used to capture the End time mentioned in a session in a standard form', - name: 'rsa.time.endtime', - type: 'date', - }, - 'rsa.time.timezone': { - category: 'rsa', - description: 'This key is used to capture the timezone of the Event Time', - name: 'rsa.time.timezone', - type: 'keyword', - }, - 'rsa.time.duration_str': { - category: 'rsa', - description: 'A text string version of the duration', - name: 'rsa.time.duration_str', - type: 'keyword', - }, - 'rsa.time.date': { - category: 'rsa', - name: 'rsa.time.date', - type: 'keyword', - }, - 'rsa.time.year': { - category: 'rsa', - name: 'rsa.time.year', - type: 'keyword', - }, - 'rsa.time.recorded_time': { - category: 'rsa', - description: - "The event time as recorded by the system the event is collected from. The usage scenario is a multi-tier application where the management layer of the system records it's own timestamp at the time of collection from its child nodes. Must be in timestamp format.", - name: 'rsa.time.recorded_time', - type: 'date', - }, - 'rsa.time.datetime': { - category: 'rsa', - name: 'rsa.time.datetime', - type: 'keyword', - }, - 'rsa.time.effective_time': { - category: 'rsa', - description: - 'This key is the effective time referenced by an individual event in a Standard Timestamp format', - name: 'rsa.time.effective_time', - type: 'date', - }, - 'rsa.time.expire_time': { - category: 'rsa', - description: 'This key is the timestamp that explicitly refers to an expiration.', - name: 'rsa.time.expire_time', - type: 'date', - }, - 'rsa.time.process_time': { - category: 'rsa', - description: 'Deprecated, use duration.time', - name: 'rsa.time.process_time', - type: 'keyword', - }, - 'rsa.time.hour': { - category: 'rsa', - name: 'rsa.time.hour', - type: 'keyword', - }, - 'rsa.time.min': { - category: 'rsa', - name: 'rsa.time.min', - type: 'keyword', - }, - 'rsa.time.timestamp': { - category: 'rsa', - name: 'rsa.time.timestamp', - type: 'keyword', - }, - 'rsa.time.event_queue_time': { - category: 'rsa', - description: 'This key is the Time that the event was queued.', - name: 'rsa.time.event_queue_time', - type: 'date', - }, - 'rsa.time.p_time1': { - category: 'rsa', - name: 'rsa.time.p_time1', - type: 'keyword', - }, - 'rsa.time.tzone': { - category: 'rsa', - name: 'rsa.time.tzone', - type: 'keyword', - }, - 'rsa.time.eventtime': { - category: 'rsa', - name: 'rsa.time.eventtime', - type: 'keyword', - }, - 'rsa.time.gmtdate': { - category: 'rsa', - name: 'rsa.time.gmtdate', - type: 'keyword', - }, - 'rsa.time.gmttime': { - category: 'rsa', - name: 'rsa.time.gmttime', - type: 'keyword', - }, - 'rsa.time.p_date': { - category: 'rsa', - name: 'rsa.time.p_date', - type: 'keyword', - }, - 'rsa.time.p_month': { - category: 'rsa', - name: 'rsa.time.p_month', - type: 'keyword', - }, - 'rsa.time.p_time': { - category: 'rsa', - name: 'rsa.time.p_time', - type: 'keyword', - }, - 'rsa.time.p_time2': { - category: 'rsa', - name: 'rsa.time.p_time2', - type: 'keyword', - }, - 'rsa.time.p_year': { - category: 'rsa', - name: 'rsa.time.p_year', - type: 'keyword', - }, - 'rsa.time.expire_time_str': { - category: 'rsa', - description: - 'This key is used to capture incomplete timestamp that explicitly refers to an expiration.', - name: 'rsa.time.expire_time_str', - type: 'keyword', - }, - 'rsa.time.stamp': { - category: 'rsa', - description: 'Deprecated key defined only in table map.', - name: 'rsa.time.stamp', - type: 'date', - }, - 'rsa.misc.action': { - category: 'rsa', - name: 'rsa.misc.action', - type: 'keyword', - }, - 'rsa.misc.result': { - category: 'rsa', - description: - 'This key is used to capture the outcome/result string value of an action in a session.', - name: 'rsa.misc.result', - type: 'keyword', - }, - 'rsa.misc.severity': { - category: 'rsa', - description: 'This key is used to capture the severity given the session', - name: 'rsa.misc.severity', - type: 'keyword', - }, - 'rsa.misc.event_type': { - category: 'rsa', - description: 'This key captures the event category type as specified by the event source.', - name: 'rsa.misc.event_type', - type: 'keyword', - }, - 'rsa.misc.reference_id': { - category: 'rsa', - description: 'This key is used to capture an event id from the session directly', - name: 'rsa.misc.reference_id', - type: 'keyword', - }, - 'rsa.misc.version': { - category: 'rsa', - description: - 'This key captures Version of the application or OS which is generating the event.', - name: 'rsa.misc.version', - type: 'keyword', - }, - 'rsa.misc.disposition': { - category: 'rsa', - description: 'This key captures the The end state of an action.', - name: 'rsa.misc.disposition', - type: 'keyword', - }, - 'rsa.misc.result_code': { - category: 'rsa', - description: - 'This key is used to capture the outcome/result numeric value of an action in a session', - name: 'rsa.misc.result_code', - type: 'keyword', - }, - 'rsa.misc.category': { - category: 'rsa', - description: - 'This key is used to capture the category of an event given by the vendor in the session', - name: 'rsa.misc.category', - type: 'keyword', - }, - 'rsa.misc.obj_name': { - category: 'rsa', - description: 'This is used to capture name of object', - name: 'rsa.misc.obj_name', - type: 'keyword', - }, - 'rsa.misc.obj_type': { - category: 'rsa', - description: 'This is used to capture type of object', - name: 'rsa.misc.obj_type', - type: 'keyword', - }, - 'rsa.misc.event_source': { - category: 'rsa', - description: 'This key captures Source of the event that’s not a hostname', - name: 'rsa.misc.event_source', - type: 'keyword', - }, - 'rsa.misc.log_session_id': { - category: 'rsa', - description: 'This key is used to capture a sessionid from the session directly', - name: 'rsa.misc.log_session_id', - type: 'keyword', - }, - 'rsa.misc.group': { - category: 'rsa', - description: 'This key captures the Group Name value', - name: 'rsa.misc.group', - type: 'keyword', - }, - 'rsa.misc.policy_name': { - category: 'rsa', - description: 'This key is used to capture the Policy Name only.', - name: 'rsa.misc.policy_name', - type: 'keyword', - }, - 'rsa.misc.rule_name': { - category: 'rsa', - description: 'This key captures the Rule Name', - name: 'rsa.misc.rule_name', - type: 'keyword', - }, - 'rsa.misc.context': { - category: 'rsa', - description: 'This key captures Information which adds additional context to the event.', - name: 'rsa.misc.context', - type: 'keyword', - }, - 'rsa.misc.change_new': { - category: 'rsa', - description: - 'This key is used to capture the new values of the attribute that’s changing in a session', - name: 'rsa.misc.change_new', - type: 'keyword', - }, - 'rsa.misc.space': { - category: 'rsa', - name: 'rsa.misc.space', - type: 'keyword', - }, - 'rsa.misc.client': { - category: 'rsa', - description: - 'This key is used to capture only the name of the client application requesting resources of the server. See the user.agent meta key for capture of the specific user agent identifier or browser identification string.', - name: 'rsa.misc.client', - type: 'keyword', - }, - 'rsa.misc.msgIdPart1': { - category: 'rsa', - name: 'rsa.misc.msgIdPart1', - type: 'keyword', - }, - 'rsa.misc.msgIdPart2': { - category: 'rsa', - name: 'rsa.misc.msgIdPart2', - type: 'keyword', - }, - 'rsa.misc.change_old': { - category: 'rsa', - description: - 'This key is used to capture the old value of the attribute that’s changing in a session', - name: 'rsa.misc.change_old', - type: 'keyword', - }, - 'rsa.misc.operation_id': { - category: 'rsa', - description: - 'An alert number or operation number. The values should be unique and non-repeating.', - name: 'rsa.misc.operation_id', - type: 'keyword', - }, - 'rsa.misc.event_state': { - category: 'rsa', - description: - 'This key captures the current state of the object/item referenced within the event. Describing an on-going event.', - name: 'rsa.misc.event_state', - type: 'keyword', - }, - 'rsa.misc.group_object': { - category: 'rsa', - description: 'This key captures a collection/grouping of entities. Specific usage', - name: 'rsa.misc.group_object', - type: 'keyword', - }, - 'rsa.misc.node': { - category: 'rsa', - description: - 'Common use case is the node name within a cluster. The cluster name is reflected by the host name.', - name: 'rsa.misc.node', - type: 'keyword', - }, - 'rsa.misc.rule': { - category: 'rsa', - description: 'This key captures the Rule number', - name: 'rsa.misc.rule', - type: 'keyword', - }, - 'rsa.misc.device_name': { - category: 'rsa', - description: - 'This is used to capture name of the Device associated with the node Like: a physical disk, printer, etc', - name: 'rsa.misc.device_name', - type: 'keyword', - }, - 'rsa.misc.param': { - category: 'rsa', - description: 'This key is the parameters passed as part of a command or application, etc.', - name: 'rsa.misc.param', - type: 'keyword', - }, - 'rsa.misc.change_attrib': { - category: 'rsa', - description: - 'This key is used to capture the name of the attribute that’s changing in a session', - name: 'rsa.misc.change_attrib', - type: 'keyword', - }, - 'rsa.misc.event_computer': { - category: 'rsa', - description: - 'This key is a windows only concept, where this key is used to capture fully qualified domain name in a windows log.', - name: 'rsa.misc.event_computer', - type: 'keyword', - }, - 'rsa.misc.reference_id1': { - category: 'rsa', - description: 'This key is for Linked ID to be used as an addition to "reference.id"', - name: 'rsa.misc.reference_id1', - type: 'keyword', - }, - 'rsa.misc.event_log': { - category: 'rsa', - description: 'This key captures the Name of the event log', - name: 'rsa.misc.event_log', - type: 'keyword', - }, - 'rsa.misc.OS': { - category: 'rsa', - description: 'This key captures the Name of the Operating System', - name: 'rsa.misc.OS', - type: 'keyword', - }, - 'rsa.misc.terminal': { - category: 'rsa', - description: 'This key captures the Terminal Names only', - name: 'rsa.misc.terminal', - type: 'keyword', - }, - 'rsa.misc.msgIdPart3': { - category: 'rsa', - name: 'rsa.misc.msgIdPart3', - type: 'keyword', - }, - 'rsa.misc.filter': { - category: 'rsa', - description: 'This key captures Filter used to reduce result set', - name: 'rsa.misc.filter', - type: 'keyword', - }, - 'rsa.misc.serial_number': { - category: 'rsa', - description: 'This key is the Serial number associated with a physical asset.', - name: 'rsa.misc.serial_number', - type: 'keyword', - }, - 'rsa.misc.checksum': { - category: 'rsa', - description: - 'This key is used to capture the checksum or hash of the entity such as a file or process. Checksum should be used over checksum.src or checksum.dst when it is unclear whether the entity is a source or target of an action.', - name: 'rsa.misc.checksum', - type: 'keyword', - }, - 'rsa.misc.event_user': { - category: 'rsa', - description: - 'This key is a windows only concept, where this key is used to capture combination of domain name and username in a windows log.', - name: 'rsa.misc.event_user', - type: 'keyword', - }, - 'rsa.misc.virusname': { - category: 'rsa', - description: 'This key captures the name of the virus', - name: 'rsa.misc.virusname', - type: 'keyword', - }, - 'rsa.misc.content_type': { - category: 'rsa', - description: 'This key is used to capture Content Type only.', - name: 'rsa.misc.content_type', - type: 'keyword', - }, - 'rsa.misc.group_id': { - category: 'rsa', - description: 'This key captures Group ID Number (related to the group name)', - name: 'rsa.misc.group_id', - type: 'keyword', - }, - 'rsa.misc.policy_id': { - category: 'rsa', - description: - 'This key is used to capture the Policy ID only, this should be a numeric value, use policy.name otherwise', - name: 'rsa.misc.policy_id', - type: 'keyword', - }, - 'rsa.misc.vsys': { - category: 'rsa', - description: 'This key captures Virtual System Name', - name: 'rsa.misc.vsys', - type: 'keyword', - }, - 'rsa.misc.connection_id': { - category: 'rsa', - description: 'This key captures the Connection ID', - name: 'rsa.misc.connection_id', - type: 'keyword', - }, - 'rsa.misc.reference_id2': { - category: 'rsa', - description: - 'This key is for the 2nd Linked ID. Can be either linked to "reference.id" or "reference.id1" value but should not be used unless the other two variables are in play.', - name: 'rsa.misc.reference_id2', - type: 'keyword', - }, - 'rsa.misc.sensor': { - category: 'rsa', - description: 'This key captures Name of the sensor. Typically used in IDS/IPS based devices', - name: 'rsa.misc.sensor', - type: 'keyword', - }, - 'rsa.misc.sig_id': { - category: 'rsa', - description: 'This key captures IDS/IPS Int Signature ID', - name: 'rsa.misc.sig_id', - type: 'long', - }, - 'rsa.misc.port_name': { - category: 'rsa', - description: - 'This key is used for Physical or logical port connection but does NOT include a network port. (Example: Printer port name).', - name: 'rsa.misc.port_name', - type: 'keyword', - }, - 'rsa.misc.rule_group': { - category: 'rsa', - description: 'This key captures the Rule group name', - name: 'rsa.misc.rule_group', - type: 'keyword', - }, - 'rsa.misc.risk_num': { - category: 'rsa', - description: 'This key captures a Numeric Risk value', - name: 'rsa.misc.risk_num', - type: 'double', - }, - 'rsa.misc.trigger_val': { - category: 'rsa', - description: 'This key captures the Value of the trigger or threshold condition.', - name: 'rsa.misc.trigger_val', - type: 'keyword', - }, - 'rsa.misc.log_session_id1': { - category: 'rsa', - description: - 'This key is used to capture a Linked (Related) Session ID from the session directly', - name: 'rsa.misc.log_session_id1', - type: 'keyword', - }, - 'rsa.misc.comp_version': { - category: 'rsa', - description: 'This key captures the Version level of a sub-component of a product.', - name: 'rsa.misc.comp_version', - type: 'keyword', - }, - 'rsa.misc.content_version': { - category: 'rsa', - description: 'This key captures Version level of a signature or database content.', - name: 'rsa.misc.content_version', - type: 'keyword', - }, - 'rsa.misc.hardware_id': { - category: 'rsa', - description: - 'This key is used to capture unique identifier for a device or system (NOT a Mac address)', - name: 'rsa.misc.hardware_id', - type: 'keyword', - }, - 'rsa.misc.risk': { - category: 'rsa', - description: 'This key captures the non-numeric risk value', - name: 'rsa.misc.risk', - type: 'keyword', - }, - 'rsa.misc.event_id': { - category: 'rsa', - name: 'rsa.misc.event_id', - type: 'keyword', - }, - 'rsa.misc.reason': { - category: 'rsa', - name: 'rsa.misc.reason', - type: 'keyword', - }, - 'rsa.misc.status': { - category: 'rsa', - name: 'rsa.misc.status', - type: 'keyword', - }, - 'rsa.misc.mail_id': { - category: 'rsa', - description: 'This key is used to capture the mailbox id/name', - name: 'rsa.misc.mail_id', - type: 'keyword', - }, - 'rsa.misc.rule_uid': { - category: 'rsa', - description: 'This key is the Unique Identifier for a rule.', - name: 'rsa.misc.rule_uid', - type: 'keyword', - }, - 'rsa.misc.trigger_desc': { - category: 'rsa', - description: 'This key captures the Description of the trigger or threshold condition.', - name: 'rsa.misc.trigger_desc', - type: 'keyword', - }, - 'rsa.misc.inout': { - category: 'rsa', - name: 'rsa.misc.inout', - type: 'keyword', - }, - 'rsa.misc.p_msgid': { - category: 'rsa', - name: 'rsa.misc.p_msgid', - type: 'keyword', - }, - 'rsa.misc.data_type': { - category: 'rsa', - name: 'rsa.misc.data_type', - type: 'keyword', - }, - 'rsa.misc.msgIdPart4': { - category: 'rsa', - name: 'rsa.misc.msgIdPart4', - type: 'keyword', - }, - 'rsa.misc.error': { - category: 'rsa', - description: 'This key captures All non successful Error codes or responses', - name: 'rsa.misc.error', - type: 'keyword', - }, - 'rsa.misc.index': { - category: 'rsa', - name: 'rsa.misc.index', - type: 'keyword', - }, - 'rsa.misc.listnum': { - category: 'rsa', - description: - 'This key is used to capture listname or listnumber, primarily for collecting access-list', - name: 'rsa.misc.listnum', - type: 'keyword', - }, - 'rsa.misc.ntype': { - category: 'rsa', - name: 'rsa.misc.ntype', - type: 'keyword', - }, - 'rsa.misc.observed_val': { - category: 'rsa', - description: - 'This key captures the Value observed (from the perspective of the device generating the log).', - name: 'rsa.misc.observed_val', - type: 'keyword', - }, - 'rsa.misc.policy_value': { - category: 'rsa', - description: - 'This key captures the contents of the policy. This contains details about the policy', - name: 'rsa.misc.policy_value', - type: 'keyword', - }, - 'rsa.misc.pool_name': { - category: 'rsa', - description: 'This key captures the name of a resource pool', - name: 'rsa.misc.pool_name', - type: 'keyword', - }, - 'rsa.misc.rule_template': { - category: 'rsa', - description: - 'A default set of parameters which are overlayed onto a rule (or rulename) which efffectively constitutes a template', - name: 'rsa.misc.rule_template', - type: 'keyword', - }, - 'rsa.misc.count': { - category: 'rsa', - name: 'rsa.misc.count', - type: 'keyword', - }, - 'rsa.misc.number': { - category: 'rsa', - name: 'rsa.misc.number', - type: 'keyword', - }, - 'rsa.misc.sigcat': { - category: 'rsa', - name: 'rsa.misc.sigcat', - type: 'keyword', - }, - 'rsa.misc.type': { - category: 'rsa', - name: 'rsa.misc.type', - type: 'keyword', - }, - 'rsa.misc.comments': { - category: 'rsa', - description: 'Comment information provided in the log message', - name: 'rsa.misc.comments', - type: 'keyword', - }, - 'rsa.misc.doc_number': { - category: 'rsa', - description: 'This key captures File Identification number', - name: 'rsa.misc.doc_number', - type: 'long', - }, - 'rsa.misc.expected_val': { - category: 'rsa', - description: - 'This key captures the Value expected (from the perspective of the device generating the log).', - name: 'rsa.misc.expected_val', - type: 'keyword', - }, - 'rsa.misc.job_num': { - category: 'rsa', - description: 'This key captures the Job Number', - name: 'rsa.misc.job_num', - type: 'keyword', - }, - 'rsa.misc.spi_dst': { - category: 'rsa', - description: 'Destination SPI Index', - name: 'rsa.misc.spi_dst', - type: 'keyword', - }, - 'rsa.misc.spi_src': { - category: 'rsa', - description: 'Source SPI Index', - name: 'rsa.misc.spi_src', - type: 'keyword', - }, - 'rsa.misc.code': { - category: 'rsa', - name: 'rsa.misc.code', - type: 'keyword', - }, - 'rsa.misc.agent_id': { - category: 'rsa', - description: 'This key is used to capture agent id', - name: 'rsa.misc.agent_id', - type: 'keyword', - }, - 'rsa.misc.message_body': { - category: 'rsa', - description: 'This key captures the The contents of the message body.', - name: 'rsa.misc.message_body', - type: 'keyword', - }, - 'rsa.misc.phone': { - category: 'rsa', - name: 'rsa.misc.phone', - type: 'keyword', - }, - 'rsa.misc.sig_id_str': { - category: 'rsa', - description: 'This key captures a string object of the sigid variable.', - name: 'rsa.misc.sig_id_str', - type: 'keyword', - }, - 'rsa.misc.cmd': { - category: 'rsa', - name: 'rsa.misc.cmd', - type: 'keyword', - }, - 'rsa.misc.misc': { - category: 'rsa', - name: 'rsa.misc.misc', - type: 'keyword', - }, - 'rsa.misc.name': { - category: 'rsa', - name: 'rsa.misc.name', - type: 'keyword', - }, - 'rsa.misc.cpu': { - category: 'rsa', - description: 'This key is the CPU time used in the execution of the event being recorded.', - name: 'rsa.misc.cpu', - type: 'long', - }, - 'rsa.misc.event_desc': { - category: 'rsa', - description: - 'This key is used to capture a description of an event available directly or inferred', - name: 'rsa.misc.event_desc', - type: 'keyword', - }, - 'rsa.misc.sig_id1': { - category: 'rsa', - description: 'This key captures IDS/IPS Int Signature ID. This must be linked to the sig.id', - name: 'rsa.misc.sig_id1', - type: 'long', - }, - 'rsa.misc.im_buddyid': { - category: 'rsa', - name: 'rsa.misc.im_buddyid', - type: 'keyword', - }, - 'rsa.misc.im_client': { - category: 'rsa', - name: 'rsa.misc.im_client', - type: 'keyword', - }, - 'rsa.misc.im_userid': { - category: 'rsa', - name: 'rsa.misc.im_userid', - type: 'keyword', - }, - 'rsa.misc.pid': { - category: 'rsa', - name: 'rsa.misc.pid', - type: 'keyword', - }, - 'rsa.misc.priority': { - category: 'rsa', - name: 'rsa.misc.priority', - type: 'keyword', - }, - 'rsa.misc.context_subject': { - category: 'rsa', - description: - 'This key is to be used in an audit context where the subject is the object being identified', - name: 'rsa.misc.context_subject', - type: 'keyword', - }, - 'rsa.misc.context_target': { - category: 'rsa', - name: 'rsa.misc.context_target', - type: 'keyword', - }, - 'rsa.misc.cve': { - category: 'rsa', - description: - 'This key captures CVE (Common Vulnerabilities and Exposures) - an identifier for known information security vulnerabilities.', - name: 'rsa.misc.cve', - type: 'keyword', - }, - 'rsa.misc.fcatnum': { - category: 'rsa', - description: 'This key captures Filter Category Number. Legacy Usage', - name: 'rsa.misc.fcatnum', - type: 'keyword', - }, - 'rsa.misc.library': { - category: 'rsa', - description: 'This key is used to capture library information in mainframe devices', - name: 'rsa.misc.library', - type: 'keyword', - }, - 'rsa.misc.parent_node': { - category: 'rsa', - description: 'This key captures the Parent Node Name. Must be related to node variable.', - name: 'rsa.misc.parent_node', - type: 'keyword', - }, - 'rsa.misc.risk_info': { - category: 'rsa', - description: 'Deprecated, use New Hunting Model (inv.*, ioc, boc, eoc, analysis.*)', - name: 'rsa.misc.risk_info', - type: 'keyword', - }, - 'rsa.misc.tcp_flags': { - category: 'rsa', - description: 'This key is captures the TCP flags set in any packet of session', - name: 'rsa.misc.tcp_flags', - type: 'long', - }, - 'rsa.misc.tos': { - category: 'rsa', - description: 'This key describes the type of service', - name: 'rsa.misc.tos', - type: 'long', - }, - 'rsa.misc.vm_target': { - category: 'rsa', - description: 'VMWare Target **VMWARE** only varaible.', - name: 'rsa.misc.vm_target', - type: 'keyword', - }, - 'rsa.misc.workspace': { - category: 'rsa', - description: 'This key captures Workspace Description', - name: 'rsa.misc.workspace', - type: 'keyword', - }, - 'rsa.misc.command': { - category: 'rsa', - name: 'rsa.misc.command', - type: 'keyword', - }, - 'rsa.misc.event_category': { - category: 'rsa', - name: 'rsa.misc.event_category', - type: 'keyword', - }, - 'rsa.misc.facilityname': { - category: 'rsa', - name: 'rsa.misc.facilityname', - type: 'keyword', - }, - 'rsa.misc.forensic_info': { - category: 'rsa', - name: 'rsa.misc.forensic_info', - type: 'keyword', - }, - 'rsa.misc.jobname': { - category: 'rsa', - name: 'rsa.misc.jobname', - type: 'keyword', - }, - 'rsa.misc.mode': { - category: 'rsa', - name: 'rsa.misc.mode', - type: 'keyword', - }, - 'rsa.misc.policy': { - category: 'rsa', - name: 'rsa.misc.policy', - type: 'keyword', - }, - 'rsa.misc.policy_waiver': { - category: 'rsa', - name: 'rsa.misc.policy_waiver', - type: 'keyword', - }, - 'rsa.misc.second': { - category: 'rsa', - name: 'rsa.misc.second', - type: 'keyword', - }, - 'rsa.misc.space1': { - category: 'rsa', - name: 'rsa.misc.space1', - type: 'keyword', - }, - 'rsa.misc.subcategory': { - category: 'rsa', - name: 'rsa.misc.subcategory', - type: 'keyword', - }, - 'rsa.misc.tbdstr2': { - category: 'rsa', - name: 'rsa.misc.tbdstr2', - type: 'keyword', - }, - 'rsa.misc.alert_id': { - category: 'rsa', - description: 'Deprecated, New Hunting Model (inv.*, ioc, boc, eoc, analysis.*)', - name: 'rsa.misc.alert_id', - type: 'keyword', - }, - 'rsa.misc.checksum_dst': { - category: 'rsa', - description: - 'This key is used to capture the checksum or hash of the the target entity such as a process or file.', - name: 'rsa.misc.checksum_dst', - type: 'keyword', - }, - 'rsa.misc.checksum_src': { - category: 'rsa', - description: - 'This key is used to capture the checksum or hash of the source entity such as a file or process.', - name: 'rsa.misc.checksum_src', - type: 'keyword', - }, - 'rsa.misc.fresult': { - category: 'rsa', - description: 'This key captures the Filter Result', - name: 'rsa.misc.fresult', - type: 'long', - }, - 'rsa.misc.payload_dst': { - category: 'rsa', - description: 'This key is used to capture destination payload', - name: 'rsa.misc.payload_dst', - type: 'keyword', - }, - 'rsa.misc.payload_src': { - category: 'rsa', - description: 'This key is used to capture source payload', - name: 'rsa.misc.payload_src', - type: 'keyword', - }, - 'rsa.misc.pool_id': { - category: 'rsa', - description: 'This key captures the identifier (typically numeric field) of a resource pool', - name: 'rsa.misc.pool_id', - type: 'keyword', - }, - 'rsa.misc.process_id_val': { - category: 'rsa', - description: 'This key is a failure key for Process ID when it is not an integer value', - name: 'rsa.misc.process_id_val', - type: 'keyword', - }, - 'rsa.misc.risk_num_comm': { - category: 'rsa', - description: 'This key captures Risk Number Community', - name: 'rsa.misc.risk_num_comm', - type: 'double', - }, - 'rsa.misc.risk_num_next': { - category: 'rsa', - description: 'This key captures Risk Number NextGen', - name: 'rsa.misc.risk_num_next', - type: 'double', - }, - 'rsa.misc.risk_num_sand': { - category: 'rsa', - description: 'This key captures Risk Number SandBox', - name: 'rsa.misc.risk_num_sand', - type: 'double', - }, - 'rsa.misc.risk_num_static': { - category: 'rsa', - description: 'This key captures Risk Number Static', - name: 'rsa.misc.risk_num_static', - type: 'double', - }, - 'rsa.misc.risk_suspicious': { - category: 'rsa', - description: 'Deprecated, use New Hunting Model (inv.*, ioc, boc, eoc, analysis.*)', - name: 'rsa.misc.risk_suspicious', - type: 'keyword', - }, - 'rsa.misc.risk_warning': { - category: 'rsa', - description: 'Deprecated, use New Hunting Model (inv.*, ioc, boc, eoc, analysis.*)', - name: 'rsa.misc.risk_warning', - type: 'keyword', - }, - 'rsa.misc.snmp_oid': { - category: 'rsa', - description: 'SNMP Object Identifier', - name: 'rsa.misc.snmp_oid', - type: 'keyword', - }, - 'rsa.misc.sql': { - category: 'rsa', - description: 'This key captures the SQL query', - name: 'rsa.misc.sql', - type: 'keyword', - }, - 'rsa.misc.vuln_ref': { - category: 'rsa', - description: 'This key captures the Vulnerability Reference details', - name: 'rsa.misc.vuln_ref', - type: 'keyword', - }, - 'rsa.misc.acl_id': { - category: 'rsa', - name: 'rsa.misc.acl_id', - type: 'keyword', - }, - 'rsa.misc.acl_op': { - category: 'rsa', - name: 'rsa.misc.acl_op', - type: 'keyword', - }, - 'rsa.misc.acl_pos': { - category: 'rsa', - name: 'rsa.misc.acl_pos', - type: 'keyword', - }, - 'rsa.misc.acl_table': { - category: 'rsa', - name: 'rsa.misc.acl_table', - type: 'keyword', - }, - 'rsa.misc.admin': { - category: 'rsa', - name: 'rsa.misc.admin', - type: 'keyword', - }, - 'rsa.misc.alarm_id': { - category: 'rsa', - name: 'rsa.misc.alarm_id', - type: 'keyword', - }, - 'rsa.misc.alarmname': { - category: 'rsa', - name: 'rsa.misc.alarmname', - type: 'keyword', - }, - 'rsa.misc.app_id': { - category: 'rsa', - name: 'rsa.misc.app_id', - type: 'keyword', - }, - 'rsa.misc.audit': { - category: 'rsa', - name: 'rsa.misc.audit', - type: 'keyword', - }, - 'rsa.misc.audit_object': { - category: 'rsa', - name: 'rsa.misc.audit_object', - type: 'keyword', - }, - 'rsa.misc.auditdata': { - category: 'rsa', - name: 'rsa.misc.auditdata', - type: 'keyword', - }, - 'rsa.misc.benchmark': { - category: 'rsa', - name: 'rsa.misc.benchmark', - type: 'keyword', - }, - 'rsa.misc.bypass': { - category: 'rsa', - name: 'rsa.misc.bypass', - type: 'keyword', - }, - 'rsa.misc.cache': { - category: 'rsa', - name: 'rsa.misc.cache', - type: 'keyword', - }, - 'rsa.misc.cache_hit': { - category: 'rsa', - name: 'rsa.misc.cache_hit', - type: 'keyword', - }, - 'rsa.misc.cefversion': { - category: 'rsa', - name: 'rsa.misc.cefversion', - type: 'keyword', - }, - 'rsa.misc.cfg_attr': { - category: 'rsa', - name: 'rsa.misc.cfg_attr', - type: 'keyword', - }, - 'rsa.misc.cfg_obj': { - category: 'rsa', - name: 'rsa.misc.cfg_obj', - type: 'keyword', - }, - 'rsa.misc.cfg_path': { - category: 'rsa', - name: 'rsa.misc.cfg_path', - type: 'keyword', - }, - 'rsa.misc.changes': { - category: 'rsa', - name: 'rsa.misc.changes', - type: 'keyword', - }, - 'rsa.misc.client_ip': { - category: 'rsa', - name: 'rsa.misc.client_ip', - type: 'keyword', - }, - 'rsa.misc.clustermembers': { - category: 'rsa', - name: 'rsa.misc.clustermembers', - type: 'keyword', - }, - 'rsa.misc.cn_acttimeout': { - category: 'rsa', - name: 'rsa.misc.cn_acttimeout', - type: 'keyword', - }, - 'rsa.misc.cn_asn_src': { - category: 'rsa', - name: 'rsa.misc.cn_asn_src', - type: 'keyword', - }, - 'rsa.misc.cn_bgpv4nxthop': { - category: 'rsa', - name: 'rsa.misc.cn_bgpv4nxthop', - type: 'keyword', - }, - 'rsa.misc.cn_ctr_dst_code': { - category: 'rsa', - name: 'rsa.misc.cn_ctr_dst_code', - type: 'keyword', - }, - 'rsa.misc.cn_dst_tos': { - category: 'rsa', - name: 'rsa.misc.cn_dst_tos', - type: 'keyword', - }, - 'rsa.misc.cn_dst_vlan': { - category: 'rsa', - name: 'rsa.misc.cn_dst_vlan', - type: 'keyword', - }, - 'rsa.misc.cn_engine_id': { - category: 'rsa', - name: 'rsa.misc.cn_engine_id', - type: 'keyword', - }, - 'rsa.misc.cn_engine_type': { - category: 'rsa', - name: 'rsa.misc.cn_engine_type', - type: 'keyword', - }, - 'rsa.misc.cn_f_switch': { - category: 'rsa', - name: 'rsa.misc.cn_f_switch', - type: 'keyword', - }, - 'rsa.misc.cn_flowsampid': { - category: 'rsa', - name: 'rsa.misc.cn_flowsampid', - type: 'keyword', - }, - 'rsa.misc.cn_flowsampintv': { - category: 'rsa', - name: 'rsa.misc.cn_flowsampintv', - type: 'keyword', - }, - 'rsa.misc.cn_flowsampmode': { - category: 'rsa', - name: 'rsa.misc.cn_flowsampmode', - type: 'keyword', - }, - 'rsa.misc.cn_inacttimeout': { - category: 'rsa', - name: 'rsa.misc.cn_inacttimeout', - type: 'keyword', - }, - 'rsa.misc.cn_inpermbyts': { - category: 'rsa', - name: 'rsa.misc.cn_inpermbyts', - type: 'keyword', - }, - 'rsa.misc.cn_inpermpckts': { - category: 'rsa', - name: 'rsa.misc.cn_inpermpckts', - type: 'keyword', - }, - 'rsa.misc.cn_invalid': { - category: 'rsa', - name: 'rsa.misc.cn_invalid', - type: 'keyword', - }, - 'rsa.misc.cn_ip_proto_ver': { - category: 'rsa', - name: 'rsa.misc.cn_ip_proto_ver', - type: 'keyword', - }, - 'rsa.misc.cn_ipv4_ident': { - category: 'rsa', - name: 'rsa.misc.cn_ipv4_ident', - type: 'keyword', - }, - 'rsa.misc.cn_l_switch': { - category: 'rsa', - name: 'rsa.misc.cn_l_switch', - type: 'keyword', - }, - 'rsa.misc.cn_log_did': { - category: 'rsa', - name: 'rsa.misc.cn_log_did', - type: 'keyword', - }, - 'rsa.misc.cn_log_rid': { - category: 'rsa', - name: 'rsa.misc.cn_log_rid', - type: 'keyword', - }, - 'rsa.misc.cn_max_ttl': { - category: 'rsa', - name: 'rsa.misc.cn_max_ttl', - type: 'keyword', - }, - 'rsa.misc.cn_maxpcktlen': { - category: 'rsa', - name: 'rsa.misc.cn_maxpcktlen', - type: 'keyword', - }, - 'rsa.misc.cn_min_ttl': { - category: 'rsa', - name: 'rsa.misc.cn_min_ttl', - type: 'keyword', - }, - 'rsa.misc.cn_minpcktlen': { - category: 'rsa', - name: 'rsa.misc.cn_minpcktlen', - type: 'keyword', - }, - 'rsa.misc.cn_mpls_lbl_1': { - category: 'rsa', - name: 'rsa.misc.cn_mpls_lbl_1', - type: 'keyword', - }, - 'rsa.misc.cn_mpls_lbl_10': { - category: 'rsa', - name: 'rsa.misc.cn_mpls_lbl_10', - type: 'keyword', - }, - 'rsa.misc.cn_mpls_lbl_2': { - category: 'rsa', - name: 'rsa.misc.cn_mpls_lbl_2', - type: 'keyword', - }, - 'rsa.misc.cn_mpls_lbl_3': { - category: 'rsa', - name: 'rsa.misc.cn_mpls_lbl_3', - type: 'keyword', - }, - 'rsa.misc.cn_mpls_lbl_4': { - category: 'rsa', - name: 'rsa.misc.cn_mpls_lbl_4', - type: 'keyword', - }, - 'rsa.misc.cn_mpls_lbl_5': { - category: 'rsa', - name: 'rsa.misc.cn_mpls_lbl_5', - type: 'keyword', - }, - 'rsa.misc.cn_mpls_lbl_6': { - category: 'rsa', - name: 'rsa.misc.cn_mpls_lbl_6', - type: 'keyword', - }, - 'rsa.misc.cn_mpls_lbl_7': { - category: 'rsa', - name: 'rsa.misc.cn_mpls_lbl_7', - type: 'keyword', - }, - 'rsa.misc.cn_mpls_lbl_8': { - category: 'rsa', - name: 'rsa.misc.cn_mpls_lbl_8', - type: 'keyword', - }, - 'rsa.misc.cn_mpls_lbl_9': { - category: 'rsa', - name: 'rsa.misc.cn_mpls_lbl_9', - type: 'keyword', - }, - 'rsa.misc.cn_mplstoplabel': { - category: 'rsa', - name: 'rsa.misc.cn_mplstoplabel', - type: 'keyword', - }, - 'rsa.misc.cn_mplstoplabip': { - category: 'rsa', - name: 'rsa.misc.cn_mplstoplabip', - type: 'keyword', - }, - 'rsa.misc.cn_mul_dst_byt': { - category: 'rsa', - name: 'rsa.misc.cn_mul_dst_byt', - type: 'keyword', - }, - 'rsa.misc.cn_mul_dst_pks': { - category: 'rsa', - name: 'rsa.misc.cn_mul_dst_pks', - type: 'keyword', - }, - 'rsa.misc.cn_muligmptype': { - category: 'rsa', - name: 'rsa.misc.cn_muligmptype', - type: 'keyword', - }, - 'rsa.misc.cn_sampalgo': { - category: 'rsa', - name: 'rsa.misc.cn_sampalgo', - type: 'keyword', - }, - 'rsa.misc.cn_sampint': { - category: 'rsa', - name: 'rsa.misc.cn_sampint', - type: 'keyword', - }, - 'rsa.misc.cn_seqctr': { - category: 'rsa', - name: 'rsa.misc.cn_seqctr', - type: 'keyword', - }, - 'rsa.misc.cn_spackets': { - category: 'rsa', - name: 'rsa.misc.cn_spackets', - type: 'keyword', - }, - 'rsa.misc.cn_src_tos': { - category: 'rsa', - name: 'rsa.misc.cn_src_tos', - type: 'keyword', - }, - 'rsa.misc.cn_src_vlan': { - category: 'rsa', - name: 'rsa.misc.cn_src_vlan', - type: 'keyword', - }, - 'rsa.misc.cn_sysuptime': { - category: 'rsa', - name: 'rsa.misc.cn_sysuptime', - type: 'keyword', - }, - 'rsa.misc.cn_template_id': { - category: 'rsa', - name: 'rsa.misc.cn_template_id', - type: 'keyword', - }, - 'rsa.misc.cn_totbytsexp': { - category: 'rsa', - name: 'rsa.misc.cn_totbytsexp', - type: 'keyword', - }, - 'rsa.misc.cn_totflowexp': { - category: 'rsa', - name: 'rsa.misc.cn_totflowexp', - type: 'keyword', - }, - 'rsa.misc.cn_totpcktsexp': { - category: 'rsa', - name: 'rsa.misc.cn_totpcktsexp', - type: 'keyword', - }, - 'rsa.misc.cn_unixnanosecs': { - category: 'rsa', - name: 'rsa.misc.cn_unixnanosecs', - type: 'keyword', - }, - 'rsa.misc.cn_v6flowlabel': { - category: 'rsa', - name: 'rsa.misc.cn_v6flowlabel', - type: 'keyword', - }, - 'rsa.misc.cn_v6optheaders': { - category: 'rsa', - name: 'rsa.misc.cn_v6optheaders', - type: 'keyword', - }, - 'rsa.misc.comp_class': { - category: 'rsa', - name: 'rsa.misc.comp_class', - type: 'keyword', - }, - 'rsa.misc.comp_name': { - category: 'rsa', - name: 'rsa.misc.comp_name', - type: 'keyword', - }, - 'rsa.misc.comp_rbytes': { - category: 'rsa', - name: 'rsa.misc.comp_rbytes', - type: 'keyword', - }, - 'rsa.misc.comp_sbytes': { - category: 'rsa', - name: 'rsa.misc.comp_sbytes', - type: 'keyword', - }, - 'rsa.misc.cpu_data': { - category: 'rsa', - name: 'rsa.misc.cpu_data', - type: 'keyword', - }, - 'rsa.misc.criticality': { - category: 'rsa', - name: 'rsa.misc.criticality', - type: 'keyword', - }, - 'rsa.misc.cs_agency_dst': { - category: 'rsa', - name: 'rsa.misc.cs_agency_dst', - type: 'keyword', - }, - 'rsa.misc.cs_analyzedby': { - category: 'rsa', - name: 'rsa.misc.cs_analyzedby', - type: 'keyword', - }, - 'rsa.misc.cs_av_other': { - category: 'rsa', - name: 'rsa.misc.cs_av_other', - type: 'keyword', - }, - 'rsa.misc.cs_av_primary': { - category: 'rsa', - name: 'rsa.misc.cs_av_primary', - type: 'keyword', - }, - 'rsa.misc.cs_av_secondary': { - category: 'rsa', - name: 'rsa.misc.cs_av_secondary', - type: 'keyword', - }, - 'rsa.misc.cs_bgpv6nxthop': { - category: 'rsa', - name: 'rsa.misc.cs_bgpv6nxthop', - type: 'keyword', - }, - 'rsa.misc.cs_bit9status': { - category: 'rsa', - name: 'rsa.misc.cs_bit9status', - type: 'keyword', - }, - 'rsa.misc.cs_context': { - category: 'rsa', - name: 'rsa.misc.cs_context', - type: 'keyword', - }, - 'rsa.misc.cs_control': { - category: 'rsa', - name: 'rsa.misc.cs_control', - type: 'keyword', - }, - 'rsa.misc.cs_data': { - category: 'rsa', - name: 'rsa.misc.cs_data', - type: 'keyword', - }, - 'rsa.misc.cs_datecret': { - category: 'rsa', - name: 'rsa.misc.cs_datecret', - type: 'keyword', - }, - 'rsa.misc.cs_dst_tld': { - category: 'rsa', - name: 'rsa.misc.cs_dst_tld', - type: 'keyword', - }, - 'rsa.misc.cs_eth_dst_ven': { - category: 'rsa', - name: 'rsa.misc.cs_eth_dst_ven', - type: 'keyword', - }, - 'rsa.misc.cs_eth_src_ven': { - category: 'rsa', - name: 'rsa.misc.cs_eth_src_ven', - type: 'keyword', - }, - 'rsa.misc.cs_event_uuid': { - category: 'rsa', - name: 'rsa.misc.cs_event_uuid', - type: 'keyword', - }, - 'rsa.misc.cs_filetype': { - category: 'rsa', - name: 'rsa.misc.cs_filetype', - type: 'keyword', - }, - 'rsa.misc.cs_fld': { - category: 'rsa', - name: 'rsa.misc.cs_fld', - type: 'keyword', - }, - 'rsa.misc.cs_if_desc': { - category: 'rsa', - name: 'rsa.misc.cs_if_desc', - type: 'keyword', - }, - 'rsa.misc.cs_if_name': { - category: 'rsa', - name: 'rsa.misc.cs_if_name', - type: 'keyword', - }, - 'rsa.misc.cs_ip_next_hop': { - category: 'rsa', - name: 'rsa.misc.cs_ip_next_hop', - type: 'keyword', - }, - 'rsa.misc.cs_ipv4dstpre': { - category: 'rsa', - name: 'rsa.misc.cs_ipv4dstpre', - type: 'keyword', - }, - 'rsa.misc.cs_ipv4srcpre': { - category: 'rsa', - name: 'rsa.misc.cs_ipv4srcpre', - type: 'keyword', - }, - 'rsa.misc.cs_lifetime': { - category: 'rsa', - name: 'rsa.misc.cs_lifetime', - type: 'keyword', - }, - 'rsa.misc.cs_log_medium': { - category: 'rsa', - name: 'rsa.misc.cs_log_medium', - type: 'keyword', - }, - 'rsa.misc.cs_loginname': { - category: 'rsa', - name: 'rsa.misc.cs_loginname', - type: 'keyword', - }, - 'rsa.misc.cs_modulescore': { - category: 'rsa', - name: 'rsa.misc.cs_modulescore', - type: 'keyword', - }, - 'rsa.misc.cs_modulesign': { - category: 'rsa', - name: 'rsa.misc.cs_modulesign', - type: 'keyword', - }, - 'rsa.misc.cs_opswatresult': { - category: 'rsa', - name: 'rsa.misc.cs_opswatresult', - type: 'keyword', - }, - 'rsa.misc.cs_payload': { - category: 'rsa', - name: 'rsa.misc.cs_payload', - type: 'keyword', - }, - 'rsa.misc.cs_registrant': { - category: 'rsa', - name: 'rsa.misc.cs_registrant', - type: 'keyword', - }, - 'rsa.misc.cs_registrar': { - category: 'rsa', - name: 'rsa.misc.cs_registrar', - type: 'keyword', - }, - 'rsa.misc.cs_represult': { - category: 'rsa', - name: 'rsa.misc.cs_represult', - type: 'keyword', - }, - 'rsa.misc.cs_rpayload': { - category: 'rsa', - name: 'rsa.misc.cs_rpayload', - type: 'keyword', - }, - 'rsa.misc.cs_sampler_name': { - category: 'rsa', - name: 'rsa.misc.cs_sampler_name', - type: 'keyword', - }, - 'rsa.misc.cs_sourcemodule': { - category: 'rsa', - name: 'rsa.misc.cs_sourcemodule', - type: 'keyword', - }, - 'rsa.misc.cs_streams': { - category: 'rsa', - name: 'rsa.misc.cs_streams', - type: 'keyword', - }, - 'rsa.misc.cs_targetmodule': { - category: 'rsa', - name: 'rsa.misc.cs_targetmodule', - type: 'keyword', - }, - 'rsa.misc.cs_v6nxthop': { - category: 'rsa', - name: 'rsa.misc.cs_v6nxthop', - type: 'keyword', - }, - 'rsa.misc.cs_whois_server': { - category: 'rsa', - name: 'rsa.misc.cs_whois_server', - type: 'keyword', - }, - 'rsa.misc.cs_yararesult': { - category: 'rsa', - name: 'rsa.misc.cs_yararesult', - type: 'keyword', - }, - 'rsa.misc.description': { - category: 'rsa', - name: 'rsa.misc.description', - type: 'keyword', - }, - 'rsa.misc.devvendor': { - category: 'rsa', - name: 'rsa.misc.devvendor', - type: 'keyword', - }, - 'rsa.misc.distance': { - category: 'rsa', - name: 'rsa.misc.distance', - type: 'keyword', - }, - 'rsa.misc.dstburb': { - category: 'rsa', - name: 'rsa.misc.dstburb', - type: 'keyword', - }, - 'rsa.misc.edomain': { - category: 'rsa', - name: 'rsa.misc.edomain', - type: 'keyword', - }, - 'rsa.misc.edomaub': { - category: 'rsa', - name: 'rsa.misc.edomaub', - type: 'keyword', - }, - 'rsa.misc.euid': { - category: 'rsa', - name: 'rsa.misc.euid', - type: 'keyword', - }, - 'rsa.misc.facility': { - category: 'rsa', - name: 'rsa.misc.facility', - type: 'keyword', - }, - 'rsa.misc.finterface': { - category: 'rsa', - name: 'rsa.misc.finterface', - type: 'keyword', - }, - 'rsa.misc.flags': { - category: 'rsa', - name: 'rsa.misc.flags', - type: 'keyword', - }, - 'rsa.misc.gaddr': { - category: 'rsa', - name: 'rsa.misc.gaddr', - type: 'keyword', - }, - 'rsa.misc.id3': { - category: 'rsa', - name: 'rsa.misc.id3', - type: 'keyword', - }, - 'rsa.misc.im_buddyname': { - category: 'rsa', - name: 'rsa.misc.im_buddyname', - type: 'keyword', - }, - 'rsa.misc.im_croomid': { - category: 'rsa', - name: 'rsa.misc.im_croomid', - type: 'keyword', - }, - 'rsa.misc.im_croomtype': { - category: 'rsa', - name: 'rsa.misc.im_croomtype', - type: 'keyword', - }, - 'rsa.misc.im_members': { - category: 'rsa', - name: 'rsa.misc.im_members', - type: 'keyword', - }, - 'rsa.misc.im_username': { - category: 'rsa', - name: 'rsa.misc.im_username', - type: 'keyword', - }, - 'rsa.misc.ipkt': { - category: 'rsa', - name: 'rsa.misc.ipkt', - type: 'keyword', - }, - 'rsa.misc.ipscat': { - category: 'rsa', - name: 'rsa.misc.ipscat', - type: 'keyword', - }, - 'rsa.misc.ipspri': { - category: 'rsa', - name: 'rsa.misc.ipspri', - type: 'keyword', - }, - 'rsa.misc.latitude': { - category: 'rsa', - name: 'rsa.misc.latitude', - type: 'keyword', - }, - 'rsa.misc.linenum': { - category: 'rsa', - name: 'rsa.misc.linenum', - type: 'keyword', - }, - 'rsa.misc.list_name': { - category: 'rsa', - name: 'rsa.misc.list_name', - type: 'keyword', - }, - 'rsa.misc.load_data': { - category: 'rsa', - name: 'rsa.misc.load_data', - type: 'keyword', - }, - 'rsa.misc.location_floor': { - category: 'rsa', - name: 'rsa.misc.location_floor', - type: 'keyword', - }, - 'rsa.misc.location_mark': { - category: 'rsa', - name: 'rsa.misc.location_mark', - type: 'keyword', - }, - 'rsa.misc.log_id': { - category: 'rsa', - name: 'rsa.misc.log_id', - type: 'keyword', - }, - 'rsa.misc.log_type': { - category: 'rsa', - name: 'rsa.misc.log_type', - type: 'keyword', - }, - 'rsa.misc.logid': { - category: 'rsa', - name: 'rsa.misc.logid', - type: 'keyword', - }, - 'rsa.misc.logip': { - category: 'rsa', - name: 'rsa.misc.logip', - type: 'keyword', - }, - 'rsa.misc.logname': { - category: 'rsa', - name: 'rsa.misc.logname', - type: 'keyword', - }, - 'rsa.misc.longitude': { - category: 'rsa', - name: 'rsa.misc.longitude', - type: 'keyword', - }, - 'rsa.misc.lport': { - category: 'rsa', - name: 'rsa.misc.lport', - type: 'keyword', - }, - 'rsa.misc.mbug_data': { - category: 'rsa', - name: 'rsa.misc.mbug_data', - type: 'keyword', - }, - 'rsa.misc.misc_name': { - category: 'rsa', - name: 'rsa.misc.misc_name', - type: 'keyword', - }, - 'rsa.misc.msg_type': { - category: 'rsa', - name: 'rsa.misc.msg_type', - type: 'keyword', - }, - 'rsa.misc.msgid': { - category: 'rsa', - name: 'rsa.misc.msgid', - type: 'keyword', - }, - 'rsa.misc.netsessid': { - category: 'rsa', - name: 'rsa.misc.netsessid', - type: 'keyword', - }, - 'rsa.misc.num': { - category: 'rsa', - name: 'rsa.misc.num', - type: 'keyword', - }, - 'rsa.misc.number1': { - category: 'rsa', - name: 'rsa.misc.number1', - type: 'keyword', - }, - 'rsa.misc.number2': { - category: 'rsa', - name: 'rsa.misc.number2', - type: 'keyword', - }, - 'rsa.misc.nwwn': { - category: 'rsa', - name: 'rsa.misc.nwwn', - type: 'keyword', - }, - 'rsa.misc.object': { - category: 'rsa', - name: 'rsa.misc.object', - type: 'keyword', - }, - 'rsa.misc.operation': { - category: 'rsa', - name: 'rsa.misc.operation', - type: 'keyword', - }, - 'rsa.misc.opkt': { - category: 'rsa', - name: 'rsa.misc.opkt', - type: 'keyword', - }, - 'rsa.misc.orig_from': { - category: 'rsa', - name: 'rsa.misc.orig_from', - type: 'keyword', - }, - 'rsa.misc.owner_id': { - category: 'rsa', - name: 'rsa.misc.owner_id', - type: 'keyword', - }, - 'rsa.misc.p_action': { - category: 'rsa', - name: 'rsa.misc.p_action', - type: 'keyword', - }, - 'rsa.misc.p_filter': { - category: 'rsa', - name: 'rsa.misc.p_filter', - type: 'keyword', - }, - 'rsa.misc.p_group_object': { - category: 'rsa', - name: 'rsa.misc.p_group_object', - type: 'keyword', - }, - 'rsa.misc.p_id': { - category: 'rsa', - name: 'rsa.misc.p_id', - type: 'keyword', - }, - 'rsa.misc.p_msgid1': { - category: 'rsa', - name: 'rsa.misc.p_msgid1', - type: 'keyword', - }, - 'rsa.misc.p_msgid2': { - category: 'rsa', - name: 'rsa.misc.p_msgid2', - type: 'keyword', - }, - 'rsa.misc.p_result1': { - category: 'rsa', - name: 'rsa.misc.p_result1', - type: 'keyword', - }, - 'rsa.misc.password_chg': { - category: 'rsa', - name: 'rsa.misc.password_chg', - type: 'keyword', - }, - 'rsa.misc.password_expire': { - category: 'rsa', - name: 'rsa.misc.password_expire', - type: 'keyword', - }, - 'rsa.misc.permgranted': { - category: 'rsa', - name: 'rsa.misc.permgranted', - type: 'keyword', - }, - 'rsa.misc.permwanted': { - category: 'rsa', - name: 'rsa.misc.permwanted', - type: 'keyword', - }, - 'rsa.misc.pgid': { - category: 'rsa', - name: 'rsa.misc.pgid', - type: 'keyword', - }, - 'rsa.misc.policyUUID': { - category: 'rsa', - name: 'rsa.misc.policyUUID', - type: 'keyword', - }, - 'rsa.misc.prog_asp_num': { - category: 'rsa', - name: 'rsa.misc.prog_asp_num', - type: 'keyword', - }, - 'rsa.misc.program': { - category: 'rsa', - name: 'rsa.misc.program', - type: 'keyword', - }, - 'rsa.misc.real_data': { - category: 'rsa', - name: 'rsa.misc.real_data', - type: 'keyword', - }, - 'rsa.misc.rec_asp_device': { - category: 'rsa', - name: 'rsa.misc.rec_asp_device', - type: 'keyword', - }, - 'rsa.misc.rec_asp_num': { - category: 'rsa', - name: 'rsa.misc.rec_asp_num', - type: 'keyword', - }, - 'rsa.misc.rec_library': { - category: 'rsa', - name: 'rsa.misc.rec_library', - type: 'keyword', - }, - 'rsa.misc.recordnum': { - category: 'rsa', - name: 'rsa.misc.recordnum', - type: 'keyword', - }, - 'rsa.misc.ruid': { - category: 'rsa', - name: 'rsa.misc.ruid', - type: 'keyword', - }, - 'rsa.misc.sburb': { - category: 'rsa', - name: 'rsa.misc.sburb', - type: 'keyword', - }, - 'rsa.misc.sdomain_fld': { - category: 'rsa', - name: 'rsa.misc.sdomain_fld', - type: 'keyword', - }, - 'rsa.misc.sec': { - category: 'rsa', - name: 'rsa.misc.sec', - type: 'keyword', - }, - 'rsa.misc.sensorname': { - category: 'rsa', - name: 'rsa.misc.sensorname', - type: 'keyword', - }, - 'rsa.misc.seqnum': { - category: 'rsa', - name: 'rsa.misc.seqnum', - type: 'keyword', - }, - 'rsa.misc.session': { - category: 'rsa', - name: 'rsa.misc.session', - type: 'keyword', - }, - 'rsa.misc.sessiontype': { - category: 'rsa', - name: 'rsa.misc.sessiontype', - type: 'keyword', - }, - 'rsa.misc.sigUUID': { - category: 'rsa', - name: 'rsa.misc.sigUUID', - type: 'keyword', - }, - 'rsa.misc.spi': { - category: 'rsa', - name: 'rsa.misc.spi', - type: 'keyword', - }, - 'rsa.misc.srcburb': { - category: 'rsa', - name: 'rsa.misc.srcburb', - type: 'keyword', - }, - 'rsa.misc.srcdom': { - category: 'rsa', - name: 'rsa.misc.srcdom', - type: 'keyword', - }, - 'rsa.misc.srcservice': { - category: 'rsa', - name: 'rsa.misc.srcservice', - type: 'keyword', - }, - 'rsa.misc.state': { - category: 'rsa', - name: 'rsa.misc.state', - type: 'keyword', - }, - 'rsa.misc.status1': { - category: 'rsa', - name: 'rsa.misc.status1', - type: 'keyword', - }, - 'rsa.misc.svcno': { - category: 'rsa', - name: 'rsa.misc.svcno', - type: 'keyword', - }, - 'rsa.misc.system': { - category: 'rsa', - name: 'rsa.misc.system', - type: 'keyword', - }, - 'rsa.misc.tbdstr1': { - category: 'rsa', - name: 'rsa.misc.tbdstr1', - type: 'keyword', - }, - 'rsa.misc.tgtdom': { - category: 'rsa', - name: 'rsa.misc.tgtdom', - type: 'keyword', - }, - 'rsa.misc.tgtdomain': { - category: 'rsa', - name: 'rsa.misc.tgtdomain', - type: 'keyword', - }, - 'rsa.misc.threshold': { - category: 'rsa', - name: 'rsa.misc.threshold', - type: 'keyword', - }, - 'rsa.misc.type1': { - category: 'rsa', - name: 'rsa.misc.type1', - type: 'keyword', - }, - 'rsa.misc.udb_class': { - category: 'rsa', - name: 'rsa.misc.udb_class', - type: 'keyword', - }, - 'rsa.misc.url_fld': { - category: 'rsa', - name: 'rsa.misc.url_fld', - type: 'keyword', - }, - 'rsa.misc.user_div': { - category: 'rsa', - name: 'rsa.misc.user_div', - type: 'keyword', - }, - 'rsa.misc.userid': { - category: 'rsa', - name: 'rsa.misc.userid', - type: 'keyword', - }, - 'rsa.misc.username_fld': { - category: 'rsa', - name: 'rsa.misc.username_fld', - type: 'keyword', - }, - 'rsa.misc.utcstamp': { - category: 'rsa', - name: 'rsa.misc.utcstamp', - type: 'keyword', - }, - 'rsa.misc.v_instafname': { - category: 'rsa', - name: 'rsa.misc.v_instafname', - type: 'keyword', - }, - 'rsa.misc.virt_data': { - category: 'rsa', - name: 'rsa.misc.virt_data', - type: 'keyword', - }, - 'rsa.misc.vpnid': { - category: 'rsa', - name: 'rsa.misc.vpnid', - type: 'keyword', - }, - 'rsa.misc.autorun_type': { - category: 'rsa', - description: 'This is used to capture Auto Run type', - name: 'rsa.misc.autorun_type', - type: 'keyword', - }, - 'rsa.misc.cc_number': { - category: 'rsa', - description: 'Valid Credit Card Numbers only', - name: 'rsa.misc.cc_number', - type: 'long', - }, - 'rsa.misc.content': { - category: 'rsa', - description: 'This key captures the content type from protocol headers', - name: 'rsa.misc.content', - type: 'keyword', - }, - 'rsa.misc.ein_number': { - category: 'rsa', - description: 'Employee Identification Numbers only', - name: 'rsa.misc.ein_number', - type: 'long', - }, - 'rsa.misc.found': { - category: 'rsa', - description: 'This is used to capture the results of regex match', - name: 'rsa.misc.found', - type: 'keyword', - }, - 'rsa.misc.language': { - category: 'rsa', - description: 'This is used to capture list of languages the client support and what it prefers', - name: 'rsa.misc.language', - type: 'keyword', - }, - 'rsa.misc.lifetime': { - category: 'rsa', - description: 'This key is used to capture the session lifetime in seconds.', - name: 'rsa.misc.lifetime', - type: 'long', - }, - 'rsa.misc.link': { - category: 'rsa', - description: - 'This key is used to link the sessions together. This key should never be used to parse Meta data from a session (Logs/Packets) Directly, this is a Reserved key in NetWitness', - name: 'rsa.misc.link', - type: 'keyword', - }, - 'rsa.misc.match': { - category: 'rsa', - description: 'This key is for regex match name from search.ini', - name: 'rsa.misc.match', - type: 'keyword', - }, - 'rsa.misc.param_dst': { - category: 'rsa', - description: 'This key captures the command line/launch argument of the target process or file', - name: 'rsa.misc.param_dst', - type: 'keyword', - }, - 'rsa.misc.param_src': { - category: 'rsa', - description: 'This key captures source parameter', - name: 'rsa.misc.param_src', - type: 'keyword', - }, - 'rsa.misc.search_text': { - category: 'rsa', - description: 'This key captures the Search Text used', - name: 'rsa.misc.search_text', - type: 'keyword', - }, - 'rsa.misc.sig_name': { - category: 'rsa', - description: 'This key is used to capture the Signature Name only.', - name: 'rsa.misc.sig_name', - type: 'keyword', - }, - 'rsa.misc.snmp_value': { - category: 'rsa', - description: 'SNMP set request value', - name: 'rsa.misc.snmp_value', - type: 'keyword', - }, - 'rsa.misc.streams': { - category: 'rsa', - description: 'This key captures number of streams in session', - name: 'rsa.misc.streams', - type: 'long', - }, - 'rsa.db.index': { - category: 'rsa', - description: 'This key captures IndexID of the index.', - name: 'rsa.db.index', - type: 'keyword', - }, - 'rsa.db.instance': { - category: 'rsa', - description: 'This key is used to capture the database server instance name', - name: 'rsa.db.instance', - type: 'keyword', - }, - 'rsa.db.database': { - category: 'rsa', - description: - 'This key is used to capture the name of a database or an instance as seen in a session', - name: 'rsa.db.database', - type: 'keyword', - }, - 'rsa.db.transact_id': { - category: 'rsa', - description: 'This key captures the SQL transantion ID of the current session', - name: 'rsa.db.transact_id', - type: 'keyword', - }, - 'rsa.db.permissions': { - category: 'rsa', - description: 'This key captures permission or privilege level assigned to a resource.', - name: 'rsa.db.permissions', - type: 'keyword', - }, - 'rsa.db.table_name': { - category: 'rsa', - description: 'This key is used to capture the table name', - name: 'rsa.db.table_name', - type: 'keyword', - }, - 'rsa.db.db_id': { - category: 'rsa', - description: 'This key is used to capture the unique identifier for a database', - name: 'rsa.db.db_id', - type: 'keyword', - }, - 'rsa.db.db_pid': { - category: 'rsa', - description: 'This key captures the process id of a connection with database server', - name: 'rsa.db.db_pid', - type: 'long', - }, - 'rsa.db.lread': { - category: 'rsa', - description: 'This key is used for the number of logical reads', - name: 'rsa.db.lread', - type: 'long', - }, - 'rsa.db.lwrite': { - category: 'rsa', - description: 'This key is used for the number of logical writes', - name: 'rsa.db.lwrite', - type: 'long', - }, - 'rsa.db.pread': { - category: 'rsa', - description: 'This key is used for the number of physical writes', - name: 'rsa.db.pread', - type: 'long', - }, - 'rsa.network.alias_host': { - category: 'rsa', - description: - 'This key should be used when the source or destination context of a hostname is not clear.Also it captures the Device Hostname. Any Hostname that isnt ad.computer.', - name: 'rsa.network.alias_host', - type: 'keyword', - }, - 'rsa.network.domain': { - category: 'rsa', - name: 'rsa.network.domain', - type: 'keyword', - }, - 'rsa.network.host_dst': { - category: 'rsa', - description: 'This key should only be used when it’s a Destination Hostname', - name: 'rsa.network.host_dst', - type: 'keyword', - }, - 'rsa.network.network_service': { - category: 'rsa', - description: 'This is used to capture layer 7 protocols/service names', - name: 'rsa.network.network_service', - type: 'keyword', - }, - 'rsa.network.interface': { - category: 'rsa', - description: - 'This key should be used when the source or destination context of an interface is not clear', - name: 'rsa.network.interface', - type: 'keyword', - }, - 'rsa.network.network_port': { - category: 'rsa', - description: - 'Deprecated, use port. NOTE: There is a type discrepancy as currently used, TM: Int32, INDEX: UInt64 (why neither chose the correct UInt16?!)', - name: 'rsa.network.network_port', - type: 'long', - }, - 'rsa.network.eth_host': { - category: 'rsa', - description: 'Deprecated, use alias.mac', - name: 'rsa.network.eth_host', - type: 'keyword', - }, - 'rsa.network.sinterface': { - category: 'rsa', - description: 'This key should only be used when it’s a Source Interface', - name: 'rsa.network.sinterface', - type: 'keyword', - }, - 'rsa.network.dinterface': { - category: 'rsa', - description: 'This key should only be used when it’s a Destination Interface', - name: 'rsa.network.dinterface', - type: 'keyword', - }, - 'rsa.network.vlan': { - category: 'rsa', - description: 'This key should only be used to capture the ID of the Virtual LAN', - name: 'rsa.network.vlan', - type: 'long', - }, - 'rsa.network.zone_src': { - category: 'rsa', - description: 'This key should only be used when it’s a Source Zone.', - name: 'rsa.network.zone_src', - type: 'keyword', - }, - 'rsa.network.zone': { - category: 'rsa', - description: - 'This key should be used when the source or destination context of a Zone is not clear', - name: 'rsa.network.zone', - type: 'keyword', - }, - 'rsa.network.zone_dst': { - category: 'rsa', - description: 'This key should only be used when it’s a Destination Zone.', - name: 'rsa.network.zone_dst', - type: 'keyword', - }, - 'rsa.network.gateway': { - category: 'rsa', - description: 'This key is used to capture the IP Address of the gateway', - name: 'rsa.network.gateway', - type: 'keyword', - }, - 'rsa.network.icmp_type': { - category: 'rsa', - description: 'This key is used to capture the ICMP type only', - name: 'rsa.network.icmp_type', - type: 'long', - }, - 'rsa.network.mask': { - category: 'rsa', - description: 'This key is used to capture the device network IPmask.', - name: 'rsa.network.mask', - type: 'keyword', - }, - 'rsa.network.icmp_code': { - category: 'rsa', - description: 'This key is used to capture the ICMP code only', - name: 'rsa.network.icmp_code', - type: 'long', - }, - 'rsa.network.protocol_detail': { - category: 'rsa', - description: 'This key should be used to capture additional protocol information', - name: 'rsa.network.protocol_detail', - type: 'keyword', - }, - 'rsa.network.dmask': { - category: 'rsa', - description: 'This key is used for Destionation Device network mask', - name: 'rsa.network.dmask', - type: 'keyword', - }, - 'rsa.network.port': { - category: 'rsa', - description: - 'This key should only be used to capture a Network Port when the directionality is not clear', - name: 'rsa.network.port', - type: 'long', - }, - 'rsa.network.smask': { - category: 'rsa', - description: 'This key is used for capturing source Network Mask', - name: 'rsa.network.smask', - type: 'keyword', - }, - 'rsa.network.netname': { - category: 'rsa', - description: - 'This key is used to capture the network name associated with an IP range. This is configured by the end user.', - name: 'rsa.network.netname', - type: 'keyword', - }, - 'rsa.network.paddr': { - category: 'rsa', - description: 'Deprecated', - name: 'rsa.network.paddr', - type: 'ip', - }, - 'rsa.network.faddr': { - category: 'rsa', - name: 'rsa.network.faddr', - type: 'keyword', - }, - 'rsa.network.lhost': { - category: 'rsa', - name: 'rsa.network.lhost', - type: 'keyword', - }, - 'rsa.network.origin': { - category: 'rsa', - name: 'rsa.network.origin', - type: 'keyword', - }, - 'rsa.network.remote_domain_id': { - category: 'rsa', - name: 'rsa.network.remote_domain_id', - type: 'keyword', - }, - 'rsa.network.addr': { - category: 'rsa', - name: 'rsa.network.addr', - type: 'keyword', - }, - 'rsa.network.dns_a_record': { - category: 'rsa', - name: 'rsa.network.dns_a_record', - type: 'keyword', - }, - 'rsa.network.dns_ptr_record': { - category: 'rsa', - name: 'rsa.network.dns_ptr_record', - type: 'keyword', - }, - 'rsa.network.fhost': { - category: 'rsa', - name: 'rsa.network.fhost', - type: 'keyword', - }, - 'rsa.network.fport': { - category: 'rsa', - name: 'rsa.network.fport', - type: 'keyword', - }, - 'rsa.network.laddr': { - category: 'rsa', - name: 'rsa.network.laddr', - type: 'keyword', - }, - 'rsa.network.linterface': { - category: 'rsa', - name: 'rsa.network.linterface', - type: 'keyword', - }, - 'rsa.network.phost': { - category: 'rsa', - name: 'rsa.network.phost', - type: 'keyword', - }, - 'rsa.network.ad_computer_dst': { - category: 'rsa', - description: 'Deprecated, use host.dst', - name: 'rsa.network.ad_computer_dst', - type: 'keyword', - }, - 'rsa.network.eth_type': { - category: 'rsa', - description: 'This key is used to capture Ethernet Type, Used for Layer 3 Protocols Only', - name: 'rsa.network.eth_type', - type: 'long', - }, - 'rsa.network.ip_proto': { - category: 'rsa', - description: - 'This key should be used to capture the Protocol number, all the protocol nubers are converted into string in UI', - name: 'rsa.network.ip_proto', - type: 'long', - }, - 'rsa.network.dns_cname_record': { - category: 'rsa', - name: 'rsa.network.dns_cname_record', - type: 'keyword', - }, - 'rsa.network.dns_id': { - category: 'rsa', - name: 'rsa.network.dns_id', - type: 'keyword', - }, - 'rsa.network.dns_opcode': { - category: 'rsa', - name: 'rsa.network.dns_opcode', - type: 'keyword', - }, - 'rsa.network.dns_resp': { - category: 'rsa', - name: 'rsa.network.dns_resp', - type: 'keyword', - }, - 'rsa.network.dns_type': { - category: 'rsa', - name: 'rsa.network.dns_type', - type: 'keyword', - }, - 'rsa.network.domain1': { - category: 'rsa', - name: 'rsa.network.domain1', - type: 'keyword', - }, - 'rsa.network.host_type': { - category: 'rsa', - name: 'rsa.network.host_type', - type: 'keyword', - }, - 'rsa.network.packet_length': { - category: 'rsa', - name: 'rsa.network.packet_length', - type: 'keyword', - }, - 'rsa.network.host_orig': { - category: 'rsa', - description: - 'This is used to capture the original hostname in case of a Forwarding Agent or a Proxy in between.', - name: 'rsa.network.host_orig', - type: 'keyword', - }, - 'rsa.network.rpayload': { - category: 'rsa', - description: - 'This key is used to capture the total number of payload bytes seen in the retransmitted packets.', - name: 'rsa.network.rpayload', - type: 'keyword', - }, - 'rsa.network.vlan_name': { - category: 'rsa', - description: 'This key should only be used to capture the name of the Virtual LAN', - name: 'rsa.network.vlan_name', - type: 'keyword', - }, - 'rsa.investigations.ec_activity': { - category: 'rsa', - description: 'This key captures the particular event activity(Ex:Logoff)', - name: 'rsa.investigations.ec_activity', - type: 'keyword', - }, - 'rsa.investigations.ec_theme': { - category: 'rsa', - description: 'This key captures the Theme of a particular Event(Ex:Authentication)', - name: 'rsa.investigations.ec_theme', - type: 'keyword', - }, - 'rsa.investigations.ec_subject': { - category: 'rsa', - description: 'This key captures the Subject of a particular Event(Ex:User)', - name: 'rsa.investigations.ec_subject', - type: 'keyword', - }, - 'rsa.investigations.ec_outcome': { - category: 'rsa', - description: 'This key captures the outcome of a particular Event(Ex:Success)', - name: 'rsa.investigations.ec_outcome', - type: 'keyword', - }, - 'rsa.investigations.event_cat': { - category: 'rsa', - description: 'This key captures the Event category number', - name: 'rsa.investigations.event_cat', - type: 'long', - }, - 'rsa.investigations.event_cat_name': { - category: 'rsa', - description: 'This key captures the event category name corresponding to the event cat code', - name: 'rsa.investigations.event_cat_name', - type: 'keyword', - }, - 'rsa.investigations.event_vcat': { - category: 'rsa', - description: - 'This is a vendor supplied category. This should be used in situations where the vendor has adopted their own event_category taxonomy.', - name: 'rsa.investigations.event_vcat', - type: 'keyword', - }, - 'rsa.investigations.analysis_file': { - category: 'rsa', - description: - 'This is used to capture all indicators used in a File Analysis. This key should be used to capture an analysis of a file', - name: 'rsa.investigations.analysis_file', - type: 'keyword', - }, - 'rsa.investigations.analysis_service': { - category: 'rsa', - description: - 'This is used to capture all indicators used in a Service Analysis. This key should be used to capture an analysis of a service', - name: 'rsa.investigations.analysis_service', - type: 'keyword', - }, - 'rsa.investigations.analysis_session': { - category: 'rsa', - description: - 'This is used to capture all indicators used for a Session Analysis. This key should be used to capture an analysis of a session', - name: 'rsa.investigations.analysis_session', - type: 'keyword', - }, - 'rsa.investigations.boc': { - category: 'rsa', - description: 'This is used to capture behaviour of compromise', - name: 'rsa.investigations.boc', - type: 'keyword', - }, - 'rsa.investigations.eoc': { - category: 'rsa', - description: 'This is used to capture Enablers of Compromise', - name: 'rsa.investigations.eoc', - type: 'keyword', - }, - 'rsa.investigations.inv_category': { - category: 'rsa', - description: 'This used to capture investigation category', - name: 'rsa.investigations.inv_category', - type: 'keyword', - }, - 'rsa.investigations.inv_context': { - category: 'rsa', - description: 'This used to capture investigation context', - name: 'rsa.investigations.inv_context', - type: 'keyword', - }, - 'rsa.investigations.ioc': { - category: 'rsa', - description: 'This is key capture indicator of compromise', - name: 'rsa.investigations.ioc', - type: 'keyword', - }, - 'rsa.counters.dclass_c1': { - category: 'rsa', - description: - 'This is a generic counter key that should be used with the label dclass.c1.str only', - name: 'rsa.counters.dclass_c1', - type: 'long', - }, - 'rsa.counters.dclass_c2': { - category: 'rsa', - description: - 'This is a generic counter key that should be used with the label dclass.c2.str only', - name: 'rsa.counters.dclass_c2', - type: 'long', - }, - 'rsa.counters.event_counter': { - category: 'rsa', - description: 'This is used to capture the number of times an event repeated', - name: 'rsa.counters.event_counter', - type: 'long', - }, - 'rsa.counters.dclass_r1': { - category: 'rsa', - description: - 'This is a generic ratio key that should be used with the label dclass.r1.str only', - name: 'rsa.counters.dclass_r1', - type: 'keyword', - }, - 'rsa.counters.dclass_c3': { - category: 'rsa', - description: - 'This is a generic counter key that should be used with the label dclass.c3.str only', - name: 'rsa.counters.dclass_c3', - type: 'long', - }, - 'rsa.counters.dclass_c1_str': { - category: 'rsa', - description: - 'This is a generic counter string key that should be used with the label dclass.c1 only', - name: 'rsa.counters.dclass_c1_str', - type: 'keyword', - }, - 'rsa.counters.dclass_c2_str': { - category: 'rsa', - description: - 'This is a generic counter string key that should be used with the label dclass.c2 only', - name: 'rsa.counters.dclass_c2_str', - type: 'keyword', - }, - 'rsa.counters.dclass_r1_str': { - category: 'rsa', - description: - 'This is a generic ratio string key that should be used with the label dclass.r1 only', - name: 'rsa.counters.dclass_r1_str', - type: 'keyword', - }, - 'rsa.counters.dclass_r2': { - category: 'rsa', - description: - 'This is a generic ratio key that should be used with the label dclass.r2.str only', - name: 'rsa.counters.dclass_r2', - type: 'keyword', - }, - 'rsa.counters.dclass_c3_str': { - category: 'rsa', - description: - 'This is a generic counter string key that should be used with the label dclass.c3 only', - name: 'rsa.counters.dclass_c3_str', - type: 'keyword', - }, - 'rsa.counters.dclass_r3': { - category: 'rsa', - description: - 'This is a generic ratio key that should be used with the label dclass.r3.str only', - name: 'rsa.counters.dclass_r3', - type: 'keyword', - }, - 'rsa.counters.dclass_r2_str': { - category: 'rsa', - description: - 'This is a generic ratio string key that should be used with the label dclass.r2 only', - name: 'rsa.counters.dclass_r2_str', - type: 'keyword', - }, - 'rsa.counters.dclass_r3_str': { - category: 'rsa', - description: - 'This is a generic ratio string key that should be used with the label dclass.r3 only', - name: 'rsa.counters.dclass_r3_str', - type: 'keyword', - }, - 'rsa.identity.auth_method': { - category: 'rsa', - description: 'This key is used to capture authentication methods used only', - name: 'rsa.identity.auth_method', - type: 'keyword', - }, - 'rsa.identity.user_role': { - category: 'rsa', - description: 'This key is used to capture the Role of a user only', - name: 'rsa.identity.user_role', - type: 'keyword', - }, - 'rsa.identity.dn': { - category: 'rsa', - description: 'X.500 (LDAP) Distinguished Name', - name: 'rsa.identity.dn', - type: 'keyword', - }, - 'rsa.identity.logon_type': { - category: 'rsa', - description: 'This key is used to capture the type of logon method used.', - name: 'rsa.identity.logon_type', - type: 'keyword', - }, - 'rsa.identity.profile': { - category: 'rsa', - description: 'This key is used to capture the user profile', - name: 'rsa.identity.profile', - type: 'keyword', - }, - 'rsa.identity.accesses': { - category: 'rsa', - description: 'This key is used to capture actual privileges used in accessing an object', - name: 'rsa.identity.accesses', - type: 'keyword', - }, - 'rsa.identity.realm': { - category: 'rsa', - description: 'Radius realm or similar grouping of accounts', - name: 'rsa.identity.realm', - type: 'keyword', - }, - 'rsa.identity.user_sid_dst': { - category: 'rsa', - description: 'This key captures Destination User Session ID', - name: 'rsa.identity.user_sid_dst', - type: 'keyword', - }, - 'rsa.identity.dn_src': { - category: 'rsa', - description: - 'An X.500 (LDAP) Distinguished name that is used in a context that indicates a Source dn', - name: 'rsa.identity.dn_src', - type: 'keyword', - }, - 'rsa.identity.org': { - category: 'rsa', - description: 'This key captures the User organization', - name: 'rsa.identity.org', - type: 'keyword', - }, - 'rsa.identity.dn_dst': { - category: 'rsa', - description: - 'An X.500 (LDAP) Distinguished name that used in a context that indicates a Destination dn', - name: 'rsa.identity.dn_dst', - type: 'keyword', - }, - 'rsa.identity.firstname': { - category: 'rsa', - description: - 'This key is for First Names only, this is used for Healthcare predominantly to capture Patients information', - name: 'rsa.identity.firstname', - type: 'keyword', - }, - 'rsa.identity.lastname': { - category: 'rsa', - description: - 'This key is for Last Names only, this is used for Healthcare predominantly to capture Patients information', - name: 'rsa.identity.lastname', - type: 'keyword', - }, - 'rsa.identity.user_dept': { - category: 'rsa', - description: "User's Department Names only", - name: 'rsa.identity.user_dept', - type: 'keyword', - }, - 'rsa.identity.user_sid_src': { - category: 'rsa', - description: 'This key captures Source User Session ID', - name: 'rsa.identity.user_sid_src', - type: 'keyword', - }, - 'rsa.identity.federated_sp': { - category: 'rsa', - description: - 'This key is the Federated Service Provider. This is the application requesting authentication.', - name: 'rsa.identity.federated_sp', - type: 'keyword', - }, - 'rsa.identity.federated_idp': { - category: 'rsa', - description: - 'This key is the federated Identity Provider. This is the server providing the authentication.', - name: 'rsa.identity.federated_idp', - type: 'keyword', - }, - 'rsa.identity.logon_type_desc': { - category: 'rsa', - description: - "This key is used to capture the textual description of an integer logon type as stored in the meta key 'logon.type'.", - name: 'rsa.identity.logon_type_desc', - type: 'keyword', - }, - 'rsa.identity.middlename': { - category: 'rsa', - description: - 'This key is for Middle Names only, this is used for Healthcare predominantly to capture Patients information', - name: 'rsa.identity.middlename', - type: 'keyword', - }, - 'rsa.identity.password': { - category: 'rsa', - description: 'This key is for Passwords seen in any session, plain text or encrypted', - name: 'rsa.identity.password', - type: 'keyword', - }, - 'rsa.identity.host_role': { - category: 'rsa', - description: 'This key should only be used to capture the role of a Host Machine', - name: 'rsa.identity.host_role', - type: 'keyword', - }, - 'rsa.identity.ldap': { - category: 'rsa', - description: - 'This key is for Uninterpreted LDAP values. Ldap Values that don’t have a clear query or response context', - name: 'rsa.identity.ldap', - type: 'keyword', - }, - 'rsa.identity.ldap_query': { - category: 'rsa', - description: 'This key is the Search criteria from an LDAP search', - name: 'rsa.identity.ldap_query', - type: 'keyword', - }, - 'rsa.identity.ldap_response': { - category: 'rsa', - description: 'This key is to capture Results from an LDAP search', - name: 'rsa.identity.ldap_response', - type: 'keyword', - }, - 'rsa.identity.owner': { - category: 'rsa', - description: - 'This is used to capture username the process or service is running as, the author of the task', - name: 'rsa.identity.owner', - type: 'keyword', - }, - 'rsa.identity.service_account': { - category: 'rsa', - description: - 'This key is a windows specific key, used for capturing name of the account a service (referenced in the event) is running under. Legacy Usage', - name: 'rsa.identity.service_account', - type: 'keyword', - }, - 'rsa.email.email_dst': { - category: 'rsa', - description: - 'This key is used to capture the Destination email address only, when the destination context is not clear use email', - name: 'rsa.email.email_dst', - type: 'keyword', - }, - 'rsa.email.email_src': { - category: 'rsa', - description: - 'This key is used to capture the source email address only, when the source context is not clear use email', - name: 'rsa.email.email_src', - type: 'keyword', - }, - 'rsa.email.subject': { - category: 'rsa', - description: 'This key is used to capture the subject string from an Email only.', - name: 'rsa.email.subject', - type: 'keyword', - }, - 'rsa.email.email': { - category: 'rsa', - description: - 'This key is used to capture a generic email address where the source or destination context is not clear', - name: 'rsa.email.email', - type: 'keyword', - }, - 'rsa.email.trans_from': { - category: 'rsa', - description: 'Deprecated key defined only in table map.', - name: 'rsa.email.trans_from', - type: 'keyword', - }, - 'rsa.email.trans_to': { - category: 'rsa', - description: 'Deprecated key defined only in table map.', - name: 'rsa.email.trans_to', - type: 'keyword', - }, - 'rsa.file.privilege': { - category: 'rsa', - description: 'Deprecated, use permissions', - name: 'rsa.file.privilege', - type: 'keyword', - }, - 'rsa.file.attachment': { - category: 'rsa', - description: 'This key captures the attachment file name', - name: 'rsa.file.attachment', - type: 'keyword', - }, - 'rsa.file.filesystem': { - category: 'rsa', - name: 'rsa.file.filesystem', - type: 'keyword', - }, - 'rsa.file.binary': { - category: 'rsa', - description: 'Deprecated key defined only in table map.', - name: 'rsa.file.binary', - type: 'keyword', - }, - 'rsa.file.filename_dst': { - category: 'rsa', - description: 'This is used to capture name of the file targeted by the action', - name: 'rsa.file.filename_dst', - type: 'keyword', - }, - 'rsa.file.filename_src': { - category: 'rsa', - description: - 'This is used to capture name of the parent filename, the file which performed the action', - name: 'rsa.file.filename_src', - type: 'keyword', - }, - 'rsa.file.filename_tmp': { - category: 'rsa', - name: 'rsa.file.filename_tmp', - type: 'keyword', - }, - 'rsa.file.directory_dst': { - category: 'rsa', - description: - 'This key is used to capture the directory of the target process or file', - name: 'rsa.file.directory_dst', - type: 'keyword', - }, - 'rsa.file.directory_src': { - category: 'rsa', - description: 'This key is used to capture the directory of the source process or file', - name: 'rsa.file.directory_src', - type: 'keyword', - }, - 'rsa.file.file_entropy': { - category: 'rsa', - description: 'This is used to capture entropy vale of a file', - name: 'rsa.file.file_entropy', - type: 'double', - }, - 'rsa.file.file_vendor': { - category: 'rsa', - description: 'This is used to capture Company name of file located in version_info', - name: 'rsa.file.file_vendor', - type: 'keyword', - }, - 'rsa.file.task_name': { - category: 'rsa', - description: 'This is used to capture name of the task', - name: 'rsa.file.task_name', - type: 'keyword', - }, - 'rsa.web.fqdn': { - category: 'rsa', - description: 'Fully Qualified Domain Names', - name: 'rsa.web.fqdn', - type: 'keyword', - }, - 'rsa.web.web_cookie': { - category: 'rsa', - description: 'This key is used to capture the Web cookies specifically.', - name: 'rsa.web.web_cookie', - type: 'keyword', - }, - 'rsa.web.alias_host': { - category: 'rsa', - name: 'rsa.web.alias_host', - type: 'keyword', - }, - 'rsa.web.reputation_num': { - category: 'rsa', - description: 'Reputation Number of an entity. Typically used for Web Domains', - name: 'rsa.web.reputation_num', - type: 'double', - }, - 'rsa.web.web_ref_domain': { - category: 'rsa', - description: "Web referer's domain", - name: 'rsa.web.web_ref_domain', - type: 'keyword', - }, - 'rsa.web.web_ref_query': { - category: 'rsa', - description: "This key captures Web referer's query portion of the URL", - name: 'rsa.web.web_ref_query', - type: 'keyword', - }, - 'rsa.web.remote_domain': { - category: 'rsa', - name: 'rsa.web.remote_domain', - type: 'keyword', - }, - 'rsa.web.web_ref_page': { - category: 'rsa', - description: "This key captures Web referer's page information", - name: 'rsa.web.web_ref_page', - type: 'keyword', - }, - 'rsa.web.web_ref_root': { - category: 'rsa', - description: "Web referer's root URL path", - name: 'rsa.web.web_ref_root', - type: 'keyword', - }, - 'rsa.web.cn_asn_dst': { - category: 'rsa', - name: 'rsa.web.cn_asn_dst', - type: 'keyword', - }, - 'rsa.web.cn_rpackets': { - category: 'rsa', - name: 'rsa.web.cn_rpackets', - type: 'keyword', - }, - 'rsa.web.urlpage': { - category: 'rsa', - name: 'rsa.web.urlpage', - type: 'keyword', - }, - 'rsa.web.urlroot': { - category: 'rsa', - name: 'rsa.web.urlroot', - type: 'keyword', - }, - 'rsa.web.p_url': { - category: 'rsa', - name: 'rsa.web.p_url', - type: 'keyword', - }, - 'rsa.web.p_user_agent': { - category: 'rsa', - name: 'rsa.web.p_user_agent', - type: 'keyword', - }, - 'rsa.web.p_web_cookie': { - category: 'rsa', - name: 'rsa.web.p_web_cookie', - type: 'keyword', - }, - 'rsa.web.p_web_method': { - category: 'rsa', - name: 'rsa.web.p_web_method', - type: 'keyword', - }, - 'rsa.web.p_web_referer': { - category: 'rsa', - name: 'rsa.web.p_web_referer', - type: 'keyword', - }, - 'rsa.web.web_extension_tmp': { - category: 'rsa', - name: 'rsa.web.web_extension_tmp', - type: 'keyword', - }, - 'rsa.web.web_page': { - category: 'rsa', - name: 'rsa.web.web_page', - type: 'keyword', - }, - 'rsa.threat.threat_category': { - category: 'rsa', - description: 'This key captures Threat Name/Threat Category/Categorization of alert', - name: 'rsa.threat.threat_category', - type: 'keyword', - }, - 'rsa.threat.threat_desc': { - category: 'rsa', - description: - 'This key is used to capture the threat description from the session directly or inferred', - name: 'rsa.threat.threat_desc', - type: 'keyword', - }, - 'rsa.threat.alert': { - category: 'rsa', - description: 'This key is used to capture name of the alert', - name: 'rsa.threat.alert', - type: 'keyword', - }, - 'rsa.threat.threat_source': { - category: 'rsa', - description: 'This key is used to capture source of the threat', - name: 'rsa.threat.threat_source', - type: 'keyword', - }, - 'rsa.crypto.crypto': { - category: 'rsa', - description: 'This key is used to capture the Encryption Type or Encryption Key only', - name: 'rsa.crypto.crypto', - type: 'keyword', - }, - 'rsa.crypto.cipher_src': { - category: 'rsa', - description: 'This key is for Source (Client) Cipher', - name: 'rsa.crypto.cipher_src', - type: 'keyword', - }, - 'rsa.crypto.cert_subject': { - category: 'rsa', - description: 'This key is used to capture the Certificate organization only', - name: 'rsa.crypto.cert_subject', - type: 'keyword', - }, - 'rsa.crypto.peer': { - category: 'rsa', - description: "This key is for Encryption peer's IP Address", - name: 'rsa.crypto.peer', - type: 'keyword', - }, - 'rsa.crypto.cipher_size_src': { - category: 'rsa', - description: 'This key captures Source (Client) Cipher Size', - name: 'rsa.crypto.cipher_size_src', - type: 'long', - }, - 'rsa.crypto.ike': { - category: 'rsa', - description: 'IKE negotiation phase.', - name: 'rsa.crypto.ike', - type: 'keyword', - }, - 'rsa.crypto.scheme': { - category: 'rsa', - description: 'This key captures the Encryption scheme used', - name: 'rsa.crypto.scheme', - type: 'keyword', - }, - 'rsa.crypto.peer_id': { - category: 'rsa', - description: 'This key is for Encryption peer’s identity', - name: 'rsa.crypto.peer_id', - type: 'keyword', - }, - 'rsa.crypto.sig_type': { - category: 'rsa', - description: 'This key captures the Signature Type', - name: 'rsa.crypto.sig_type', - type: 'keyword', - }, - 'rsa.crypto.cert_issuer': { - category: 'rsa', - name: 'rsa.crypto.cert_issuer', - type: 'keyword', - }, - 'rsa.crypto.cert_host_name': { - category: 'rsa', - description: 'Deprecated key defined only in table map.', - name: 'rsa.crypto.cert_host_name', - type: 'keyword', - }, - 'rsa.crypto.cert_error': { - category: 'rsa', - description: 'This key captures the Certificate Error String', - name: 'rsa.crypto.cert_error', - type: 'keyword', - }, - 'rsa.crypto.cipher_dst': { - category: 'rsa', - description: 'This key is for Destination (Server) Cipher', - name: 'rsa.crypto.cipher_dst', - type: 'keyword', - }, - 'rsa.crypto.cipher_size_dst': { - category: 'rsa', - description: 'This key captures Destination (Server) Cipher Size', - name: 'rsa.crypto.cipher_size_dst', - type: 'long', - }, - 'rsa.crypto.ssl_ver_src': { - category: 'rsa', - description: 'Deprecated, use version', - name: 'rsa.crypto.ssl_ver_src', - type: 'keyword', - }, - 'rsa.crypto.d_certauth': { - category: 'rsa', - name: 'rsa.crypto.d_certauth', - type: 'keyword', - }, - 'rsa.crypto.s_certauth': { - category: 'rsa', - name: 'rsa.crypto.s_certauth', - type: 'keyword', - }, - 'rsa.crypto.ike_cookie1': { - category: 'rsa', - description: 'ID of the negotiation — sent for ISAKMP Phase One', - name: 'rsa.crypto.ike_cookie1', - type: 'keyword', - }, - 'rsa.crypto.ike_cookie2': { - category: 'rsa', - description: 'ID of the negotiation — sent for ISAKMP Phase Two', - name: 'rsa.crypto.ike_cookie2', - type: 'keyword', - }, - 'rsa.crypto.cert_checksum': { - category: 'rsa', - name: 'rsa.crypto.cert_checksum', - type: 'keyword', - }, - 'rsa.crypto.cert_host_cat': { - category: 'rsa', - description: 'This key is used for the hostname category value of a certificate', - name: 'rsa.crypto.cert_host_cat', - type: 'keyword', - }, - 'rsa.crypto.cert_serial': { - category: 'rsa', - description: 'This key is used to capture the Certificate serial number only', - name: 'rsa.crypto.cert_serial', - type: 'keyword', - }, - 'rsa.crypto.cert_status': { - category: 'rsa', - description: 'This key captures Certificate validation status', - name: 'rsa.crypto.cert_status', - type: 'keyword', - }, - 'rsa.crypto.ssl_ver_dst': { - category: 'rsa', - description: 'Deprecated, use version', - name: 'rsa.crypto.ssl_ver_dst', - type: 'keyword', - }, - 'rsa.crypto.cert_keysize': { - category: 'rsa', - name: 'rsa.crypto.cert_keysize', - type: 'keyword', - }, - 'rsa.crypto.cert_username': { - category: 'rsa', - name: 'rsa.crypto.cert_username', - type: 'keyword', - }, - 'rsa.crypto.https_insact': { - category: 'rsa', - name: 'rsa.crypto.https_insact', - type: 'keyword', - }, - 'rsa.crypto.https_valid': { - category: 'rsa', - name: 'rsa.crypto.https_valid', - type: 'keyword', - }, - 'rsa.crypto.cert_ca': { - category: 'rsa', - description: 'This key is used to capture the Certificate signing authority only', - name: 'rsa.crypto.cert_ca', - type: 'keyword', - }, - 'rsa.crypto.cert_common': { - category: 'rsa', - description: 'This key is used to capture the Certificate common name only', - name: 'rsa.crypto.cert_common', - type: 'keyword', - }, - 'rsa.wireless.wlan_ssid': { - category: 'rsa', - description: 'This key is used to capture the ssid of a Wireless Session', - name: 'rsa.wireless.wlan_ssid', - type: 'keyword', - }, - 'rsa.wireless.access_point': { - category: 'rsa', - description: 'This key is used to capture the access point name.', - name: 'rsa.wireless.access_point', - type: 'keyword', - }, - 'rsa.wireless.wlan_channel': { - category: 'rsa', - description: 'This is used to capture the channel names', - name: 'rsa.wireless.wlan_channel', - type: 'long', - }, - 'rsa.wireless.wlan_name': { - category: 'rsa', - description: 'This key captures either WLAN number/name', - name: 'rsa.wireless.wlan_name', - type: 'keyword', - }, - 'rsa.storage.disk_volume': { - category: 'rsa', - description: 'A unique name assigned to logical units (volumes) within a physical disk', - name: 'rsa.storage.disk_volume', - type: 'keyword', - }, - 'rsa.storage.lun': { - category: 'rsa', - description: 'Logical Unit Number.This key is a very useful concept in Storage.', - name: 'rsa.storage.lun', - type: 'keyword', - }, - 'rsa.storage.pwwn': { - category: 'rsa', - description: 'This uniquely identifies a port on a HBA.', - name: 'rsa.storage.pwwn', - type: 'keyword', - }, - 'rsa.physical.org_dst': { - category: 'rsa', - description: - 'This is used to capture the destination organization based on the GEOPIP Maxmind database.', - name: 'rsa.physical.org_dst', - type: 'keyword', - }, - 'rsa.physical.org_src': { - category: 'rsa', - description: - 'This is used to capture the source organization based on the GEOPIP Maxmind database.', - name: 'rsa.physical.org_src', - type: 'keyword', - }, - 'rsa.healthcare.patient_fname': { - category: 'rsa', - description: - 'This key is for First Names only, this is used for Healthcare predominantly to capture Patients information', - name: 'rsa.healthcare.patient_fname', - type: 'keyword', - }, - 'rsa.healthcare.patient_id': { - category: 'rsa', - description: 'This key captures the unique ID for a patient', - name: 'rsa.healthcare.patient_id', - type: 'keyword', - }, - 'rsa.healthcare.patient_lname': { - category: 'rsa', - description: - 'This key is for Last Names only, this is used for Healthcare predominantly to capture Patients information', - name: 'rsa.healthcare.patient_lname', - type: 'keyword', - }, - 'rsa.healthcare.patient_mname': { - category: 'rsa', - description: - 'This key is for Middle Names only, this is used for Healthcare predominantly to capture Patients information', - name: 'rsa.healthcare.patient_mname', - type: 'keyword', - }, - 'rsa.endpoint.host_state': { - category: 'rsa', - description: - 'This key is used to capture the current state of the machine, such as blacklisted, infected, firewall disabled and so on', - name: 'rsa.endpoint.host_state', - type: 'keyword', - }, - 'rsa.endpoint.registry_key': { - category: 'rsa', - description: 'This key captures the path to the registry key', - name: 'rsa.endpoint.registry_key', - type: 'keyword', - }, - 'rsa.endpoint.registry_value': { - category: 'rsa', - description: 'This key captures values or decorators used within a registry entry', - name: 'rsa.endpoint.registry_value', - type: 'keyword', - }, - 'forcepoint.virus_id': { - category: 'forcepoint', - description: 'Virus ID ', - name: 'forcepoint.virus_id', - type: 'keyword', - }, - 'checkpoint.app_risk': { - category: 'checkpoint', - description: 'Application risk.', - name: 'checkpoint.app_risk', - type: 'keyword', - }, - 'checkpoint.app_severity': { - category: 'checkpoint', - description: 'Application threat severity.', - name: 'checkpoint.app_severity', - type: 'keyword', - }, - 'checkpoint.app_sig_id': { - category: 'checkpoint', - description: 'The signature ID which the application was detected by.', - name: 'checkpoint.app_sig_id', - type: 'keyword', - }, - 'checkpoint.auth_method': { - category: 'checkpoint', - description: 'Password authentication protocol used.', - name: 'checkpoint.auth_method', - type: 'keyword', - }, - 'checkpoint.category': { - category: 'checkpoint', - description: 'Category.', - name: 'checkpoint.category', - type: 'keyword', - }, - 'checkpoint.confidence_level': { - category: 'checkpoint', - description: 'Confidence level determined.', - name: 'checkpoint.confidence_level', - type: 'integer', - }, - 'checkpoint.connectivity_state': { - category: 'checkpoint', - description: 'Connectivity state.', - name: 'checkpoint.connectivity_state', - type: 'keyword', - }, - 'checkpoint.cookie': { - category: 'checkpoint', - description: 'IKE cookie.', - name: 'checkpoint.cookie', - type: 'keyword', - }, - 'checkpoint.dst_phone_number': { - category: 'checkpoint', - description: 'Destination IP-Phone.', - name: 'checkpoint.dst_phone_number', - type: 'keyword', - }, - 'checkpoint.email_control': { - category: 'checkpoint', - description: 'Engine name.', - name: 'checkpoint.email_control', - type: 'keyword', - }, - 'checkpoint.email_id': { - category: 'checkpoint', - description: 'Internal email ID.', - name: 'checkpoint.email_id', - type: 'keyword', - }, - 'checkpoint.email_recipients_num': { - category: 'checkpoint', - description: 'Number of recipients.', - name: 'checkpoint.email_recipients_num', - type: 'long', - }, - 'checkpoint.email_session_id': { - category: 'checkpoint', - description: 'Internal email session ID.', - name: 'checkpoint.email_session_id', - type: 'keyword', - }, - 'checkpoint.email_spool_id': { - category: 'checkpoint', - description: 'Internal email spool ID.', - name: 'checkpoint.email_spool_id', - type: 'keyword', - }, - 'checkpoint.email_subject': { - category: 'checkpoint', - description: 'Email subject.', - name: 'checkpoint.email_subject', - type: 'keyword', - }, - 'checkpoint.event_count': { - category: 'checkpoint', - description: 'Number of events associated with the log.', - name: 'checkpoint.event_count', - type: 'long', - }, - 'checkpoint.frequency': { - category: 'checkpoint', - description: 'Scan frequency.', - name: 'checkpoint.frequency', - type: 'keyword', - }, - 'checkpoint.icmp_type': { - category: 'checkpoint', - description: 'ICMP type.', - name: 'checkpoint.icmp_type', - type: 'long', - }, - 'checkpoint.icmp_code': { - category: 'checkpoint', - description: 'ICMP code.', - name: 'checkpoint.icmp_code', - type: 'long', - }, - 'checkpoint.identity_type': { - category: 'checkpoint', - description: 'Identity type.', - name: 'checkpoint.identity_type', - type: 'keyword', - }, - 'checkpoint.incident_extension': { - category: 'checkpoint', - description: 'Format of original data.', - name: 'checkpoint.incident_extension', - type: 'keyword', - }, - 'checkpoint.integrity_av_invoke_type': { - category: 'checkpoint', - description: 'Scan invoke type.', - name: 'checkpoint.integrity_av_invoke_type', - type: 'keyword', - }, - 'checkpoint.malware_family': { - category: 'checkpoint', - description: 'Malware family.', - name: 'checkpoint.malware_family', - type: 'keyword', - }, - 'checkpoint.peer_gateway': { - category: 'checkpoint', - description: 'Main IP of the peer Security Gateway.', - name: 'checkpoint.peer_gateway', - type: 'ip', - }, - 'checkpoint.performance_impact': { - category: 'checkpoint', - description: 'Protection performance impact.', - name: 'checkpoint.performance_impact', - type: 'integer', - }, - 'checkpoint.protection_id': { - category: 'checkpoint', - description: 'Protection malware ID.', - name: 'checkpoint.protection_id', - type: 'keyword', - }, - 'checkpoint.protection_name': { - category: 'checkpoint', - description: 'Specific signature name of the attack.', - name: 'checkpoint.protection_name', - type: 'keyword', - }, - 'checkpoint.protection_type': { - category: 'checkpoint', - description: 'Type of protection used to detect the attack.', - name: 'checkpoint.protection_type', - type: 'keyword', - }, - 'checkpoint.scan_result': { - category: 'checkpoint', - description: 'Scan result.', - name: 'checkpoint.scan_result', - type: 'keyword', - }, - 'checkpoint.sensor_mode': { - category: 'checkpoint', - description: 'Sensor mode.', - name: 'checkpoint.sensor_mode', - type: 'keyword', - }, - 'checkpoint.severity': { - category: 'checkpoint', - description: 'Threat severity.', - name: 'checkpoint.severity', - type: 'keyword', - }, - 'checkpoint.spyware_name': { - category: 'checkpoint', - description: 'Spyware name.', - name: 'checkpoint.spyware_name', - type: 'keyword', - }, - 'checkpoint.spyware_status': { - category: 'checkpoint', - description: 'Spyware status.', - name: 'checkpoint.spyware_status', - type: 'keyword', - }, - 'checkpoint.subs_exp': { - category: 'checkpoint', - description: 'The expiration date of the subscription.', - name: 'checkpoint.subs_exp', - type: 'date', - }, - 'checkpoint.tcp_flags': { - category: 'checkpoint', - description: 'TCP packet flags.', - name: 'checkpoint.tcp_flags', - type: 'keyword', - }, - 'checkpoint.termination_reason': { - category: 'checkpoint', - description: 'Termination reason.', - name: 'checkpoint.termination_reason', - type: 'keyword', - }, - 'checkpoint.update_status': { - category: 'checkpoint', - description: 'Update status.', - name: 'checkpoint.update_status', - type: 'keyword', - }, - 'checkpoint.user_status': { - category: 'checkpoint', - description: 'User response.', - name: 'checkpoint.user_status', - type: 'keyword', - }, - 'checkpoint.uuid': { - category: 'checkpoint', - description: 'External ID.', - name: 'checkpoint.uuid', - type: 'keyword', - }, - 'checkpoint.virus_name': { - category: 'checkpoint', - description: 'Virus name.', - name: 'checkpoint.virus_name', - type: 'keyword', - }, - 'checkpoint.voip_log_type': { - category: 'checkpoint', - description: 'VoIP log types.', - name: 'checkpoint.voip_log_type', - type: 'keyword', - }, - 'cef.extensions.cp_app_risk': { - category: 'cef', - name: 'cef.extensions.cp_app_risk', - type: 'keyword', - }, - 'cef.extensions.cp_severity': { - category: 'cef', - name: 'cef.extensions.cp_severity', - type: 'keyword', - }, - 'cef.extensions.ifname': { - category: 'cef', - name: 'cef.extensions.ifname', - type: 'keyword', - }, - 'cef.extensions.inzone': { - category: 'cef', - name: 'cef.extensions.inzone', - type: 'keyword', - }, - 'cef.extensions.layer_uuid': { - category: 'cef', - name: 'cef.extensions.layer_uuid', - type: 'keyword', - }, - 'cef.extensions.layer_name': { - category: 'cef', - name: 'cef.extensions.layer_name', - type: 'keyword', - }, - 'cef.extensions.logid': { - category: 'cef', - name: 'cef.extensions.logid', - type: 'keyword', - }, - 'cef.extensions.loguid': { - category: 'cef', - name: 'cef.extensions.loguid', - type: 'keyword', - }, - 'cef.extensions.match_id': { - category: 'cef', - name: 'cef.extensions.match_id', - type: 'keyword', - }, - 'cef.extensions.nat_addtnl_rulenum': { - category: 'cef', - name: 'cef.extensions.nat_addtnl_rulenum', - type: 'keyword', - }, - 'cef.extensions.nat_rulenum': { - category: 'cef', - name: 'cef.extensions.nat_rulenum', - type: 'keyword', - }, - 'cef.extensions.origin': { - category: 'cef', - name: 'cef.extensions.origin', - type: 'keyword', - }, - 'cef.extensions.originsicname': { - category: 'cef', - name: 'cef.extensions.originsicname', - type: 'keyword', - }, - 'cef.extensions.outzone': { - category: 'cef', - name: 'cef.extensions.outzone', - type: 'keyword', - }, - 'cef.extensions.parent_rule': { - category: 'cef', - name: 'cef.extensions.parent_rule', - type: 'keyword', - }, - 'cef.extensions.product': { - category: 'cef', - name: 'cef.extensions.product', - type: 'keyword', - }, - 'cef.extensions.rule_action': { - category: 'cef', - name: 'cef.extensions.rule_action', - type: 'keyword', - }, - 'cef.extensions.rule_uid': { - category: 'cef', - name: 'cef.extensions.rule_uid', - type: 'keyword', - }, - 'cef.extensions.sequencenum': { - category: 'cef', - name: 'cef.extensions.sequencenum', - type: 'keyword', - }, - 'cef.extensions.service_id': { - category: 'cef', - name: 'cef.extensions.service_id', - type: 'keyword', - }, - 'cef.extensions.version': { - category: 'cef', - name: 'cef.extensions.version', - type: 'keyword', - }, - 'checkpoint.calc_desc': { - category: 'checkpoint', - description: 'Log description. ', - name: 'checkpoint.calc_desc', - type: 'keyword', - }, - 'checkpoint.dst_country': { - category: 'checkpoint', - description: 'Destination country. ', - name: 'checkpoint.dst_country', - type: 'keyword', - }, - 'checkpoint.dst_user_name': { - category: 'checkpoint', - description: 'Connected user name on the destination IP. ', - name: 'checkpoint.dst_user_name', - type: 'keyword', - }, - 'checkpoint.sys_message': { - category: 'checkpoint', - description: 'System messages ', - name: 'checkpoint.sys_message', - type: 'keyword', - }, - 'checkpoint.logid': { - category: 'checkpoint', - description: 'System messages ', - name: 'checkpoint.logid', - type: 'keyword', - }, - 'checkpoint.failure_impact': { - category: 'checkpoint', - description: 'The impact of update service failure. ', - name: 'checkpoint.failure_impact', - type: 'keyword', - }, - 'checkpoint.id': { - category: 'checkpoint', - description: 'Override application ID. ', - name: 'checkpoint.id', - type: 'integer', - }, - 'checkpoint.information': { - category: 'checkpoint', - description: 'Policy installation status for a specific blade. ', - name: 'checkpoint.information', - type: 'keyword', - }, - 'checkpoint.layer_name': { - category: 'checkpoint', - description: 'Layer name. ', - name: 'checkpoint.layer_name', - type: 'keyword', - }, - 'checkpoint.layer_uuid': { - category: 'checkpoint', - description: 'Layer UUID. ', - name: 'checkpoint.layer_uuid', - type: 'keyword', - }, - 'checkpoint.log_id': { - category: 'checkpoint', - description: 'Unique identity for logs. ', - name: 'checkpoint.log_id', - type: 'integer', - }, - 'checkpoint.origin_sic_name': { - category: 'checkpoint', - description: 'Machine SIC. ', - name: 'checkpoint.origin_sic_name', - type: 'keyword', - }, - 'checkpoint.policy_mgmt': { - category: 'checkpoint', - description: 'Name of the Management Server that manages this Security Gateway. ', - name: 'checkpoint.policy_mgmt', - type: 'keyword', - }, - 'checkpoint.policy_name': { - category: 'checkpoint', - description: 'Name of the last policy that this Security Gateway fetched. ', - name: 'checkpoint.policy_name', - type: 'keyword', - }, - 'checkpoint.protocol': { - category: 'checkpoint', - description: 'Protocol detected on the connection. ', - name: 'checkpoint.protocol', - type: 'keyword', - }, - 'checkpoint.proxy_src_ip': { - category: 'checkpoint', - description: 'Sender source IP (even when using proxy). ', - name: 'checkpoint.proxy_src_ip', - type: 'ip', - }, - 'checkpoint.rule': { - category: 'checkpoint', - description: 'Matched rule number. ', - name: 'checkpoint.rule', - type: 'integer', - }, - 'checkpoint.rule_action': { - category: 'checkpoint', - description: 'Action of the matched rule in the access policy. ', - name: 'checkpoint.rule_action', - type: 'keyword', - }, - 'checkpoint.scan_direction': { - category: 'checkpoint', - description: 'Scan direction. ', - name: 'checkpoint.scan_direction', - type: 'keyword', - }, - 'checkpoint.session_id': { - category: 'checkpoint', - description: 'Log uuid. ', - name: 'checkpoint.session_id', - type: 'keyword', - }, - 'checkpoint.source_os': { - category: 'checkpoint', - description: 'OS which generated the attack. ', - name: 'checkpoint.source_os', - type: 'keyword', - }, - 'checkpoint.src_country': { - category: 'checkpoint', - description: 'Country name, derived from connection source IP address. ', - name: 'checkpoint.src_country', - type: 'keyword', - }, - 'checkpoint.src_user_name': { - category: 'checkpoint', - description: 'User name connected to source IP ', - name: 'checkpoint.src_user_name', - type: 'keyword', - }, - 'checkpoint.ticket_id': { - category: 'checkpoint', - description: 'Unique ID per file. ', - name: 'checkpoint.ticket_id', - type: 'keyword', - }, - 'checkpoint.tls_server_host_name': { - category: 'checkpoint', - description: 'SNI/CN from encrypted TLS connection used by URLF for categorization. ', - name: 'checkpoint.tls_server_host_name', - type: 'keyword', - }, - 'checkpoint.verdict': { - category: 'checkpoint', - description: 'TE engine verdict Possible values: Malicious/Benign/Error. ', - name: 'checkpoint.verdict', - type: 'keyword', - }, - 'checkpoint.user': { - category: 'checkpoint', - description: 'Source user name. ', - name: 'checkpoint.user', - type: 'keyword', - }, - 'checkpoint.vendor_list': { - category: 'checkpoint', - description: 'The vendor name that provided the verdict for a malicious URL. ', - name: 'checkpoint.vendor_list', - type: 'keyword', - }, - 'checkpoint.web_server_type': { - category: 'checkpoint', - description: 'Web server detected in the HTTP response. ', - name: 'checkpoint.web_server_type', - type: 'keyword', - }, - 'checkpoint.client_name': { - category: 'checkpoint', - description: 'Client Application or Software Blade that detected the event. ', - name: 'checkpoint.client_name', - type: 'keyword', - }, - 'checkpoint.client_version': { - category: 'checkpoint', - description: 'Build version of SandBlast Agent client installed on the computer. ', - name: 'checkpoint.client_version', - type: 'keyword', - }, - 'checkpoint.extension_version': { - category: 'checkpoint', - description: 'Build version of the SandBlast Agent browser extension. ', - name: 'checkpoint.extension_version', - type: 'keyword', - }, - 'checkpoint.host_time': { - category: 'checkpoint', - description: 'Local time on the endpoint computer. ', - name: 'checkpoint.host_time', - type: 'keyword', - }, - 'checkpoint.installed_products': { - category: 'checkpoint', - description: 'List of installed Endpoint Software Blades. ', - name: 'checkpoint.installed_products', - type: 'keyword', - }, - 'checkpoint.cc': { - category: 'checkpoint', - description: 'The Carbon Copy address of the email. ', - name: 'checkpoint.cc', - type: 'keyword', - }, - 'checkpoint.parent_process_username': { - category: 'checkpoint', - description: 'Owner username of the parent process of the process that triggered the attack. ', - name: 'checkpoint.parent_process_username', - type: 'keyword', - }, - 'checkpoint.process_username': { - category: 'checkpoint', - description: 'Owner username of the process that triggered the attack. ', - name: 'checkpoint.process_username', - type: 'keyword', - }, - 'checkpoint.audit_status': { - category: 'checkpoint', - description: 'Audit Status. Can be Success or Failure. ', - name: 'checkpoint.audit_status', - type: 'keyword', - }, - 'checkpoint.objecttable': { - category: 'checkpoint', - description: 'Table of affected objects. ', - name: 'checkpoint.objecttable', - type: 'keyword', - }, - 'checkpoint.objecttype': { - category: 'checkpoint', - description: 'The type of the affected object. ', - name: 'checkpoint.objecttype', - type: 'keyword', - }, - 'checkpoint.operation_number': { - category: 'checkpoint', - description: 'The operation nuber. ', - name: 'checkpoint.operation_number', - type: 'keyword', - }, - 'checkpoint.suppressed_logs': { - category: 'checkpoint', - description: - 'Aggregated connections for five minutes on the same source, destination and port. ', - name: 'checkpoint.suppressed_logs', - type: 'integer', - }, - 'checkpoint.blade_name': { - category: 'checkpoint', - description: 'Blade name. ', - name: 'checkpoint.blade_name', - type: 'keyword', - }, - 'checkpoint.status': { - category: 'checkpoint', - description: 'Ok/Warning/Error. ', - name: 'checkpoint.status', - type: 'keyword', - }, - 'checkpoint.short_desc': { - category: 'checkpoint', - description: 'Short description of the process that was executed. ', - name: 'checkpoint.short_desc', - type: 'keyword', - }, - 'checkpoint.long_desc': { - category: 'checkpoint', - description: 'More information on the process (usually describing error reason in failure). ', - name: 'checkpoint.long_desc', - type: 'keyword', - }, - 'checkpoint.scan_hosts_hour': { - category: 'checkpoint', - description: 'Number of unique hosts during the last hour. ', - name: 'checkpoint.scan_hosts_hour', - type: 'integer', - }, - 'checkpoint.scan_hosts_day': { - category: 'checkpoint', - description: 'Number of unique hosts during the last day. ', - name: 'checkpoint.scan_hosts_day', - type: 'integer', - }, - 'checkpoint.scan_hosts_week': { - category: 'checkpoint', - description: 'Number of unique hosts during the last week. ', - name: 'checkpoint.scan_hosts_week', - type: 'integer', - }, - 'checkpoint.unique_detected_hour': { - category: 'checkpoint', - description: 'Detected virus for a specific host during the last hour. ', - name: 'checkpoint.unique_detected_hour', - type: 'integer', - }, - 'checkpoint.unique_detected_day': { - category: 'checkpoint', - description: 'Detected virus for a specific host during the last day. ', - name: 'checkpoint.unique_detected_day', - type: 'integer', - }, - 'checkpoint.unique_detected_week': { - category: 'checkpoint', - description: 'Detected virus for a specific host during the last week. ', - name: 'checkpoint.unique_detected_week', - type: 'integer', - }, - 'checkpoint.scan_mail': { - category: 'checkpoint', - description: 'Number of emails that were scanned by "AB malicious activity" engine. ', - name: 'checkpoint.scan_mail', - type: 'integer', - }, - 'checkpoint.additional_ip': { - category: 'checkpoint', - description: 'DNS host name. ', - name: 'checkpoint.additional_ip', - type: 'keyword', - }, - 'checkpoint.description': { - category: 'checkpoint', - description: 'Additional explanation how the security gateway enforced the connection. ', - name: 'checkpoint.description', - type: 'keyword', - }, - 'checkpoint.email_spam_category': { - category: 'checkpoint', - description: 'Email categories. Possible values: spam/not spam/phishing. ', - name: 'checkpoint.email_spam_category', - type: 'keyword', - }, - 'checkpoint.email_control_analysis': { - category: 'checkpoint', - description: 'Message classification, received from spam vendor engine. ', - name: 'checkpoint.email_control_analysis', - type: 'keyword', - }, - 'checkpoint.scan_results': { - category: 'checkpoint', - description: '"Infected"/description of a failure. ', - name: 'checkpoint.scan_results', - type: 'keyword', - }, - 'checkpoint.original_queue_id': { - category: 'checkpoint', - description: 'Original postfix email queue id. ', - name: 'checkpoint.original_queue_id', - type: 'keyword', - }, - 'checkpoint.risk': { - category: 'checkpoint', - description: 'Risk level we got from the engine. ', - name: 'checkpoint.risk', - type: 'keyword', - }, - 'checkpoint.observable_name': { - category: 'checkpoint', - description: 'IOC observable signature name. ', - name: 'checkpoint.observable_name', - type: 'keyword', - }, - 'checkpoint.observable_id': { - category: 'checkpoint', - description: 'IOC observable signature id. ', - name: 'checkpoint.observable_id', - type: 'keyword', - }, - 'checkpoint.observable_comment': { - category: 'checkpoint', - description: 'IOC observable signature description. ', - name: 'checkpoint.observable_comment', - type: 'keyword', - }, - 'checkpoint.indicator_name': { - category: 'checkpoint', - description: 'IOC indicator name. ', - name: 'checkpoint.indicator_name', - type: 'keyword', - }, - 'checkpoint.indicator_description': { - category: 'checkpoint', - description: 'IOC indicator description. ', - name: 'checkpoint.indicator_description', - type: 'keyword', - }, - 'checkpoint.indicator_reference': { - category: 'checkpoint', - description: 'IOC indicator reference. ', - name: 'checkpoint.indicator_reference', - type: 'keyword', - }, - 'checkpoint.indicator_uuid': { - category: 'checkpoint', - description: 'IOC indicator uuid. ', - name: 'checkpoint.indicator_uuid', - type: 'keyword', - }, - 'checkpoint.app_desc': { - category: 'checkpoint', - description: 'Application description. ', - name: 'checkpoint.app_desc', - type: 'keyword', - }, - 'checkpoint.app_id': { - category: 'checkpoint', - description: 'Application ID. ', - name: 'checkpoint.app_id', - type: 'integer', - }, - 'checkpoint.certificate_resource': { - category: 'checkpoint', - description: 'HTTPS resource Possible values: SNI or domain name (DN). ', - name: 'checkpoint.certificate_resource', - type: 'keyword', - }, - 'checkpoint.certificate_validation': { - category: 'checkpoint', - description: - 'Precise error, describing HTTPS certificate failure under "HTTPS categorize websites" feature. ', - name: 'checkpoint.certificate_validation', - type: 'keyword', - }, - 'checkpoint.browse_time': { - category: 'checkpoint', - description: 'Application session browse time. ', - name: 'checkpoint.browse_time', - type: 'keyword', - }, - 'checkpoint.limit_requested': { - category: 'checkpoint', - description: 'Indicates whether data limit was requested for the session. ', - name: 'checkpoint.limit_requested', - type: 'integer', - }, - 'checkpoint.limit_applied': { - category: 'checkpoint', - description: 'Indicates whether the session was actually date limited. ', - name: 'checkpoint.limit_applied', - type: 'integer', - }, - 'checkpoint.dropped_total': { - category: 'checkpoint', - description: 'Amount of dropped packets (both incoming and outgoing). ', - name: 'checkpoint.dropped_total', - type: 'integer', - }, - 'checkpoint.client_type_os': { - category: 'checkpoint', - description: 'Client OS detected in the HTTP request. ', - name: 'checkpoint.client_type_os', - type: 'keyword', - }, - 'checkpoint.name': { - category: 'checkpoint', - description: 'Application name. ', - name: 'checkpoint.name', - type: 'keyword', - }, - 'checkpoint.properties': { - category: 'checkpoint', - description: 'Application categories. ', - name: 'checkpoint.properties', - type: 'keyword', - }, - 'checkpoint.sig_id': { - category: 'checkpoint', - description: "Application's signature ID which how it was detected by. ", - name: 'checkpoint.sig_id', - type: 'keyword', - }, - 'checkpoint.desc': { - category: 'checkpoint', - description: 'Override application description. ', - name: 'checkpoint.desc', - type: 'keyword', - }, - 'checkpoint.referrer_self_uid': { - category: 'checkpoint', - description: 'UUID of the current log. ', - name: 'checkpoint.referrer_self_uid', - type: 'keyword', - }, - 'checkpoint.referrer_parent_uid': { - category: 'checkpoint', - description: 'Log UUID of the referring application. ', - name: 'checkpoint.referrer_parent_uid', - type: 'keyword', - }, - 'checkpoint.needs_browse_time': { - category: 'checkpoint', - description: 'Browse time required for the connection. ', - name: 'checkpoint.needs_browse_time', - type: 'integer', - }, - 'checkpoint.cluster_info': { - category: 'checkpoint', - description: - 'Cluster information. Possible options: Failover reason/cluster state changes/CP cluster or 3rd party. ', - name: 'checkpoint.cluster_info', - type: 'keyword', - }, - 'checkpoint.sync': { - category: 'checkpoint', - description: 'Sync status and the reason (stable, at risk). ', - name: 'checkpoint.sync', - type: 'keyword', - }, - 'checkpoint.file_direction': { - category: 'checkpoint', - description: 'File direction. Possible options: upload/download. ', - name: 'checkpoint.file_direction', - type: 'keyword', - }, - 'checkpoint.invalid_file_size': { - category: 'checkpoint', - description: 'File_size field is valid only if this field is set to 0. ', - name: 'checkpoint.invalid_file_size', - type: 'integer', - }, - 'checkpoint.top_archive_file_name': { - category: 'checkpoint', - description: 'In case of archive file: the file that was sent/received. ', - name: 'checkpoint.top_archive_file_name', - type: 'keyword', - }, - 'checkpoint.data_type_name': { - category: 'checkpoint', - description: 'Data type in rulebase that was matched. ', - name: 'checkpoint.data_type_name', - type: 'keyword', - }, - 'checkpoint.specific_data_type_name': { - category: 'checkpoint', - description: 'Compound/Group scenario, data type that was matched. ', - name: 'checkpoint.specific_data_type_name', - type: 'keyword', - }, - 'checkpoint.word_list': { - category: 'checkpoint', - description: 'Words matched by data type. ', - name: 'checkpoint.word_list', - type: 'keyword', - }, - 'checkpoint.info': { - category: 'checkpoint', - description: 'Special log message. ', - name: 'checkpoint.info', - type: 'keyword', - }, - 'checkpoint.outgoing_url': { - category: 'checkpoint', - description: 'URL related to this log (for HTTP). ', - name: 'checkpoint.outgoing_url', - type: 'keyword', - }, - 'checkpoint.dlp_rule_name': { - category: 'checkpoint', - description: 'Matched rule name. ', - name: 'checkpoint.dlp_rule_name', - type: 'keyword', - }, - 'checkpoint.dlp_recipients': { - category: 'checkpoint', - description: 'Mail recipients. ', - name: 'checkpoint.dlp_recipients', - type: 'keyword', - }, - 'checkpoint.dlp_subject': { - category: 'checkpoint', - description: 'Mail subject. ', - name: 'checkpoint.dlp_subject', - type: 'keyword', - }, - 'checkpoint.dlp_word_list': { - category: 'checkpoint', - description: 'Phrases matched by data type. ', - name: 'checkpoint.dlp_word_list', - type: 'keyword', - }, - 'checkpoint.dlp_template_score': { - category: 'checkpoint', - description: 'Template data type match score. ', - name: 'checkpoint.dlp_template_score', - type: 'keyword', - }, - 'checkpoint.message_size': { - category: 'checkpoint', - description: 'Mail/post size. ', - name: 'checkpoint.message_size', - type: 'integer', - }, - 'checkpoint.dlp_incident_uid': { - category: 'checkpoint', - description: 'Unique ID of the matched rule. ', - name: 'checkpoint.dlp_incident_uid', - type: 'keyword', - }, - 'checkpoint.dlp_related_incident_uid': { - category: 'checkpoint', - description: 'Other ID related to this one. ', - name: 'checkpoint.dlp_related_incident_uid', - type: 'keyword', - }, - 'checkpoint.dlp_data_type_name': { - category: 'checkpoint', - description: 'Matched data type. ', - name: 'checkpoint.dlp_data_type_name', - type: 'keyword', - }, - 'checkpoint.dlp_data_type_uid': { - category: 'checkpoint', - description: 'Unique ID of the matched data type. ', - name: 'checkpoint.dlp_data_type_uid', - type: 'keyword', - }, - 'checkpoint.dlp_violation_description': { - category: 'checkpoint', - description: 'Violation descriptions described in the rulebase. ', - name: 'checkpoint.dlp_violation_description', - type: 'keyword', - }, - 'checkpoint.dlp_relevant_data_types': { - category: 'checkpoint', - description: 'In case of Compound/Group: the inner data types that were matched. ', - name: 'checkpoint.dlp_relevant_data_types', - type: 'keyword', - }, - 'checkpoint.dlp_action_reason': { - category: 'checkpoint', - description: 'Action chosen reason. ', - name: 'checkpoint.dlp_action_reason', - type: 'keyword', - }, - 'checkpoint.dlp_categories': { - category: 'checkpoint', - description: 'Data type category. ', - name: 'checkpoint.dlp_categories', - type: 'keyword', - }, - 'checkpoint.dlp_transint': { - category: 'checkpoint', - description: 'HTTP/SMTP/FTP. ', - name: 'checkpoint.dlp_transint', - type: 'keyword', - }, - 'checkpoint.duplicate': { - category: 'checkpoint', - description: - 'Log marked as duplicated, when mail is split and the Security Gateway sees it twice. ', - name: 'checkpoint.duplicate', - type: 'keyword', - }, - 'checkpoint.matched_file': { - category: 'checkpoint', - description: 'Unique ID of the matched data type. ', - name: 'checkpoint.matched_file', - type: 'keyword', - }, - 'checkpoint.matched_file_text_segments': { - category: 'checkpoint', - description: 'Fingerprint: number of text segments matched by this traffic. ', - name: 'checkpoint.matched_file_text_segments', - type: 'integer', - }, - 'checkpoint.matched_file_percentage': { - category: 'checkpoint', - description: 'Fingerprint: match percentage of the traffic. ', - name: 'checkpoint.matched_file_percentage', - type: 'integer', - }, - 'checkpoint.dlp_additional_action': { - category: 'checkpoint', - description: 'Watermark/None. ', - name: 'checkpoint.dlp_additional_action', - type: 'keyword', - }, - 'checkpoint.dlp_watermark_profile': { - category: 'checkpoint', - description: 'Watermark which was applied. ', - name: 'checkpoint.dlp_watermark_profile', - type: 'keyword', - }, - 'checkpoint.dlp_repository_id': { - category: 'checkpoint', - description: 'ID of scanned repository. ', - name: 'checkpoint.dlp_repository_id', - type: 'keyword', - }, - 'checkpoint.dlp_repository_root_path': { - category: 'checkpoint', - description: 'Repository path. ', - name: 'checkpoint.dlp_repository_root_path', - type: 'keyword', - }, - 'checkpoint.scan_id': { - category: 'checkpoint', - description: 'Sequential number of scan. ', - name: 'checkpoint.scan_id', - type: 'keyword', - }, - 'checkpoint.special_properties': { - category: 'checkpoint', - description: - "If this field is set to '1' the log will not be shown (in use for monitoring scan progress). ", - name: 'checkpoint.special_properties', - type: 'integer', - }, - 'checkpoint.dlp_repository_total_size': { - category: 'checkpoint', - description: 'Repository size. ', - name: 'checkpoint.dlp_repository_total_size', - type: 'integer', - }, - 'checkpoint.dlp_repository_files_number': { - category: 'checkpoint', - description: 'Number of files in repository. ', - name: 'checkpoint.dlp_repository_files_number', - type: 'integer', - }, - 'checkpoint.dlp_repository_scanned_files_number': { - category: 'checkpoint', - description: 'Number of scanned files in repository. ', - name: 'checkpoint.dlp_repository_scanned_files_number', - type: 'integer', - }, - 'checkpoint.duration': { - category: 'checkpoint', - description: 'Scan duration. ', - name: 'checkpoint.duration', - type: 'keyword', - }, - 'checkpoint.dlp_fingerprint_long_status': { - category: 'checkpoint', - description: 'Scan status - long format. ', - name: 'checkpoint.dlp_fingerprint_long_status', - type: 'keyword', - }, - 'checkpoint.dlp_fingerprint_short_status': { - category: 'checkpoint', - description: 'Scan status - short format. ', - name: 'checkpoint.dlp_fingerprint_short_status', - type: 'keyword', - }, - 'checkpoint.dlp_repository_directories_number': { - category: 'checkpoint', - description: 'Number of directories in repository. ', - name: 'checkpoint.dlp_repository_directories_number', - type: 'integer', - }, - 'checkpoint.dlp_repository_unreachable_directories_number': { - category: 'checkpoint', - description: 'Number of directories the Security Gateway was unable to read. ', - name: 'checkpoint.dlp_repository_unreachable_directories_number', - type: 'integer', - }, - 'checkpoint.dlp_fingerprint_files_number': { - category: 'checkpoint', - description: 'Number of successfully scanned files in repository. ', - name: 'checkpoint.dlp_fingerprint_files_number', - type: 'integer', - }, - 'checkpoint.dlp_repository_skipped_files_number': { - category: 'checkpoint', - description: 'Skipped number of files because of configuration. ', - name: 'checkpoint.dlp_repository_skipped_files_number', - type: 'integer', - }, - 'checkpoint.dlp_repository_scanned_directories_number': { - category: 'checkpoint', - description: 'Amount of directories scanned. ', - name: 'checkpoint.dlp_repository_scanned_directories_number', - type: 'integer', - }, - 'checkpoint.number_of_errors': { - category: 'checkpoint', - description: 'Number of files that were not scanned due to an error. ', - name: 'checkpoint.number_of_errors', - type: 'integer', - }, - 'checkpoint.next_scheduled_scan_date': { - category: 'checkpoint', - description: 'Next scan scheduled time according to time object. ', - name: 'checkpoint.next_scheduled_scan_date', - type: 'keyword', - }, - 'checkpoint.dlp_repository_scanned_total_size': { - category: 'checkpoint', - description: 'Size scanned. ', - name: 'checkpoint.dlp_repository_scanned_total_size', - type: 'integer', - }, - 'checkpoint.dlp_repository_reached_directories_number': { - category: 'checkpoint', - description: 'Number of scanned directories in repository. ', - name: 'checkpoint.dlp_repository_reached_directories_number', - type: 'integer', - }, - 'checkpoint.dlp_repository_not_scanned_directories_percentage': { - category: 'checkpoint', - description: 'Percentage of directories the Security Gateway was unable to read. ', - name: 'checkpoint.dlp_repository_not_scanned_directories_percentage', - type: 'integer', - }, - 'checkpoint.speed': { - category: 'checkpoint', - description: 'Current scan speed. ', - name: 'checkpoint.speed', - type: 'integer', - }, - 'checkpoint.dlp_repository_scan_progress': { - category: 'checkpoint', - description: 'Scan percentage. ', - name: 'checkpoint.dlp_repository_scan_progress', - type: 'integer', - }, - 'checkpoint.sub_policy_name': { - category: 'checkpoint', - description: 'Layer name. ', - name: 'checkpoint.sub_policy_name', - type: 'keyword', - }, - 'checkpoint.sub_policy_uid': { - category: 'checkpoint', - description: 'Layer uid. ', - name: 'checkpoint.sub_policy_uid', - type: 'keyword', - }, - 'checkpoint.fw_message': { - category: 'checkpoint', - description: 'Used for various firewall errors. ', - name: 'checkpoint.fw_message', - type: 'keyword', - }, - 'checkpoint.message': { - category: 'checkpoint', - description: 'ISP link has failed. ', - name: 'checkpoint.message', - type: 'keyword', - }, - 'checkpoint.isp_link': { - category: 'checkpoint', - description: 'Name of ISP link. ', - name: 'checkpoint.isp_link', - type: 'keyword', - }, - 'checkpoint.fw_subproduct': { - category: 'checkpoint', - description: 'Can be vpn/non vpn. ', - name: 'checkpoint.fw_subproduct', - type: 'keyword', - }, - 'checkpoint.sctp_error': { - category: 'checkpoint', - description: 'Error information, what caused sctp to fail on out_of_state. ', - name: 'checkpoint.sctp_error', - type: 'keyword', - }, - 'checkpoint.chunk_type': { - category: 'checkpoint', - description: 'Chunck of the sctp stream. ', - name: 'checkpoint.chunk_type', - type: 'keyword', - }, - 'checkpoint.sctp_association_state': { - category: 'checkpoint', - description: 'The bad state you were trying to update to. ', - name: 'checkpoint.sctp_association_state', - type: 'keyword', - }, - 'checkpoint.tcp_packet_out_of_state': { - category: 'checkpoint', - description: 'State violation. ', - name: 'checkpoint.tcp_packet_out_of_state', - type: 'keyword', - }, - 'checkpoint.connectivity_level': { - category: 'checkpoint', - description: 'Log for a new connection in wire mode. ', - name: 'checkpoint.connectivity_level', - type: 'keyword', - }, - 'checkpoint.ip_option': { - category: 'checkpoint', - description: 'IP option that was dropped. ', - name: 'checkpoint.ip_option', - type: 'integer', - }, - 'checkpoint.tcp_state': { - category: 'checkpoint', - description: 'Log reinting a tcp state change. ', - name: 'checkpoint.tcp_state', - type: 'keyword', - }, - 'checkpoint.expire_time': { - category: 'checkpoint', - description: 'Connection closing time. ', - name: 'checkpoint.expire_time', - type: 'keyword', - }, - 'checkpoint.rpc_prog': { - category: 'checkpoint', - description: 'Log for new RPC state - prog values. ', - name: 'checkpoint.rpc_prog', - type: 'integer', - }, - 'checkpoint.dce-rpc_interface_uuid': { - category: 'checkpoint', - description: 'Log for new RPC state - UUID values ', - name: 'checkpoint.dce-rpc_interface_uuid', - type: 'keyword', - }, - 'checkpoint.elapsed': { - category: 'checkpoint', - description: 'Time passed since start time. ', - name: 'checkpoint.elapsed', - type: 'keyword', - }, - 'checkpoint.icmp': { - category: 'checkpoint', - description: 'Number of packets, received by the client. ', - name: 'checkpoint.icmp', - type: 'keyword', - }, - 'checkpoint.capture_uuid': { - category: 'checkpoint', - description: 'UUID generated for the capture. Used when enabling the capture when logging. ', - name: 'checkpoint.capture_uuid', - type: 'keyword', - }, - 'checkpoint.diameter_app_ID': { - category: 'checkpoint', - description: 'The ID of diameter application. ', - name: 'checkpoint.diameter_app_ID', - type: 'integer', - }, - 'checkpoint.diameter_cmd_code': { - category: 'checkpoint', - description: 'Diameter not allowed application command id. ', - name: 'checkpoint.diameter_cmd_code', - type: 'integer', - }, - 'checkpoint.diameter_msg_type': { - category: 'checkpoint', - description: 'Diameter message type. ', - name: 'checkpoint.diameter_msg_type', - type: 'keyword', - }, - 'checkpoint.cp_message': { - category: 'checkpoint', - description: 'Used to log a general message. ', - name: 'checkpoint.cp_message', - type: 'integer', - }, - 'checkpoint.log_delay': { - category: 'checkpoint', - description: 'Time left before deleting template. ', - name: 'checkpoint.log_delay', - type: 'integer', - }, - 'checkpoint.attack_status': { - category: 'checkpoint', - description: 'In case of a malicious event on an endpoint computer, the status of the attack. ', - name: 'checkpoint.attack_status', - type: 'keyword', - }, - 'checkpoint.impacted_files': { - category: 'checkpoint', - description: - 'In case of an infection on an endpoint computer, the list of files that the malware impacted. ', - name: 'checkpoint.impacted_files', - type: 'keyword', - }, - 'checkpoint.remediated_files': { - category: 'checkpoint', - description: - 'In case of an infection and a successful cleaning of that infection, this is a list of remediated files on the computer. ', - name: 'checkpoint.remediated_files', - type: 'keyword', - }, - 'checkpoint.triggered_by': { - category: 'checkpoint', - description: - 'The name of the mechanism that triggered the Software Blade to enforce a protection. ', - name: 'checkpoint.triggered_by', - type: 'keyword', - }, - 'checkpoint.https_inspection_rule_id': { - category: 'checkpoint', - description: 'ID of the matched rule. ', - name: 'checkpoint.https_inspection_rule_id', - type: 'keyword', - }, - 'checkpoint.https_inspection_rule_name': { - category: 'checkpoint', - description: 'Name of the matched rule. ', - name: 'checkpoint.https_inspection_rule_name', - type: 'keyword', - }, - 'checkpoint.app_properties': { - category: 'checkpoint', - description: 'List of all found categories. ', - name: 'checkpoint.app_properties', - type: 'keyword', - }, - 'checkpoint.https_validation': { - category: 'checkpoint', - description: 'Precise error, describing HTTPS inspection failure. ', - name: 'checkpoint.https_validation', - type: 'keyword', - }, - 'checkpoint.https_inspection_action': { - category: 'checkpoint', - description: 'HTTPS inspection action (Inspect/Bypass/Error). ', - name: 'checkpoint.https_inspection_action', - type: 'keyword', - }, - 'checkpoint.icap_service_id': { - category: 'checkpoint', - description: 'Service ID, can work with multiple servers, treated as services. ', - name: 'checkpoint.icap_service_id', - type: 'integer', - }, - 'checkpoint.icap_server_name': { - category: 'checkpoint', - description: 'Server name. ', - name: 'checkpoint.icap_server_name', - type: 'keyword', - }, - 'checkpoint.internal_error': { - category: 'checkpoint', - description: 'Internal error, for troubleshooting ', - name: 'checkpoint.internal_error', - type: 'keyword', - }, - 'checkpoint.icap_more_info': { - category: 'checkpoint', - description: 'Free text for verdict. ', - name: 'checkpoint.icap_more_info', - type: 'integer', - }, - 'checkpoint.reply_status': { - category: 'checkpoint', - description: 'ICAP reply status code, e.g. 200 or 204. ', - name: 'checkpoint.reply_status', - type: 'integer', - }, - 'checkpoint.icap_server_service': { - category: 'checkpoint', - description: 'Service name, as given in the ICAP URI ', - name: 'checkpoint.icap_server_service', - type: 'keyword', - }, - 'checkpoint.mirror_and_decrypt_type': { - category: 'checkpoint', - description: - 'Information about decrypt and forward. Possible values: Mirror only, Decrypt and mirror, Partial mirroring (HTTPS inspection Bypass). ', - name: 'checkpoint.mirror_and_decrypt_type', - type: 'keyword', - }, - 'checkpoint.interface_name': { - category: 'checkpoint', - description: 'Designated interface for mirror And decrypt. ', - name: 'checkpoint.interface_name', - type: 'keyword', - }, - 'checkpoint.session_uid': { - category: 'checkpoint', - description: 'HTTP session-id. ', - name: 'checkpoint.session_uid', - type: 'keyword', - }, - 'checkpoint.broker_publisher': { - category: 'checkpoint', - description: 'IP address of the broker publisher who shared the session information. ', - name: 'checkpoint.broker_publisher', - type: 'ip', - }, - 'checkpoint.src_user_dn': { - category: 'checkpoint', - description: 'User distinguished name connected to source IP. ', - name: 'checkpoint.src_user_dn', - type: 'keyword', - }, - 'checkpoint.proxy_user_name': { - category: 'checkpoint', - description: 'User name connected to proxy IP. ', - name: 'checkpoint.proxy_user_name', - type: 'keyword', - }, - 'checkpoint.proxy_machine_name': { - category: 'checkpoint', - description: 'Machine name connected to proxy IP. ', - name: 'checkpoint.proxy_machine_name', - type: 'integer', - }, - 'checkpoint.proxy_user_dn': { - category: 'checkpoint', - description: 'User distinguished name connected to proxy IP. ', - name: 'checkpoint.proxy_user_dn', - type: 'keyword', - }, - 'checkpoint.query': { - category: 'checkpoint', - description: 'DNS query. ', - name: 'checkpoint.query', - type: 'keyword', - }, - 'checkpoint.dns_query': { - category: 'checkpoint', - description: 'DNS query. ', - name: 'checkpoint.dns_query', - type: 'keyword', - }, - 'checkpoint.inspection_item': { - category: 'checkpoint', - description: 'Blade element performed inspection. ', - name: 'checkpoint.inspection_item', - type: 'keyword', - }, - 'checkpoint.inspection_category': { - category: 'checkpoint', - description: 'Inspection category: protocol anomaly, signature etc. ', - name: 'checkpoint.inspection_category', - type: 'keyword', - }, - 'checkpoint.inspection_profile': { - category: 'checkpoint', - description: 'Profile which the activated protection belongs to. ', - name: 'checkpoint.inspection_profile', - type: 'keyword', - }, - 'checkpoint.summary': { - category: 'checkpoint', - description: 'Summary message of a non-compliant DNS traffic drops or detects. ', - name: 'checkpoint.summary', - type: 'keyword', - }, - 'checkpoint.question_rdata': { - category: 'checkpoint', - description: 'List of question records domains. ', - name: 'checkpoint.question_rdata', - type: 'keyword', - }, - 'checkpoint.answer_rdata': { - category: 'checkpoint', - description: 'List of answer resource records to the questioned domains. ', - name: 'checkpoint.answer_rdata', - type: 'keyword', - }, - 'checkpoint.authority_rdata': { - category: 'checkpoint', - description: 'List of authoritative servers. ', - name: 'checkpoint.authority_rdata', - type: 'keyword', - }, - 'checkpoint.additional_rdata': { - category: 'checkpoint', - description: 'List of additional resource records. ', - name: 'checkpoint.additional_rdata', - type: 'keyword', - }, - 'checkpoint.files_names': { - category: 'checkpoint', - description: 'List of files requested by FTP. ', - name: 'checkpoint.files_names', - type: 'keyword', - }, - 'checkpoint.ftp_user': { - category: 'checkpoint', - description: 'FTP username. ', - name: 'checkpoint.ftp_user', - type: 'keyword', - }, - 'checkpoint.mime_from': { - category: 'checkpoint', - description: "Sender's address. ", - name: 'checkpoint.mime_from', - type: 'keyword', - }, - 'checkpoint.mime_to': { - category: 'checkpoint', - description: 'List of receiver address. ', - name: 'checkpoint.mime_to', - type: 'keyword', - }, - 'checkpoint.bcc': { - category: 'checkpoint', - description: 'List of BCC addresses. ', - name: 'checkpoint.bcc', - type: 'keyword', - }, - 'checkpoint.content_type': { - category: 'checkpoint', - description: - 'Mail content type. Possible values: application/msword, text/html, image/gif etc. ', - name: 'checkpoint.content_type', - type: 'keyword', - }, - 'checkpoint.user_agent': { - category: 'checkpoint', - description: 'String identifying requesting software user agent. ', - name: 'checkpoint.user_agent', - type: 'keyword', - }, - 'checkpoint.referrer': { - category: 'checkpoint', - description: 'Referrer HTTP request header, previous web page address. ', - name: 'checkpoint.referrer', - type: 'keyword', - }, - 'checkpoint.http_location': { - category: 'checkpoint', - description: 'Response header, indicates the URL to redirect a page to. ', - name: 'checkpoint.http_location', - type: 'keyword', - }, - 'checkpoint.content_disposition': { - category: 'checkpoint', - description: 'Indicates how the content is expected to be displayed inline in the browser. ', - name: 'checkpoint.content_disposition', - type: 'keyword', - }, - 'checkpoint.via': { - category: 'checkpoint', - description: - 'Via header is added by proxies for tracking purposes to avoid sending reqests in loop. ', - name: 'checkpoint.via', - type: 'keyword', - }, - 'checkpoint.http_server': { - category: 'checkpoint', - description: - 'Server HTTP header value, contains information about the software used by the origin server, which handles the request. ', - name: 'checkpoint.http_server', - type: 'keyword', - }, - 'checkpoint.content_length': { - category: 'checkpoint', - description: 'Indicates the size of the entity-body of the HTTP header. ', - name: 'checkpoint.content_length', - type: 'keyword', - }, - 'checkpoint.authorization': { - category: 'checkpoint', - description: 'Authorization HTTP header value. ', - name: 'checkpoint.authorization', - type: 'keyword', - }, - 'checkpoint.http_host': { - category: 'checkpoint', - description: 'Domain name of the server that the HTTP request is sent to. ', - name: 'checkpoint.http_host', - type: 'keyword', - }, - 'checkpoint.inspection_settings_log': { - category: 'checkpoint', - description: 'Indicats that the log was released by inspection settings. ', - name: 'checkpoint.inspection_settings_log', - type: 'keyword', - }, - 'checkpoint.cvpn_resource': { - category: 'checkpoint', - description: 'Mobile Access application. ', - name: 'checkpoint.cvpn_resource', - type: 'keyword', - }, - 'checkpoint.cvpn_category': { - category: 'checkpoint', - description: 'Mobile Access application type. ', - name: 'checkpoint.cvpn_category', - type: 'keyword', - }, - 'checkpoint.url': { - category: 'checkpoint', - description: 'Translated URL. ', - name: 'checkpoint.url', - type: 'keyword', - }, - 'checkpoint.reject_id': { - category: 'checkpoint', - description: - 'A reject ID that corresponds to the one presented in the Mobile Access error page. ', - name: 'checkpoint.reject_id', - type: 'keyword', - }, - 'checkpoint.fs-proto': { - category: 'checkpoint', - description: 'The file share protocol used in mobile acess file share application. ', - name: 'checkpoint.fs-proto', - type: 'keyword', - }, - 'checkpoint.app_package': { - category: 'checkpoint', - description: 'Unique identifier of the application on the protected mobile device. ', - name: 'checkpoint.app_package', - type: 'keyword', - }, - 'checkpoint.appi_name': { - category: 'checkpoint', - description: 'Name of application downloaded on the protected mobile device. ', - name: 'checkpoint.appi_name', - type: 'keyword', - }, - 'checkpoint.app_repackaged': { - category: 'checkpoint', - description: - 'Indicates whether the original application was repackage not by the official developer. ', - name: 'checkpoint.app_repackaged', - type: 'keyword', - }, - 'checkpoint.app_sid_id': { - category: 'checkpoint', - description: 'Unique SHA identifier of a mobile application. ', - name: 'checkpoint.app_sid_id', - type: 'keyword', - }, - 'checkpoint.app_version': { - category: 'checkpoint', - description: 'Version of the application downloaded on the protected mobile device. ', - name: 'checkpoint.app_version', - type: 'keyword', - }, - 'checkpoint.developer_certificate_name': { - category: 'checkpoint', - description: - "Name of the developer's certificate that was used to sign the mobile application. ", - name: 'checkpoint.developer_certificate_name', - type: 'keyword', - }, - 'checkpoint.email_message_id': { - category: 'checkpoint', - description: 'Email session id (uniqe ID of the mail). ', - name: 'checkpoint.email_message_id', - type: 'keyword', - }, - 'checkpoint.email_queue_id': { - category: 'checkpoint', - description: 'Postfix email queue id. ', - name: 'checkpoint.email_queue_id', - type: 'keyword', - }, - 'checkpoint.email_queue_name': { - category: 'checkpoint', - description: 'Postfix email queue name. ', - name: 'checkpoint.email_queue_name', - type: 'keyword', - }, - 'checkpoint.file_name': { - category: 'checkpoint', - description: 'Malicious file name. ', - name: 'checkpoint.file_name', - type: 'keyword', - }, - 'checkpoint.failure_reason': { - category: 'checkpoint', - description: 'MTA failure description. ', - name: 'checkpoint.failure_reason', - type: 'keyword', - }, - 'checkpoint.email_headers': { - category: 'checkpoint', - description: 'String containing all the email headers. ', - name: 'checkpoint.email_headers', - type: 'keyword', - }, - 'checkpoint.arrival_time': { - category: 'checkpoint', - description: 'Email arrival timestamp. ', - name: 'checkpoint.arrival_time', - type: 'keyword', - }, - 'checkpoint.email_status': { - category: 'checkpoint', - description: - "Describes the email's state. Possible options: delivered, deferred, skipped, bounced, hold, new, scan_started, scan_ended ", - name: 'checkpoint.email_status', - type: 'keyword', - }, - 'checkpoint.status_update': { - category: 'checkpoint', - description: 'Last time log was updated. ', - name: 'checkpoint.status_update', - type: 'keyword', - }, - 'checkpoint.delivery_time': { - category: 'checkpoint', - description: 'Timestamp of when email was delivered (MTA finished handling the email. ', - name: 'checkpoint.delivery_time', - type: 'keyword', - }, - 'checkpoint.links_num': { - category: 'checkpoint', - description: 'Number of links in the mail. ', - name: 'checkpoint.links_num', - type: 'integer', - }, - 'checkpoint.attachments_num': { - category: 'checkpoint', - description: 'Number of attachments in the mail. ', - name: 'checkpoint.attachments_num', - type: 'integer', - }, - 'checkpoint.email_content': { - category: 'checkpoint', - description: - 'Mail contents. Possible options: attachments/links & attachments/links/text only. ', - name: 'checkpoint.email_content', - type: 'keyword', - }, - 'checkpoint.allocated_ports': { - category: 'checkpoint', - description: 'Amount of allocated ports. ', - name: 'checkpoint.allocated_ports', - type: 'integer', - }, - 'checkpoint.capacity': { - category: 'checkpoint', - description: 'Capacity of the ports. ', - name: 'checkpoint.capacity', - type: 'integer', - }, - 'checkpoint.ports_usage': { - category: 'checkpoint', - description: 'Percentage of allocated ports. ', - name: 'checkpoint.ports_usage', - type: 'integer', - }, - 'checkpoint.nat_exhausted_pool': { - category: 'checkpoint', - description: '4-tuple of an exhausted pool. ', - name: 'checkpoint.nat_exhausted_pool', - type: 'keyword', - }, - 'checkpoint.nat_rulenum': { - category: 'checkpoint', - description: 'NAT rulebase first matched rule. ', - name: 'checkpoint.nat_rulenum', - type: 'integer', - }, - 'checkpoint.nat_addtnl_rulenum': { - category: 'checkpoint', - description: - 'When matching 2 automatic rules , second rule match will be shown otherwise field will be 0. ', - name: 'checkpoint.nat_addtnl_rulenum', - type: 'integer', - }, - 'checkpoint.message_info': { - category: 'checkpoint', - description: 'Used for information messages, for example:NAT connection has ended. ', - name: 'checkpoint.message_info', - type: 'keyword', - }, - 'checkpoint.nat46': { - category: 'checkpoint', - description: 'NAT 46 status, in most cases "enabled". ', - name: 'checkpoint.nat46', - type: 'keyword', - }, - 'checkpoint.end_time': { - category: 'checkpoint', - description: 'TCP connection end time. ', - name: 'checkpoint.end_time', - type: 'keyword', - }, - 'checkpoint.tcp_end_reason': { - category: 'checkpoint', - description: 'Reason for TCP connection closure. ', - name: 'checkpoint.tcp_end_reason', - type: 'keyword', - }, - 'checkpoint.cgnet': { - category: 'checkpoint', - description: 'Describes NAT allocation for specific subscriber. ', - name: 'checkpoint.cgnet', - type: 'keyword', - }, - 'checkpoint.subscriber': { - category: 'checkpoint', - description: 'Source IP before CGNAT. ', - name: 'checkpoint.subscriber', - type: 'ip', - }, - 'checkpoint.hide_ip': { - category: 'checkpoint', - description: 'Source IP which will be used after CGNAT. ', - name: 'checkpoint.hide_ip', - type: 'ip', - }, - 'checkpoint.int_start': { - category: 'checkpoint', - description: 'Subscriber start int which will be used for NAT. ', - name: 'checkpoint.int_start', - type: 'integer', - }, - 'checkpoint.int_end': { - category: 'checkpoint', - description: 'Subscriber end int which will be used for NAT. ', - name: 'checkpoint.int_end', - type: 'integer', - }, - 'checkpoint.packet_amount': { - category: 'checkpoint', - description: 'Amount of packets dropped. ', - name: 'checkpoint.packet_amount', - type: 'integer', - }, - 'checkpoint.monitor_reason': { - category: 'checkpoint', - description: 'Aggregated logs of monitored packets. ', - name: 'checkpoint.monitor_reason', - type: 'keyword', - }, - 'checkpoint.drops_amount': { - category: 'checkpoint', - description: 'Amount of multicast packets dropped. ', - name: 'checkpoint.drops_amount', - type: 'integer', - }, - 'checkpoint.securexl_message': { - category: 'checkpoint', - description: - 'Two options for a SecureXL message: 1. Missed accounting records after heavy load on logging system. 2. FW log message regarding a packet drop. ', - name: 'checkpoint.securexl_message', - type: 'keyword', - }, - 'checkpoint.conns_amount': { - category: 'checkpoint', - description: 'Connections amount of aggregated log info. ', - name: 'checkpoint.conns_amount', - type: 'integer', - }, - 'checkpoint.scope': { - category: 'checkpoint', - description: 'IP related to the attack. ', - name: 'checkpoint.scope', - type: 'keyword', - }, - 'checkpoint.analyzed_on': { - category: 'checkpoint', - description: 'Check Point ThreatCloud / emulator name. ', - name: 'checkpoint.analyzed_on', - type: 'keyword', - }, - 'checkpoint.detected_on': { - category: 'checkpoint', - description: 'System and applications version the file was emulated on. ', - name: 'checkpoint.detected_on', - type: 'keyword', - }, - 'checkpoint.dropped_file_name': { - category: 'checkpoint', - description: 'List of names dropped from the original file. ', - name: 'checkpoint.dropped_file_name', - type: 'keyword', - }, - 'checkpoint.dropped_file_type': { - category: 'checkpoint', - description: 'List of file types dropped from the original file. ', - name: 'checkpoint.dropped_file_type', - type: 'keyword', - }, - 'checkpoint.dropped_file_hash': { - category: 'checkpoint', - description: 'List of file hashes dropped from the original file. ', - name: 'checkpoint.dropped_file_hash', - type: 'keyword', - }, - 'checkpoint.dropped_file_verdict': { - category: 'checkpoint', - description: 'List of file verdics dropped from the original file. ', - name: 'checkpoint.dropped_file_verdict', - type: 'keyword', - }, - 'checkpoint.emulated_on': { - category: 'checkpoint', - description: 'Images the files were emulated on. ', - name: 'checkpoint.emulated_on', - type: 'keyword', - }, - 'checkpoint.extracted_file_type': { - category: 'checkpoint', - description: 'Types of extracted files in case of an archive. ', - name: 'checkpoint.extracted_file_type', - type: 'keyword', - }, - 'checkpoint.extracted_file_names': { - category: 'checkpoint', - description: 'Names of extracted files in case of an archive. ', - name: 'checkpoint.extracted_file_names', - type: 'keyword', - }, - 'checkpoint.extracted_file_hash': { - category: 'checkpoint', - description: 'Archive hash in case of extracted files. ', - name: 'checkpoint.extracted_file_hash', - type: 'keyword', - }, - 'checkpoint.extracted_file_verdict': { - category: 'checkpoint', - description: 'Verdict of extracted files in case of an archive. ', - name: 'checkpoint.extracted_file_verdict', - type: 'keyword', - }, - 'checkpoint.extracted_file_uid': { - category: 'checkpoint', - description: 'UID of extracted files in case of an archive. ', - name: 'checkpoint.extracted_file_uid', - type: 'keyword', - }, - 'checkpoint.mitre_initial_access': { - category: 'checkpoint', - description: 'The adversary is trying to break into your network. ', - name: 'checkpoint.mitre_initial_access', - type: 'keyword', - }, - 'checkpoint.mitre_execution': { - category: 'checkpoint', - description: 'The adversary is trying to run malicious code. ', - name: 'checkpoint.mitre_execution', - type: 'keyword', - }, - 'checkpoint.mitre_persistence': { - category: 'checkpoint', - description: 'The adversary is trying to maintain his foothold. ', - name: 'checkpoint.mitre_persistence', - type: 'keyword', - }, - 'checkpoint.mitre_privilege_escalation': { - category: 'checkpoint', - description: 'The adversary is trying to gain higher-level permissions. ', - name: 'checkpoint.mitre_privilege_escalation', - type: 'keyword', - }, - 'checkpoint.mitre_defense_evasion': { - category: 'checkpoint', - description: 'The adversary is trying to avoid being detected. ', - name: 'checkpoint.mitre_defense_evasion', - type: 'keyword', - }, - 'checkpoint.mitre_credential_access': { - category: 'checkpoint', - description: 'The adversary is trying to steal account names and passwords. ', - name: 'checkpoint.mitre_credential_access', - type: 'keyword', - }, - 'checkpoint.mitre_discovery': { - category: 'checkpoint', - description: 'The adversary is trying to expose information about your environment. ', - name: 'checkpoint.mitre_discovery', - type: 'keyword', - }, - 'checkpoint.mitre_lateral_movement': { - category: 'checkpoint', - description: 'The adversary is trying to explore your environment. ', - name: 'checkpoint.mitre_lateral_movement', - type: 'keyword', - }, - 'checkpoint.mitre_collection': { - category: 'checkpoint', - description: 'The adversary is trying to collect data of interest to achieve his goal. ', - name: 'checkpoint.mitre_collection', - type: 'keyword', - }, - 'checkpoint.mitre_command_and_control': { - category: 'checkpoint', - description: - 'The adversary is trying to communicate with compromised systems in order to control them. ', - name: 'checkpoint.mitre_command_and_control', - type: 'keyword', - }, - 'checkpoint.mitre_exfiltration': { - category: 'checkpoint', - description: 'The adversary is trying to steal data. ', - name: 'checkpoint.mitre_exfiltration', - type: 'keyword', - }, - 'checkpoint.mitre_impact': { - category: 'checkpoint', - description: - 'The adversary is trying to manipulate, interrupt, or destroy your systems and data. ', - name: 'checkpoint.mitre_impact', - type: 'keyword', - }, - 'checkpoint.parent_file_hash': { - category: 'checkpoint', - description: "Archive's hash in case of extracted files. ", - name: 'checkpoint.parent_file_hash', - type: 'keyword', - }, - 'checkpoint.parent_file_name': { - category: 'checkpoint', - description: "Archive's name in case of extracted files. ", - name: 'checkpoint.parent_file_name', - type: 'keyword', - }, - 'checkpoint.parent_file_uid': { - category: 'checkpoint', - description: "Archive's UID in case of extracted files. ", - name: 'checkpoint.parent_file_uid', - type: 'keyword', - }, - 'checkpoint.similiar_iocs': { - category: 'checkpoint', - description: 'Other IoCs similar to the ones found, related to the malicious file. ', - name: 'checkpoint.similiar_iocs', - type: 'keyword', - }, - 'checkpoint.similar_hashes': { - category: 'checkpoint', - description: 'Hashes found similar to the malicious file. ', - name: 'checkpoint.similar_hashes', - type: 'keyword', - }, - 'checkpoint.similar_strings': { - category: 'checkpoint', - description: 'Strings found similar to the malicious file. ', - name: 'checkpoint.similar_strings', - type: 'keyword', - }, - 'checkpoint.similar_communication': { - category: 'checkpoint', - description: 'Network action found similar to the malicious file. ', - name: 'checkpoint.similar_communication', - type: 'keyword', - }, - 'checkpoint.te_verdict_determined_by': { - category: 'checkpoint', - description: 'Emulators determined file verdict. ', - name: 'checkpoint.te_verdict_determined_by', - type: 'keyword', - }, - 'checkpoint.packet_capture_unique_id': { - category: 'checkpoint', - description: 'Identifier of the packet capture files. ', - name: 'checkpoint.packet_capture_unique_id', - type: 'keyword', - }, - 'checkpoint.total_attachments': { - category: 'checkpoint', - description: 'The number of attachments in an email. ', - name: 'checkpoint.total_attachments', - type: 'integer', - }, - 'checkpoint.additional_info': { - category: 'checkpoint', - description: 'ID of original file/mail which are sent by admin. ', - name: 'checkpoint.additional_info', - type: 'keyword', - }, - 'checkpoint.content_risk': { - category: 'checkpoint', - description: 'File risk. ', - name: 'checkpoint.content_risk', - type: 'integer', - }, - 'checkpoint.operation': { - category: 'checkpoint', - description: 'Operation made by Threat Extraction. ', - name: 'checkpoint.operation', - type: 'keyword', - }, - 'checkpoint.scrubbed_content': { - category: 'checkpoint', - description: 'Active content that was found. ', - name: 'checkpoint.scrubbed_content', - type: 'keyword', - }, - 'checkpoint.scrub_time': { - category: 'checkpoint', - description: 'Extraction process duration. ', - name: 'checkpoint.scrub_time', - type: 'keyword', - }, - 'checkpoint.scrub_download_time': { - category: 'checkpoint', - description: 'File download time from resource. ', - name: 'checkpoint.scrub_download_time', - type: 'keyword', - }, - 'checkpoint.scrub_total_time': { - category: 'checkpoint', - description: 'Threat extraction total file handling time. ', - name: 'checkpoint.scrub_total_time', - type: 'keyword', - }, - 'checkpoint.scrub_activity': { - category: 'checkpoint', - description: 'The result of the extraction ', - name: 'checkpoint.scrub_activity', - type: 'keyword', - }, - 'checkpoint.watermark': { - category: 'checkpoint', - description: 'Reports whether watermark is added to the cleaned file. ', - name: 'checkpoint.watermark', - type: 'keyword', - }, - 'checkpoint.source_object': { - category: 'checkpoint', - description: 'Matched object name on source column. ', - name: 'checkpoint.source_object', - type: 'keyword', - }, - 'checkpoint.destination_object': { - category: 'checkpoint', - description: 'Matched object name on destination column. ', - name: 'checkpoint.destination_object', - type: 'keyword', - }, - 'checkpoint.drop_reason': { - category: 'checkpoint', - description: 'Drop reason description. ', - name: 'checkpoint.drop_reason', - type: 'keyword', - }, - 'checkpoint.hit': { - category: 'checkpoint', - description: 'Number of hits on a rule. ', - name: 'checkpoint.hit', - type: 'integer', - }, - 'checkpoint.rulebase_id': { - category: 'checkpoint', - description: 'Layer number. ', - name: 'checkpoint.rulebase_id', - type: 'integer', - }, - 'checkpoint.first_hit_time': { - category: 'checkpoint', - description: 'First hit time in current interval. ', - name: 'checkpoint.first_hit_time', - type: 'integer', - }, - 'checkpoint.last_hit_time': { - category: 'checkpoint', - description: 'Last hit time in current interval. ', - name: 'checkpoint.last_hit_time', - type: 'integer', - }, - 'checkpoint.rematch_info': { - category: 'checkpoint', - description: - 'Information sent when old connections cannot be matched during policy installation. ', - name: 'checkpoint.rematch_info', - type: 'keyword', - }, - 'checkpoint.last_rematch_time': { - category: 'checkpoint', - description: 'Connection rematched time. ', - name: 'checkpoint.last_rematch_time', - type: 'keyword', - }, - 'checkpoint.action_reason': { - category: 'checkpoint', - description: 'Connection drop reason. ', - name: 'checkpoint.action_reason', - type: 'integer', - }, - 'checkpoint.action_reason_msg': { - category: 'checkpoint', - description: 'Connection drop reason message. ', - name: 'checkpoint.action_reason_msg', - type: 'keyword', - }, - 'checkpoint.c_bytes': { - category: 'checkpoint', - description: 'Boolean value indicates whether bytes sent from the client side are used. ', - name: 'checkpoint.c_bytes', - type: 'integer', - }, - 'checkpoint.context_num': { - category: 'checkpoint', - description: 'Serial number of the log for a specific connection. ', - name: 'checkpoint.context_num', - type: 'integer', - }, - 'checkpoint.match_id': { - category: 'checkpoint', - description: 'Private key of the rule ', - name: 'checkpoint.match_id', - type: 'integer', - }, - 'checkpoint.alert': { - category: 'checkpoint', - description: 'Alert level of matched rule (for connection logs). ', - name: 'checkpoint.alert', - type: 'keyword', - }, - 'checkpoint.parent_rule': { - category: 'checkpoint', - description: 'Parent rule number, in case of inline layer. ', - name: 'checkpoint.parent_rule', - type: 'integer', - }, - 'checkpoint.match_fk': { - category: 'checkpoint', - description: 'Rule number. ', - name: 'checkpoint.match_fk', - type: 'integer', - }, - 'checkpoint.dropped_outgoing': { - category: 'checkpoint', - description: 'Number of outgoing bytes dropped when using UP-limit feature. ', - name: 'checkpoint.dropped_outgoing', - type: 'integer', - }, - 'checkpoint.dropped_incoming': { - category: 'checkpoint', - description: 'Number of incoming bytes dropped when using UP-limit feature. ', - name: 'checkpoint.dropped_incoming', - type: 'integer', - }, - 'checkpoint.media_type': { - category: 'checkpoint', - description: 'Media used (audio, video, etc.) ', - name: 'checkpoint.media_type', - type: 'keyword', - }, - 'checkpoint.sip_reason': { - category: 'checkpoint', - description: "Explains why 'source_ip' isn't allowed to redirect (handover). ", - name: 'checkpoint.sip_reason', - type: 'keyword', - }, - 'checkpoint.voip_method': { - category: 'checkpoint', - description: 'Registration request. ', - name: 'checkpoint.voip_method', - type: 'keyword', - }, - 'checkpoint.registered_ip-phones': { - category: 'checkpoint', - description: 'Registered IP-Phones. ', - name: 'checkpoint.registered_ip-phones', - type: 'keyword', - }, - 'checkpoint.voip_reg_user_type': { - category: 'checkpoint', - description: 'Registered IP-Phone type. ', - name: 'checkpoint.voip_reg_user_type', - type: 'keyword', - }, - 'checkpoint.voip_call_id': { - category: 'checkpoint', - description: 'Call-ID. ', - name: 'checkpoint.voip_call_id', - type: 'keyword', - }, - 'checkpoint.voip_reg_int': { - category: 'checkpoint', - description: 'Registration port. ', - name: 'checkpoint.voip_reg_int', - type: 'integer', - }, - 'checkpoint.voip_reg_ipp': { - category: 'checkpoint', - description: 'Registration IP protocol. ', - name: 'checkpoint.voip_reg_ipp', - type: 'integer', - }, - 'checkpoint.voip_reg_period': { - category: 'checkpoint', - description: 'Registration period. ', - name: 'checkpoint.voip_reg_period', - type: 'integer', - }, - 'checkpoint.src_phone_number': { - category: 'checkpoint', - description: 'Source IP-Phone. ', - name: 'checkpoint.src_phone_number', - type: 'keyword', - }, - 'checkpoint.voip_from_user_type': { - category: 'checkpoint', - description: 'Source IP-Phone type. ', - name: 'checkpoint.voip_from_user_type', - type: 'keyword', - }, - 'checkpoint.voip_to_user_type': { - category: 'checkpoint', - description: 'Destination IP-Phone type. ', - name: 'checkpoint.voip_to_user_type', - type: 'keyword', - }, - 'checkpoint.voip_call_dir': { - category: 'checkpoint', - description: 'Call direction: in/out. ', - name: 'checkpoint.voip_call_dir', - type: 'keyword', - }, - 'checkpoint.voip_call_state': { - category: 'checkpoint', - description: 'Call state. Possible values: in/out. ', - name: 'checkpoint.voip_call_state', - type: 'keyword', - }, - 'checkpoint.voip_call_term_time': { - category: 'checkpoint', - description: 'Call termination time stamp. ', - name: 'checkpoint.voip_call_term_time', - type: 'keyword', - }, - 'checkpoint.voip_duration': { - category: 'checkpoint', - description: 'Call duration (seconds). ', - name: 'checkpoint.voip_duration', - type: 'keyword', - }, - 'checkpoint.voip_media_port': { - category: 'checkpoint', - description: 'Media int. ', - name: 'checkpoint.voip_media_port', - type: 'keyword', - }, - 'checkpoint.voip_media_ipp': { - category: 'checkpoint', - description: 'Media IP protocol. ', - name: 'checkpoint.voip_media_ipp', - type: 'keyword', - }, - 'checkpoint.voip_est_codec': { - category: 'checkpoint', - description: 'Estimated codec. ', - name: 'checkpoint.voip_est_codec', - type: 'keyword', - }, - 'checkpoint.voip_exp': { - category: 'checkpoint', - description: 'Expiration. ', - name: 'checkpoint.voip_exp', - type: 'integer', - }, - 'checkpoint.voip_attach_sz': { - category: 'checkpoint', - description: 'Attachment size. ', - name: 'checkpoint.voip_attach_sz', - type: 'integer', - }, - 'checkpoint.voip_attach_action_info': { - category: 'checkpoint', - description: 'Attachment action Info. ', - name: 'checkpoint.voip_attach_action_info', - type: 'keyword', - }, - 'checkpoint.voip_media_codec': { - category: 'checkpoint', - description: 'Estimated codec. ', - name: 'checkpoint.voip_media_codec', - type: 'keyword', - }, - 'checkpoint.voip_reject_reason': { - category: 'checkpoint', - description: 'Reject reason. ', - name: 'checkpoint.voip_reject_reason', - type: 'keyword', - }, - 'checkpoint.voip_reason_info': { - category: 'checkpoint', - description: 'Information. ', - name: 'checkpoint.voip_reason_info', - type: 'keyword', - }, - 'checkpoint.voip_config': { - category: 'checkpoint', - description: 'Configuration. ', - name: 'checkpoint.voip_config', - type: 'keyword', - }, - 'checkpoint.voip_reg_server': { - category: 'checkpoint', - description: 'Registrar server IP address. ', - name: 'checkpoint.voip_reg_server', - type: 'ip', - }, - 'checkpoint.scv_user': { - category: 'checkpoint', - description: 'Username whose packets are dropped on SCV. ', - name: 'checkpoint.scv_user', - type: 'keyword', - }, - 'checkpoint.scv_message_info': { - category: 'checkpoint', - description: 'Drop reason. ', - name: 'checkpoint.scv_message_info', - type: 'keyword', - }, - 'checkpoint.ppp': { - category: 'checkpoint', - description: 'Authentication status. ', - name: 'checkpoint.ppp', - type: 'keyword', - }, - 'checkpoint.scheme': { - category: 'checkpoint', - description: 'Describes the scheme used for the log. ', - name: 'checkpoint.scheme', - type: 'keyword', - }, - 'checkpoint.machine': { - category: 'checkpoint', - description: 'L2TP machine which triggered the log and the log refers to it. ', - name: 'checkpoint.machine', - type: 'keyword', - }, - 'checkpoint.vpn_feature_name': { - category: 'checkpoint', - description: 'L2TP /IKE / Link Selection. ', - name: 'checkpoint.vpn_feature_name', - type: 'keyword', - }, - 'checkpoint.reject_category': { - category: 'checkpoint', - description: 'Authentication failure reason. ', - name: 'checkpoint.reject_category', - type: 'keyword', - }, - 'checkpoint.peer_ip_probing_status_update': { - category: 'checkpoint', - description: 'IP address response status. ', - name: 'checkpoint.peer_ip_probing_status_update', - type: 'keyword', - }, - 'checkpoint.peer_ip': { - category: 'checkpoint', - description: 'IP address which the client connects to. ', - name: 'checkpoint.peer_ip', - type: 'keyword', - }, - 'checkpoint.link_probing_status_update': { - category: 'checkpoint', - description: 'IP address response status. ', - name: 'checkpoint.link_probing_status_update', - type: 'keyword', - }, - 'checkpoint.source_interface': { - category: 'checkpoint', - description: 'External Interface name for source interface or Null if not found. ', - name: 'checkpoint.source_interface', - type: 'keyword', - }, - 'checkpoint.next_hop_ip': { - category: 'checkpoint', - description: 'Next hop IP address. ', - name: 'checkpoint.next_hop_ip', - type: 'keyword', - }, - 'checkpoint.srckeyid': { - category: 'checkpoint', - description: 'Initiator Spi ID. ', - name: 'checkpoint.srckeyid', - type: 'keyword', - }, - 'checkpoint.dstkeyid': { - category: 'checkpoint', - description: 'Responder Spi ID. ', - name: 'checkpoint.dstkeyid', - type: 'keyword', - }, - 'checkpoint.encryption_failure': { - category: 'checkpoint', - description: 'Message indicating why the encryption failed. ', - name: 'checkpoint.encryption_failure', - type: 'keyword', - }, - 'checkpoint.ike_ids': { - category: 'checkpoint', - description: 'All QM ids. ', - name: 'checkpoint.ike_ids', - type: 'keyword', - }, - 'checkpoint.community': { - category: 'checkpoint', - description: 'Community name for the IPSec key and the use of the IKEv. ', - name: 'checkpoint.community', - type: 'keyword', - }, - 'checkpoint.ike': { - category: 'checkpoint', - description: 'IKEMode (PHASE1, PHASE2, etc..). ', - name: 'checkpoint.ike', - type: 'keyword', - }, - 'checkpoint.cookieI': { - category: 'checkpoint', - description: 'Initiator cookie. ', - name: 'checkpoint.cookieI', - type: 'keyword', - }, - 'checkpoint.cookieR': { - category: 'checkpoint', - description: 'Responder cookie. ', - name: 'checkpoint.cookieR', - type: 'keyword', - }, - 'checkpoint.msgid': { - category: 'checkpoint', - description: 'Message ID. ', - name: 'checkpoint.msgid', - type: 'keyword', - }, - 'checkpoint.methods': { - category: 'checkpoint', - description: 'IPSEc methods. ', - name: 'checkpoint.methods', - type: 'keyword', - }, - 'checkpoint.connection_uid': { - category: 'checkpoint', - description: 'Calculation of md5 of the IP and user name as UID. ', - name: 'checkpoint.connection_uid', - type: 'keyword', - }, - 'checkpoint.site_name': { - category: 'checkpoint', - description: 'Site name. ', - name: 'checkpoint.site_name', - type: 'keyword', - }, - 'checkpoint.esod_rule_name': { - category: 'checkpoint', - description: 'Unknown rule name. ', - name: 'checkpoint.esod_rule_name', - type: 'keyword', - }, - 'checkpoint.esod_rule_action': { - category: 'checkpoint', - description: 'Unknown rule action. ', - name: 'checkpoint.esod_rule_action', - type: 'keyword', - }, - 'checkpoint.esod_rule_type': { - category: 'checkpoint', - description: 'Unknown rule type. ', - name: 'checkpoint.esod_rule_type', - type: 'keyword', - }, - 'checkpoint.esod_noncompliance_reason': { - category: 'checkpoint', - description: 'Non-compliance reason. ', - name: 'checkpoint.esod_noncompliance_reason', - type: 'keyword', - }, - 'checkpoint.esod_associated_policies': { - category: 'checkpoint', - description: 'Associated policies. ', - name: 'checkpoint.esod_associated_policies', - type: 'keyword', - }, - 'checkpoint.spyware_type': { - category: 'checkpoint', - description: 'Spyware type. ', - name: 'checkpoint.spyware_type', - type: 'keyword', - }, - 'checkpoint.anti_virus_type': { - category: 'checkpoint', - description: 'Anti virus type. ', - name: 'checkpoint.anti_virus_type', - type: 'keyword', - }, - 'checkpoint.end_user_firewall_type': { - category: 'checkpoint', - description: 'End user firewall type. ', - name: 'checkpoint.end_user_firewall_type', - type: 'keyword', - }, - 'checkpoint.esod_scan_status': { - category: 'checkpoint', - description: 'Scan failed. ', - name: 'checkpoint.esod_scan_status', - type: 'keyword', - }, - 'checkpoint.esod_access_status': { - category: 'checkpoint', - description: 'Access denied. ', - name: 'checkpoint.esod_access_status', - type: 'keyword', - }, - 'checkpoint.client_type': { - category: 'checkpoint', - description: 'Endpoint Connect. ', - name: 'checkpoint.client_type', - type: 'keyword', - }, - 'checkpoint.precise_error': { - category: 'checkpoint', - description: 'HTTP parser error. ', - name: 'checkpoint.precise_error', - type: 'keyword', - }, - 'checkpoint.method': { - category: 'checkpoint', - description: 'HTTP method. ', - name: 'checkpoint.method', - type: 'keyword', - }, - 'checkpoint.trusted_domain': { - category: 'checkpoint', - description: 'In case of phishing event, the domain, which the attacker was impersonating. ', - name: 'checkpoint.trusted_domain', - type: 'keyword', - }, - 'cisco.amp.timestamp_nanoseconds': { - category: 'cisco', - description: 'The timestamp in Epoch nanoseconds. ', - name: 'cisco.amp.timestamp_nanoseconds', - type: 'date', - }, - 'cisco.amp.event_type_id': { - category: 'cisco', - description: 'A sub ID of the event, depending on event type. ', - name: 'cisco.amp.event_type_id', - type: 'keyword', - }, - 'cisco.amp.detection': { - category: 'cisco', - description: 'The name of the malware detected. ', - name: 'cisco.amp.detection', - type: 'keyword', - }, - 'cisco.amp.detection_id': { - category: 'cisco', - description: 'The ID of the detection. ', - name: 'cisco.amp.detection_id', - type: 'keyword', - }, - 'cisco.amp.connector_guid': { - category: 'cisco', - description: 'The GUID of the connector sending information to AMP. ', - name: 'cisco.amp.connector_guid', - type: 'keyword', - }, - 'cisco.amp.group_guids': { - category: 'cisco', - description: 'An array of group GUIDS related to the connector sending information to AMP. ', - name: 'cisco.amp.group_guids', - type: 'keyword', - }, - 'cisco.amp.vulnerabilities': { - category: 'cisco', - description: 'An array of related vulnerabilities to the malicious event. ', - name: 'cisco.amp.vulnerabilities', - type: 'flattened', - }, - 'cisco.amp.scan.description': { - category: 'cisco', - description: - 'Description of an event related to a scan being initiated, for example the specific directory name. ', - name: 'cisco.amp.scan.description', - type: 'keyword', - }, - 'cisco.amp.scan.clean': { - category: 'cisco', - description: 'Boolean value if a scanned file was clean or not. ', - name: 'cisco.amp.scan.clean', - type: 'boolean', - }, - 'cisco.amp.scan.scanned_files': { - category: 'cisco', - description: 'Count of files scanned in a directory. ', - name: 'cisco.amp.scan.scanned_files', - type: 'long', - }, - 'cisco.amp.scan.scanned_processes': { - category: 'cisco', - description: 'Count of processes scanned related to a single scan event. ', - name: 'cisco.amp.scan.scanned_processes', - type: 'long', - }, - 'cisco.amp.scan.scanned_paths': { - category: 'cisco', - description: 'Count of different directories scanned related to a single scan event. ', - name: 'cisco.amp.scan.scanned_paths', - type: 'long', - }, - 'cisco.amp.scan.malicious_detections': { - category: 'cisco', - description: 'Count of malicious files or documents detected related to a single scan event. ', - name: 'cisco.amp.scan.malicious_detections', - type: 'long', - }, - 'cisco.amp.computer.connector_guid': { - category: 'cisco', - description: - 'The GUID of the connector, similar to top level connector_guid, but unique if multiple connectors are involved. ', - name: 'cisco.amp.computer.connector_guid', - type: 'keyword', - }, - 'cisco.amp.computer.external_ip': { - category: 'cisco', - description: 'The external IP of the related host. ', - name: 'cisco.amp.computer.external_ip', - type: 'ip', - }, - 'cisco.amp.computer.active': { - category: 'cisco', - description: 'If the current endpoint is active or not. ', - name: 'cisco.amp.computer.active', - type: 'boolean', - }, - 'cisco.amp.computer.network_addresses': { - category: 'cisco', - description: 'All network interface information on the related host. ', - name: 'cisco.amp.computer.network_addresses', - type: 'flattened', - }, - 'cisco.amp.file.disposition': { - category: 'cisco', - description: 'Categorization of file, for example "Malicious" or "Clean". ', - name: 'cisco.amp.file.disposition', - type: 'keyword', - }, - 'cisco.amp.network_info.disposition': { - category: 'cisco', - description: - 'Categorization of a network event related to a file, for example "Malicious" or "Clean". ', - name: 'cisco.amp.network_info.disposition', - type: 'keyword', - }, - 'cisco.amp.network_info.nfm.direction': { - category: 'cisco', - description: 'The current direction based on source and destination IP. ', - name: 'cisco.amp.network_info.nfm.direction', - type: 'keyword', - }, - 'cisco.amp.related.mac': { - category: 'cisco', - description: 'An array of all related MAC addresses. ', - name: 'cisco.amp.related.mac', - type: 'keyword', - }, - 'cisco.amp.related.cve': { - category: 'cisco', - description: 'An array of all related MAC addresses. ', - name: 'cisco.amp.related.cve', - type: 'keyword', - }, - 'cisco.amp.cloud_ioc.description': { - category: 'cisco', - description: 'Description of the related IOC for specific IOC events from AMP. ', - name: 'cisco.amp.cloud_ioc.description', - type: 'keyword', - }, - 'cisco.amp.cloud_ioc.short_description': { - category: 'cisco', - description: 'Short description of the related IOC for specific IOC events from AMP. ', - name: 'cisco.amp.cloud_ioc.short_description', - type: 'keyword', - }, - 'cisco.amp.network_info.parent.disposition': { - category: 'cisco', - description: 'Categorization of a IOC for example "Malicious" or "Clean". ', - name: 'cisco.amp.network_info.parent.disposition', - type: 'keyword', - }, - 'cisco.amp.network_info.parent.identity.md5': { - category: 'cisco', - description: 'MD5 hash of the related IOC. ', - name: 'cisco.amp.network_info.parent.identity.md5', - type: 'keyword', - }, - 'cisco.amp.network_info.parent.identity.sha1': { - category: 'cisco', - description: 'SHA1 hash of the related IOC. ', - name: 'cisco.amp.network_info.parent.identity.sha1', - type: 'keyword', - }, - 'cisco.amp.network_info.parent.identify.sha256': { - category: 'cisco', - description: 'SHA256 hash of the related IOC. ', - name: 'cisco.amp.network_info.parent.identify.sha256', - type: 'keyword', - }, - 'cisco.amp.file.archived_file.disposition': { - category: 'cisco', - description: - 'Categorization of a file archive related to a file, for example "Malicious" or "Clean". ', - name: 'cisco.amp.file.archived_file.disposition', - type: 'keyword', - }, - 'cisco.amp.file.archived_file.identity.md5': { - category: 'cisco', - description: 'MD5 hash of the archived file related to the malicious event. ', - name: 'cisco.amp.file.archived_file.identity.md5', - type: 'keyword', - }, - 'cisco.amp.file.archived_file.identity.sha1': { - category: 'cisco', - description: 'SHA1 hash of the archived file related to the malicious event. ', - name: 'cisco.amp.file.archived_file.identity.sha1', - type: 'keyword', - }, - 'cisco.amp.file.archived_file.identity.sha256': { - category: 'cisco', - description: 'SHA256 hash of the archived file related to the malicious event. ', - name: 'cisco.amp.file.archived_file.identity.sha256', - type: 'keyword', - }, - 'cisco.amp.file.attack_details.application': { - category: 'cisco', - description: 'The application name related to Exploit Prevention events. ', - name: 'cisco.amp.file.attack_details.application', - type: 'keyword', - }, - 'cisco.amp.file.attack_details.attacked_module': { - category: 'cisco', - description: - 'Path to the executable or dll that was attacked and detected by Exploit Prevention. ', - name: 'cisco.amp.file.attack_details.attacked_module', - type: 'keyword', - }, - 'cisco.amp.file.attack_details.base_address': { - category: 'cisco', - description: 'The base memory address related to the exploit detected. ', - name: 'cisco.amp.file.attack_details.base_address', - type: 'keyword', - }, - 'cisco.amp.file.attack_details.suspicious_files': { - category: 'cisco', - description: 'An array of related files when an attack is detected by Exploit Prevention. ', - name: 'cisco.amp.file.attack_details.suspicious_files', - type: 'keyword', - }, - 'cisco.amp.file.parent.disposition': { - category: 'cisco', - description: 'Categorization of parrent, for example "Malicious" or "Clean". ', - name: 'cisco.amp.file.parent.disposition', - type: 'keyword', - }, - 'cisco.amp.error.description': { - category: 'cisco', - description: 'Description of an endpoint error event. ', - name: 'cisco.amp.error.description', - type: 'keyword', - }, - 'cisco.amp.error.error_code': { - category: 'cisco', - description: 'The error code describing the related error event. ', - name: 'cisco.amp.error.error_code', - type: 'keyword', - }, - 'cisco.amp.threat_hunting.severity': { - category: 'cisco', - description: - 'Severity result of the threat hunt registered to the malicious event. Can be Low-Critical. ', - name: 'cisco.amp.threat_hunting.severity', - type: 'keyword', - }, - 'cisco.amp.threat_hunting.incident_report_guid': { - category: 'cisco', - description: 'The GUID of the related threat hunting report. ', - name: 'cisco.amp.threat_hunting.incident_report_guid', - type: 'keyword', - }, - 'cisco.amp.threat_hunting.incident_hunt_guid': { - category: 'cisco', - description: 'The GUID of the related investigation tracking issue. ', - name: 'cisco.amp.threat_hunting.incident_hunt_guid', - type: 'keyword', - }, - 'cisco.amp.threat_hunting.incident_title': { - category: 'cisco', - description: 'Title of the incident related to the threat hunting activity. ', - name: 'cisco.amp.threat_hunting.incident_title', - type: 'keyword', - }, - 'cisco.amp.threat_hunting.incident_summary': { - category: 'cisco', - description: 'Summary of the outcome on the threat hunting activity. ', - name: 'cisco.amp.threat_hunting.incident_summary', - type: 'keyword', - }, - 'cisco.amp.threat_hunting.incident_remediation': { - category: 'cisco', - description: 'Recommendations to resolve the vulnerability or exploited host. ', - name: 'cisco.amp.threat_hunting.incident_remediation', - type: 'keyword', - }, - 'cisco.amp.threat_hunting.incident_id': { - category: 'cisco', - description: 'The id of the related incident for the threat hunting activity. ', - name: 'cisco.amp.threat_hunting.incident_id', - type: 'keyword', - }, - 'cisco.amp.threat_hunting.incident_end_time': { - category: 'cisco', - description: 'When the threat hunt finalized or closed. ', - name: 'cisco.amp.threat_hunting.incident_end_time', - type: 'date', - }, - 'cisco.amp.threat_hunting.incident_start_time': { - category: 'cisco', - description: 'When the threat hunt was initiated. ', - name: 'cisco.amp.threat_hunting.incident_start_time', - type: 'date', - }, - 'cisco.amp.file.attack_details.indicators': { - category: 'cisco', - description: - 'Different indicator types that matches the exploit detected, for example different MITRE tactics. ', - name: 'cisco.amp.file.attack_details.indicators', - type: 'flattened', - }, - 'cisco.amp.threat_hunting.tactics': { - category: 'cisco', - description: 'List of all MITRE tactics related to the incident found. ', - name: 'cisco.amp.threat_hunting.tactics', - type: 'flattened', - }, - 'cisco.amp.threat_hunting.techniques': { - category: 'cisco', - description: 'List of all MITRE techniques related to the incident found. ', - name: 'cisco.amp.threat_hunting.techniques', - type: 'flattened', - }, - 'cisco.amp.tactics': { - category: 'cisco', - description: 'List of all MITRE tactics related to the incident found. ', - name: 'cisco.amp.tactics', - type: 'flattened', - }, - 'cisco.amp.mitre_tactics': { - category: 'cisco', - description: "Array of all related mitre tactic ID's ", - name: 'cisco.amp.mitre_tactics', - type: 'keyword', - }, - 'cisco.amp.techniques': { - category: 'cisco', - description: 'List of all MITRE techniques related to the incident found. ', - name: 'cisco.amp.techniques', - type: 'flattened', - }, - 'cisco.amp.mitre_techniques': { - category: 'cisco', - description: "Array of all related mitre technique ID's ", - name: 'cisco.amp.mitre_techniques', - type: 'keyword', - }, - 'cisco.amp.command_line.arguments': { - category: 'cisco', - description: 'The CLI arguments related to the Cloud Threat IOC reported by Cisco. ', - name: 'cisco.amp.command_line.arguments', - type: 'keyword', - }, - 'cisco.amp.bp_data': { - category: 'cisco', - description: 'Endpoint isolation information ', - name: 'cisco.amp.bp_data', - type: 'flattened', - }, - 'cisco.asa.message_id': { - category: 'cisco', - description: 'The Cisco ASA message identifier. ', - name: 'cisco.asa.message_id', - type: 'keyword', - }, - 'cisco.asa.suffix': { - category: 'cisco', - description: 'Optional suffix after %ASA identifier. ', - example: 'session', - name: 'cisco.asa.suffix', - type: 'keyword', - }, - 'cisco.asa.source_interface': { - category: 'cisco', - description: 'Source interface for the flow or event. ', - name: 'cisco.asa.source_interface', - type: 'keyword', - }, - 'cisco.asa.destination_interface': { - category: 'cisco', - description: 'Destination interface for the flow or event. ', - name: 'cisco.asa.destination_interface', - type: 'keyword', - }, - 'cisco.asa.rule_name': { - category: 'cisco', - description: 'Name of the Access Control List rule that matched this event. ', - name: 'cisco.asa.rule_name', - type: 'keyword', - }, - 'cisco.asa.source_username': { - category: 'cisco', - description: 'Name of the user that is the source for this event. ', - name: 'cisco.asa.source_username', - type: 'keyword', - }, - 'cisco.asa.destination_username': { - category: 'cisco', - description: 'Name of the user that is the destination for this event. ', - name: 'cisco.asa.destination_username', - type: 'keyword', - }, - 'cisco.asa.mapped_source_ip': { - category: 'cisco', - description: 'The translated source IP address. ', - name: 'cisco.asa.mapped_source_ip', - type: 'ip', - }, - 'cisco.asa.mapped_source_host': { - category: 'cisco', - description: 'The translated source host. ', - name: 'cisco.asa.mapped_source_host', - type: 'keyword', - }, - 'cisco.asa.mapped_source_port': { - category: 'cisco', - description: 'The translated source port. ', - name: 'cisco.asa.mapped_source_port', - type: 'long', - }, - 'cisco.asa.mapped_destination_ip': { - category: 'cisco', - description: 'The translated destination IP address. ', - name: 'cisco.asa.mapped_destination_ip', - type: 'ip', - }, - 'cisco.asa.mapped_destination_host': { - category: 'cisco', - description: 'The translated destination host. ', - name: 'cisco.asa.mapped_destination_host', - type: 'keyword', - }, - 'cisco.asa.mapped_destination_port': { - category: 'cisco', - description: 'The translated destination port. ', - name: 'cisco.asa.mapped_destination_port', - type: 'long', - }, - 'cisco.asa.threat_level': { - category: 'cisco', - description: - 'Threat level for malware / botnet traffic. One of very-low, low, moderate, high or very-high. ', - name: 'cisco.asa.threat_level', - type: 'keyword', - }, - 'cisco.asa.threat_category': { - category: 'cisco', - description: - 'Category for the malware / botnet traffic. For example: virus, botnet, trojan, etc. ', - name: 'cisco.asa.threat_category', - type: 'keyword', - }, - 'cisco.asa.connection_id': { - category: 'cisco', - description: 'Unique identifier for a flow. ', - name: 'cisco.asa.connection_id', - type: 'keyword', - }, - 'cisco.asa.icmp_type': { - category: 'cisco', - description: 'ICMP type. ', - name: 'cisco.asa.icmp_type', - type: 'short', - }, - 'cisco.asa.icmp_code': { - category: 'cisco', - description: 'ICMP code. ', - name: 'cisco.asa.icmp_code', - type: 'short', - }, - 'cisco.asa.connection_type': { - category: 'cisco', - description: 'The VPN connection type ', - name: 'cisco.asa.connection_type', - type: 'keyword', - }, - 'cisco.asa.dap_records': { - category: 'cisco', - description: 'The assigned DAP records ', - name: 'cisco.asa.dap_records', - type: 'keyword', - }, - 'cisco.asa.command_line_arguments': { - category: 'cisco', - description: 'The command line arguments logged by the local audit log ', - name: 'cisco.asa.command_line_arguments', - type: 'keyword', - }, - 'cisco.asa.assigned_ip': { - category: 'cisco', - description: 'The IP address assigned to a VPN client successfully connecting ', - name: 'cisco.asa.assigned_ip', - type: 'ip', - }, - 'cisco.asa.privilege.old': { - category: 'cisco', - description: 'When a users privilege is changed this is the old value ', - name: 'cisco.asa.privilege.old', - type: 'keyword', - }, - 'cisco.asa.privilege.new': { - category: 'cisco', - description: 'When a users privilege is changed this is the new value ', - name: 'cisco.asa.privilege.new', - type: 'keyword', - }, - 'cisco.asa.burst.object': { - category: 'cisco', - description: 'The related object for burst warnings ', - name: 'cisco.asa.burst.object', - type: 'keyword', - }, - 'cisco.asa.burst.id': { - category: 'cisco', - description: 'The related rate ID for burst warnings ', - name: 'cisco.asa.burst.id', - type: 'keyword', - }, - 'cisco.asa.burst.current_rate': { - category: 'cisco', - description: 'The current burst rate seen ', - name: 'cisco.asa.burst.current_rate', - type: 'keyword', - }, - 'cisco.asa.burst.configured_rate': { - category: 'cisco', - description: 'The current configured burst rate ', - name: 'cisco.asa.burst.configured_rate', - type: 'keyword', - }, - 'cisco.asa.burst.avg_rate': { - category: 'cisco', - description: 'The current average burst rate seen ', - name: 'cisco.asa.burst.avg_rate', - type: 'keyword', - }, - 'cisco.asa.burst.configured_avg_rate': { - category: 'cisco', - description: 'The current configured average burst rate allowed ', - name: 'cisco.asa.burst.configured_avg_rate', - type: 'keyword', - }, - 'cisco.asa.burst.cumulative_count': { - category: 'cisco', - description: 'The total count of burst rate hits since the object was created or cleared ', - name: 'cisco.asa.burst.cumulative_count', - type: 'keyword', - }, - 'cisco.asa.termination_user': { - category: 'cisco', - description: 'AAA name of user requesting termination ', - name: 'cisco.asa.termination_user', - type: 'keyword', - }, - 'cisco.asa.webvpn.group_name': { - category: 'cisco', - description: 'The WebVPN group name the user belongs to ', - name: 'cisco.asa.webvpn.group_name', - type: 'keyword', - }, - 'cisco.ftd.message_id': { - category: 'cisco', - description: 'The Cisco FTD message identifier. ', - name: 'cisco.ftd.message_id', - type: 'keyword', - }, - 'cisco.ftd.suffix': { - category: 'cisco', - description: 'Optional suffix after %FTD identifier. ', - example: 'session', - name: 'cisco.ftd.suffix', - type: 'keyword', - }, - 'cisco.ftd.source_interface': { - category: 'cisco', - description: 'Source interface for the flow or event. ', - name: 'cisco.ftd.source_interface', - type: 'keyword', - }, - 'cisco.ftd.destination_interface': { - category: 'cisco', - description: 'Destination interface for the flow or event. ', - name: 'cisco.ftd.destination_interface', - type: 'keyword', - }, - 'cisco.ftd.rule_name': { - category: 'cisco', - description: 'Name of the Access Control List rule that matched this event. ', - name: 'cisco.ftd.rule_name', - type: 'keyword', - }, - 'cisco.ftd.source_username': { - category: 'cisco', - description: 'Name of the user that is the source for this event. ', - name: 'cisco.ftd.source_username', - type: 'keyword', - }, - 'cisco.ftd.destination_username': { - category: 'cisco', - description: 'Name of the user that is the destination for this event. ', - name: 'cisco.ftd.destination_username', - type: 'keyword', - }, - 'cisco.ftd.mapped_source_ip': { - category: 'cisco', - description: 'The translated source IP address. Use ECS source.nat.ip. ', - name: 'cisco.ftd.mapped_source_ip', - type: 'ip', - }, - 'cisco.ftd.mapped_source_host': { - category: 'cisco', - description: 'The translated source host. ', - name: 'cisco.ftd.mapped_source_host', - type: 'keyword', - }, - 'cisco.ftd.mapped_source_port': { - category: 'cisco', - description: 'The translated source port. Use ECS source.nat.port. ', - name: 'cisco.ftd.mapped_source_port', - type: 'long', - }, - 'cisco.ftd.mapped_destination_ip': { - category: 'cisco', - description: 'The translated destination IP address. Use ECS destination.nat.ip. ', - name: 'cisco.ftd.mapped_destination_ip', - type: 'ip', - }, - 'cisco.ftd.mapped_destination_host': { - category: 'cisco', - description: 'The translated destination host. ', - name: 'cisco.ftd.mapped_destination_host', - type: 'keyword', - }, - 'cisco.ftd.mapped_destination_port': { - category: 'cisco', - description: 'The translated destination port. Use ECS destination.nat.port. ', - name: 'cisco.ftd.mapped_destination_port', - type: 'long', - }, - 'cisco.ftd.threat_level': { - category: 'cisco', - description: - 'Threat level for malware / botnet traffic. One of very-low, low, moderate, high or very-high. ', - name: 'cisco.ftd.threat_level', - type: 'keyword', - }, - 'cisco.ftd.threat_category': { - category: 'cisco', - description: - 'Category for the malware / botnet traffic. For example: virus, botnet, trojan, etc. ', - name: 'cisco.ftd.threat_category', - type: 'keyword', - }, - 'cisco.ftd.connection_id': { - category: 'cisco', - description: 'Unique identifier for a flow. ', - name: 'cisco.ftd.connection_id', - type: 'keyword', - }, - 'cisco.ftd.icmp_type': { - category: 'cisco', - description: 'ICMP type. ', - name: 'cisco.ftd.icmp_type', - type: 'short', - }, - 'cisco.ftd.icmp_code': { - category: 'cisco', - description: 'ICMP code. ', - name: 'cisco.ftd.icmp_code', - type: 'short', - }, - 'cisco.ftd.security': { - category: 'cisco', - description: 'Raw fields for Security Events.', - name: 'cisco.ftd.security', - type: 'object', - }, - 'cisco.ftd.connection_type': { - category: 'cisco', - description: 'The VPN connection type ', - name: 'cisco.ftd.connection_type', - type: 'keyword', - }, - 'cisco.ftd.dap_records': { - category: 'cisco', - description: 'The assigned DAP records ', - name: 'cisco.ftd.dap_records', - type: 'keyword', - }, - 'cisco.ftd.termination_user': { - category: 'cisco', - description: 'AAA name of user requesting termination ', - name: 'cisco.ftd.termination_user', - type: 'keyword', - }, - 'cisco.ftd.webvpn.group_name': { - category: 'cisco', - description: 'The WebVPN group name the user belongs to ', - name: 'cisco.ftd.webvpn.group_name', - type: 'keyword', - }, - 'cisco.ios.access_list': { - category: 'cisco', - description: 'Name of the IP access list. ', - name: 'cisco.ios.access_list', - type: 'keyword', - }, - 'cisco.ios.facility': { - category: 'cisco', - description: - 'The facility to which the message refers (for example, SNMP, SYS, and so forth). A facility can be a hardware device, a protocol, or a module of the system software. It denotes the source or the cause of the system message. ', - example: 'SEC', - name: 'cisco.ios.facility', - type: 'keyword', - }, - 'cisco.umbrella.identities': { - category: 'cisco', - description: 'An array of the different identities related to the event. ', - name: 'cisco.umbrella.identities', - type: 'keyword', - }, - 'cisco.umbrella.categories': { - category: 'cisco', - description: 'The security or content categories that the destination matches. ', - name: 'cisco.umbrella.categories', - type: 'keyword', - }, - 'cisco.umbrella.policy_identity_type': { - category: 'cisco', - description: - 'The first identity type matched with this request. Available in version 3 and above. ', - name: 'cisco.umbrella.policy_identity_type', - type: 'keyword', - }, - 'cisco.umbrella.identity_types': { - category: 'cisco', - description: - 'The type of identity that made the request. For example, Roaming Computer or Network. ', - name: 'cisco.umbrella.identity_types', - type: 'keyword', - }, - 'cisco.umbrella.blocked_categories': { - category: 'cisco', - description: - 'The categories that resulted in the destination being blocked. Available in version 4 and above. ', - name: 'cisco.umbrella.blocked_categories', - type: 'keyword', - }, - 'cisco.umbrella.content_type': { - category: 'cisco', - description: 'The type of web content, typically text/html. ', - name: 'cisco.umbrella.content_type', - type: 'keyword', - }, - 'cisco.umbrella.sha_sha256': { - category: 'cisco', - description: 'Hex digest of the response content. ', - name: 'cisco.umbrella.sha_sha256', - type: 'keyword', - }, - 'cisco.umbrella.av_detections': { - category: 'cisco', - description: 'The detection name according to the antivirus engine used in file inspection. ', - name: 'cisco.umbrella.av_detections', - type: 'keyword', - }, - 'cisco.umbrella.puas': { - category: 'cisco', - description: - 'A list of all potentially unwanted application (PUA) results for the proxied file as returned by the antivirus scanner. ', - name: 'cisco.umbrella.puas', - type: 'keyword', - }, - 'cisco.umbrella.amp_disposition': { - category: 'cisco', - description: - 'The status of the files proxied and scanned by Cisco Advanced Malware Protection (AMP) as part of the Umbrella File Inspection feature; can be Clean, Malicious or Unknown. ', - name: 'cisco.umbrella.amp_disposition', - type: 'keyword', - }, - 'cisco.umbrella.amp_malware_name': { - category: 'cisco', - description: 'If Malicious, the name of the malware according to AMP. ', - name: 'cisco.umbrella.amp_malware_name', - type: 'keyword', - }, - 'cisco.umbrella.amp_score': { - category: 'cisco', - description: - 'The score of the malware from AMP. This field is not currently used and will be blank. ', - name: 'cisco.umbrella.amp_score', - type: 'keyword', - }, - 'cisco.umbrella.datacenter': { - category: 'cisco', - description: 'The name of the Umbrella Data Center that processed the user-generated traffic. ', - name: 'cisco.umbrella.datacenter', - type: 'keyword', - }, - 'cisco.umbrella.origin_id': { - category: 'cisco', - description: 'The unique identity of the network tunnel. ', - name: 'cisco.umbrella.origin_id', - type: 'keyword', - }, - 'coredns.id': { - category: 'coredns', - description: 'id of the DNS transaction ', - name: 'coredns.id', - type: 'keyword', - }, - 'coredns.query.size': { - category: 'coredns', - description: 'size of the DNS query ', - name: 'coredns.query.size', - type: 'integer', - format: 'bytes', - }, - 'coredns.query.class': { - category: 'coredns', - description: 'DNS query class ', - name: 'coredns.query.class', - type: 'keyword', - }, - 'coredns.query.name': { - category: 'coredns', - description: 'DNS query name ', - name: 'coredns.query.name', - type: 'keyword', - }, - 'coredns.query.type': { - category: 'coredns', - description: 'DNS query type ', - name: 'coredns.query.type', - type: 'keyword', - }, - 'coredns.response.code': { - category: 'coredns', - description: 'DNS response code ', - name: 'coredns.response.code', - type: 'keyword', - }, - 'coredns.response.flags': { - category: 'coredns', - description: 'DNS response flags ', - name: 'coredns.response.flags', - type: 'keyword', - }, - 'coredns.response.size': { - category: 'coredns', - description: 'size of the DNS response ', - name: 'coredns.response.size', - type: 'integer', - format: 'bytes', - }, - 'coredns.dnssec_ok': { - category: 'coredns', - description: 'dnssec flag ', - name: 'coredns.dnssec_ok', - type: 'boolean', - }, - 'crowdstrike.metadata.eventType': { - category: 'crowdstrike', - description: - 'DetectionSummaryEvent, FirewallMatchEvent, IncidentSummaryEvent, RemoteResponseSessionStartEvent, RemoteResponseSessionEndEvent, AuthActivityAuditEvent, or UserActivityAuditEvent ', - name: 'crowdstrike.metadata.eventType', - type: 'keyword', - }, - 'crowdstrike.metadata.eventCreationTime': { - category: 'crowdstrike', - description: 'The time this event occurred on the endpoint in UTC UNIX_MS format. ', - name: 'crowdstrike.metadata.eventCreationTime', - type: 'date', - }, - 'crowdstrike.metadata.offset': { - category: 'crowdstrike', - description: - 'Offset number that tracks the location of the event in stream. This is used to identify unique detection events. ', - name: 'crowdstrike.metadata.offset', - type: 'integer', - }, - 'crowdstrike.metadata.customerIDString': { - category: 'crowdstrike', - description: 'Customer identifier ', - name: 'crowdstrike.metadata.customerIDString', - type: 'keyword', - }, - 'crowdstrike.metadata.version': { - category: 'crowdstrike', - description: 'Schema version ', - name: 'crowdstrike.metadata.version', - type: 'keyword', - }, - 'crowdstrike.event.ProcessStartTime': { - category: 'crowdstrike', - description: 'The process start time in UTC UNIX_MS format. ', - name: 'crowdstrike.event.ProcessStartTime', - type: 'date', - }, - 'crowdstrike.event.ProcessEndTime': { - category: 'crowdstrike', - description: 'The process termination time in UTC UNIX_MS format. ', - name: 'crowdstrike.event.ProcessEndTime', - type: 'date', - }, - 'crowdstrike.event.ProcessId': { - category: 'crowdstrike', - description: 'Process ID related to the detection. ', - name: 'crowdstrike.event.ProcessId', - type: 'integer', - }, - 'crowdstrike.event.ParentProcessId': { - category: 'crowdstrike', - description: 'Parent process ID related to the detection. ', - name: 'crowdstrike.event.ParentProcessId', - type: 'integer', - }, - 'crowdstrike.event.ComputerName': { - category: 'crowdstrike', - description: 'Name of the computer where the detection occurred. ', - name: 'crowdstrike.event.ComputerName', - type: 'keyword', - }, - 'crowdstrike.event.UserName': { - category: 'crowdstrike', - description: 'User name associated with the detection. ', - name: 'crowdstrike.event.UserName', - type: 'keyword', - }, - 'crowdstrike.event.DetectName': { - category: 'crowdstrike', - description: 'Name of the detection. ', - name: 'crowdstrike.event.DetectName', - type: 'keyword', - }, - 'crowdstrike.event.DetectDescription': { - category: 'crowdstrike', - description: 'Description of the detection. ', - name: 'crowdstrike.event.DetectDescription', - type: 'keyword', - }, - 'crowdstrike.event.Severity': { - category: 'crowdstrike', - description: 'Severity score of the detection. ', - name: 'crowdstrike.event.Severity', - type: 'integer', - }, - 'crowdstrike.event.SeverityName': { - category: 'crowdstrike', - description: 'Severity score text. ', - name: 'crowdstrike.event.SeverityName', - type: 'keyword', - }, - 'crowdstrike.event.FileName': { - category: 'crowdstrike', - description: 'File name of the associated process for the detection. ', - name: 'crowdstrike.event.FileName', - type: 'keyword', - }, - 'crowdstrike.event.FilePath': { - category: 'crowdstrike', - description: 'Path of the executable associated with the detection. ', - name: 'crowdstrike.event.FilePath', - type: 'keyword', - }, - 'crowdstrike.event.CommandLine': { - category: 'crowdstrike', - description: 'Executable path with command line arguments. ', - name: 'crowdstrike.event.CommandLine', - type: 'keyword', - }, - 'crowdstrike.event.SHA1String': { - category: 'crowdstrike', - description: 'SHA1 sum of the executable associated with the detection. ', - name: 'crowdstrike.event.SHA1String', - type: 'keyword', - }, - 'crowdstrike.event.SHA256String': { - category: 'crowdstrike', - description: 'SHA256 sum of the executable associated with the detection. ', - name: 'crowdstrike.event.SHA256String', - type: 'keyword', - }, - 'crowdstrike.event.MD5String': { - category: 'crowdstrike', - description: 'MD5 sum of the executable associated with the detection. ', - name: 'crowdstrike.event.MD5String', - type: 'keyword', - }, - 'crowdstrike.event.MachineDomain': { - category: 'crowdstrike', - description: 'Domain for the machine associated with the detection. ', - name: 'crowdstrike.event.MachineDomain', - type: 'keyword', - }, - 'crowdstrike.event.FalconHostLink': { - category: 'crowdstrike', - description: 'URL to view the detection in Falcon. ', - name: 'crowdstrike.event.FalconHostLink', - type: 'keyword', - }, - 'crowdstrike.event.SensorId': { - category: 'crowdstrike', - description: 'Unique ID associated with the Falcon sensor. ', - name: 'crowdstrike.event.SensorId', - type: 'keyword', - }, - 'crowdstrike.event.DetectId': { - category: 'crowdstrike', - description: 'Unique ID associated with the detection. ', - name: 'crowdstrike.event.DetectId', - type: 'keyword', - }, - 'crowdstrike.event.LocalIP': { - category: 'crowdstrike', - description: 'IP address of the host associated with the detection. ', - name: 'crowdstrike.event.LocalIP', - type: 'keyword', - }, - 'crowdstrike.event.MACAddress': { - category: 'crowdstrike', - description: 'MAC address of the host associated with the detection. ', - name: 'crowdstrike.event.MACAddress', - type: 'keyword', - }, - 'crowdstrike.event.Tactic': { - category: 'crowdstrike', - description: 'MITRE tactic category of the detection. ', - name: 'crowdstrike.event.Tactic', - type: 'keyword', - }, - 'crowdstrike.event.Technique': { - category: 'crowdstrike', - description: 'MITRE technique category of the detection. ', - name: 'crowdstrike.event.Technique', - type: 'keyword', - }, - 'crowdstrike.event.Objective': { - category: 'crowdstrike', - description: 'Method of detection. ', - name: 'crowdstrike.event.Objective', - type: 'keyword', - }, - 'crowdstrike.event.PatternDispositionDescription': { - category: 'crowdstrike', - description: 'Action taken by Falcon. ', - name: 'crowdstrike.event.PatternDispositionDescription', - type: 'keyword', - }, - 'crowdstrike.event.PatternDispositionValue': { - category: 'crowdstrike', - description: 'Unique ID associated with action taken. ', - name: 'crowdstrike.event.PatternDispositionValue', - type: 'integer', - }, - 'crowdstrike.event.PatternDispositionFlags': { - category: 'crowdstrike', - description: 'Flags indicating actions taken. ', - name: 'crowdstrike.event.PatternDispositionFlags', - type: 'object', - }, - 'crowdstrike.event.State': { - category: 'crowdstrike', - description: 'Whether the incident summary is open and ongoing or closed. ', - name: 'crowdstrike.event.State', - type: 'keyword', - }, - 'crowdstrike.event.IncidentStartTime': { - category: 'crowdstrike', - description: 'Start time for the incident in UTC UNIX format. ', - name: 'crowdstrike.event.IncidentStartTime', - type: 'date', - }, - 'crowdstrike.event.IncidentEndTime': { - category: 'crowdstrike', - description: 'End time for the incident in UTC UNIX format. ', - name: 'crowdstrike.event.IncidentEndTime', - type: 'date', - }, - 'crowdstrike.event.FineScore': { - category: 'crowdstrike', - description: 'Score for incident. ', - name: 'crowdstrike.event.FineScore', - type: 'float', - }, - 'crowdstrike.event.UserId': { - category: 'crowdstrike', - description: 'Email address or user ID associated with the event. ', - name: 'crowdstrike.event.UserId', - type: 'keyword', - }, - 'crowdstrike.event.UserIp': { - category: 'crowdstrike', - description: 'IP address associated with the user. ', - name: 'crowdstrike.event.UserIp', - type: 'keyword', - }, - 'crowdstrike.event.OperationName': { - category: 'crowdstrike', - description: 'Event subtype. ', - name: 'crowdstrike.event.OperationName', - type: 'keyword', - }, - 'crowdstrike.event.ServiceName': { - category: 'crowdstrike', - description: 'Service associated with this event. ', - name: 'crowdstrike.event.ServiceName', - type: 'keyword', - }, - 'crowdstrike.event.Success': { - category: 'crowdstrike', - description: 'Indicator of whether or not this event was successful. ', - name: 'crowdstrike.event.Success', - type: 'boolean', - }, - 'crowdstrike.event.UTCTimestamp': { - category: 'crowdstrike', - description: 'Timestamp associated with this event in UTC UNIX format. ', - name: 'crowdstrike.event.UTCTimestamp', - type: 'date', - }, - 'crowdstrike.event.AuditKeyValues': { - category: 'crowdstrike', - description: 'Fields that were changed in this event. ', - name: 'crowdstrike.event.AuditKeyValues', - type: 'nested', - }, - 'crowdstrike.event.ExecutablesWritten': { - category: 'crowdstrike', - description: 'Detected executables written to disk by a process. ', - name: 'crowdstrike.event.ExecutablesWritten', - type: 'nested', - }, - 'crowdstrike.event.SessionId': { - category: 'crowdstrike', - description: 'Session ID of the remote response session. ', - name: 'crowdstrike.event.SessionId', - type: 'keyword', - }, - 'crowdstrike.event.HostnameField': { - category: 'crowdstrike', - description: 'Host name of the machine for the remote session. ', - name: 'crowdstrike.event.HostnameField', - type: 'keyword', - }, - 'crowdstrike.event.StartTimestamp': { - category: 'crowdstrike', - description: 'Start time for the remote session in UTC UNIX format. ', - name: 'crowdstrike.event.StartTimestamp', - type: 'date', - }, - 'crowdstrike.event.EndTimestamp': { - category: 'crowdstrike', - description: 'End time for the remote session in UTC UNIX format. ', - name: 'crowdstrike.event.EndTimestamp', - type: 'date', - }, - 'crowdstrike.event.LateralMovement': { - category: 'crowdstrike', - description: 'Lateral movement field for incident. ', - name: 'crowdstrike.event.LateralMovement', - type: 'long', - }, - 'crowdstrike.event.ParentImageFileName': { - category: 'crowdstrike', - description: 'Path to the parent process. ', - name: 'crowdstrike.event.ParentImageFileName', - type: 'keyword', - }, - 'crowdstrike.event.ParentCommandLine': { - category: 'crowdstrike', - description: 'Parent process command line arguments. ', - name: 'crowdstrike.event.ParentCommandLine', - type: 'keyword', - }, - 'crowdstrike.event.GrandparentImageFileName': { - category: 'crowdstrike', - description: 'Path to the grandparent process. ', - name: 'crowdstrike.event.GrandparentImageFileName', - type: 'keyword', - }, - 'crowdstrike.event.GrandparentCommandLine': { - category: 'crowdstrike', - description: 'Grandparent process command line arguments. ', - name: 'crowdstrike.event.GrandparentCommandLine', - type: 'keyword', - }, - 'crowdstrike.event.IOCType': { - category: 'crowdstrike', - description: 'CrowdStrike type for indicator of compromise. ', - name: 'crowdstrike.event.IOCType', - type: 'keyword', - }, - 'crowdstrike.event.IOCValue': { - category: 'crowdstrike', - description: 'CrowdStrike value for indicator of compromise. ', - name: 'crowdstrike.event.IOCValue', - type: 'keyword', - }, - 'crowdstrike.event.CustomerId': { - category: 'crowdstrike', - description: 'Customer identifier. ', - name: 'crowdstrike.event.CustomerId', - type: 'keyword', - }, - 'crowdstrike.event.DeviceId': { - category: 'crowdstrike', - description: 'Device on which the event occurred. ', - name: 'crowdstrike.event.DeviceId', - type: 'keyword', - }, - 'crowdstrike.event.Ipv': { - category: 'crowdstrike', - description: 'Protocol for network request. ', - name: 'crowdstrike.event.Ipv', - type: 'keyword', - }, - 'crowdstrike.event.ConnectionDirection': { - category: 'crowdstrike', - description: 'Direction for network connection. ', - name: 'crowdstrike.event.ConnectionDirection', - type: 'keyword', - }, - 'crowdstrike.event.EventType': { - category: 'crowdstrike', - description: 'CrowdStrike provided event type. ', - name: 'crowdstrike.event.EventType', - type: 'keyword', - }, - 'crowdstrike.event.HostName': { - category: 'crowdstrike', - description: 'Host name of the local machine. ', - name: 'crowdstrike.event.HostName', - type: 'keyword', - }, - 'crowdstrike.event.ICMPCode': { - category: 'crowdstrike', - description: 'RFC2780 ICMP Code field. ', - name: 'crowdstrike.event.ICMPCode', - type: 'keyword', - }, - 'crowdstrike.event.ICMPType': { - category: 'crowdstrike', - description: 'RFC2780 ICMP Type field. ', - name: 'crowdstrike.event.ICMPType', - type: 'keyword', - }, - 'crowdstrike.event.ImageFileName': { - category: 'crowdstrike', - description: 'File name of the associated process for the detection. ', - name: 'crowdstrike.event.ImageFileName', - type: 'keyword', - }, - 'crowdstrike.event.PID': { - category: 'crowdstrike', - description: 'Associated process id for the detection. ', - name: 'crowdstrike.event.PID', - type: 'long', - }, - 'crowdstrike.event.LocalAddress': { - category: 'crowdstrike', - description: 'IP address of local machine. ', - name: 'crowdstrike.event.LocalAddress', - type: 'ip', - }, - 'crowdstrike.event.LocalPort': { - category: 'crowdstrike', - description: 'Port of local machine. ', - name: 'crowdstrike.event.LocalPort', - type: 'long', - }, - 'crowdstrike.event.RemoteAddress': { - category: 'crowdstrike', - description: 'IP address of remote machine. ', - name: 'crowdstrike.event.RemoteAddress', - type: 'ip', - }, - 'crowdstrike.event.RemotePort': { - category: 'crowdstrike', - description: 'Port of remote machine. ', - name: 'crowdstrike.event.RemotePort', - type: 'long', - }, - 'crowdstrike.event.RuleAction': { - category: 'crowdstrike', - description: 'Firewall rule action. ', - name: 'crowdstrike.event.RuleAction', - type: 'keyword', - }, - 'crowdstrike.event.RuleDescription': { - category: 'crowdstrike', - description: 'Firewall rule description. ', - name: 'crowdstrike.event.RuleDescription', - type: 'keyword', - }, - 'crowdstrike.event.RuleFamilyID': { - category: 'crowdstrike', - description: 'Firewall rule family id. ', - name: 'crowdstrike.event.RuleFamilyID', - type: 'keyword', - }, - 'crowdstrike.event.RuleGroupName': { - category: 'crowdstrike', - description: 'Firewall rule group name. ', - name: 'crowdstrike.event.RuleGroupName', - type: 'keyword', - }, - 'crowdstrike.event.RuleName': { - category: 'crowdstrike', - description: 'Firewall rule name. ', - name: 'crowdstrike.event.RuleName', - type: 'keyword', - }, - 'crowdstrike.event.RuleId': { - category: 'crowdstrike', - description: 'Firewall rule id. ', - name: 'crowdstrike.event.RuleId', - type: 'keyword', - }, - 'crowdstrike.event.MatchCount': { - category: 'crowdstrike', - description: 'Number of firewall rule matches. ', - name: 'crowdstrike.event.MatchCount', - type: 'long', - }, - 'crowdstrike.event.MatchCountSinceLastReport': { - category: 'crowdstrike', - description: 'Number of firewall rule matches since the last report. ', - name: 'crowdstrike.event.MatchCountSinceLastReport', - type: 'long', - }, - 'crowdstrike.event.Timestamp': { - category: 'crowdstrike', - description: 'Firewall rule triggered timestamp. ', - name: 'crowdstrike.event.Timestamp', - type: 'date', - }, - 'crowdstrike.event.Flags.Audit': { - category: 'crowdstrike', - description: 'CrowdStrike audit flag. ', - name: 'crowdstrike.event.Flags.Audit', - type: 'boolean', - }, - 'crowdstrike.event.Flags.Log': { - category: 'crowdstrike', - description: 'CrowdStrike log flag. ', - name: 'crowdstrike.event.Flags.Log', - type: 'boolean', - }, - 'crowdstrike.event.Flags.Monitor': { - category: 'crowdstrike', - description: 'CrowdStrike monitor flag. ', - name: 'crowdstrike.event.Flags.Monitor', - type: 'boolean', - }, - 'crowdstrike.event.Protocol': { - category: 'crowdstrike', - description: 'CrowdStrike provided protocol. ', - name: 'crowdstrike.event.Protocol', - type: 'keyword', - }, - 'crowdstrike.event.NetworkProfile': { - category: 'crowdstrike', - description: 'CrowdStrike network profile. ', - name: 'crowdstrike.event.NetworkProfile', - type: 'keyword', - }, - 'crowdstrike.event.PolicyName': { - category: 'crowdstrike', - description: 'CrowdStrike policy name. ', - name: 'crowdstrike.event.PolicyName', - type: 'keyword', - }, - 'crowdstrike.event.PolicyID': { - category: 'crowdstrike', - description: 'CrowdStrike policy id. ', - name: 'crowdstrike.event.PolicyID', - type: 'keyword', - }, - 'crowdstrike.event.Status': { - category: 'crowdstrike', - description: 'CrowdStrike status. ', - name: 'crowdstrike.event.Status', - type: 'keyword', - }, - 'crowdstrike.event.TreeID': { - category: 'crowdstrike', - description: 'CrowdStrike tree id. ', - name: 'crowdstrike.event.TreeID', - type: 'keyword', - }, - 'crowdstrike.event.Commands': { - category: 'crowdstrike', - description: 'Commands run in a remote session. ', - name: 'crowdstrike.event.Commands', - type: 'keyword', - }, - 'cyberarkpas.audit.action': { - category: 'cyberarkpas', - description: 'A description of the audit record.', - name: 'cyberarkpas.audit.action', - type: 'keyword', - }, - 'cyberarkpas.audit.ca_properties.address': { - category: 'cyberarkpas', - name: 'cyberarkpas.audit.ca_properties.address', - type: 'keyword', - }, - 'cyberarkpas.audit.ca_properties.cpm_disabled': { - category: 'cyberarkpas', - name: 'cyberarkpas.audit.ca_properties.cpm_disabled', - type: 'keyword', - }, - 'cyberarkpas.audit.ca_properties.cpm_error_details': { - category: 'cyberarkpas', - name: 'cyberarkpas.audit.ca_properties.cpm_error_details', - type: 'keyword', - }, - 'cyberarkpas.audit.ca_properties.cpm_status': { - category: 'cyberarkpas', - name: 'cyberarkpas.audit.ca_properties.cpm_status', - type: 'keyword', - }, - 'cyberarkpas.audit.ca_properties.creation_method': { - category: 'cyberarkpas', - name: 'cyberarkpas.audit.ca_properties.creation_method', - type: 'keyword', - }, - 'cyberarkpas.audit.ca_properties.customer': { - category: 'cyberarkpas', - name: 'cyberarkpas.audit.ca_properties.customer', - type: 'keyword', - }, - 'cyberarkpas.audit.ca_properties.database': { - category: 'cyberarkpas', - name: 'cyberarkpas.audit.ca_properties.database', - type: 'keyword', - }, - 'cyberarkpas.audit.ca_properties.device_type': { - category: 'cyberarkpas', - name: 'cyberarkpas.audit.ca_properties.device_type', - type: 'keyword', - }, - 'cyberarkpas.audit.ca_properties.dual_account_status': { - category: 'cyberarkpas', - name: 'cyberarkpas.audit.ca_properties.dual_account_status', - type: 'keyword', - }, - 'cyberarkpas.audit.ca_properties.group_name': { - category: 'cyberarkpas', - name: 'cyberarkpas.audit.ca_properties.group_name', - type: 'keyword', - }, - 'cyberarkpas.audit.ca_properties.in_process': { - category: 'cyberarkpas', - name: 'cyberarkpas.audit.ca_properties.in_process', - type: 'keyword', - }, - 'cyberarkpas.audit.ca_properties.index': { - category: 'cyberarkpas', - name: 'cyberarkpas.audit.ca_properties.index', - type: 'keyword', - }, - 'cyberarkpas.audit.ca_properties.last_fail_date': { - category: 'cyberarkpas', - name: 'cyberarkpas.audit.ca_properties.last_fail_date', - type: 'keyword', - }, - 'cyberarkpas.audit.ca_properties.last_success_change': { - category: 'cyberarkpas', - name: 'cyberarkpas.audit.ca_properties.last_success_change', - type: 'keyword', - }, - 'cyberarkpas.audit.ca_properties.last_success_reconciliation': { - category: 'cyberarkpas', - name: 'cyberarkpas.audit.ca_properties.last_success_reconciliation', - type: 'keyword', - }, - 'cyberarkpas.audit.ca_properties.last_success_verification': { - category: 'cyberarkpas', - name: 'cyberarkpas.audit.ca_properties.last_success_verification', - type: 'keyword', - }, - 'cyberarkpas.audit.ca_properties.last_task': { - category: 'cyberarkpas', - name: 'cyberarkpas.audit.ca_properties.last_task', - type: 'keyword', - }, - 'cyberarkpas.audit.ca_properties.logon_domain': { - category: 'cyberarkpas', - name: 'cyberarkpas.audit.ca_properties.logon_domain', - type: 'keyword', - }, - 'cyberarkpas.audit.ca_properties.policy_id': { - category: 'cyberarkpas', - name: 'cyberarkpas.audit.ca_properties.policy_id', - type: 'keyword', - }, - 'cyberarkpas.audit.ca_properties.port': { - category: 'cyberarkpas', - name: 'cyberarkpas.audit.ca_properties.port', - type: 'keyword', - }, - 'cyberarkpas.audit.ca_properties.privcloud': { - category: 'cyberarkpas', - name: 'cyberarkpas.audit.ca_properties.privcloud', - type: 'keyword', - }, - 'cyberarkpas.audit.ca_properties.reset_immediately': { - category: 'cyberarkpas', - name: 'cyberarkpas.audit.ca_properties.reset_immediately', - type: 'keyword', - }, - 'cyberarkpas.audit.ca_properties.retries_count': { - category: 'cyberarkpas', - name: 'cyberarkpas.audit.ca_properties.retries_count', - type: 'keyword', - }, - 'cyberarkpas.audit.ca_properties.sequence_id': { - category: 'cyberarkpas', - name: 'cyberarkpas.audit.ca_properties.sequence_id', - type: 'keyword', - }, - 'cyberarkpas.audit.ca_properties.tags': { - category: 'cyberarkpas', - name: 'cyberarkpas.audit.ca_properties.tags', - type: 'keyword', - }, - 'cyberarkpas.audit.ca_properties.user_dn': { - category: 'cyberarkpas', - name: 'cyberarkpas.audit.ca_properties.user_dn', - type: 'keyword', - }, - 'cyberarkpas.audit.ca_properties.user_name': { - category: 'cyberarkpas', - name: 'cyberarkpas.audit.ca_properties.user_name', - type: 'keyword', - }, - 'cyberarkpas.audit.ca_properties.virtual_username': { - category: 'cyberarkpas', - name: 'cyberarkpas.audit.ca_properties.virtual_username', - type: 'keyword', - }, - 'cyberarkpas.audit.ca_properties.other': { - category: 'cyberarkpas', - name: 'cyberarkpas.audit.ca_properties.other', - type: 'flattened', - }, - 'cyberarkpas.audit.category': { - category: 'cyberarkpas', - description: 'The category name (for category-related operations).', - name: 'cyberarkpas.audit.category', - type: 'keyword', - }, - 'cyberarkpas.audit.desc': { - category: 'cyberarkpas', - description: 'A static value that displays a description of the audit codes.', - name: 'cyberarkpas.audit.desc', - type: 'keyword', - }, - 'cyberarkpas.audit.extra_details.ad_process_id': { - category: 'cyberarkpas', - name: 'cyberarkpas.audit.extra_details.ad_process_id', - type: 'keyword', - }, - 'cyberarkpas.audit.extra_details.ad_process_name': { - category: 'cyberarkpas', - name: 'cyberarkpas.audit.extra_details.ad_process_name', - type: 'keyword', - }, - 'cyberarkpas.audit.extra_details.application_type': { - category: 'cyberarkpas', - name: 'cyberarkpas.audit.extra_details.application_type', - type: 'keyword', - }, - 'cyberarkpas.audit.extra_details.command': { - category: 'cyberarkpas', - name: 'cyberarkpas.audit.extra_details.command', - type: 'keyword', - }, - 'cyberarkpas.audit.extra_details.connection_component_id': { - category: 'cyberarkpas', - name: 'cyberarkpas.audit.extra_details.connection_component_id', - type: 'keyword', - }, - 'cyberarkpas.audit.extra_details.dst_host': { - category: 'cyberarkpas', - name: 'cyberarkpas.audit.extra_details.dst_host', - type: 'keyword', - }, - 'cyberarkpas.audit.extra_details.logon_account': { - category: 'cyberarkpas', - name: 'cyberarkpas.audit.extra_details.logon_account', - type: 'keyword', - }, - 'cyberarkpas.audit.extra_details.managed_account': { - category: 'cyberarkpas', - name: 'cyberarkpas.audit.extra_details.managed_account', - type: 'keyword', - }, - 'cyberarkpas.audit.extra_details.process_id': { - category: 'cyberarkpas', - name: 'cyberarkpas.audit.extra_details.process_id', - type: 'keyword', - }, - 'cyberarkpas.audit.extra_details.process_name': { - category: 'cyberarkpas', - name: 'cyberarkpas.audit.extra_details.process_name', - type: 'keyword', - }, - 'cyberarkpas.audit.extra_details.protocol': { - category: 'cyberarkpas', - name: 'cyberarkpas.audit.extra_details.protocol', - type: 'keyword', - }, - 'cyberarkpas.audit.extra_details.psmid': { - category: 'cyberarkpas', - name: 'cyberarkpas.audit.extra_details.psmid', - type: 'keyword', - }, - 'cyberarkpas.audit.extra_details.session_duration': { - category: 'cyberarkpas', - name: 'cyberarkpas.audit.extra_details.session_duration', - type: 'keyword', - }, - 'cyberarkpas.audit.extra_details.session_id': { - category: 'cyberarkpas', - name: 'cyberarkpas.audit.extra_details.session_id', - type: 'keyword', - }, - 'cyberarkpas.audit.extra_details.src_host': { - category: 'cyberarkpas', - name: 'cyberarkpas.audit.extra_details.src_host', - type: 'keyword', - }, - 'cyberarkpas.audit.extra_details.username': { - category: 'cyberarkpas', - name: 'cyberarkpas.audit.extra_details.username', - type: 'keyword', - }, - 'cyberarkpas.audit.extra_details.other': { - category: 'cyberarkpas', - name: 'cyberarkpas.audit.extra_details.other', - type: 'flattened', - }, - 'cyberarkpas.audit.file': { - category: 'cyberarkpas', - description: 'The name of the target file.', - name: 'cyberarkpas.audit.file', - type: 'keyword', - }, - 'cyberarkpas.audit.gateway_station': { - category: 'cyberarkpas', - description: 'The IP of the web application machine (PVWA).', - name: 'cyberarkpas.audit.gateway_station', - type: 'ip', - }, - 'cyberarkpas.audit.hostname': { - category: 'cyberarkpas', - description: 'The hostname, in upper case.', - example: 'MY-COMPUTER', - name: 'cyberarkpas.audit.hostname', - type: 'keyword', - }, - 'cyberarkpas.audit.iso_timestamp': { - category: 'cyberarkpas', - description: 'The timestamp, in ISO Timestamp format (RFC 3339).', - example: '"2013-06-25T10:47:19.000Z"', - name: 'cyberarkpas.audit.iso_timestamp', - type: 'date', - }, - 'cyberarkpas.audit.issuer': { - category: 'cyberarkpas', - description: - 'The Vault user who wrote the audit. This is usually the user who performed the operation.', - name: 'cyberarkpas.audit.issuer', - type: 'keyword', - }, - 'cyberarkpas.audit.location': { - category: 'cyberarkpas', - description: 'The target Location (for Location operations).', - name: 'cyberarkpas.audit.location', - type: 'keyword', - }, - 'cyberarkpas.audit.message': { - category: 'cyberarkpas', - description: 'A description of the audit records (same information as in the Desc field).', - name: 'cyberarkpas.audit.message', - type: 'keyword', - }, - 'cyberarkpas.audit.message_id': { - category: 'cyberarkpas', - description: 'The code ID of the audit records.', - name: 'cyberarkpas.audit.message_id', - type: 'keyword', - }, - 'cyberarkpas.audit.product': { - category: 'cyberarkpas', - description: 'A static value that represents the product.', - name: 'cyberarkpas.audit.product', - type: 'keyword', - }, - 'cyberarkpas.audit.pvwa_details': { - category: 'cyberarkpas', - description: 'Specific details of the PVWA audit records.', - name: 'cyberarkpas.audit.pvwa_details', - type: 'flattened', - }, - 'cyberarkpas.audit.raw': { - category: 'cyberarkpas', - description: - 'Raw XML for the original audit record. Only present when XSLT file has debugging enabled. ', - name: 'cyberarkpas.audit.raw', - type: 'keyword', - }, - 'cyberarkpas.audit.reason': { - category: 'cyberarkpas', - description: 'The reason entered by the user.', - name: 'cyberarkpas.audit.reason', - type: 'text', - }, - 'cyberarkpas.audit.rfc5424': { - category: 'cyberarkpas', - description: 'Whether the syslog format complies with RFC5424.', - example: 'yes', - name: 'cyberarkpas.audit.rfc5424', - type: 'boolean', - }, - 'cyberarkpas.audit.safe': { - category: 'cyberarkpas', - description: 'The name of the target Safe.', - name: 'cyberarkpas.audit.safe', - type: 'keyword', - }, - 'cyberarkpas.audit.severity': { - category: 'cyberarkpas', - description: 'The severity of the audit records.', - name: 'cyberarkpas.audit.severity', - type: 'keyword', - }, - 'cyberarkpas.audit.source_user': { - category: 'cyberarkpas', - description: 'The name of the Vault user who performed the operation.', - name: 'cyberarkpas.audit.source_user', - type: 'keyword', - }, - 'cyberarkpas.audit.station': { - category: 'cyberarkpas', - description: - 'The IP from where the operation was performed. For PVWA sessions, this will be the real client machine IP.', - name: 'cyberarkpas.audit.station', - type: 'ip', - }, - 'cyberarkpas.audit.target_user': { - category: 'cyberarkpas', - description: 'The name of the Vault user on which the operation was performed.', - name: 'cyberarkpas.audit.target_user', - type: 'keyword', - }, - 'cyberarkpas.audit.timestamp': { - category: 'cyberarkpas', - description: 'The timestamp, in MMM DD HH:MM:SS format.', - example: 'Jun 25 10:47:19', - name: 'cyberarkpas.audit.timestamp', - type: 'keyword', - }, - 'cyberarkpas.audit.vendor': { - category: 'cyberarkpas', - description: 'A static value that represents the vendor.', - name: 'cyberarkpas.audit.vendor', - type: 'keyword', - }, - 'cyberarkpas.audit.version': { - category: 'cyberarkpas', - description: 'A static value that represents the version of the Vault.', - name: 'cyberarkpas.audit.version', - type: 'keyword', - }, - 'envoyproxy.log_type': { - category: 'envoyproxy', - description: 'Envoy log type, normally ACCESS ', - name: 'envoyproxy.log_type', - type: 'keyword', - }, - 'envoyproxy.response_flags': { - category: 'envoyproxy', - description: 'Response flags ', - name: 'envoyproxy.response_flags', - type: 'keyword', - }, - 'envoyproxy.upstream_service_time': { - category: 'envoyproxy', - description: 'Upstream service time in nanoseconds ', - name: 'envoyproxy.upstream_service_time', - type: 'long', - format: 'duration', - }, - 'envoyproxy.request_id': { - category: 'envoyproxy', - description: 'ID of the request ', - name: 'envoyproxy.request_id', - type: 'keyword', - }, - 'envoyproxy.authority': { - category: 'envoyproxy', - description: 'Envoy proxy authority field ', - name: 'envoyproxy.authority', - type: 'keyword', - }, - 'envoyproxy.proxy_type': { - category: 'envoyproxy', - description: 'Envoy proxy type, tcp or http ', - name: 'envoyproxy.proxy_type', - type: 'keyword', - }, - 'fortinet.file.hash.crc32': { - category: 'fortinet', - description: 'CRC32 Hash of file ', - name: 'fortinet.file.hash.crc32', - type: 'keyword', - }, - 'fortinet.firewall.acct_stat': { - category: 'fortinet', - description: 'Accounting state (RADIUS) ', - name: 'fortinet.firewall.acct_stat', - type: 'keyword', - }, - 'fortinet.firewall.acktime': { - category: 'fortinet', - description: 'Alarm Acknowledge Time ', - name: 'fortinet.firewall.acktime', - type: 'keyword', - }, - 'fortinet.firewall.act': { - category: 'fortinet', - description: 'Action ', - name: 'fortinet.firewall.act', - type: 'keyword', - }, - 'fortinet.firewall.action': { - category: 'fortinet', - description: 'Status of the session ', - name: 'fortinet.firewall.action', - type: 'keyword', - }, - 'fortinet.firewall.activity': { - category: 'fortinet', - description: 'HA activity message ', - name: 'fortinet.firewall.activity', - type: 'keyword', - }, - 'fortinet.firewall.addr': { - category: 'fortinet', - description: 'IP Address ', - name: 'fortinet.firewall.addr', - type: 'ip', - }, - 'fortinet.firewall.addr_type': { - category: 'fortinet', - description: 'Address Type ', - name: 'fortinet.firewall.addr_type', - type: 'keyword', - }, - 'fortinet.firewall.addrgrp': { - category: 'fortinet', - description: 'Address Group ', - name: 'fortinet.firewall.addrgrp', - type: 'keyword', - }, - 'fortinet.firewall.adgroup': { - category: 'fortinet', - description: 'AD Group Name ', - name: 'fortinet.firewall.adgroup', - type: 'keyword', - }, - 'fortinet.firewall.admin': { - category: 'fortinet', - description: 'Admin User ', - name: 'fortinet.firewall.admin', - type: 'keyword', - }, - 'fortinet.firewall.age': { - category: 'fortinet', - description: 'Time in seconds - time passed since last seen ', - name: 'fortinet.firewall.age', - type: 'integer', - }, - 'fortinet.firewall.agent': { - category: 'fortinet', - description: 'User agent - eg. agent="Mozilla/5.0" ', - name: 'fortinet.firewall.agent', - type: 'keyword', - }, - 'fortinet.firewall.alarmid': { - category: 'fortinet', - description: 'Alarm ID ', - name: 'fortinet.firewall.alarmid', - type: 'integer', - }, - 'fortinet.firewall.alert': { - category: 'fortinet', - description: 'Alert ', - name: 'fortinet.firewall.alert', - type: 'keyword', - }, - 'fortinet.firewall.analyticscksum': { - category: 'fortinet', - description: 'The checksum of the file submitted for analytics ', - name: 'fortinet.firewall.analyticscksum', - type: 'keyword', - }, - 'fortinet.firewall.analyticssubmit': { - category: 'fortinet', - description: 'The flag for analytics submission ', - name: 'fortinet.firewall.analyticssubmit', - type: 'keyword', - }, - 'fortinet.firewall.ap': { - category: 'fortinet', - description: 'Access Point ', - name: 'fortinet.firewall.ap', - type: 'keyword', - }, - 'fortinet.firewall.app-type': { - category: 'fortinet', - description: 'Address Type ', - name: 'fortinet.firewall.app-type', - type: 'keyword', - }, - 'fortinet.firewall.appact': { - category: 'fortinet', - description: 'The security action from app control ', - name: 'fortinet.firewall.appact', - type: 'keyword', - }, - 'fortinet.firewall.appid': { - category: 'fortinet', - description: 'Application ID ', - name: 'fortinet.firewall.appid', - type: 'integer', - }, - 'fortinet.firewall.applist': { - category: 'fortinet', - description: 'Application Control profile ', - name: 'fortinet.firewall.applist', - type: 'keyword', - }, - 'fortinet.firewall.apprisk': { - category: 'fortinet', - description: 'Application Risk Level ', - name: 'fortinet.firewall.apprisk', - type: 'keyword', - }, - 'fortinet.firewall.apscan': { - category: 'fortinet', - description: 'The name of the AP, which scanned and detected the rogue AP ', - name: 'fortinet.firewall.apscan', - type: 'keyword', - }, - 'fortinet.firewall.apsn': { - category: 'fortinet', - description: 'Access Point ', - name: 'fortinet.firewall.apsn', - type: 'keyword', - }, - 'fortinet.firewall.apstatus': { - category: 'fortinet', - description: 'Access Point status ', - name: 'fortinet.firewall.apstatus', - type: 'keyword', - }, - 'fortinet.firewall.aptype': { - category: 'fortinet', - description: 'Access Point type ', - name: 'fortinet.firewall.aptype', - type: 'keyword', - }, - 'fortinet.firewall.assigned': { - category: 'fortinet', - description: 'Assigned IP Address ', - name: 'fortinet.firewall.assigned', - type: 'ip', - }, - 'fortinet.firewall.assignip': { - category: 'fortinet', - description: 'Assigned IP Address ', - name: 'fortinet.firewall.assignip', - type: 'ip', - }, - 'fortinet.firewall.attachment': { - category: 'fortinet', - description: 'The flag for email attachement ', - name: 'fortinet.firewall.attachment', - type: 'keyword', - }, - 'fortinet.firewall.attack': { - category: 'fortinet', - description: 'Attack Name ', - name: 'fortinet.firewall.attack', - type: 'keyword', - }, - 'fortinet.firewall.attackcontext': { - category: 'fortinet', - description: 'The trigger patterns and the packetdata with base64 encoding ', - name: 'fortinet.firewall.attackcontext', - type: 'keyword', - }, - 'fortinet.firewall.attackcontextid': { - category: 'fortinet', - description: 'Attack context id / total ', - name: 'fortinet.firewall.attackcontextid', - type: 'keyword', - }, - 'fortinet.firewall.attackid': { - category: 'fortinet', - description: 'Attack ID ', - name: 'fortinet.firewall.attackid', - type: 'integer', - }, - 'fortinet.firewall.auditid': { - category: 'fortinet', - description: 'Audit ID ', - name: 'fortinet.firewall.auditid', - type: 'long', - }, - 'fortinet.firewall.auditscore': { - category: 'fortinet', - description: 'The Audit Score ', - name: 'fortinet.firewall.auditscore', - type: 'keyword', - }, - 'fortinet.firewall.audittime': { - category: 'fortinet', - description: 'The time of the audit ', - name: 'fortinet.firewall.audittime', - type: 'long', - }, - 'fortinet.firewall.authgrp': { - category: 'fortinet', - description: 'Authorization Group ', - name: 'fortinet.firewall.authgrp', - type: 'keyword', - }, - 'fortinet.firewall.authid': { - category: 'fortinet', - description: 'Authentication ID ', - name: 'fortinet.firewall.authid', - type: 'keyword', - }, - 'fortinet.firewall.authproto': { - category: 'fortinet', - description: 'The protocol that initiated the authentication ', - name: 'fortinet.firewall.authproto', - type: 'keyword', - }, - 'fortinet.firewall.authserver': { - category: 'fortinet', - description: 'Authentication server ', - name: 'fortinet.firewall.authserver', - type: 'keyword', - }, - 'fortinet.firewall.bandwidth': { - category: 'fortinet', - description: 'Bandwidth ', - name: 'fortinet.firewall.bandwidth', - type: 'keyword', - }, - 'fortinet.firewall.banned_rule': { - category: 'fortinet', - description: 'NAC quarantine Banned Rule Name ', - name: 'fortinet.firewall.banned_rule', - type: 'keyword', - }, - 'fortinet.firewall.banned_src': { - category: 'fortinet', - description: 'NAC quarantine Banned Source IP ', - name: 'fortinet.firewall.banned_src', - type: 'keyword', - }, - 'fortinet.firewall.banword': { - category: 'fortinet', - description: 'Banned word ', - name: 'fortinet.firewall.banword', - type: 'keyword', - }, - 'fortinet.firewall.botnetdomain': { - category: 'fortinet', - description: 'Botnet Domain Name ', - name: 'fortinet.firewall.botnetdomain', - type: 'keyword', - }, - 'fortinet.firewall.botnetip': { - category: 'fortinet', - description: 'Botnet IP Address ', - name: 'fortinet.firewall.botnetip', - type: 'ip', - }, - 'fortinet.firewall.bssid': { - category: 'fortinet', - description: 'Service Set ID ', - name: 'fortinet.firewall.bssid', - type: 'keyword', - }, - 'fortinet.firewall.call_id': { - category: 'fortinet', - description: 'Caller ID ', - name: 'fortinet.firewall.call_id', - type: 'keyword', - }, - 'fortinet.firewall.carrier_ep': { - category: 'fortinet', - description: 'The FortiOS Carrier end-point identification ', - name: 'fortinet.firewall.carrier_ep', - type: 'keyword', - }, - 'fortinet.firewall.cat': { - category: 'fortinet', - description: 'DNS category ID ', - name: 'fortinet.firewall.cat', - type: 'integer', - }, - 'fortinet.firewall.category': { - category: 'fortinet', - description: 'Authentication category ', - name: 'fortinet.firewall.category', - type: 'keyword', - }, - 'fortinet.firewall.cc': { - category: 'fortinet', - description: 'CC Email Address ', - name: 'fortinet.firewall.cc', - type: 'keyword', - }, - 'fortinet.firewall.cdrcontent': { - category: 'fortinet', - description: 'Cdrcontent ', - name: 'fortinet.firewall.cdrcontent', - type: 'keyword', - }, - 'fortinet.firewall.centralnatid': { - category: 'fortinet', - description: 'Central NAT ID ', - name: 'fortinet.firewall.centralnatid', - type: 'integer', - }, - 'fortinet.firewall.cert': { - category: 'fortinet', - description: 'Certificate ', - name: 'fortinet.firewall.cert', - type: 'keyword', - }, - 'fortinet.firewall.cert-type': { - category: 'fortinet', - description: 'Certificate type ', - name: 'fortinet.firewall.cert-type', - type: 'keyword', - }, - 'fortinet.firewall.certhash': { - category: 'fortinet', - description: 'Certificate hash ', - name: 'fortinet.firewall.certhash', - type: 'keyword', - }, - 'fortinet.firewall.cfgattr': { - category: 'fortinet', - description: 'Configuration attribute ', - name: 'fortinet.firewall.cfgattr', - type: 'keyword', - }, - 'fortinet.firewall.cfgobj': { - category: 'fortinet', - description: 'Configuration object ', - name: 'fortinet.firewall.cfgobj', - type: 'keyword', - }, - 'fortinet.firewall.cfgpath': { - category: 'fortinet', - description: 'Configuration path ', - name: 'fortinet.firewall.cfgpath', - type: 'keyword', - }, - 'fortinet.firewall.cfgtid': { - category: 'fortinet', - description: 'Configuration transaction ID ', - name: 'fortinet.firewall.cfgtid', - type: 'keyword', - }, - 'fortinet.firewall.cfgtxpower': { - category: 'fortinet', - description: 'Configuration TX power ', - name: 'fortinet.firewall.cfgtxpower', - type: 'integer', - }, - 'fortinet.firewall.channel': { - category: 'fortinet', - description: 'Wireless Channel ', - name: 'fortinet.firewall.channel', - type: 'integer', - }, - 'fortinet.firewall.channeltype': { - category: 'fortinet', - description: 'SSH channel type ', - name: 'fortinet.firewall.channeltype', - type: 'keyword', - }, - 'fortinet.firewall.chassisid': { - category: 'fortinet', - description: 'Chassis ID ', - name: 'fortinet.firewall.chassisid', - type: 'integer', - }, - 'fortinet.firewall.checksum': { - category: 'fortinet', - description: 'The checksum of the scanned file ', - name: 'fortinet.firewall.checksum', - type: 'keyword', - }, - 'fortinet.firewall.chgheaders': { - category: 'fortinet', - description: 'HTTP Headers ', - name: 'fortinet.firewall.chgheaders', - type: 'keyword', - }, - 'fortinet.firewall.cldobjid': { - category: 'fortinet', - description: 'Connector object ID ', - name: 'fortinet.firewall.cldobjid', - type: 'keyword', - }, - 'fortinet.firewall.client_addr': { - category: 'fortinet', - description: 'Wifi client address ', - name: 'fortinet.firewall.client_addr', - type: 'keyword', - }, - 'fortinet.firewall.cloudaction': { - category: 'fortinet', - description: 'Cloud Action ', - name: 'fortinet.firewall.cloudaction', - type: 'keyword', - }, - 'fortinet.firewall.clouduser': { - category: 'fortinet', - description: 'Cloud User ', - name: 'fortinet.firewall.clouduser', - type: 'keyword', - }, - 'fortinet.firewall.column': { - category: 'fortinet', - description: 'VOIP Column ', - name: 'fortinet.firewall.column', - type: 'integer', - }, - 'fortinet.firewall.command': { - category: 'fortinet', - description: 'CLI Command ', - name: 'fortinet.firewall.command', - type: 'keyword', - }, - 'fortinet.firewall.community': { - category: 'fortinet', - description: 'SNMP Community ', - name: 'fortinet.firewall.community', - type: 'keyword', - }, - 'fortinet.firewall.configcountry': { - category: 'fortinet', - description: 'Configuration country ', - name: 'fortinet.firewall.configcountry', - type: 'keyword', - }, - 'fortinet.firewall.connection_type': { - category: 'fortinet', - description: 'FortiClient Connection Type ', - name: 'fortinet.firewall.connection_type', - type: 'keyword', - }, - 'fortinet.firewall.conserve': { - category: 'fortinet', - description: 'Flag for conserve mode ', - name: 'fortinet.firewall.conserve', - type: 'keyword', - }, - 'fortinet.firewall.constraint': { - category: 'fortinet', - description: 'WAF http protocol restrictions ', - name: 'fortinet.firewall.constraint', - type: 'keyword', - }, - 'fortinet.firewall.contentdisarmed': { - category: 'fortinet', - description: 'Email scanned content ', - name: 'fortinet.firewall.contentdisarmed', - type: 'keyword', - }, - 'fortinet.firewall.contenttype': { - category: 'fortinet', - description: 'Content Type from HTTP header ', - name: 'fortinet.firewall.contenttype', - type: 'keyword', - }, - 'fortinet.firewall.cookies': { - category: 'fortinet', - description: 'VPN Cookie ', - name: 'fortinet.firewall.cookies', - type: 'keyword', - }, - 'fortinet.firewall.count': { - category: 'fortinet', - description: 'Counts of action type ', - name: 'fortinet.firewall.count', - type: 'integer', - }, - 'fortinet.firewall.countapp': { - category: 'fortinet', - description: 'Number of App Ctrl logs associated with the session ', - name: 'fortinet.firewall.countapp', - type: 'integer', - }, - 'fortinet.firewall.countav': { - category: 'fortinet', - description: 'Number of AV logs associated with the session ', - name: 'fortinet.firewall.countav', - type: 'integer', - }, - 'fortinet.firewall.countcifs': { - category: 'fortinet', - description: 'Number of CIFS logs associated with the session ', - name: 'fortinet.firewall.countcifs', - type: 'integer', - }, - 'fortinet.firewall.countdlp': { - category: 'fortinet', - description: 'Number of DLP logs associated with the session ', - name: 'fortinet.firewall.countdlp', - type: 'integer', - }, - 'fortinet.firewall.countdns': { - category: 'fortinet', - description: 'Number of DNS logs associated with the session ', - name: 'fortinet.firewall.countdns', - type: 'integer', - }, - 'fortinet.firewall.countemail': { - category: 'fortinet', - description: 'Number of email logs associated with the session ', - name: 'fortinet.firewall.countemail', - type: 'integer', - }, - 'fortinet.firewall.countff': { - category: 'fortinet', - description: 'Number of ff logs associated with the session ', - name: 'fortinet.firewall.countff', - type: 'integer', - }, - 'fortinet.firewall.countips': { - category: 'fortinet', - description: 'Number of IPS logs associated with the session ', - name: 'fortinet.firewall.countips', - type: 'integer', - }, - 'fortinet.firewall.countssh': { - category: 'fortinet', - description: 'Number of SSH logs associated with the session ', - name: 'fortinet.firewall.countssh', - type: 'integer', - }, - 'fortinet.firewall.countssl': { - category: 'fortinet', - description: 'Number of SSL logs associated with the session ', - name: 'fortinet.firewall.countssl', - type: 'integer', - }, - 'fortinet.firewall.countwaf': { - category: 'fortinet', - description: 'Number of WAF logs associated with the session ', - name: 'fortinet.firewall.countwaf', - type: 'integer', - }, - 'fortinet.firewall.countweb': { - category: 'fortinet', - description: 'Number of Web filter logs associated with the session ', - name: 'fortinet.firewall.countweb', - type: 'integer', - }, - 'fortinet.firewall.cpu': { - category: 'fortinet', - description: 'CPU Usage ', - name: 'fortinet.firewall.cpu', - type: 'integer', - }, - 'fortinet.firewall.craction': { - category: 'fortinet', - description: 'Client Reputation Action ', - name: 'fortinet.firewall.craction', - type: 'integer', - }, - 'fortinet.firewall.criticalcount': { - category: 'fortinet', - description: 'Number of critical ratings ', - name: 'fortinet.firewall.criticalcount', - type: 'integer', - }, - 'fortinet.firewall.crl': { - category: 'fortinet', - description: 'Client Reputation Level ', - name: 'fortinet.firewall.crl', - type: 'keyword', - }, - 'fortinet.firewall.crlevel': { - category: 'fortinet', - description: 'Client Reputation Level ', - name: 'fortinet.firewall.crlevel', - type: 'keyword', - }, - 'fortinet.firewall.crscore': { - category: 'fortinet', - description: 'Some description ', - name: 'fortinet.firewall.crscore', - type: 'integer', - }, - 'fortinet.firewall.cveid': { - category: 'fortinet', - description: 'CVE ID ', - name: 'fortinet.firewall.cveid', - type: 'keyword', - }, - 'fortinet.firewall.daemon': { - category: 'fortinet', - description: 'Daemon name ', - name: 'fortinet.firewall.daemon', - type: 'keyword', - }, - 'fortinet.firewall.datarange': { - category: 'fortinet', - description: 'Data range for reports ', - name: 'fortinet.firewall.datarange', - type: 'keyword', - }, - 'fortinet.firewall.date': { - category: 'fortinet', - description: 'Date ', - name: 'fortinet.firewall.date', - type: 'keyword', - }, - 'fortinet.firewall.ddnsserver': { - category: 'fortinet', - description: 'DDNS server ', - name: 'fortinet.firewall.ddnsserver', - type: 'ip', - }, - 'fortinet.firewall.desc': { - category: 'fortinet', - description: 'Description ', - name: 'fortinet.firewall.desc', - type: 'keyword', - }, - 'fortinet.firewall.detectionmethod': { - category: 'fortinet', - description: 'Detection method ', - name: 'fortinet.firewall.detectionmethod', - type: 'keyword', - }, - 'fortinet.firewall.devcategory': { - category: 'fortinet', - description: 'Device category ', - name: 'fortinet.firewall.devcategory', - type: 'keyword', - }, - 'fortinet.firewall.devintfname': { - category: 'fortinet', - description: 'HA device Interface Name ', - name: 'fortinet.firewall.devintfname', - type: 'keyword', - }, - 'fortinet.firewall.devtype': { - category: 'fortinet', - description: 'Device type ', - name: 'fortinet.firewall.devtype', - type: 'keyword', - }, - 'fortinet.firewall.dhcp_msg': { - category: 'fortinet', - description: 'DHCP Message ', - name: 'fortinet.firewall.dhcp_msg', - type: 'keyword', - }, - 'fortinet.firewall.dintf': { - category: 'fortinet', - description: 'Destination interface ', - name: 'fortinet.firewall.dintf', - type: 'keyword', - }, - 'fortinet.firewall.disk': { - category: 'fortinet', - description: 'Assosciated disk ', - name: 'fortinet.firewall.disk', - type: 'keyword', - }, - 'fortinet.firewall.disklograte': { - category: 'fortinet', - description: 'Disk logging rate ', - name: 'fortinet.firewall.disklograte', - type: 'long', - }, - 'fortinet.firewall.dlpextra': { - category: 'fortinet', - description: 'DLP extra information ', - name: 'fortinet.firewall.dlpextra', - type: 'keyword', - }, - 'fortinet.firewall.docsource': { - category: 'fortinet', - description: 'DLP fingerprint document source ', - name: 'fortinet.firewall.docsource', - type: 'keyword', - }, - 'fortinet.firewall.domainctrlauthstate': { - category: 'fortinet', - description: 'CIFS domain auth state ', - name: 'fortinet.firewall.domainctrlauthstate', - type: 'integer', - }, - 'fortinet.firewall.domainctrlauthtype': { - category: 'fortinet', - description: 'CIFS domain auth type ', - name: 'fortinet.firewall.domainctrlauthtype', - type: 'integer', - }, - 'fortinet.firewall.domainctrldomain': { - category: 'fortinet', - description: 'CIFS domain auth domain ', - name: 'fortinet.firewall.domainctrldomain', - type: 'keyword', - }, - 'fortinet.firewall.domainctrlip': { - category: 'fortinet', - description: 'CIFS Domain IP ', - name: 'fortinet.firewall.domainctrlip', - type: 'ip', - }, - 'fortinet.firewall.domainctrlname': { - category: 'fortinet', - description: 'CIFS Domain name ', - name: 'fortinet.firewall.domainctrlname', - type: 'keyword', - }, - 'fortinet.firewall.domainctrlprotocoltype': { - category: 'fortinet', - description: 'CIFS Domain connection protocol ', - name: 'fortinet.firewall.domainctrlprotocoltype', - type: 'integer', - }, - 'fortinet.firewall.domainctrlusername': { - category: 'fortinet', - description: 'CIFS Domain username ', - name: 'fortinet.firewall.domainctrlusername', - type: 'keyword', - }, - 'fortinet.firewall.domainfilteridx': { - category: 'fortinet', - description: 'Domain filter ID ', - name: 'fortinet.firewall.domainfilteridx', - type: 'integer', - }, - 'fortinet.firewall.domainfilterlist': { - category: 'fortinet', - description: 'Domain filter name ', - name: 'fortinet.firewall.domainfilterlist', - type: 'keyword', - }, - 'fortinet.firewall.ds': { - category: 'fortinet', - description: 'Direction with distribution system ', - name: 'fortinet.firewall.ds', - type: 'keyword', - }, - 'fortinet.firewall.dst_int': { - category: 'fortinet', - description: 'Destination interface ', - name: 'fortinet.firewall.dst_int', - type: 'keyword', - }, - 'fortinet.firewall.dstintfrole': { - category: 'fortinet', - description: 'Destination interface role ', - name: 'fortinet.firewall.dstintfrole', - type: 'keyword', - }, - 'fortinet.firewall.dstcountry': { - category: 'fortinet', - description: 'Destination country ', - name: 'fortinet.firewall.dstcountry', - type: 'keyword', - }, - 'fortinet.firewall.dstdevcategory': { - category: 'fortinet', - description: 'Destination device category ', - name: 'fortinet.firewall.dstdevcategory', - type: 'keyword', - }, - 'fortinet.firewall.dstdevtype': { - category: 'fortinet', - description: 'Destination device type ', - name: 'fortinet.firewall.dstdevtype', - type: 'keyword', - }, - 'fortinet.firewall.dstfamily': { - category: 'fortinet', - description: 'Destination OS family ', - name: 'fortinet.firewall.dstfamily', - type: 'keyword', - }, - 'fortinet.firewall.dsthwvendor': { - category: 'fortinet', - description: 'Destination HW vendor ', - name: 'fortinet.firewall.dsthwvendor', - type: 'keyword', - }, - 'fortinet.firewall.dsthwversion': { - category: 'fortinet', - description: 'Destination HW version ', - name: 'fortinet.firewall.dsthwversion', - type: 'keyword', - }, - 'fortinet.firewall.dstinetsvc': { - category: 'fortinet', - description: 'Destination interface service ', - name: 'fortinet.firewall.dstinetsvc', - type: 'keyword', - }, - 'fortinet.firewall.dstosname': { - category: 'fortinet', - description: 'Destination OS name ', - name: 'fortinet.firewall.dstosname', - type: 'keyword', - }, - 'fortinet.firewall.dstosversion': { - category: 'fortinet', - description: 'Destination OS version ', - name: 'fortinet.firewall.dstosversion', - type: 'keyword', - }, - 'fortinet.firewall.dstserver': { - category: 'fortinet', - description: 'Destination server ', - name: 'fortinet.firewall.dstserver', - type: 'integer', - }, - 'fortinet.firewall.dstssid': { - category: 'fortinet', - description: 'Destination SSID ', - name: 'fortinet.firewall.dstssid', - type: 'keyword', - }, - 'fortinet.firewall.dstswversion': { - category: 'fortinet', - description: 'Destination software version ', - name: 'fortinet.firewall.dstswversion', - type: 'keyword', - }, - 'fortinet.firewall.dstunauthusersource': { - category: 'fortinet', - description: 'Destination unauthenticated source ', - name: 'fortinet.firewall.dstunauthusersource', - type: 'keyword', - }, - 'fortinet.firewall.dstuuid': { - category: 'fortinet', - description: 'UUID of the Destination IP address ', - name: 'fortinet.firewall.dstuuid', - type: 'keyword', - }, - 'fortinet.firewall.duid': { - category: 'fortinet', - description: 'DHCP UID ', - name: 'fortinet.firewall.duid', - type: 'keyword', - }, - 'fortinet.firewall.eapolcnt': { - category: 'fortinet', - description: 'EAPOL packet count ', - name: 'fortinet.firewall.eapolcnt', - type: 'integer', - }, - 'fortinet.firewall.eapoltype': { - category: 'fortinet', - description: 'EAPOL packet type ', - name: 'fortinet.firewall.eapoltype', - type: 'keyword', - }, - 'fortinet.firewall.encrypt': { - category: 'fortinet', - description: 'Whether the packet is encrypted or not ', - name: 'fortinet.firewall.encrypt', - type: 'integer', - }, - 'fortinet.firewall.encryption': { - category: 'fortinet', - description: 'Encryption method ', - name: 'fortinet.firewall.encryption', - type: 'keyword', - }, - 'fortinet.firewall.epoch': { - category: 'fortinet', - description: 'Epoch used for locating file ', - name: 'fortinet.firewall.epoch', - type: 'integer', - }, - 'fortinet.firewall.espauth': { - category: 'fortinet', - description: 'ESP Authentication ', - name: 'fortinet.firewall.espauth', - type: 'keyword', - }, - 'fortinet.firewall.esptransform': { - category: 'fortinet', - description: 'ESP Transform ', - name: 'fortinet.firewall.esptransform', - type: 'keyword', - }, - 'fortinet.firewall.eventtype': { - category: 'fortinet', - description: 'UTM Event Type ', - name: 'fortinet.firewall.eventtype', - type: 'keyword', - }, - 'fortinet.firewall.exch': { - category: 'fortinet', - description: 'Mail Exchanges from DNS response answer section ', - name: 'fortinet.firewall.exch', - type: 'keyword', - }, - 'fortinet.firewall.exchange': { - category: 'fortinet', - description: 'Mail Exchanges from DNS response answer section ', - name: 'fortinet.firewall.exchange', - type: 'keyword', - }, - 'fortinet.firewall.expectedsignature': { - category: 'fortinet', - description: 'Expected SSL signature ', - name: 'fortinet.firewall.expectedsignature', - type: 'keyword', - }, - 'fortinet.firewall.expiry': { - category: 'fortinet', - description: 'FortiGuard override expiry timestamp ', - name: 'fortinet.firewall.expiry', - type: 'keyword', - }, - 'fortinet.firewall.fams_pause': { - category: 'fortinet', - description: 'Fortinet Analysis and Management Service Pause ', - name: 'fortinet.firewall.fams_pause', - type: 'integer', - }, - 'fortinet.firewall.fazlograte': { - category: 'fortinet', - description: 'FortiAnalyzer Logging Rate ', - name: 'fortinet.firewall.fazlograte', - type: 'long', - }, - 'fortinet.firewall.fctemssn': { - category: 'fortinet', - description: 'FortiClient Endpoint SSN ', - name: 'fortinet.firewall.fctemssn', - type: 'keyword', - }, - 'fortinet.firewall.fctuid': { - category: 'fortinet', - description: 'FortiClient UID ', - name: 'fortinet.firewall.fctuid', - type: 'keyword', - }, - 'fortinet.firewall.field': { - category: 'fortinet', - description: 'NTP status field ', - name: 'fortinet.firewall.field', - type: 'keyword', - }, - 'fortinet.firewall.filefilter': { - category: 'fortinet', - description: 'The filter used to identify the affected file ', - name: 'fortinet.firewall.filefilter', - type: 'keyword', - }, - 'fortinet.firewall.filehashsrc': { - category: 'fortinet', - description: 'Filehash source ', - name: 'fortinet.firewall.filehashsrc', - type: 'keyword', - }, - 'fortinet.firewall.filtercat': { - category: 'fortinet', - description: 'DLP filter category ', - name: 'fortinet.firewall.filtercat', - type: 'keyword', - }, - 'fortinet.firewall.filteridx': { - category: 'fortinet', - description: 'DLP filter ID ', - name: 'fortinet.firewall.filteridx', - type: 'integer', - }, - 'fortinet.firewall.filtername': { - category: 'fortinet', - description: 'DLP rule name ', - name: 'fortinet.firewall.filtername', - type: 'keyword', - }, - 'fortinet.firewall.filtertype': { - category: 'fortinet', - description: 'DLP filter type ', - name: 'fortinet.firewall.filtertype', - type: 'keyword', - }, - 'fortinet.firewall.fortiguardresp': { - category: 'fortinet', - description: 'Antispam ESP value ', - name: 'fortinet.firewall.fortiguardresp', - type: 'keyword', - }, - 'fortinet.firewall.forwardedfor': { - category: 'fortinet', - description: 'Email address forwarded ', - name: 'fortinet.firewall.forwardedfor', - type: 'keyword', - }, - 'fortinet.firewall.fqdn': { - category: 'fortinet', - description: 'FQDN ', - name: 'fortinet.firewall.fqdn', - type: 'keyword', - }, - 'fortinet.firewall.frametype': { - category: 'fortinet', - description: 'Wireless frametype ', - name: 'fortinet.firewall.frametype', - type: 'keyword', - }, - 'fortinet.firewall.freediskstorage': { - category: 'fortinet', - description: 'Free disk integer ', - name: 'fortinet.firewall.freediskstorage', - type: 'integer', - }, - 'fortinet.firewall.from': { - category: 'fortinet', - description: 'From email address ', - name: 'fortinet.firewall.from', - type: 'keyword', - }, - 'fortinet.firewall.from_vcluster': { - category: 'fortinet', - description: 'Source virtual cluster number ', - name: 'fortinet.firewall.from_vcluster', - type: 'integer', - }, - 'fortinet.firewall.fsaverdict': { - category: 'fortinet', - description: 'FSA verdict ', - name: 'fortinet.firewall.fsaverdict', - type: 'keyword', - }, - 'fortinet.firewall.fwserver_name': { - category: 'fortinet', - description: 'Web proxy server name ', - name: 'fortinet.firewall.fwserver_name', - type: 'keyword', - }, - 'fortinet.firewall.gateway': { - category: 'fortinet', - description: 'Gateway ip address for PPPoE status report ', - name: 'fortinet.firewall.gateway', - type: 'ip', - }, - 'fortinet.firewall.green': { - category: 'fortinet', - description: 'Memory status ', - name: 'fortinet.firewall.green', - type: 'keyword', - }, - 'fortinet.firewall.groupid': { - category: 'fortinet', - description: 'User Group ID ', - name: 'fortinet.firewall.groupid', - type: 'integer', - }, - 'fortinet.firewall.ha-prio': { - category: 'fortinet', - description: 'HA Priority ', - name: 'fortinet.firewall.ha-prio', - type: 'integer', - }, - 'fortinet.firewall.ha_group': { - category: 'fortinet', - description: 'HA Group ', - name: 'fortinet.firewall.ha_group', - type: 'keyword', - }, - 'fortinet.firewall.ha_role': { - category: 'fortinet', - description: 'HA Role ', - name: 'fortinet.firewall.ha_role', - type: 'keyword', - }, - 'fortinet.firewall.handshake': { - category: 'fortinet', - description: 'SSL Handshake ', - name: 'fortinet.firewall.handshake', - type: 'keyword', - }, - 'fortinet.firewall.hash': { - category: 'fortinet', - description: 'Hash value of downloaded file ', - name: 'fortinet.firewall.hash', - type: 'keyword', - }, - 'fortinet.firewall.hbdn_reason': { - category: 'fortinet', - description: 'Heartbeat down reason ', - name: 'fortinet.firewall.hbdn_reason', - type: 'keyword', - }, - 'fortinet.firewall.highcount': { - category: 'fortinet', - description: 'Highcount fabric summary ', - name: 'fortinet.firewall.highcount', - type: 'integer', - }, - 'fortinet.firewall.host': { - category: 'fortinet', - description: 'Hostname ', - name: 'fortinet.firewall.host', - type: 'keyword', - }, - 'fortinet.firewall.iaid': { - category: 'fortinet', - description: 'DHCPv6 id ', - name: 'fortinet.firewall.iaid', - type: 'keyword', - }, - 'fortinet.firewall.icmpcode': { - category: 'fortinet', - description: 'Destination Port of the ICMP message ', - name: 'fortinet.firewall.icmpcode', - type: 'keyword', - }, - 'fortinet.firewall.icmpid': { - category: 'fortinet', - description: 'Source port of the ICMP message ', - name: 'fortinet.firewall.icmpid', - type: 'keyword', - }, - 'fortinet.firewall.icmptype': { - category: 'fortinet', - description: 'The type of ICMP message ', - name: 'fortinet.firewall.icmptype', - type: 'keyword', - }, - 'fortinet.firewall.identifier': { - category: 'fortinet', - description: 'Network traffic identifier ', - name: 'fortinet.firewall.identifier', - type: 'integer', - }, - 'fortinet.firewall.in_spi': { - category: 'fortinet', - description: 'IPSEC inbound SPI ', - name: 'fortinet.firewall.in_spi', - type: 'keyword', - }, - 'fortinet.firewall.incidentserialno': { - category: 'fortinet', - description: 'Incident serial number ', - name: 'fortinet.firewall.incidentserialno', - type: 'integer', - }, - 'fortinet.firewall.infected': { - category: 'fortinet', - description: 'Infected MMS ', - name: 'fortinet.firewall.infected', - type: 'integer', - }, - 'fortinet.firewall.infectedfilelevel': { - category: 'fortinet', - description: 'DLP infected file level ', - name: 'fortinet.firewall.infectedfilelevel', - type: 'integer', - }, - 'fortinet.firewall.informationsource': { - category: 'fortinet', - description: 'Information source ', - name: 'fortinet.firewall.informationsource', - type: 'keyword', - }, - 'fortinet.firewall.init': { - category: 'fortinet', - description: 'IPSEC init stage ', - name: 'fortinet.firewall.init', - type: 'keyword', - }, - 'fortinet.firewall.initiator': { - category: 'fortinet', - description: 'Original login user name for Fortiguard override ', - name: 'fortinet.firewall.initiator', - type: 'keyword', - }, - 'fortinet.firewall.interface': { - category: 'fortinet', - description: 'Related interface ', - name: 'fortinet.firewall.interface', - type: 'keyword', - }, - 'fortinet.firewall.intf': { - category: 'fortinet', - description: 'Related interface ', - name: 'fortinet.firewall.intf', - type: 'keyword', - }, - 'fortinet.firewall.invalidmac': { - category: 'fortinet', - description: 'The MAC address with invalid OUI ', - name: 'fortinet.firewall.invalidmac', - type: 'keyword', - }, - 'fortinet.firewall.ip': { - category: 'fortinet', - description: 'Related IP ', - name: 'fortinet.firewall.ip', - type: 'ip', - }, - 'fortinet.firewall.iptype': { - category: 'fortinet', - description: 'Related IP type ', - name: 'fortinet.firewall.iptype', - type: 'keyword', - }, - 'fortinet.firewall.keyword': { - category: 'fortinet', - description: 'Keyword used for search ', - name: 'fortinet.firewall.keyword', - type: 'keyword', - }, - 'fortinet.firewall.kind': { - category: 'fortinet', - description: 'VOIP kind ', - name: 'fortinet.firewall.kind', - type: 'keyword', - }, - 'fortinet.firewall.lanin': { - category: 'fortinet', - description: 'LAN incoming traffic in bytes ', - name: 'fortinet.firewall.lanin', - type: 'long', - }, - 'fortinet.firewall.lanout': { - category: 'fortinet', - description: 'LAN outbound traffic in bytes ', - name: 'fortinet.firewall.lanout', - type: 'long', - }, - 'fortinet.firewall.lease': { - category: 'fortinet', - description: 'DHCP lease ', - name: 'fortinet.firewall.lease', - type: 'integer', - }, - 'fortinet.firewall.license_limit': { - category: 'fortinet', - description: 'Maximum Number of FortiClients for the License ', - name: 'fortinet.firewall.license_limit', - type: 'keyword', - }, - 'fortinet.firewall.limit': { - category: 'fortinet', - description: 'Virtual Domain Resource Limit ', - name: 'fortinet.firewall.limit', - type: 'integer', - }, - 'fortinet.firewall.line': { - category: 'fortinet', - description: 'VOIP line ', - name: 'fortinet.firewall.line', - type: 'keyword', - }, - 'fortinet.firewall.live': { - category: 'fortinet', - description: 'Time in seconds ', - name: 'fortinet.firewall.live', - type: 'integer', - }, - 'fortinet.firewall.local': { - category: 'fortinet', - description: 'Local IP for a PPPD Connection ', - name: 'fortinet.firewall.local', - type: 'ip', - }, - 'fortinet.firewall.log': { - category: 'fortinet', - description: 'Log message ', - name: 'fortinet.firewall.log', - type: 'keyword', - }, - 'fortinet.firewall.login': { - category: 'fortinet', - description: 'SSH login ', - name: 'fortinet.firewall.login', - type: 'keyword', - }, - 'fortinet.firewall.lowcount': { - category: 'fortinet', - description: 'Fabric lowcount ', - name: 'fortinet.firewall.lowcount', - type: 'integer', - }, - 'fortinet.firewall.mac': { - category: 'fortinet', - description: 'DHCP mac address ', - name: 'fortinet.firewall.mac', - type: 'keyword', - }, - 'fortinet.firewall.malform_data': { - category: 'fortinet', - description: 'VOIP malformed data ', - name: 'fortinet.firewall.malform_data', - type: 'integer', - }, - 'fortinet.firewall.malform_desc': { - category: 'fortinet', - description: 'VOIP malformed data description ', - name: 'fortinet.firewall.malform_desc', - type: 'keyword', - }, - 'fortinet.firewall.manuf': { - category: 'fortinet', - description: 'Manufacturer name ', - name: 'fortinet.firewall.manuf', - type: 'keyword', - }, - 'fortinet.firewall.masterdstmac': { - category: 'fortinet', - description: 'Master mac address for a host with multiple network interfaces ', - name: 'fortinet.firewall.masterdstmac', - type: 'keyword', - }, - 'fortinet.firewall.mastersrcmac': { - category: 'fortinet', - description: 'The master MAC address for a host that has multiple network interfaces ', - name: 'fortinet.firewall.mastersrcmac', - type: 'keyword', - }, - 'fortinet.firewall.mediumcount': { - category: 'fortinet', - description: 'Fabric medium count ', - name: 'fortinet.firewall.mediumcount', - type: 'integer', - }, - 'fortinet.firewall.mem': { - category: 'fortinet', - description: 'Memory usage system statistics ', - name: 'fortinet.firewall.mem', - type: 'integer', - }, - 'fortinet.firewall.meshmode': { - category: 'fortinet', - description: 'Wireless mesh mode ', - name: 'fortinet.firewall.meshmode', - type: 'keyword', - }, - 'fortinet.firewall.message_type': { - category: 'fortinet', - description: 'VOIP message type ', - name: 'fortinet.firewall.message_type', - type: 'keyword', - }, - 'fortinet.firewall.method': { - category: 'fortinet', - description: 'HTTP method ', - name: 'fortinet.firewall.method', - type: 'keyword', - }, - 'fortinet.firewall.mgmtcnt': { - category: 'fortinet', - description: 'The number of unauthorized client flooding managemet frames ', - name: 'fortinet.firewall.mgmtcnt', - type: 'integer', - }, - 'fortinet.firewall.mode': { - category: 'fortinet', - description: 'IPSEC mode ', - name: 'fortinet.firewall.mode', - type: 'keyword', - }, - 'fortinet.firewall.module': { - category: 'fortinet', - description: 'PCI-DSS module ', - name: 'fortinet.firewall.module', - type: 'keyword', - }, - 'fortinet.firewall.monitor-name': { - category: 'fortinet', - description: 'Health Monitor Name ', - name: 'fortinet.firewall.monitor-name', - type: 'keyword', - }, - 'fortinet.firewall.monitor-type': { - category: 'fortinet', - description: 'Health Monitor Type ', - name: 'fortinet.firewall.monitor-type', - type: 'keyword', - }, - 'fortinet.firewall.mpsk': { - category: 'fortinet', - description: 'Wireless MPSK ', - name: 'fortinet.firewall.mpsk', - type: 'keyword', - }, - 'fortinet.firewall.msgproto': { - category: 'fortinet', - description: 'Message Protocol Number ', - name: 'fortinet.firewall.msgproto', - type: 'keyword', - }, - 'fortinet.firewall.mtu': { - category: 'fortinet', - description: 'Max Transmission Unit Value ', - name: 'fortinet.firewall.mtu', - type: 'integer', - }, - 'fortinet.firewall.name': { - category: 'fortinet', - description: 'Name ', - name: 'fortinet.firewall.name', - type: 'keyword', - }, - 'fortinet.firewall.nat': { - category: 'fortinet', - description: 'NAT IP Address ', - name: 'fortinet.firewall.nat', - type: 'keyword', - }, - 'fortinet.firewall.netid': { - category: 'fortinet', - description: 'Connector NetID ', - name: 'fortinet.firewall.netid', - type: 'keyword', - }, - 'fortinet.firewall.new_status': { - category: 'fortinet', - description: 'New status on user change ', - name: 'fortinet.firewall.new_status', - type: 'keyword', - }, - 'fortinet.firewall.new_value': { - category: 'fortinet', - description: 'New Virtual Domain Name ', - name: 'fortinet.firewall.new_value', - type: 'keyword', - }, - 'fortinet.firewall.newchannel': { - category: 'fortinet', - description: 'New Channel Number ', - name: 'fortinet.firewall.newchannel', - type: 'integer', - }, - 'fortinet.firewall.newchassisid': { - category: 'fortinet', - description: 'New Chassis ID ', - name: 'fortinet.firewall.newchassisid', - type: 'integer', - }, - 'fortinet.firewall.newslot': { - category: 'fortinet', - description: 'New Slot Number ', - name: 'fortinet.firewall.newslot', - type: 'integer', - }, - 'fortinet.firewall.nextstat': { - category: 'fortinet', - description: 'Time interval in seconds for the next statistics. ', - name: 'fortinet.firewall.nextstat', - type: 'integer', - }, - 'fortinet.firewall.nf_type': { - category: 'fortinet', - description: 'Notification Type ', - name: 'fortinet.firewall.nf_type', - type: 'keyword', - }, - 'fortinet.firewall.noise': { - category: 'fortinet', - description: 'Wifi Noise ', - name: 'fortinet.firewall.noise', - type: 'integer', - }, - 'fortinet.firewall.old_status': { - category: 'fortinet', - description: 'Original Status ', - name: 'fortinet.firewall.old_status', - type: 'keyword', - }, - 'fortinet.firewall.old_value': { - category: 'fortinet', - description: 'Original Virtual Domain name ', - name: 'fortinet.firewall.old_value', - type: 'keyword', - }, - 'fortinet.firewall.oldchannel': { - category: 'fortinet', - description: 'Original channel ', - name: 'fortinet.firewall.oldchannel', - type: 'integer', - }, - 'fortinet.firewall.oldchassisid': { - category: 'fortinet', - description: 'Original Chassis Number ', - name: 'fortinet.firewall.oldchassisid', - type: 'integer', - }, - 'fortinet.firewall.oldslot': { - category: 'fortinet', - description: 'Original Slot Number ', - name: 'fortinet.firewall.oldslot', - type: 'integer', - }, - 'fortinet.firewall.oldsn': { - category: 'fortinet', - description: 'Old Serial number ', - name: 'fortinet.firewall.oldsn', - type: 'keyword', - }, - 'fortinet.firewall.oldwprof': { - category: 'fortinet', - description: 'Old Web Filter Profile ', - name: 'fortinet.firewall.oldwprof', - type: 'keyword', - }, - 'fortinet.firewall.onwire': { - category: 'fortinet', - description: 'A flag to indicate if the AP is onwire or not ', - name: 'fortinet.firewall.onwire', - type: 'keyword', - }, - 'fortinet.firewall.opercountry': { - category: 'fortinet', - description: 'Operating Country ', - name: 'fortinet.firewall.opercountry', - type: 'keyword', - }, - 'fortinet.firewall.opertxpower': { - category: 'fortinet', - description: 'Operating TX power ', - name: 'fortinet.firewall.opertxpower', - type: 'integer', - }, - 'fortinet.firewall.osname': { - category: 'fortinet', - description: 'Operating System name ', - name: 'fortinet.firewall.osname', - type: 'keyword', - }, - 'fortinet.firewall.osversion': { - category: 'fortinet', - description: 'Operating System version ', - name: 'fortinet.firewall.osversion', - type: 'keyword', - }, - 'fortinet.firewall.out_spi': { - category: 'fortinet', - description: 'Out SPI ', - name: 'fortinet.firewall.out_spi', - type: 'keyword', - }, - 'fortinet.firewall.outintf': { - category: 'fortinet', - description: 'Out interface ', - name: 'fortinet.firewall.outintf', - type: 'keyword', - }, - 'fortinet.firewall.passedcount': { - category: 'fortinet', - description: 'Fabric passed count ', - name: 'fortinet.firewall.passedcount', - type: 'integer', - }, - 'fortinet.firewall.passwd': { - category: 'fortinet', - description: 'Changed user password information ', - name: 'fortinet.firewall.passwd', - type: 'keyword', - }, - 'fortinet.firewall.path': { - category: 'fortinet', - description: 'Path of looped configuration for security fabric ', - name: 'fortinet.firewall.path', - type: 'keyword', - }, - 'fortinet.firewall.peer': { - category: 'fortinet', - description: 'WAN optimization peer ', - name: 'fortinet.firewall.peer', - type: 'keyword', - }, - 'fortinet.firewall.peer_notif': { - category: 'fortinet', - description: 'VPN peer notification ', - name: 'fortinet.firewall.peer_notif', - type: 'keyword', - }, - 'fortinet.firewall.phase2_name': { - category: 'fortinet', - description: 'VPN phase2 name ', - name: 'fortinet.firewall.phase2_name', - type: 'keyword', - }, - 'fortinet.firewall.phone': { - category: 'fortinet', - description: 'VOIP Phone ', - name: 'fortinet.firewall.phone', - type: 'keyword', - }, - 'fortinet.firewall.pid': { - category: 'fortinet', - description: 'Process ID ', - name: 'fortinet.firewall.pid', - type: 'integer', - }, - 'fortinet.firewall.policytype': { - category: 'fortinet', - description: 'Policy Type ', - name: 'fortinet.firewall.policytype', - type: 'keyword', - }, - 'fortinet.firewall.poolname': { - category: 'fortinet', - description: 'IP Pool name ', - name: 'fortinet.firewall.poolname', - type: 'keyword', - }, - 'fortinet.firewall.port': { - category: 'fortinet', - description: 'Log upload error port ', - name: 'fortinet.firewall.port', - type: 'integer', - }, - 'fortinet.firewall.portbegin': { - category: 'fortinet', - description: 'IP Pool port number to begin ', - name: 'fortinet.firewall.portbegin', - type: 'integer', - }, - 'fortinet.firewall.portend': { - category: 'fortinet', - description: 'IP Pool port number to end ', - name: 'fortinet.firewall.portend', - type: 'integer', - }, - 'fortinet.firewall.probeproto': { - category: 'fortinet', - description: 'Link Monitor Probe Protocol ', - name: 'fortinet.firewall.probeproto', - type: 'keyword', - }, - 'fortinet.firewall.process': { - category: 'fortinet', - description: 'URL Filter process ', - name: 'fortinet.firewall.process', - type: 'keyword', - }, - 'fortinet.firewall.processtime': { - category: 'fortinet', - description: 'Process time for reports ', - name: 'fortinet.firewall.processtime', - type: 'integer', - }, - 'fortinet.firewall.profile': { - category: 'fortinet', - description: 'Profile Name ', - name: 'fortinet.firewall.profile', - type: 'keyword', - }, - 'fortinet.firewall.profile_vd': { - category: 'fortinet', - description: 'Virtual Domain Name ', - name: 'fortinet.firewall.profile_vd', - type: 'keyword', - }, - 'fortinet.firewall.profilegroup': { - category: 'fortinet', - description: 'Profile Group Name ', - name: 'fortinet.firewall.profilegroup', - type: 'keyword', - }, - 'fortinet.firewall.profiletype': { - category: 'fortinet', - description: 'Profile Type ', - name: 'fortinet.firewall.profiletype', - type: 'keyword', - }, - 'fortinet.firewall.qtypeval': { - category: 'fortinet', - description: 'DNS question type value ', - name: 'fortinet.firewall.qtypeval', - type: 'integer', - }, - 'fortinet.firewall.quarskip': { - category: 'fortinet', - description: 'Quarantine skip explanation ', - name: 'fortinet.firewall.quarskip', - type: 'keyword', - }, - 'fortinet.firewall.quotaexceeded': { - category: 'fortinet', - description: 'If quota has been exceeded ', - name: 'fortinet.firewall.quotaexceeded', - type: 'keyword', - }, - 'fortinet.firewall.quotamax': { - category: 'fortinet', - description: 'Maximum quota allowed - in seconds if time-based - in bytes if traffic-based ', - name: 'fortinet.firewall.quotamax', - type: 'long', - }, - 'fortinet.firewall.quotatype': { - category: 'fortinet', - description: 'Quota type ', - name: 'fortinet.firewall.quotatype', - type: 'keyword', - }, - 'fortinet.firewall.quotaused': { - category: 'fortinet', - description: 'Quota used - in seconds if time-based - in bytes if trafficbased) ', - name: 'fortinet.firewall.quotaused', - type: 'long', - }, - 'fortinet.firewall.radioband': { - category: 'fortinet', - description: 'Radio band ', - name: 'fortinet.firewall.radioband', - type: 'keyword', - }, - 'fortinet.firewall.radioid': { - category: 'fortinet', - description: 'Radio ID ', - name: 'fortinet.firewall.radioid', - type: 'integer', - }, - 'fortinet.firewall.radioidclosest': { - category: 'fortinet', - description: 'Radio ID on the AP closest the rogue AP ', - name: 'fortinet.firewall.radioidclosest', - type: 'integer', - }, - 'fortinet.firewall.radioiddetected': { - category: 'fortinet', - description: 'Radio ID on the AP which detected the rogue AP ', - name: 'fortinet.firewall.radioiddetected', - type: 'integer', - }, - 'fortinet.firewall.rate': { - category: 'fortinet', - description: 'Wireless rogue rate value ', - name: 'fortinet.firewall.rate', - type: 'keyword', - }, - 'fortinet.firewall.rawdata': { - category: 'fortinet', - description: 'Raw data value ', - name: 'fortinet.firewall.rawdata', - type: 'keyword', - }, - 'fortinet.firewall.rawdataid': { - category: 'fortinet', - description: 'Raw data ID ', - name: 'fortinet.firewall.rawdataid', - type: 'keyword', - }, - 'fortinet.firewall.rcvddelta': { - category: 'fortinet', - description: 'Received bytes delta ', - name: 'fortinet.firewall.rcvddelta', - type: 'keyword', - }, - 'fortinet.firewall.reason': { - category: 'fortinet', - description: 'Alert reason ', - name: 'fortinet.firewall.reason', - type: 'keyword', - }, - 'fortinet.firewall.received': { - category: 'fortinet', - description: 'Server key exchange received ', - name: 'fortinet.firewall.received', - type: 'integer', - }, - 'fortinet.firewall.receivedsignature': { - category: 'fortinet', - description: 'Server key exchange received signature ', - name: 'fortinet.firewall.receivedsignature', - type: 'keyword', - }, - 'fortinet.firewall.red': { - category: 'fortinet', - description: 'Memory information in red ', - name: 'fortinet.firewall.red', - type: 'keyword', - }, - 'fortinet.firewall.referralurl': { - category: 'fortinet', - description: 'Web filter referralurl ', - name: 'fortinet.firewall.referralurl', - type: 'keyword', - }, - 'fortinet.firewall.remote': { - category: 'fortinet', - description: 'Remote PPP IP address ', - name: 'fortinet.firewall.remote', - type: 'ip', - }, - 'fortinet.firewall.remotewtptime': { - category: 'fortinet', - description: 'Remote Wifi Radius authentication time ', - name: 'fortinet.firewall.remotewtptime', - type: 'keyword', - }, - 'fortinet.firewall.reporttype': { - category: 'fortinet', - description: 'Report type ', - name: 'fortinet.firewall.reporttype', - type: 'keyword', - }, - 'fortinet.firewall.reqtype': { - category: 'fortinet', - description: 'Request type ', - name: 'fortinet.firewall.reqtype', - type: 'keyword', - }, - 'fortinet.firewall.request_name': { - category: 'fortinet', - description: 'VOIP request name ', - name: 'fortinet.firewall.request_name', - type: 'keyword', - }, - 'fortinet.firewall.result': { - category: 'fortinet', - description: 'VPN phase result ', - name: 'fortinet.firewall.result', - type: 'keyword', - }, - 'fortinet.firewall.role': { - category: 'fortinet', - description: 'VPN Phase 2 role ', - name: 'fortinet.firewall.role', - type: 'keyword', - }, - 'fortinet.firewall.rssi': { - category: 'fortinet', - description: 'Received signal strength indicator ', - name: 'fortinet.firewall.rssi', - type: 'integer', - }, - 'fortinet.firewall.rsso_key': { - category: 'fortinet', - description: 'RADIUS SSO attribute value ', - name: 'fortinet.firewall.rsso_key', - type: 'keyword', - }, - 'fortinet.firewall.ruledata': { - category: 'fortinet', - description: 'Rule data ', - name: 'fortinet.firewall.ruledata', - type: 'keyword', - }, - 'fortinet.firewall.ruletype': { - category: 'fortinet', - description: 'Rule type ', - name: 'fortinet.firewall.ruletype', - type: 'keyword', - }, - 'fortinet.firewall.scanned': { - category: 'fortinet', - description: 'Number of Scanned MMSs ', - name: 'fortinet.firewall.scanned', - type: 'integer', - }, - 'fortinet.firewall.scantime': { - category: 'fortinet', - description: 'Scanned time ', - name: 'fortinet.firewall.scantime', - type: 'long', - }, - 'fortinet.firewall.scope': { - category: 'fortinet', - description: 'FortiGuard Override Scope ', - name: 'fortinet.firewall.scope', - type: 'keyword', - }, - 'fortinet.firewall.security': { - category: 'fortinet', - description: 'Wireless rogue security ', - name: 'fortinet.firewall.security', - type: 'keyword', - }, - 'fortinet.firewall.sensitivity': { - category: 'fortinet', - description: 'Sensitivity for document fingerprint ', - name: 'fortinet.firewall.sensitivity', - type: 'keyword', - }, - 'fortinet.firewall.sensor': { - category: 'fortinet', - description: 'NAC Sensor Name ', - name: 'fortinet.firewall.sensor', - type: 'keyword', - }, - 'fortinet.firewall.sentdelta': { - category: 'fortinet', - description: 'Sent bytes delta ', - name: 'fortinet.firewall.sentdelta', - type: 'keyword', - }, - 'fortinet.firewall.seq': { - category: 'fortinet', - description: 'Sequence number ', - name: 'fortinet.firewall.seq', - type: 'keyword', - }, - 'fortinet.firewall.serial': { - category: 'fortinet', - description: 'WAN optimisation serial ', - name: 'fortinet.firewall.serial', - type: 'keyword', - }, - 'fortinet.firewall.serialno': { - category: 'fortinet', - description: 'Serial number ', - name: 'fortinet.firewall.serialno', - type: 'keyword', - }, - 'fortinet.firewall.server': { - category: 'fortinet', - description: 'AD server FQDN or IP ', - name: 'fortinet.firewall.server', - type: 'keyword', - }, - 'fortinet.firewall.session_id': { - category: 'fortinet', - description: 'Session ID ', - name: 'fortinet.firewall.session_id', - type: 'keyword', - }, - 'fortinet.firewall.sessionid': { - category: 'fortinet', - description: 'WAD Session ID ', - name: 'fortinet.firewall.sessionid', - type: 'integer', - }, - 'fortinet.firewall.setuprate': { - category: 'fortinet', - description: 'Session Setup Rate ', - name: 'fortinet.firewall.setuprate', - type: 'long', - }, - 'fortinet.firewall.severity': { - category: 'fortinet', - description: 'Severity ', - name: 'fortinet.firewall.severity', - type: 'keyword', - }, - 'fortinet.firewall.shaperdroprcvdbyte': { - category: 'fortinet', - description: 'Received bytes dropped by shaper ', - name: 'fortinet.firewall.shaperdroprcvdbyte', - type: 'integer', - }, - 'fortinet.firewall.shaperdropsentbyte': { - category: 'fortinet', - description: 'Sent bytes dropped by shaper ', - name: 'fortinet.firewall.shaperdropsentbyte', - type: 'integer', - }, - 'fortinet.firewall.shaperperipdropbyte': { - category: 'fortinet', - description: 'Dropped bytes per IP by shaper ', - name: 'fortinet.firewall.shaperperipdropbyte', - type: 'integer', - }, - 'fortinet.firewall.shaperperipname': { - category: 'fortinet', - description: 'Traffic shaper name (per IP) ', - name: 'fortinet.firewall.shaperperipname', - type: 'keyword', - }, - 'fortinet.firewall.shaperrcvdname': { - category: 'fortinet', - description: 'Traffic shaper name for received traffic ', - name: 'fortinet.firewall.shaperrcvdname', - type: 'keyword', - }, - 'fortinet.firewall.shapersentname': { - category: 'fortinet', - description: 'Traffic shaper name for sent traffic ', - name: 'fortinet.firewall.shapersentname', - type: 'keyword', - }, - 'fortinet.firewall.shapingpolicyid': { - category: 'fortinet', - description: 'Traffic shaper policy ID ', - name: 'fortinet.firewall.shapingpolicyid', - type: 'integer', - }, - 'fortinet.firewall.signal': { - category: 'fortinet', - description: 'Wireless rogue API signal ', - name: 'fortinet.firewall.signal', - type: 'integer', - }, - 'fortinet.firewall.size': { - category: 'fortinet', - description: 'Email size in bytes ', - name: 'fortinet.firewall.size', - type: 'long', - }, - 'fortinet.firewall.slot': { - category: 'fortinet', - description: 'Slot number ', - name: 'fortinet.firewall.slot', - type: 'integer', - }, - 'fortinet.firewall.sn': { - category: 'fortinet', - description: 'Security fabric serial number ', - name: 'fortinet.firewall.sn', - type: 'keyword', - }, - 'fortinet.firewall.snclosest': { - category: 'fortinet', - description: 'SN of the AP closest to the rogue AP ', - name: 'fortinet.firewall.snclosest', - type: 'keyword', - }, - 'fortinet.firewall.sndetected': { - category: 'fortinet', - description: 'SN of the AP which detected the rogue AP ', - name: 'fortinet.firewall.sndetected', - type: 'keyword', - }, - 'fortinet.firewall.snmeshparent': { - category: 'fortinet', - description: 'SN of the mesh parent ', - name: 'fortinet.firewall.snmeshparent', - type: 'keyword', - }, - 'fortinet.firewall.spi': { - category: 'fortinet', - description: 'IPSEC SPI ', - name: 'fortinet.firewall.spi', - type: 'keyword', - }, - 'fortinet.firewall.src_int': { - category: 'fortinet', - description: 'Source interface ', - name: 'fortinet.firewall.src_int', - type: 'keyword', - }, - 'fortinet.firewall.srcintfrole': { - category: 'fortinet', - description: 'Source interface role ', - name: 'fortinet.firewall.srcintfrole', - type: 'keyword', - }, - 'fortinet.firewall.srccountry': { - category: 'fortinet', - description: 'Source country ', - name: 'fortinet.firewall.srccountry', - type: 'keyword', - }, - 'fortinet.firewall.srcfamily': { - category: 'fortinet', - description: 'Source family ', - name: 'fortinet.firewall.srcfamily', - type: 'keyword', - }, - 'fortinet.firewall.srchwvendor': { - category: 'fortinet', - description: 'Source hardware vendor ', - name: 'fortinet.firewall.srchwvendor', - type: 'keyword', - }, - 'fortinet.firewall.srchwversion': { - category: 'fortinet', - description: 'Source hardware version ', - name: 'fortinet.firewall.srchwversion', - type: 'keyword', - }, - 'fortinet.firewall.srcinetsvc': { - category: 'fortinet', - description: 'Source interface service ', - name: 'fortinet.firewall.srcinetsvc', - type: 'keyword', - }, - 'fortinet.firewall.srcname': { - category: 'fortinet', - description: 'Source name ', - name: 'fortinet.firewall.srcname', - type: 'keyword', - }, - 'fortinet.firewall.srcserver': { - category: 'fortinet', - description: 'Source server ', - name: 'fortinet.firewall.srcserver', - type: 'integer', - }, - 'fortinet.firewall.srcssid': { - category: 'fortinet', - description: 'Source SSID ', - name: 'fortinet.firewall.srcssid', - type: 'keyword', - }, - 'fortinet.firewall.srcswversion': { - category: 'fortinet', - description: 'Source software version ', - name: 'fortinet.firewall.srcswversion', - type: 'keyword', - }, - 'fortinet.firewall.srcuuid': { - category: 'fortinet', - description: 'Source UUID ', - name: 'fortinet.firewall.srcuuid', - type: 'keyword', - }, - 'fortinet.firewall.sscname': { - category: 'fortinet', - description: 'SSC name ', - name: 'fortinet.firewall.sscname', - type: 'keyword', - }, - 'fortinet.firewall.ssid': { - category: 'fortinet', - description: 'Base Service Set ID ', - name: 'fortinet.firewall.ssid', - type: 'keyword', - }, - 'fortinet.firewall.sslaction': { - category: 'fortinet', - description: 'SSL Action ', - name: 'fortinet.firewall.sslaction', - type: 'keyword', - }, - 'fortinet.firewall.ssllocal': { - category: 'fortinet', - description: 'WAD SSL local ', - name: 'fortinet.firewall.ssllocal', - type: 'keyword', - }, - 'fortinet.firewall.sslremote': { - category: 'fortinet', - description: 'WAD SSL remote ', - name: 'fortinet.firewall.sslremote', - type: 'keyword', - }, - 'fortinet.firewall.stacount': { - category: 'fortinet', - description: 'Number of stations/clients ', - name: 'fortinet.firewall.stacount', - type: 'integer', - }, - 'fortinet.firewall.stage': { - category: 'fortinet', - description: 'IPSEC stage ', - name: 'fortinet.firewall.stage', - type: 'keyword', - }, - 'fortinet.firewall.stamac': { - category: 'fortinet', - description: '802.1x station mac ', - name: 'fortinet.firewall.stamac', - type: 'keyword', - }, - 'fortinet.firewall.state': { - category: 'fortinet', - description: 'Admin login state ', - name: 'fortinet.firewall.state', - type: 'keyword', - }, - 'fortinet.firewall.status': { - category: 'fortinet', - description: 'Status ', - name: 'fortinet.firewall.status', - type: 'keyword', - }, - 'fortinet.firewall.stitch': { - category: 'fortinet', - description: 'Automation stitch triggered ', - name: 'fortinet.firewall.stitch', - type: 'keyword', - }, - 'fortinet.firewall.subject': { - category: 'fortinet', - description: 'Email subject ', - name: 'fortinet.firewall.subject', - type: 'keyword', - }, - 'fortinet.firewall.submodule': { - category: 'fortinet', - description: 'Configuration Sub-Module Name ', - name: 'fortinet.firewall.submodule', - type: 'keyword', - }, - 'fortinet.firewall.subservice': { - category: 'fortinet', - description: 'AV subservice ', - name: 'fortinet.firewall.subservice', - type: 'keyword', - }, - 'fortinet.firewall.subtype': { - category: 'fortinet', - description: 'Log subtype ', - name: 'fortinet.firewall.subtype', - type: 'keyword', - }, - 'fortinet.firewall.suspicious': { - category: 'fortinet', - description: 'Number of Suspicious MMSs ', - name: 'fortinet.firewall.suspicious', - type: 'integer', - }, - 'fortinet.firewall.switchproto': { - category: 'fortinet', - description: 'Protocol change information ', - name: 'fortinet.firewall.switchproto', - type: 'keyword', - }, - 'fortinet.firewall.sync_status': { - category: 'fortinet', - description: 'The sync status with the master ', - name: 'fortinet.firewall.sync_status', - type: 'keyword', - }, - 'fortinet.firewall.sync_type': { - category: 'fortinet', - description: 'The sync type with the master ', - name: 'fortinet.firewall.sync_type', - type: 'keyword', - }, - 'fortinet.firewall.sysuptime': { - category: 'fortinet', - description: 'System uptime ', - name: 'fortinet.firewall.sysuptime', - type: 'keyword', - }, - 'fortinet.firewall.tamac': { - category: 'fortinet', - description: 'the MAC address of Transmitter, if none, then Receiver ', - name: 'fortinet.firewall.tamac', - type: 'keyword', - }, - 'fortinet.firewall.threattype': { - category: 'fortinet', - description: 'WIDS threat type ', - name: 'fortinet.firewall.threattype', - type: 'keyword', - }, - 'fortinet.firewall.time': { - category: 'fortinet', - description: 'Time of the event ', - name: 'fortinet.firewall.time', - type: 'keyword', - }, - 'fortinet.firewall.to': { - category: 'fortinet', - description: 'Email to field ', - name: 'fortinet.firewall.to', - type: 'keyword', - }, - 'fortinet.firewall.to_vcluster': { - category: 'fortinet', - description: 'destination virtual cluster number ', - name: 'fortinet.firewall.to_vcluster', - type: 'integer', - }, - 'fortinet.firewall.total': { - category: 'fortinet', - description: 'Total memory ', - name: 'fortinet.firewall.total', - type: 'integer', - }, - 'fortinet.firewall.totalsession': { - category: 'fortinet', - description: 'Total Number of Sessions ', - name: 'fortinet.firewall.totalsession', - type: 'integer', - }, - 'fortinet.firewall.trace_id': { - category: 'fortinet', - description: 'Session clash trace ID ', - name: 'fortinet.firewall.trace_id', - type: 'keyword', - }, - 'fortinet.firewall.trandisp': { - category: 'fortinet', - description: 'NAT translation type ', - name: 'fortinet.firewall.trandisp', - type: 'keyword', - }, - 'fortinet.firewall.transid': { - category: 'fortinet', - description: 'HTTP transaction ID ', - name: 'fortinet.firewall.transid', - type: 'integer', - }, - 'fortinet.firewall.translationid': { - category: 'fortinet', - description: 'DNS filter transaltion ID ', - name: 'fortinet.firewall.translationid', - type: 'keyword', - }, - 'fortinet.firewall.trigger': { - category: 'fortinet', - description: 'Automation stitch trigger ', - name: 'fortinet.firewall.trigger', - type: 'keyword', - }, - 'fortinet.firewall.trueclntip': { - category: 'fortinet', - description: 'File filter true client IP ', - name: 'fortinet.firewall.trueclntip', - type: 'ip', - }, - 'fortinet.firewall.tunnelid': { - category: 'fortinet', - description: 'IPSEC tunnel ID ', - name: 'fortinet.firewall.tunnelid', - type: 'integer', - }, - 'fortinet.firewall.tunnelip': { - category: 'fortinet', - description: 'IPSEC tunnel IP ', - name: 'fortinet.firewall.tunnelip', - type: 'ip', - }, - 'fortinet.firewall.tunneltype': { - category: 'fortinet', - description: 'IPSEC tunnel type ', - name: 'fortinet.firewall.tunneltype', - type: 'keyword', - }, - 'fortinet.firewall.type': { - category: 'fortinet', - description: 'Module type ', - name: 'fortinet.firewall.type', - type: 'keyword', - }, - 'fortinet.firewall.ui': { - category: 'fortinet', - description: 'Admin authentication UI type ', - name: 'fortinet.firewall.ui', - type: 'keyword', - }, - 'fortinet.firewall.unauthusersource': { - category: 'fortinet', - description: 'Unauthenticated user source ', - name: 'fortinet.firewall.unauthusersource', - type: 'keyword', - }, - 'fortinet.firewall.unit': { - category: 'fortinet', - description: 'Power supply unit ', - name: 'fortinet.firewall.unit', - type: 'integer', - }, - 'fortinet.firewall.urlfilteridx': { - category: 'fortinet', - description: 'URL filter ID ', - name: 'fortinet.firewall.urlfilteridx', - type: 'integer', - }, - 'fortinet.firewall.urlfilterlist': { - category: 'fortinet', - description: 'URL filter list ', - name: 'fortinet.firewall.urlfilterlist', - type: 'keyword', - }, - 'fortinet.firewall.urlsource': { - category: 'fortinet', - description: 'URL filter source ', - name: 'fortinet.firewall.urlsource', - type: 'keyword', - }, - 'fortinet.firewall.urltype': { - category: 'fortinet', - description: 'URL filter type ', - name: 'fortinet.firewall.urltype', - type: 'keyword', - }, - 'fortinet.firewall.used': { - category: 'fortinet', - description: 'Number of Used IPs ', - name: 'fortinet.firewall.used', - type: 'integer', - }, - 'fortinet.firewall.used_for_type': { - category: 'fortinet', - description: 'Connection for the type ', - name: 'fortinet.firewall.used_for_type', - type: 'integer', - }, - 'fortinet.firewall.utmaction': { - category: 'fortinet', - description: 'Security action performed by UTM ', - name: 'fortinet.firewall.utmaction', - type: 'keyword', - }, - 'fortinet.firewall.utmref': { - category: 'fortinet', - description: 'Reference to UTM ', - name: 'fortinet.firewall.utmref', - type: 'keyword', - }, - 'fortinet.firewall.vap': { - category: 'fortinet', - description: 'Virtual AP ', - name: 'fortinet.firewall.vap', - type: 'keyword', - }, - 'fortinet.firewall.vapmode': { - category: 'fortinet', - description: 'Virtual AP mode ', - name: 'fortinet.firewall.vapmode', - type: 'keyword', - }, - 'fortinet.firewall.vcluster': { - category: 'fortinet', - description: 'virtual cluster id ', - name: 'fortinet.firewall.vcluster', - type: 'integer', - }, - 'fortinet.firewall.vcluster_member': { - category: 'fortinet', - description: 'Virtual cluster member ', - name: 'fortinet.firewall.vcluster_member', - type: 'integer', - }, - 'fortinet.firewall.vcluster_state': { - category: 'fortinet', - description: 'Virtual cluster state ', - name: 'fortinet.firewall.vcluster_state', - type: 'keyword', - }, - 'fortinet.firewall.vd': { - category: 'fortinet', - description: 'Virtual Domain Name ', - name: 'fortinet.firewall.vd', - type: 'keyword', - }, - 'fortinet.firewall.vdname': { - category: 'fortinet', - description: 'Virtual Domain Name ', - name: 'fortinet.firewall.vdname', - type: 'keyword', - }, - 'fortinet.firewall.vendorurl': { - category: 'fortinet', - description: 'Vulnerability scan vendor name ', - name: 'fortinet.firewall.vendorurl', - type: 'keyword', - }, - 'fortinet.firewall.version': { - category: 'fortinet', - description: 'Version ', - name: 'fortinet.firewall.version', - type: 'keyword', - }, - 'fortinet.firewall.vip': { - category: 'fortinet', - description: 'Virtual IP ', - name: 'fortinet.firewall.vip', - type: 'keyword', - }, - 'fortinet.firewall.virus': { - category: 'fortinet', - description: 'Virus name ', - name: 'fortinet.firewall.virus', - type: 'keyword', - }, - 'fortinet.firewall.virusid': { - category: 'fortinet', - description: 'Virus ID (unique virus identifier) ', - name: 'fortinet.firewall.virusid', - type: 'integer', - }, - 'fortinet.firewall.voip_proto': { - category: 'fortinet', - description: 'VOIP protocol ', - name: 'fortinet.firewall.voip_proto', - type: 'keyword', - }, - 'fortinet.firewall.vpn': { - category: 'fortinet', - description: 'VPN description ', - name: 'fortinet.firewall.vpn', - type: 'keyword', - }, - 'fortinet.firewall.vpntunnel': { - category: 'fortinet', - description: 'IPsec Vpn Tunnel Name ', - name: 'fortinet.firewall.vpntunnel', - type: 'keyword', - }, - 'fortinet.firewall.vpntype': { - category: 'fortinet', - description: 'The type of the VPN tunnel ', - name: 'fortinet.firewall.vpntype', - type: 'keyword', - }, - 'fortinet.firewall.vrf': { - category: 'fortinet', - description: 'VRF number ', - name: 'fortinet.firewall.vrf', - type: 'integer', - }, - 'fortinet.firewall.vulncat': { - category: 'fortinet', - description: 'Vulnerability Category ', - name: 'fortinet.firewall.vulncat', - type: 'keyword', - }, - 'fortinet.firewall.vulnid': { - category: 'fortinet', - description: 'Vulnerability ID ', - name: 'fortinet.firewall.vulnid', - type: 'integer', - }, - 'fortinet.firewall.vulnname': { - category: 'fortinet', - description: 'Vulnerability name ', - name: 'fortinet.firewall.vulnname', - type: 'keyword', - }, - 'fortinet.firewall.vwlid': { - category: 'fortinet', - description: 'VWL ID ', - name: 'fortinet.firewall.vwlid', - type: 'integer', - }, - 'fortinet.firewall.vwlquality': { - category: 'fortinet', - description: 'VWL quality ', - name: 'fortinet.firewall.vwlquality', - type: 'keyword', - }, - 'fortinet.firewall.vwlservice': { - category: 'fortinet', - description: 'VWL service ', - name: 'fortinet.firewall.vwlservice', - type: 'keyword', - }, - 'fortinet.firewall.vwpvlanid': { - category: 'fortinet', - description: 'VWP VLAN ID ', - name: 'fortinet.firewall.vwpvlanid', - type: 'integer', - }, - 'fortinet.firewall.wanin': { - category: 'fortinet', - description: 'WAN incoming traffic in bytes ', - name: 'fortinet.firewall.wanin', - type: 'long', - }, - 'fortinet.firewall.wanoptapptype': { - category: 'fortinet', - description: 'WAN Optimization Application type ', - name: 'fortinet.firewall.wanoptapptype', - type: 'keyword', - }, - 'fortinet.firewall.wanout': { - category: 'fortinet', - description: 'WAN outgoing traffic in bytes ', - name: 'fortinet.firewall.wanout', - type: 'long', - }, - 'fortinet.firewall.weakwepiv': { - category: 'fortinet', - description: 'Weak Wep Initiation Vector ', - name: 'fortinet.firewall.weakwepiv', - type: 'keyword', - }, - 'fortinet.firewall.xauthgroup': { - category: 'fortinet', - description: 'XAuth Group Name ', - name: 'fortinet.firewall.xauthgroup', - type: 'keyword', - }, - 'fortinet.firewall.xauthuser': { - category: 'fortinet', - description: 'XAuth User Name ', - name: 'fortinet.firewall.xauthuser', - type: 'keyword', - }, - 'fortinet.firewall.xid': { - category: 'fortinet', - description: 'Wireless X ID ', - name: 'fortinet.firewall.xid', - type: 'integer', - }, - 'gcp.destination.instance.project_id': { - category: 'gcp', - description: 'ID of the project containing the VM. ', - name: 'gcp.destination.instance.project_id', - type: 'keyword', - }, - 'gcp.destination.instance.region': { - category: 'gcp', - description: 'Region of the VM. ', - name: 'gcp.destination.instance.region', - type: 'keyword', - }, - 'gcp.destination.instance.zone': { - category: 'gcp', - description: 'Zone of the VM. ', - name: 'gcp.destination.instance.zone', - type: 'keyword', - }, - 'gcp.destination.vpc.project_id': { - category: 'gcp', - description: 'ID of the project containing the VM. ', - name: 'gcp.destination.vpc.project_id', - type: 'keyword', - }, - 'gcp.destination.vpc.vpc_name': { - category: 'gcp', - description: 'VPC on which the VM is operating. ', - name: 'gcp.destination.vpc.vpc_name', - type: 'keyword', - }, - 'gcp.destination.vpc.subnetwork_name': { - category: 'gcp', - description: 'Subnetwork on which the VM is operating. ', - name: 'gcp.destination.vpc.subnetwork_name', - type: 'keyword', - }, - 'gcp.source.instance.project_id': { - category: 'gcp', - description: 'ID of the project containing the VM. ', - name: 'gcp.source.instance.project_id', - type: 'keyword', - }, - 'gcp.source.instance.region': { - category: 'gcp', - description: 'Region of the VM. ', - name: 'gcp.source.instance.region', - type: 'keyword', - }, - 'gcp.source.instance.zone': { - category: 'gcp', - description: 'Zone of the VM. ', - name: 'gcp.source.instance.zone', - type: 'keyword', - }, - 'gcp.source.vpc.project_id': { - category: 'gcp', - description: 'ID of the project containing the VM. ', - name: 'gcp.source.vpc.project_id', - type: 'keyword', - }, - 'gcp.source.vpc.vpc_name': { - category: 'gcp', - description: 'VPC on which the VM is operating. ', - name: 'gcp.source.vpc.vpc_name', - type: 'keyword', - }, - 'gcp.source.vpc.subnetwork_name': { - category: 'gcp', - description: 'Subnetwork on which the VM is operating. ', - name: 'gcp.source.vpc.subnetwork_name', - type: 'keyword', - }, - 'gcp.audit.type': { - category: 'gcp', - description: 'Type property. ', - name: 'gcp.audit.type', - type: 'keyword', - }, - 'gcp.audit.authentication_info.principal_email': { - category: 'gcp', - description: 'The email address of the authenticated user making the request. ', - name: 'gcp.audit.authentication_info.principal_email', - type: 'keyword', - }, - 'gcp.audit.authentication_info.authority_selector': { - category: 'gcp', - description: - 'The authority selector specified by the requestor, if any. It is not guaranteed that the principal was allowed to use this authority. ', - name: 'gcp.audit.authentication_info.authority_selector', - type: 'keyword', - }, - 'gcp.audit.authorization_info.permission': { - category: 'gcp', - description: 'The required IAM permission. ', - name: 'gcp.audit.authorization_info.permission', - type: 'keyword', - }, - 'gcp.audit.authorization_info.granted': { - category: 'gcp', - description: 'Whether or not authorization for resource and permission was granted. ', - name: 'gcp.audit.authorization_info.granted', - type: 'boolean', - }, - 'gcp.audit.authorization_info.resource_attributes.service': { - category: 'gcp', - description: 'The name of the service. ', - name: 'gcp.audit.authorization_info.resource_attributes.service', - type: 'keyword', - }, - 'gcp.audit.authorization_info.resource_attributes.name': { - category: 'gcp', - description: 'The name of the resource. ', - name: 'gcp.audit.authorization_info.resource_attributes.name', - type: 'keyword', - }, - 'gcp.audit.authorization_info.resource_attributes.type': { - category: 'gcp', - description: 'The type of the resource. ', - name: 'gcp.audit.authorization_info.resource_attributes.type', - type: 'keyword', - }, - 'gcp.audit.method_name': { - category: 'gcp', - description: - "The name of the service method or operation. For API calls, this should be the name of the API method. For example, 'google.datastore.v1.Datastore.RunQuery'. ", - name: 'gcp.audit.method_name', - type: 'keyword', - }, - 'gcp.audit.num_response_items': { - category: 'gcp', - description: 'The number of items returned from a List or Query API method, if applicable. ', - name: 'gcp.audit.num_response_items', - type: 'long', - }, - 'gcp.audit.request.proto_name': { - category: 'gcp', - description: 'Type property of the request. ', - name: 'gcp.audit.request.proto_name', - type: 'keyword', - }, - 'gcp.audit.request.filter': { - category: 'gcp', - description: 'Filter of the request. ', - name: 'gcp.audit.request.filter', - type: 'keyword', - }, - 'gcp.audit.request.name': { - category: 'gcp', - description: 'Name of the request. ', - name: 'gcp.audit.request.name', - type: 'keyword', - }, - 'gcp.audit.request.resource_name': { - category: 'gcp', - description: 'Name of the request resource. ', - name: 'gcp.audit.request.resource_name', - type: 'keyword', - }, - 'gcp.audit.request_metadata.caller_ip': { - category: 'gcp', - description: 'The IP address of the caller. ', - name: 'gcp.audit.request_metadata.caller_ip', - type: 'ip', - }, - 'gcp.audit.request_metadata.caller_supplied_user_agent': { - category: 'gcp', - description: - 'The user agent of the caller. This information is not authenticated and should be treated accordingly. ', - name: 'gcp.audit.request_metadata.caller_supplied_user_agent', - type: 'keyword', - }, - 'gcp.audit.response.proto_name': { - category: 'gcp', - description: 'Type property of the response. ', - name: 'gcp.audit.response.proto_name', - type: 'keyword', - }, - 'gcp.audit.response.details.group': { - category: 'gcp', - description: 'The name of the group. ', - name: 'gcp.audit.response.details.group', - type: 'keyword', - }, - 'gcp.audit.response.details.kind': { - category: 'gcp', - description: 'The kind of the response details. ', - name: 'gcp.audit.response.details.kind', - type: 'keyword', - }, - 'gcp.audit.response.details.name': { - category: 'gcp', - description: 'The name of the response details. ', - name: 'gcp.audit.response.details.name', - type: 'keyword', - }, - 'gcp.audit.response.details.uid': { - category: 'gcp', - description: 'The uid of the response details. ', - name: 'gcp.audit.response.details.uid', - type: 'keyword', - }, - 'gcp.audit.response.status': { - category: 'gcp', - description: 'Status of the response. ', - name: 'gcp.audit.response.status', - type: 'keyword', - }, - 'gcp.audit.resource_name': { - category: 'gcp', - description: - "The resource or collection that is the target of the operation. The name is a scheme-less URI, not including the API service name. For example, 'shelves/SHELF_ID/books'. ", - name: 'gcp.audit.resource_name', - type: 'keyword', - }, - 'gcp.audit.resource_location.current_locations': { - category: 'gcp', - description: 'Current locations of the resource. ', - name: 'gcp.audit.resource_location.current_locations', - type: 'keyword', - }, - 'gcp.audit.service_name': { - category: 'gcp', - description: - 'The name of the API service performing the operation. For example, datastore.googleapis.com. ', - name: 'gcp.audit.service_name', - type: 'keyword', - }, - 'gcp.audit.status.code': { - category: 'gcp', - description: 'The status code, which should be an enum value of google.rpc.Code. ', - name: 'gcp.audit.status.code', - type: 'integer', - }, - 'gcp.audit.status.message': { - category: 'gcp', - description: - 'A developer-facing error message, which should be in English. Any user-facing error message should be localized and sent in the google.rpc.Status.details field, or localized by the client. ', - name: 'gcp.audit.status.message', - type: 'keyword', - }, - 'gcp.firewall.rule_details.priority': { - category: 'gcp', - description: 'The priority for the firewall rule.', - name: 'gcp.firewall.rule_details.priority', - type: 'long', - }, - 'gcp.firewall.rule_details.action': { - category: 'gcp', - description: 'Action that the rule performs on match.', - name: 'gcp.firewall.rule_details.action', - type: 'keyword', - }, - 'gcp.firewall.rule_details.direction': { - category: 'gcp', - description: 'Direction of traffic that matches this rule.', - name: 'gcp.firewall.rule_details.direction', - type: 'keyword', - }, - 'gcp.firewall.rule_details.reference': { - category: 'gcp', - description: 'Reference to the firewall rule.', - name: 'gcp.firewall.rule_details.reference', - type: 'keyword', - }, - 'gcp.firewall.rule_details.source_range': { - category: 'gcp', - description: 'List of source ranges that the firewall rule applies to.', - name: 'gcp.firewall.rule_details.source_range', - type: 'keyword', - }, - 'gcp.firewall.rule_details.destination_range': { - category: 'gcp', - description: 'List of destination ranges that the firewall applies to.', - name: 'gcp.firewall.rule_details.destination_range', - type: 'keyword', - }, - 'gcp.firewall.rule_details.source_tag': { - category: 'gcp', - description: 'List of all the source tags that the firewall rule applies to. ', - name: 'gcp.firewall.rule_details.source_tag', - type: 'keyword', - }, - 'gcp.firewall.rule_details.target_tag': { - category: 'gcp', - description: 'List of all the target tags that the firewall rule applies to. ', - name: 'gcp.firewall.rule_details.target_tag', - type: 'keyword', - }, - 'gcp.firewall.rule_details.ip_port_info': { - category: 'gcp', - description: 'List of ip protocols and applicable port ranges for rules. ', - name: 'gcp.firewall.rule_details.ip_port_info', - type: 'array', - }, - 'gcp.firewall.rule_details.source_service_account': { - category: 'gcp', - description: 'List of all the source service accounts that the firewall rule applies to. ', - name: 'gcp.firewall.rule_details.source_service_account', - type: 'keyword', - }, - 'gcp.firewall.rule_details.target_service_account': { - category: 'gcp', - description: 'List of all the target service accounts that the firewall rule applies to. ', - name: 'gcp.firewall.rule_details.target_service_account', - type: 'keyword', - }, - 'gcp.vpcflow.reporter': { - category: 'gcp', - description: "The side which reported the flow. Can be either 'SRC' or 'DEST'. ", - name: 'gcp.vpcflow.reporter', - type: 'keyword', - }, - 'gcp.vpcflow.rtt.ms': { - category: 'gcp', - description: - 'Latency as measured (for TCP flows only) during the time interval. This is the time elapsed between sending a SEQ and receiving a corresponding ACK and it contains the network RTT as well as the application related delay. ', - name: 'gcp.vpcflow.rtt.ms', - type: 'long', - }, - 'google_workspace.actor.type': { - category: 'google_workspace', - description: - 'The type of actor. Values can be: *USER*: Another user in the same domain. *EXTERNAL_USER*: A user outside the domain. *KEY*: A non-human actor. ', - name: 'google_workspace.actor.type', - type: 'keyword', - }, - 'google_workspace.actor.key': { - category: 'google_workspace', - description: - 'Only present when `actor.type` is `KEY`. Can be the `consumer_key` of the requestor for OAuth 2LO API requests or an identifier for robot accounts. ', - name: 'google_workspace.actor.key', - type: 'keyword', - }, - 'google_workspace.event.type': { - category: 'google_workspace', - description: - 'The type of Google Workspace event, mapped from `items[].events[].type` in the original payload. Each fileset can have a different set of values for it, more details can be found at https://developers.google.com/admin-sdk/reports/v1/reference/activities/list ', - example: 'audit#activity', - name: 'google_workspace.event.type', - type: 'keyword', - }, - 'google_workspace.kind': { - category: 'google_workspace', - description: - 'The type of API resource, mapped from `kind` in the original payload. More details can be found at https://developers.google.com/admin-sdk/reports/v1/reference/activities/list ', - example: 'audit#activity', - name: 'google_workspace.kind', - type: 'keyword', - }, - 'google_workspace.organization.domain': { - category: 'google_workspace', - description: "The domain that is affected by the report's event. ", - name: 'google_workspace.organization.domain', - type: 'keyword', - }, - 'google_workspace.admin.application.edition': { - category: 'google_workspace', - description: 'The Google Workspace edition.', - name: 'google_workspace.admin.application.edition', - type: 'keyword', - }, - 'google_workspace.admin.application.name': { - category: 'google_workspace', - description: "The application's name.", - name: 'google_workspace.admin.application.name', - type: 'keyword', - }, - 'google_workspace.admin.application.enabled': { - category: 'google_workspace', - description: 'The enabled application.', - name: 'google_workspace.admin.application.enabled', - type: 'keyword', - }, - 'google_workspace.admin.application.licences_order_number': { - category: 'google_workspace', - description: 'Order number used to redeem licenses.', - name: 'google_workspace.admin.application.licences_order_number', - type: 'keyword', - }, - 'google_workspace.admin.application.licences_purchased': { - category: 'google_workspace', - description: 'Number of licences purchased.', - name: 'google_workspace.admin.application.licences_purchased', - type: 'keyword', - }, - 'google_workspace.admin.application.id': { - category: 'google_workspace', - description: 'The application ID.', - name: 'google_workspace.admin.application.id', - type: 'keyword', - }, - 'google_workspace.admin.application.asp_id': { - category: 'google_workspace', - description: 'The application specific password ID.', - name: 'google_workspace.admin.application.asp_id', - type: 'keyword', - }, - 'google_workspace.admin.application.package_id': { - category: 'google_workspace', - description: 'The mobile application package ID.', - name: 'google_workspace.admin.application.package_id', - type: 'keyword', - }, - 'google_workspace.admin.group.email': { - category: 'google_workspace', - description: "The group's primary email address.", - name: 'google_workspace.admin.group.email', - type: 'keyword', - }, - 'google_workspace.admin.new_value': { - category: 'google_workspace', - description: 'The new value for the setting.', - name: 'google_workspace.admin.new_value', - type: 'keyword', - }, - 'google_workspace.admin.old_value': { - category: 'google_workspace', - description: 'The old value for the setting.', - name: 'google_workspace.admin.old_value', - type: 'keyword', - }, - 'google_workspace.admin.org_unit.name': { - category: 'google_workspace', - description: 'The organizational unit name.', - name: 'google_workspace.admin.org_unit.name', - type: 'keyword', - }, - 'google_workspace.admin.org_unit.full': { - category: 'google_workspace', - description: 'The org unit full path including the root org unit name.', - name: 'google_workspace.admin.org_unit.full', - type: 'keyword', - }, - 'google_workspace.admin.setting.name': { - category: 'google_workspace', - description: 'The setting name.', - name: 'google_workspace.admin.setting.name', - type: 'keyword', - }, - 'google_workspace.admin.user_defined_setting.name': { - category: 'google_workspace', - description: 'The name of the user-defined setting.', - name: 'google_workspace.admin.user_defined_setting.name', - type: 'keyword', - }, - 'google_workspace.admin.setting.description': { - category: 'google_workspace', - description: 'The setting name.', - name: 'google_workspace.admin.setting.description', - type: 'keyword', - }, - 'google_workspace.admin.group.priorities': { - category: 'google_workspace', - description: 'Group priorities.', - name: 'google_workspace.admin.group.priorities', - type: 'keyword', - }, - 'google_workspace.admin.domain.alias': { - category: 'google_workspace', - description: 'The domain alias.', - name: 'google_workspace.admin.domain.alias', - type: 'keyword', - }, - 'google_workspace.admin.domain.name': { - category: 'google_workspace', - description: 'The primary domain name.', - name: 'google_workspace.admin.domain.name', - type: 'keyword', - }, - 'google_workspace.admin.domain.secondary_name': { - category: 'google_workspace', - description: 'The secondary domain name.', - name: 'google_workspace.admin.domain.secondary_name', - type: 'keyword', - }, - 'google_workspace.admin.managed_configuration': { - category: 'google_workspace', - description: 'The name of the managed configuration.', - name: 'google_workspace.admin.managed_configuration', - type: 'keyword', - }, - 'google_workspace.admin.non_featured_services_selection': { - category: 'google_workspace', - description: - 'Non-featured services selection. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/admin-application-settings#FLASHLIGHT_EDU_NON_FEATURED_SERVICES_SELECTED ', - name: 'google_workspace.admin.non_featured_services_selection', - type: 'keyword', - }, - 'google_workspace.admin.field': { - category: 'google_workspace', - description: 'The name of the field.', - name: 'google_workspace.admin.field', - type: 'keyword', - }, - 'google_workspace.admin.resource.id': { - category: 'google_workspace', - description: 'The name of the resource identifier.', - name: 'google_workspace.admin.resource.id', - type: 'keyword', - }, - 'google_workspace.admin.user.email': { - category: 'google_workspace', - description: "The user's primary email address.", - name: 'google_workspace.admin.user.email', - type: 'keyword', - }, - 'google_workspace.admin.user.nickname': { - category: 'google_workspace', - description: "The user's nickname.", - name: 'google_workspace.admin.user.nickname', - type: 'keyword', - }, - 'google_workspace.admin.user.birthdate': { - category: 'google_workspace', - description: "The user's birth date.", - name: 'google_workspace.admin.user.birthdate', - type: 'date', - }, - 'google_workspace.admin.gateway.name': { - category: 'google_workspace', - description: 'Gateway name. Present on some chat settings.', - name: 'google_workspace.admin.gateway.name', - type: 'keyword', - }, - 'google_workspace.admin.chrome_os.session_type': { - category: 'google_workspace', - description: 'Chrome OS session type.', - name: 'google_workspace.admin.chrome_os.session_type', - type: 'keyword', - }, - 'google_workspace.admin.device.serial_number': { - category: 'google_workspace', - description: 'Device serial number.', - name: 'google_workspace.admin.device.serial_number', - type: 'keyword', - }, - 'google_workspace.admin.device.id': { - category: 'google_workspace', - name: 'google_workspace.admin.device.id', - type: 'keyword', - }, - 'google_workspace.admin.device.type': { - category: 'google_workspace', - description: 'Device type.', - name: 'google_workspace.admin.device.type', - type: 'keyword', - }, - 'google_workspace.admin.print_server.name': { - category: 'google_workspace', - description: 'The name of the print server.', - name: 'google_workspace.admin.print_server.name', - type: 'keyword', - }, - 'google_workspace.admin.printer.name': { - category: 'google_workspace', - description: 'The name of the printer.', - name: 'google_workspace.admin.printer.name', - type: 'keyword', - }, - 'google_workspace.admin.device.command_details': { - category: 'google_workspace', - description: 'Command details.', - name: 'google_workspace.admin.device.command_details', - type: 'keyword', - }, - 'google_workspace.admin.role.id': { - category: 'google_workspace', - description: 'Unique identifier for this role privilege.', - name: 'google_workspace.admin.role.id', - type: 'keyword', - }, - 'google_workspace.admin.role.name': { - category: 'google_workspace', - description: - 'The role name. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/admin-delegated-admin-settings ', - name: 'google_workspace.admin.role.name', - type: 'keyword', - }, - 'google_workspace.admin.privilege.name': { - category: 'google_workspace', - description: 'Privilege name.', - name: 'google_workspace.admin.privilege.name', - type: 'keyword', - }, - 'google_workspace.admin.service.name': { - category: 'google_workspace', - description: 'The service name.', - name: 'google_workspace.admin.service.name', - type: 'keyword', - }, - 'google_workspace.admin.url.name': { - category: 'google_workspace', - description: 'The website name.', - name: 'google_workspace.admin.url.name', - type: 'keyword', - }, - 'google_workspace.admin.product.name': { - category: 'google_workspace', - description: 'The product name.', - name: 'google_workspace.admin.product.name', - type: 'keyword', - }, - 'google_workspace.admin.product.sku': { - category: 'google_workspace', - description: 'The product SKU.', - name: 'google_workspace.admin.product.sku', - type: 'keyword', - }, - 'google_workspace.admin.bulk_upload.failed': { - category: 'google_workspace', - description: 'Number of failed records in bulk upload operation.', - name: 'google_workspace.admin.bulk_upload.failed', - type: 'long', - }, - 'google_workspace.admin.bulk_upload.total': { - category: 'google_workspace', - description: 'Number of total records in bulk upload operation.', - name: 'google_workspace.admin.bulk_upload.total', - type: 'long', - }, - 'google_workspace.admin.group.allowed_list': { - category: 'google_workspace', - description: 'Names of allow-listed groups.', - name: 'google_workspace.admin.group.allowed_list', - type: 'keyword', - }, - 'google_workspace.admin.email.quarantine_name': { - category: 'google_workspace', - description: 'The name of the quarantine.', - name: 'google_workspace.admin.email.quarantine_name', - type: 'keyword', - }, - 'google_workspace.admin.email.log_search_filter.message_id': { - category: 'google_workspace', - description: "The log search filter's email message ID.", - name: 'google_workspace.admin.email.log_search_filter.message_id', - type: 'keyword', - }, - 'google_workspace.admin.email.log_search_filter.start_date': { - category: 'google_workspace', - description: "The log search filter's start date.", - name: 'google_workspace.admin.email.log_search_filter.start_date', - type: 'date', - }, - 'google_workspace.admin.email.log_search_filter.end_date': { - category: 'google_workspace', - description: "The log search filter's ending date.", - name: 'google_workspace.admin.email.log_search_filter.end_date', - type: 'date', - }, - 'google_workspace.admin.email.log_search_filter.recipient.value': { - category: 'google_workspace', - description: "The log search filter's email recipient.", - name: 'google_workspace.admin.email.log_search_filter.recipient.value', - type: 'keyword', - }, - 'google_workspace.admin.email.log_search_filter.sender.value': { - category: 'google_workspace', - description: "The log search filter's email sender.", - name: 'google_workspace.admin.email.log_search_filter.sender.value', - type: 'keyword', - }, - 'google_workspace.admin.email.log_search_filter.recipient.ip': { - category: 'google_workspace', - description: "The log search filter's email recipient's IP address.", - name: 'google_workspace.admin.email.log_search_filter.recipient.ip', - type: 'ip', - }, - 'google_workspace.admin.email.log_search_filter.sender.ip': { - category: 'google_workspace', - description: "The log search filter's email sender's IP address.", - name: 'google_workspace.admin.email.log_search_filter.sender.ip', - type: 'ip', - }, - 'google_workspace.admin.chrome_licenses.enabled': { - category: 'google_workspace', - description: - 'Licences enabled. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/admin-org-settings ', - name: 'google_workspace.admin.chrome_licenses.enabled', - type: 'keyword', - }, - 'google_workspace.admin.chrome_licenses.allowed': { - category: 'google_workspace', - description: - 'Licences enabled. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/admin-org-settings ', - name: 'google_workspace.admin.chrome_licenses.allowed', - type: 'keyword', - }, - 'google_workspace.admin.oauth2.service.name': { - category: 'google_workspace', - description: - 'OAuth2 service name. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/admin-security-settings ', - name: 'google_workspace.admin.oauth2.service.name', - type: 'keyword', - }, - 'google_workspace.admin.oauth2.application.id': { - category: 'google_workspace', - description: 'OAuth2 application ID.', - name: 'google_workspace.admin.oauth2.application.id', - type: 'keyword', - }, - 'google_workspace.admin.oauth2.application.name': { - category: 'google_workspace', - description: 'OAuth2 application name.', - name: 'google_workspace.admin.oauth2.application.name', - type: 'keyword', - }, - 'google_workspace.admin.oauth2.application.type': { - category: 'google_workspace', - description: - 'OAuth2 application type. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/admin-security-settings ', - name: 'google_workspace.admin.oauth2.application.type', - type: 'keyword', - }, - 'google_workspace.admin.verification_method': { - category: 'google_workspace', - description: - 'Related verification method. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/admin-security-settings and https://developers.google.com/admin-sdk/reports/v1/appendix/activity/admin-domain-settings ', - name: 'google_workspace.admin.verification_method', - type: 'keyword', - }, - 'google_workspace.admin.alert.name': { - category: 'google_workspace', - description: 'The alert name.', - name: 'google_workspace.admin.alert.name', - type: 'keyword', - }, - 'google_workspace.admin.rule.name': { - category: 'google_workspace', - description: 'The rule name.', - name: 'google_workspace.admin.rule.name', - type: 'keyword', - }, - 'google_workspace.admin.api.client.name': { - category: 'google_workspace', - description: 'The API client name.', - name: 'google_workspace.admin.api.client.name', - type: 'keyword', - }, - 'google_workspace.admin.api.scopes': { - category: 'google_workspace', - description: 'The API scopes.', - name: 'google_workspace.admin.api.scopes', - type: 'keyword', - }, - 'google_workspace.admin.mdm.token': { - category: 'google_workspace', - description: 'The MDM vendor enrollment token.', - name: 'google_workspace.admin.mdm.token', - type: 'keyword', - }, - 'google_workspace.admin.mdm.vendor': { - category: 'google_workspace', - description: "The MDM vendor's name.", - name: 'google_workspace.admin.mdm.vendor', - type: 'keyword', - }, - 'google_workspace.admin.info_type': { - category: 'google_workspace', - description: - 'This will be used to state what kind of information was changed. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/admin-domain-settings ', - name: 'google_workspace.admin.info_type', - type: 'keyword', - }, - 'google_workspace.admin.email_monitor.dest_email': { - category: 'google_workspace', - description: 'The destination address of the email monitor.', - name: 'google_workspace.admin.email_monitor.dest_email', - type: 'keyword', - }, - 'google_workspace.admin.email_monitor.level.chat': { - category: 'google_workspace', - description: 'The chat email monitor level.', - name: 'google_workspace.admin.email_monitor.level.chat', - type: 'keyword', - }, - 'google_workspace.admin.email_monitor.level.draft': { - category: 'google_workspace', - description: 'The draft email monitor level.', - name: 'google_workspace.admin.email_monitor.level.draft', - type: 'keyword', - }, - 'google_workspace.admin.email_monitor.level.incoming': { - category: 'google_workspace', - description: 'The incoming email monitor level.', - name: 'google_workspace.admin.email_monitor.level.incoming', - type: 'keyword', - }, - 'google_workspace.admin.email_monitor.level.outgoing': { - category: 'google_workspace', - description: 'The outgoing email monitor level.', - name: 'google_workspace.admin.email_monitor.level.outgoing', - type: 'keyword', - }, - 'google_workspace.admin.email_dump.include_deleted': { - category: 'google_workspace', - description: 'Indicates if deleted emails are included in the export.', - name: 'google_workspace.admin.email_dump.include_deleted', - type: 'boolean', - }, - 'google_workspace.admin.email_dump.package_content': { - category: 'google_workspace', - description: 'The contents of the mailbox package.', - name: 'google_workspace.admin.email_dump.package_content', - type: 'keyword', - }, - 'google_workspace.admin.email_dump.query': { - category: 'google_workspace', - description: 'The search query used for the dump.', - name: 'google_workspace.admin.email_dump.query', - type: 'keyword', - }, - 'google_workspace.admin.request.id': { - category: 'google_workspace', - description: 'The request ID.', - name: 'google_workspace.admin.request.id', - type: 'keyword', - }, - 'google_workspace.admin.mobile.action.id': { - category: 'google_workspace', - description: "The mobile device action's ID.", - name: 'google_workspace.admin.mobile.action.id', - type: 'keyword', - }, - 'google_workspace.admin.mobile.action.type': { - category: 'google_workspace', - description: - "The mobile device action's type. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/admin-mobile-settings ", - name: 'google_workspace.admin.mobile.action.type', - type: 'keyword', - }, - 'google_workspace.admin.mobile.certificate.name': { - category: 'google_workspace', - description: 'The mobile certificate common name.', - name: 'google_workspace.admin.mobile.certificate.name', - type: 'keyword', - }, - 'google_workspace.admin.mobile.company_owned_devices': { - category: 'google_workspace', - description: 'The number of devices a company owns.', - name: 'google_workspace.admin.mobile.company_owned_devices', - type: 'long', - }, - 'google_workspace.admin.distribution.entity.name': { - category: 'google_workspace', - description: - 'The distribution entity value, which can be a group name or an org-unit name. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/admin-mobile-settings ', - name: 'google_workspace.admin.distribution.entity.name', - type: 'keyword', - }, - 'google_workspace.admin.distribution.entity.type': { - category: 'google_workspace', - description: - 'The distribution entity type, which can be a group or an org-unit. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/admin-mobile-settings ', - name: 'google_workspace.admin.distribution.entity.type', - type: 'keyword', - }, - 'google_workspace.drive.billable': { - category: 'google_workspace', - description: 'Whether this activity is billable.', - name: 'google_workspace.drive.billable', - type: 'boolean', - }, - 'google_workspace.drive.source_folder_id': { - category: 'google_workspace', - name: 'google_workspace.drive.source_folder_id', - type: 'keyword', - }, - 'google_workspace.drive.source_folder_title': { - category: 'google_workspace', - name: 'google_workspace.drive.source_folder_title', - type: 'keyword', - }, - 'google_workspace.drive.destination_folder_id': { - category: 'google_workspace', - name: 'google_workspace.drive.destination_folder_id', - type: 'keyword', - }, - 'google_workspace.drive.destination_folder_title': { - category: 'google_workspace', - name: 'google_workspace.drive.destination_folder_title', - type: 'keyword', - }, - 'google_workspace.drive.file.id': { - category: 'google_workspace', - name: 'google_workspace.drive.file.id', - type: 'keyword', - }, - 'google_workspace.drive.file.type': { - category: 'google_workspace', - description: - 'Document Drive type. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/drive ', - name: 'google_workspace.drive.file.type', - type: 'keyword', - }, - 'google_workspace.drive.originating_app_id': { - category: 'google_workspace', - description: 'The Google Cloud Project ID of the application that performed the action. ', - name: 'google_workspace.drive.originating_app_id', - type: 'keyword', - }, - 'google_workspace.drive.file.owner.email': { - category: 'google_workspace', - name: 'google_workspace.drive.file.owner.email', - type: 'keyword', - }, - 'google_workspace.drive.file.owner.is_shared_drive': { - category: 'google_workspace', - description: 'Boolean flag denoting whether owner is a shared drive. ', - name: 'google_workspace.drive.file.owner.is_shared_drive', - type: 'boolean', - }, - 'google_workspace.drive.primary_event': { - category: 'google_workspace', - description: - 'Whether this is a primary event. A single user action in Drive may generate several events. ', - name: 'google_workspace.drive.primary_event', - type: 'boolean', - }, - 'google_workspace.drive.shared_drive_id': { - category: 'google_workspace', - description: - 'The unique identifier of the Team Drive. Only populated for for events relating to a Team Drive or item contained inside a Team Drive. ', - name: 'google_workspace.drive.shared_drive_id', - type: 'keyword', - }, - 'google_workspace.drive.visibility': { - category: 'google_workspace', - description: - 'Visibility of target file. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/drive ', - name: 'google_workspace.drive.visibility', - type: 'keyword', - }, - 'google_workspace.drive.new_value': { - category: 'google_workspace', - description: - 'When a setting or property of the file changes, the new value for it will appear here. ', - name: 'google_workspace.drive.new_value', - type: 'keyword', - }, - 'google_workspace.drive.old_value': { - category: 'google_workspace', - description: - 'When a setting or property of the file changes, the old value for it will appear here. ', - name: 'google_workspace.drive.old_value', - type: 'keyword', - }, - 'google_workspace.drive.sheets_import_range_recipient_doc': { - category: 'google_workspace', - description: 'Doc ID of the recipient of a sheets import range.', - name: 'google_workspace.drive.sheets_import_range_recipient_doc', - type: 'keyword', - }, - 'google_workspace.drive.old_visibility': { - category: 'google_workspace', - description: 'When visibility changes, this holds the old value. ', - name: 'google_workspace.drive.old_visibility', - type: 'keyword', - }, - 'google_workspace.drive.visibility_change': { - category: 'google_workspace', - description: 'When visibility changes, this holds the new overall visibility of the file. ', - name: 'google_workspace.drive.visibility_change', - type: 'keyword', - }, - 'google_workspace.drive.target_domain': { - category: 'google_workspace', - description: - 'The domain for which the acccess scope was changed. This can also be the alias all to indicate the access scope was changed for all domains that have visibility for this document. ', - name: 'google_workspace.drive.target_domain', - type: 'keyword', - }, - 'google_workspace.drive.added_role': { - category: 'google_workspace', - description: - 'Added membership role of a user/group in a Team Drive. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/drive ', - name: 'google_workspace.drive.added_role', - type: 'keyword', - }, - 'google_workspace.drive.membership_change_type': { - category: 'google_workspace', - description: - 'Type of change in Team Drive membership of a user/group. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/drive ', - name: 'google_workspace.drive.membership_change_type', - type: 'keyword', - }, - 'google_workspace.drive.shared_drive_settings_change_type': { - category: 'google_workspace', - description: - 'Type of change in Team Drive settings. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/drive ', - name: 'google_workspace.drive.shared_drive_settings_change_type', - type: 'keyword', - }, - 'google_workspace.drive.removed_role': { - category: 'google_workspace', - description: - 'Removed membership role of a user/group in a Team Drive. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/drive ', - name: 'google_workspace.drive.removed_role', - type: 'keyword', - }, - 'google_workspace.drive.target': { - category: 'google_workspace', - description: 'Target user or group.', - name: 'google_workspace.drive.target', - type: 'keyword', - }, - 'google_workspace.groups.acl_permission': { - category: 'google_workspace', - description: - 'Group permission setting updated. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/groups ', - name: 'google_workspace.groups.acl_permission', - type: 'keyword', - }, - 'google_workspace.groups.email': { - category: 'google_workspace', - description: 'Group email. ', - name: 'google_workspace.groups.email', - type: 'keyword', - }, - 'google_workspace.groups.member.email': { - category: 'google_workspace', - description: 'Member email. ', - name: 'google_workspace.groups.member.email', - type: 'keyword', - }, - 'google_workspace.groups.member.role': { - category: 'google_workspace', - description: - 'Member role. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/groups ', - name: 'google_workspace.groups.member.role', - type: 'keyword', - }, - 'google_workspace.groups.setting': { - category: 'google_workspace', - description: - 'Group setting updated. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/groups ', - name: 'google_workspace.groups.setting', - type: 'keyword', - }, - 'google_workspace.groups.new_value': { - category: 'google_workspace', - description: - 'New value(s) of the group setting. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/groups ', - name: 'google_workspace.groups.new_value', - type: 'keyword', - }, - 'google_workspace.groups.old_value': { - category: 'google_workspace', - description: - 'Old value(s) of the group setting. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/groups', - name: 'google_workspace.groups.old_value', - type: 'keyword', - }, - 'google_workspace.groups.value': { - category: 'google_workspace', - description: - 'Value of the group setting. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/groups ', - name: 'google_workspace.groups.value', - type: 'keyword', - }, - 'google_workspace.groups.message.id': { - category: 'google_workspace', - description: 'SMTP message Id of an email message. Present for moderation events. ', - name: 'google_workspace.groups.message.id', - type: 'keyword', - }, - 'google_workspace.groups.message.moderation_action': { - category: 'google_workspace', - description: 'Message moderation action. Possible values are `approved` and `rejected`. ', - name: 'google_workspace.groups.message.moderation_action', - type: 'keyword', - }, - 'google_workspace.groups.status': { - category: 'google_workspace', - description: - 'A status describing the output of an operation. Possible values are `failed` and `succeeded`. ', - name: 'google_workspace.groups.status', - type: 'keyword', - }, - 'google_workspace.login.affected_email_address': { - category: 'google_workspace', - name: 'google_workspace.login.affected_email_address', - type: 'keyword', - }, - 'google_workspace.login.challenge_method': { - category: 'google_workspace', - description: - 'Login challenge method. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/login. ', - name: 'google_workspace.login.challenge_method', - type: 'keyword', - }, - 'google_workspace.login.failure_type': { - category: 'google_workspace', - description: - 'Login failure type. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/login. ', - name: 'google_workspace.login.failure_type', - type: 'keyword', - }, - 'google_workspace.login.type': { - category: 'google_workspace', - description: - 'Login credentials type. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/login. ', - name: 'google_workspace.login.type', - type: 'keyword', - }, - 'google_workspace.login.is_second_factor': { - category: 'google_workspace', - name: 'google_workspace.login.is_second_factor', - type: 'boolean', - }, - 'google_workspace.login.is_suspicious': { - category: 'google_workspace', - name: 'google_workspace.login.is_suspicious', - type: 'boolean', - }, - 'google_workspace.saml.application_name': { - category: 'google_workspace', - description: 'Saml SP application name. ', - name: 'google_workspace.saml.application_name', - type: 'keyword', - }, - 'google_workspace.saml.failure_type': { - category: 'google_workspace', - description: - 'Login failure type. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/saml. ', - name: 'google_workspace.saml.failure_type', - type: 'keyword', - }, - 'google_workspace.saml.initiated_by': { - category: 'google_workspace', - description: 'Requester of SAML authentication. ', - name: 'google_workspace.saml.initiated_by', - type: 'keyword', - }, - 'google_workspace.saml.orgunit_path': { - category: 'google_workspace', - description: 'User orgunit. ', - name: 'google_workspace.saml.orgunit_path', - type: 'keyword', - }, - 'google_workspace.saml.status_code': { - category: 'google_workspace', - description: 'SAML status code. ', - name: 'google_workspace.saml.status_code', - type: 'keyword', - }, - 'google_workspace.saml.second_level_status_code': { - category: 'google_workspace', - description: 'SAML second level status code. ', - name: 'google_workspace.saml.second_level_status_code', - type: 'keyword', - }, - 'gsuite.actor.type': { - category: 'gsuite', - description: - 'The type of actor. Values can be: *USER*: Another user in the same domain. *EXTERNAL_USER*: A user outside the domain. *KEY*: A non-human actor. ', - name: 'gsuite.actor.type', - type: 'keyword', - }, - 'gsuite.actor.key': { - category: 'gsuite', - description: - 'Only present when `actor.type` is `KEY`. Can be the `consumer_key` of the requestor for OAuth 2LO API requests or an identifier for robot accounts. ', - name: 'gsuite.actor.key', - type: 'keyword', - }, - 'gsuite.event.type': { - category: 'gsuite', - description: - 'The type of GSuite event, mapped from `items[].events[].type` in the original payload. Each fileset can have a different set of values for it, more details can be found at https://developers.google.com/admin-sdk/reports/v1/reference/activities/list ', - example: 'audit#activity', - name: 'gsuite.event.type', - type: 'keyword', - }, - 'gsuite.kind': { - category: 'gsuite', - description: - 'The type of API resource, mapped from `kind` in the original payload. More details can be found at https://developers.google.com/admin-sdk/reports/v1/reference/activities/list ', - example: 'audit#activity', - name: 'gsuite.kind', - type: 'keyword', - }, - 'gsuite.organization.domain': { - category: 'gsuite', - description: "The domain that is affected by the report's event. ", - name: 'gsuite.organization.domain', - type: 'keyword', - }, - 'gsuite.admin.application.edition': { - category: 'gsuite', - description: 'The GSuite edition.', - name: 'gsuite.admin.application.edition', - type: 'keyword', - }, - 'gsuite.admin.application.name': { - category: 'gsuite', - description: "The application's name.", - name: 'gsuite.admin.application.name', - type: 'keyword', - }, - 'gsuite.admin.application.enabled': { - category: 'gsuite', - description: 'The enabled application.', - name: 'gsuite.admin.application.enabled', - type: 'keyword', - }, - 'gsuite.admin.application.licences_order_number': { - category: 'gsuite', - description: 'Order number used to redeem licenses.', - name: 'gsuite.admin.application.licences_order_number', - type: 'keyword', - }, - 'gsuite.admin.application.licences_purchased': { - category: 'gsuite', - description: 'Number of licences purchased.', - name: 'gsuite.admin.application.licences_purchased', - type: 'keyword', - }, - 'gsuite.admin.application.id': { - category: 'gsuite', - description: 'The application ID.', - name: 'gsuite.admin.application.id', - type: 'keyword', - }, - 'gsuite.admin.application.asp_id': { - category: 'gsuite', - description: 'The application specific password ID.', - name: 'gsuite.admin.application.asp_id', - type: 'keyword', - }, - 'gsuite.admin.application.package_id': { - category: 'gsuite', - description: 'The mobile application package ID.', - name: 'gsuite.admin.application.package_id', - type: 'keyword', - }, - 'gsuite.admin.group.email': { - category: 'gsuite', - description: "The group's primary email address.", - name: 'gsuite.admin.group.email', - type: 'keyword', - }, - 'gsuite.admin.new_value': { - category: 'gsuite', - description: 'The new value for the setting.', - name: 'gsuite.admin.new_value', - type: 'keyword', - }, - 'gsuite.admin.old_value': { - category: 'gsuite', - description: 'The old value for the setting.', - name: 'gsuite.admin.old_value', - type: 'keyword', - }, - 'gsuite.admin.org_unit.name': { - category: 'gsuite', - description: 'The organizational unit name.', - name: 'gsuite.admin.org_unit.name', - type: 'keyword', - }, - 'gsuite.admin.org_unit.full': { - category: 'gsuite', - description: 'The org unit full path including the root org unit name.', - name: 'gsuite.admin.org_unit.full', - type: 'keyword', - }, - 'gsuite.admin.setting.name': { - category: 'gsuite', - description: 'The setting name.', - name: 'gsuite.admin.setting.name', - type: 'keyword', - }, - 'gsuite.admin.user_defined_setting.name': { - category: 'gsuite', - description: 'The name of the user-defined setting.', - name: 'gsuite.admin.user_defined_setting.name', - type: 'keyword', - }, - 'gsuite.admin.setting.description': { - category: 'gsuite', - description: 'The setting name.', - name: 'gsuite.admin.setting.description', - type: 'keyword', - }, - 'gsuite.admin.group.priorities': { - category: 'gsuite', - description: 'Group priorities.', - name: 'gsuite.admin.group.priorities', - type: 'keyword', - }, - 'gsuite.admin.domain.alias': { - category: 'gsuite', - description: 'The domain alias.', - name: 'gsuite.admin.domain.alias', - type: 'keyword', - }, - 'gsuite.admin.domain.name': { - category: 'gsuite', - description: 'The primary domain name.', - name: 'gsuite.admin.domain.name', - type: 'keyword', - }, - 'gsuite.admin.domain.secondary_name': { - category: 'gsuite', - description: 'The secondary domain name.', - name: 'gsuite.admin.domain.secondary_name', - type: 'keyword', - }, - 'gsuite.admin.managed_configuration': { - category: 'gsuite', - description: 'The name of the managed configuration.', - name: 'gsuite.admin.managed_configuration', - type: 'keyword', - }, - 'gsuite.admin.non_featured_services_selection': { - category: 'gsuite', - description: - 'Non-featured services selection. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/admin-application-settings#FLASHLIGHT_EDU_NON_FEATURED_SERVICES_SELECTED ', - name: 'gsuite.admin.non_featured_services_selection', - type: 'keyword', - }, - 'gsuite.admin.field': { - category: 'gsuite', - description: 'The name of the field.', - name: 'gsuite.admin.field', - type: 'keyword', - }, - 'gsuite.admin.resource.id': { - category: 'gsuite', - description: 'The name of the resource identifier.', - name: 'gsuite.admin.resource.id', - type: 'keyword', - }, - 'gsuite.admin.user.email': { - category: 'gsuite', - description: "The user's primary email address.", - name: 'gsuite.admin.user.email', - type: 'keyword', - }, - 'gsuite.admin.user.nickname': { - category: 'gsuite', - description: "The user's nickname.", - name: 'gsuite.admin.user.nickname', - type: 'keyword', - }, - 'gsuite.admin.user.birthdate': { - category: 'gsuite', - description: "The user's birth date.", - name: 'gsuite.admin.user.birthdate', - type: 'date', - }, - 'gsuite.admin.gateway.name': { - category: 'gsuite', - description: 'Gateway name. Present on some chat settings.', - name: 'gsuite.admin.gateway.name', - type: 'keyword', - }, - 'gsuite.admin.chrome_os.session_type': { - category: 'gsuite', - description: 'Chrome OS session type.', - name: 'gsuite.admin.chrome_os.session_type', - type: 'keyword', - }, - 'gsuite.admin.device.serial_number': { - category: 'gsuite', - description: 'Device serial number.', - name: 'gsuite.admin.device.serial_number', - type: 'keyword', - }, - 'gsuite.admin.device.id': { - category: 'gsuite', - name: 'gsuite.admin.device.id', - type: 'keyword', - }, - 'gsuite.admin.device.type': { - category: 'gsuite', - description: 'Device type.', - name: 'gsuite.admin.device.type', - type: 'keyword', - }, - 'gsuite.admin.print_server.name': { - category: 'gsuite', - description: 'The name of the print server.', - name: 'gsuite.admin.print_server.name', - type: 'keyword', - }, - 'gsuite.admin.printer.name': { - category: 'gsuite', - description: 'The name of the printer.', - name: 'gsuite.admin.printer.name', - type: 'keyword', - }, - 'gsuite.admin.device.command_details': { - category: 'gsuite', - description: 'Command details.', - name: 'gsuite.admin.device.command_details', - type: 'keyword', - }, - 'gsuite.admin.role.id': { - category: 'gsuite', - description: 'Unique identifier for this role privilege.', - name: 'gsuite.admin.role.id', - type: 'keyword', - }, - 'gsuite.admin.role.name': { - category: 'gsuite', - description: - 'The role name. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/admin-delegated-admin-settings ', - name: 'gsuite.admin.role.name', - type: 'keyword', - }, - 'gsuite.admin.privilege.name': { - category: 'gsuite', - description: 'Privilege name.', - name: 'gsuite.admin.privilege.name', - type: 'keyword', - }, - 'gsuite.admin.service.name': { - category: 'gsuite', - description: 'The service name.', - name: 'gsuite.admin.service.name', - type: 'keyword', - }, - 'gsuite.admin.url.name': { - category: 'gsuite', - description: 'The website name.', - name: 'gsuite.admin.url.name', - type: 'keyword', - }, - 'gsuite.admin.product.name': { - category: 'gsuite', - description: 'The product name.', - name: 'gsuite.admin.product.name', - type: 'keyword', - }, - 'gsuite.admin.product.sku': { - category: 'gsuite', - description: 'The product SKU.', - name: 'gsuite.admin.product.sku', - type: 'keyword', - }, - 'gsuite.admin.bulk_upload.failed': { - category: 'gsuite', - description: 'Number of failed records in bulk upload operation.', - name: 'gsuite.admin.bulk_upload.failed', - type: 'long', - }, - 'gsuite.admin.bulk_upload.total': { - category: 'gsuite', - description: 'Number of total records in bulk upload operation.', - name: 'gsuite.admin.bulk_upload.total', - type: 'long', - }, - 'gsuite.admin.group.allowed_list': { - category: 'gsuite', - description: 'Names of allow-listed groups.', - name: 'gsuite.admin.group.allowed_list', - type: 'keyword', - }, - 'gsuite.admin.email.quarantine_name': { - category: 'gsuite', - description: 'The name of the quarantine.', - name: 'gsuite.admin.email.quarantine_name', - type: 'keyword', - }, - 'gsuite.admin.email.log_search_filter.message_id': { - category: 'gsuite', - description: "The log search filter's email message ID.", - name: 'gsuite.admin.email.log_search_filter.message_id', - type: 'keyword', - }, - 'gsuite.admin.email.log_search_filter.start_date': { - category: 'gsuite', - description: "The log search filter's start date.", - name: 'gsuite.admin.email.log_search_filter.start_date', - type: 'date', - }, - 'gsuite.admin.email.log_search_filter.end_date': { - category: 'gsuite', - description: "The log search filter's ending date.", - name: 'gsuite.admin.email.log_search_filter.end_date', - type: 'date', - }, - 'gsuite.admin.email.log_search_filter.recipient.value': { - category: 'gsuite', - description: "The log search filter's email recipient.", - name: 'gsuite.admin.email.log_search_filter.recipient.value', - type: 'keyword', - }, - 'gsuite.admin.email.log_search_filter.sender.value': { - category: 'gsuite', - description: "The log search filter's email sender.", - name: 'gsuite.admin.email.log_search_filter.sender.value', - type: 'keyword', - }, - 'gsuite.admin.email.log_search_filter.recipient.ip': { - category: 'gsuite', - description: "The log search filter's email recipient's IP address.", - name: 'gsuite.admin.email.log_search_filter.recipient.ip', - type: 'ip', - }, - 'gsuite.admin.email.log_search_filter.sender.ip': { - category: 'gsuite', - description: "The log search filter's email sender's IP address.", - name: 'gsuite.admin.email.log_search_filter.sender.ip', - type: 'ip', - }, - 'gsuite.admin.chrome_licenses.enabled': { - category: 'gsuite', - description: - 'Licences enabled. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/admin-org-settings ', - name: 'gsuite.admin.chrome_licenses.enabled', - type: 'keyword', - }, - 'gsuite.admin.chrome_licenses.allowed': { - category: 'gsuite', - description: - 'Licences enabled. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/admin-org-settings ', - name: 'gsuite.admin.chrome_licenses.allowed', - type: 'keyword', - }, - 'gsuite.admin.oauth2.service.name': { - category: 'gsuite', - description: - 'OAuth2 service name. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/admin-security-settings ', - name: 'gsuite.admin.oauth2.service.name', - type: 'keyword', - }, - 'gsuite.admin.oauth2.application.id': { - category: 'gsuite', - description: 'OAuth2 application ID.', - name: 'gsuite.admin.oauth2.application.id', - type: 'keyword', - }, - 'gsuite.admin.oauth2.application.name': { - category: 'gsuite', - description: 'OAuth2 application name.', - name: 'gsuite.admin.oauth2.application.name', - type: 'keyword', - }, - 'gsuite.admin.oauth2.application.type': { - category: 'gsuite', - description: - 'OAuth2 application type. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/admin-security-settings ', - name: 'gsuite.admin.oauth2.application.type', - type: 'keyword', - }, - 'gsuite.admin.verification_method': { - category: 'gsuite', - description: - 'Related verification method. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/admin-security-settings and https://developers.google.com/admin-sdk/reports/v1/appendix/activity/admin-domain-settings ', - name: 'gsuite.admin.verification_method', - type: 'keyword', - }, - 'gsuite.admin.alert.name': { - category: 'gsuite', - description: 'The alert name.', - name: 'gsuite.admin.alert.name', - type: 'keyword', - }, - 'gsuite.admin.rule.name': { - category: 'gsuite', - description: 'The rule name.', - name: 'gsuite.admin.rule.name', - type: 'keyword', - }, - 'gsuite.admin.api.client.name': { - category: 'gsuite', - description: 'The API client name.', - name: 'gsuite.admin.api.client.name', - type: 'keyword', - }, - 'gsuite.admin.api.scopes': { - category: 'gsuite', - description: 'The API scopes.', - name: 'gsuite.admin.api.scopes', - type: 'keyword', - }, - 'gsuite.admin.mdm.token': { - category: 'gsuite', - description: 'The MDM vendor enrollment token.', - name: 'gsuite.admin.mdm.token', - type: 'keyword', - }, - 'gsuite.admin.mdm.vendor': { - category: 'gsuite', - description: "The MDM vendor's name.", - name: 'gsuite.admin.mdm.vendor', - type: 'keyword', - }, - 'gsuite.admin.info_type': { - category: 'gsuite', - description: - 'This will be used to state what kind of information was changed. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/admin-domain-settings ', - name: 'gsuite.admin.info_type', - type: 'keyword', - }, - 'gsuite.admin.email_monitor.dest_email': { - category: 'gsuite', - description: 'The destination address of the email monitor.', - name: 'gsuite.admin.email_monitor.dest_email', - type: 'keyword', - }, - 'gsuite.admin.email_monitor.level.chat': { - category: 'gsuite', - description: 'The chat email monitor level.', - name: 'gsuite.admin.email_monitor.level.chat', - type: 'keyword', - }, - 'gsuite.admin.email_monitor.level.draft': { - category: 'gsuite', - description: 'The draft email monitor level.', - name: 'gsuite.admin.email_monitor.level.draft', - type: 'keyword', - }, - 'gsuite.admin.email_monitor.level.incoming': { - category: 'gsuite', - description: 'The incoming email monitor level.', - name: 'gsuite.admin.email_monitor.level.incoming', - type: 'keyword', - }, - 'gsuite.admin.email_monitor.level.outgoing': { - category: 'gsuite', - description: 'The outgoing email monitor level.', - name: 'gsuite.admin.email_monitor.level.outgoing', - type: 'keyword', - }, - 'gsuite.admin.email_dump.include_deleted': { - category: 'gsuite', - description: 'Indicates if deleted emails are included in the export.', - name: 'gsuite.admin.email_dump.include_deleted', - type: 'boolean', - }, - 'gsuite.admin.email_dump.package_content': { - category: 'gsuite', - description: 'The contents of the mailbox package.', - name: 'gsuite.admin.email_dump.package_content', - type: 'keyword', - }, - 'gsuite.admin.email_dump.query': { - category: 'gsuite', - description: 'The search query used for the dump.', - name: 'gsuite.admin.email_dump.query', - type: 'keyword', - }, - 'gsuite.admin.request.id': { - category: 'gsuite', - description: 'The request ID.', - name: 'gsuite.admin.request.id', - type: 'keyword', - }, - 'gsuite.admin.mobile.action.id': { - category: 'gsuite', - description: "The mobile device action's ID.", - name: 'gsuite.admin.mobile.action.id', - type: 'keyword', - }, - 'gsuite.admin.mobile.action.type': { - category: 'gsuite', - description: - "The mobile device action's type. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/admin-mobile-settings ", - name: 'gsuite.admin.mobile.action.type', - type: 'keyword', - }, - 'gsuite.admin.mobile.certificate.name': { - category: 'gsuite', - description: 'The mobile certificate common name.', - name: 'gsuite.admin.mobile.certificate.name', - type: 'keyword', - }, - 'gsuite.admin.mobile.company_owned_devices': { - category: 'gsuite', - description: 'The number of devices a company owns.', - name: 'gsuite.admin.mobile.company_owned_devices', - type: 'long', - }, - 'gsuite.admin.distribution.entity.name': { - category: 'gsuite', - description: - 'The distribution entity value, which can be a group name or an org-unit name. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/admin-mobile-settings ', - name: 'gsuite.admin.distribution.entity.name', - type: 'keyword', - }, - 'gsuite.admin.distribution.entity.type': { - category: 'gsuite', - description: - 'The distribution entity type, which can be a group or an org-unit. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/admin-mobile-settings ', - name: 'gsuite.admin.distribution.entity.type', - type: 'keyword', - }, - 'gsuite.drive.billable': { - category: 'gsuite', - description: 'Whether this activity is billable.', - name: 'gsuite.drive.billable', - type: 'boolean', - }, - 'gsuite.drive.source_folder_id': { - category: 'gsuite', - name: 'gsuite.drive.source_folder_id', - type: 'keyword', - }, - 'gsuite.drive.source_folder_title': { - category: 'gsuite', - name: 'gsuite.drive.source_folder_title', - type: 'keyword', - }, - 'gsuite.drive.destination_folder_id': { - category: 'gsuite', - name: 'gsuite.drive.destination_folder_id', - type: 'keyword', - }, - 'gsuite.drive.destination_folder_title': { - category: 'gsuite', - name: 'gsuite.drive.destination_folder_title', - type: 'keyword', - }, - 'gsuite.drive.file.id': { - category: 'gsuite', - name: 'gsuite.drive.file.id', - type: 'keyword', - }, - 'gsuite.drive.file.type': { - category: 'gsuite', - description: - 'Document Drive type. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/drive ', - name: 'gsuite.drive.file.type', - type: 'keyword', - }, - 'gsuite.drive.originating_app_id': { - category: 'gsuite', - description: 'The Google Cloud Project ID of the application that performed the action. ', - name: 'gsuite.drive.originating_app_id', - type: 'keyword', - }, - 'gsuite.drive.file.owner.email': { - category: 'gsuite', - name: 'gsuite.drive.file.owner.email', - type: 'keyword', - }, - 'gsuite.drive.file.owner.is_shared_drive': { - category: 'gsuite', - description: 'Boolean flag denoting whether owner is a shared drive. ', - name: 'gsuite.drive.file.owner.is_shared_drive', - type: 'boolean', - }, - 'gsuite.drive.primary_event': { - category: 'gsuite', - description: - 'Whether this is a primary event. A single user action in Drive may generate several events. ', - name: 'gsuite.drive.primary_event', - type: 'boolean', - }, - 'gsuite.drive.shared_drive_id': { - category: 'gsuite', - description: - 'The unique identifier of the Team Drive. Only populated for for events relating to a Team Drive or item contained inside a Team Drive. ', - name: 'gsuite.drive.shared_drive_id', - type: 'keyword', - }, - 'gsuite.drive.visibility': { - category: 'gsuite', - description: - 'Visibility of target file. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/drive ', - name: 'gsuite.drive.visibility', - type: 'keyword', - }, - 'gsuite.drive.new_value': { - category: 'gsuite', - description: - 'When a setting or property of the file changes, the new value for it will appear here. ', - name: 'gsuite.drive.new_value', - type: 'keyword', - }, - 'gsuite.drive.old_value': { - category: 'gsuite', - description: - 'When a setting or property of the file changes, the old value for it will appear here. ', - name: 'gsuite.drive.old_value', - type: 'keyword', - }, - 'gsuite.drive.sheets_import_range_recipient_doc': { - category: 'gsuite', - description: 'Doc ID of the recipient of a sheets import range.', - name: 'gsuite.drive.sheets_import_range_recipient_doc', - type: 'keyword', - }, - 'gsuite.drive.old_visibility': { - category: 'gsuite', - description: 'When visibility changes, this holds the old value. ', - name: 'gsuite.drive.old_visibility', - type: 'keyword', - }, - 'gsuite.drive.visibility_change': { - category: 'gsuite', - description: 'When visibility changes, this holds the new overall visibility of the file. ', - name: 'gsuite.drive.visibility_change', - type: 'keyword', - }, - 'gsuite.drive.target_domain': { - category: 'gsuite', - description: - 'The domain for which the acccess scope was changed. This can also be the alias all to indicate the access scope was changed for all domains that have visibility for this document. ', - name: 'gsuite.drive.target_domain', - type: 'keyword', - }, - 'gsuite.drive.added_role': { - category: 'gsuite', - description: - 'Added membership role of a user/group in a Team Drive. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/drive ', - name: 'gsuite.drive.added_role', - type: 'keyword', - }, - 'gsuite.drive.membership_change_type': { - category: 'gsuite', - description: - 'Type of change in Team Drive membership of a user/group. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/drive ', - name: 'gsuite.drive.membership_change_type', - type: 'keyword', - }, - 'gsuite.drive.shared_drive_settings_change_type': { - category: 'gsuite', - description: - 'Type of change in Team Drive settings. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/drive ', - name: 'gsuite.drive.shared_drive_settings_change_type', - type: 'keyword', - }, - 'gsuite.drive.removed_role': { - category: 'gsuite', - description: - 'Removed membership role of a user/group in a Team Drive. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/drive ', - name: 'gsuite.drive.removed_role', - type: 'keyword', - }, - 'gsuite.drive.target': { - category: 'gsuite', - description: 'Target user or group.', - name: 'gsuite.drive.target', - type: 'keyword', - }, - 'gsuite.groups.acl_permission': { - category: 'gsuite', - description: - 'Group permission setting updated. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/groups ', - name: 'gsuite.groups.acl_permission', - type: 'keyword', - }, - 'gsuite.groups.email': { - category: 'gsuite', - description: 'Group email. ', - name: 'gsuite.groups.email', - type: 'keyword', - }, - 'gsuite.groups.member.email': { - category: 'gsuite', - description: 'Member email. ', - name: 'gsuite.groups.member.email', - type: 'keyword', - }, - 'gsuite.groups.member.role': { - category: 'gsuite', - description: - 'Member role. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/groups ', - name: 'gsuite.groups.member.role', - type: 'keyword', - }, - 'gsuite.groups.setting': { - category: 'gsuite', - description: - 'Group setting updated. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/groups ', - name: 'gsuite.groups.setting', - type: 'keyword', - }, - 'gsuite.groups.new_value': { - category: 'gsuite', - description: - 'New value(s) of the group setting. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/groups ', - name: 'gsuite.groups.new_value', - type: 'keyword', - }, - 'gsuite.groups.old_value': { - category: 'gsuite', - description: - 'Old value(s) of the group setting. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/groups', - name: 'gsuite.groups.old_value', - type: 'keyword', - }, - 'gsuite.groups.value': { - category: 'gsuite', - description: - 'Value of the group setting. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/groups ', - name: 'gsuite.groups.value', - type: 'keyword', - }, - 'gsuite.groups.message.id': { - category: 'gsuite', - description: 'SMTP message Id of an email message. Present for moderation events. ', - name: 'gsuite.groups.message.id', - type: 'keyword', - }, - 'gsuite.groups.message.moderation_action': { - category: 'gsuite', - description: 'Message moderation action. Possible values are `approved` and `rejected`. ', - name: 'gsuite.groups.message.moderation_action', - type: 'keyword', - }, - 'gsuite.groups.status': { - category: 'gsuite', - description: - 'A status describing the output of an operation. Possible values are `failed` and `succeeded`. ', - name: 'gsuite.groups.status', - type: 'keyword', - }, - 'gsuite.login.affected_email_address': { - category: 'gsuite', - name: 'gsuite.login.affected_email_address', - type: 'keyword', - }, - 'gsuite.login.challenge_method': { - category: 'gsuite', - description: - 'Login challenge method. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/login. ', - name: 'gsuite.login.challenge_method', - type: 'keyword', - }, - 'gsuite.login.failure_type': { - category: 'gsuite', - description: - 'Login failure type. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/login. ', - name: 'gsuite.login.failure_type', - type: 'keyword', - }, - 'gsuite.login.type': { - category: 'gsuite', - description: - 'Login credentials type. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/login. ', - name: 'gsuite.login.type', - type: 'keyword', - }, - 'gsuite.login.is_second_factor': { - category: 'gsuite', - name: 'gsuite.login.is_second_factor', - type: 'boolean', - }, - 'gsuite.login.is_suspicious': { - category: 'gsuite', - name: 'gsuite.login.is_suspicious', - type: 'boolean', - }, - 'gsuite.saml.application_name': { - category: 'gsuite', - description: 'Saml SP application name. ', - name: 'gsuite.saml.application_name', - type: 'keyword', - }, - 'gsuite.saml.failure_type': { - category: 'gsuite', - description: - 'Login failure type. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/saml. ', - name: 'gsuite.saml.failure_type', - type: 'keyword', - }, - 'gsuite.saml.initiated_by': { - category: 'gsuite', - description: 'Requester of SAML authentication. ', - name: 'gsuite.saml.initiated_by', - type: 'keyword', - }, - 'gsuite.saml.orgunit_path': { - category: 'gsuite', - description: 'User orgunit. ', - name: 'gsuite.saml.orgunit_path', - type: 'keyword', - }, - 'gsuite.saml.status_code': { - category: 'gsuite', - description: 'SAML status code. ', - name: 'gsuite.saml.status_code', - type: 'keyword', - }, - 'gsuite.saml.second_level_status_code': { - category: 'gsuite', - description: 'SAML second level status code. ', - name: 'gsuite.saml.second_level_status_code', - type: 'keyword', - }, - 'ibmmq.errorlog.installation': { - category: 'ibmmq', - description: - 'This is the installation name which can be given at installation time. Each installation of IBM MQ on UNIX, Linux, and Windows, has a unique identifier known as an installation name. The installation name is used to associate things such as queue managers and configuration files with an installation. ', - name: 'ibmmq.errorlog.installation', - type: 'keyword', - }, - 'ibmmq.errorlog.qmgr': { - category: 'ibmmq', - description: - 'Name of the queue manager. Queue managers provide queuing services to applications, and manages the queues that belong to them. ', - name: 'ibmmq.errorlog.qmgr', - type: 'keyword', - }, - 'ibmmq.errorlog.arithinsert': { - category: 'ibmmq', - description: 'Changing content based on error.id', - name: 'ibmmq.errorlog.arithinsert', - type: 'keyword', - }, - 'ibmmq.errorlog.commentinsert': { - category: 'ibmmq', - description: 'Changing content based on error.id', - name: 'ibmmq.errorlog.commentinsert', - type: 'keyword', - }, - 'ibmmq.errorlog.errordescription': { - category: 'ibmmq', - description: 'Please add description', - example: 'Please add example', - name: 'ibmmq.errorlog.errordescription', - type: 'text', - }, - 'ibmmq.errorlog.explanation': { - category: 'ibmmq', - description: 'Explaines the error in more detail', - name: 'ibmmq.errorlog.explanation', - type: 'keyword', - }, - 'ibmmq.errorlog.action': { - category: 'ibmmq', - description: 'Defines what to do when the error occurs', - name: 'ibmmq.errorlog.action', - type: 'keyword', - }, - 'ibmmq.errorlog.code': { - category: 'ibmmq', - description: 'Error code.', - name: 'ibmmq.errorlog.code', - type: 'keyword', - }, - 'iptables.ether_type': { - category: 'iptables', - description: 'Value of the ethernet type field identifying the network layer protocol. ', - name: 'iptables.ether_type', - type: 'long', - }, - 'iptables.flow_label': { - category: 'iptables', - description: 'IPv6 flow label. ', - name: 'iptables.flow_label', - type: 'integer', - }, - 'iptables.fragment_flags': { - category: 'iptables', - description: 'IP fragment flags. A combination of CE, DF and MF. ', - name: 'iptables.fragment_flags', - type: 'keyword', - }, - 'iptables.fragment_offset': { - category: 'iptables', - description: 'Offset of the current IP fragment. ', - name: 'iptables.fragment_offset', - type: 'long', - }, - 'iptables.icmp.code': { - category: 'iptables', - description: 'ICMP code. ', - name: 'iptables.icmp.code', - type: 'long', - }, - 'iptables.icmp.id': { - category: 'iptables', - description: 'ICMP ID. ', - name: 'iptables.icmp.id', - type: 'long', - }, - 'iptables.icmp.parameter': { - category: 'iptables', - description: 'ICMP parameter. ', - name: 'iptables.icmp.parameter', - type: 'long', - }, - 'iptables.icmp.redirect': { - category: 'iptables', - description: 'ICMP redirect address. ', - name: 'iptables.icmp.redirect', - type: 'ip', - }, - 'iptables.icmp.seq': { - category: 'iptables', - description: 'ICMP sequence number. ', - name: 'iptables.icmp.seq', - type: 'long', - }, - 'iptables.icmp.type': { - category: 'iptables', - description: 'ICMP type. ', - name: 'iptables.icmp.type', - type: 'long', - }, - 'iptables.id': { - category: 'iptables', - description: 'Packet identifier. ', - name: 'iptables.id', - type: 'long', - }, - 'iptables.incomplete_bytes': { - category: 'iptables', - description: 'Number of incomplete bytes. ', - name: 'iptables.incomplete_bytes', - type: 'long', - }, - 'iptables.input_device': { - category: 'iptables', - description: 'Device that received the packet. ', - name: 'iptables.input_device', - type: 'keyword', - }, - 'iptables.precedence_bits': { - category: 'iptables', - description: 'IP precedence bits. ', - name: 'iptables.precedence_bits', - type: 'short', - }, - 'iptables.tos': { - category: 'iptables', - description: 'IP Type of Service field. ', - name: 'iptables.tos', - type: 'long', - }, - 'iptables.length': { - category: 'iptables', - description: 'Packet length. ', - name: 'iptables.length', - type: 'long', - }, - 'iptables.output_device': { - category: 'iptables', - description: 'Device that output the packet. ', - name: 'iptables.output_device', - type: 'keyword', - }, - 'iptables.tcp.flags': { - category: 'iptables', - description: 'TCP flags. ', - name: 'iptables.tcp.flags', - type: 'keyword', - }, - 'iptables.tcp.reserved_bits': { - category: 'iptables', - description: 'TCP reserved bits. ', - name: 'iptables.tcp.reserved_bits', - type: 'short', - }, - 'iptables.tcp.seq': { - category: 'iptables', - description: 'TCP sequence number. ', - name: 'iptables.tcp.seq', - type: 'long', - }, - 'iptables.tcp.ack': { - category: 'iptables', - description: 'TCP Acknowledgment number. ', - name: 'iptables.tcp.ack', - type: 'long', - }, - 'iptables.tcp.window': { - category: 'iptables', - description: 'Advertised TCP window size. ', - name: 'iptables.tcp.window', - type: 'long', - }, - 'iptables.ttl': { - category: 'iptables', - description: 'Time To Live field. ', - name: 'iptables.ttl', - type: 'integer', - }, - 'iptables.udp.length': { - category: 'iptables', - description: 'Length of the UDP header and payload. ', - name: 'iptables.udp.length', - type: 'long', - }, - 'iptables.ubiquiti.input_zone': { - category: 'iptables', - description: 'Input zone. ', - name: 'iptables.ubiquiti.input_zone', - type: 'keyword', - }, - 'iptables.ubiquiti.output_zone': { - category: 'iptables', - description: 'Output zone. ', - name: 'iptables.ubiquiti.output_zone', - type: 'keyword', - }, - 'iptables.ubiquiti.rule_number': { - category: 'iptables', - description: 'The rule number within the rule set.', - name: 'iptables.ubiquiti.rule_number', - type: 'keyword', - }, - 'iptables.ubiquiti.rule_set': { - category: 'iptables', - description: 'The rule set name.', - name: 'iptables.ubiquiti.rule_set', - type: 'keyword', - }, - 'juniper.srx.reason': { - category: 'juniper', - description: 'reason ', - name: 'juniper.srx.reason', - type: 'keyword', - }, - 'juniper.srx.connection_tag': { - category: 'juniper', - description: 'connection tag ', - name: 'juniper.srx.connection_tag', - type: 'keyword', - }, - 'juniper.srx.service_name': { - category: 'juniper', - description: 'service name ', - name: 'juniper.srx.service_name', - type: 'keyword', - }, - 'juniper.srx.nat_connection_tag': { - category: 'juniper', - description: 'nat connection tag ', - name: 'juniper.srx.nat_connection_tag', - type: 'keyword', - }, - 'juniper.srx.src_nat_rule_type': { - category: 'juniper', - description: 'src nat rule type ', - name: 'juniper.srx.src_nat_rule_type', - type: 'keyword', - }, - 'juniper.srx.src_nat_rule_name': { - category: 'juniper', - description: 'src nat rule name ', - name: 'juniper.srx.src_nat_rule_name', - type: 'keyword', - }, - 'juniper.srx.dst_nat_rule_type': { - category: 'juniper', - description: 'dst nat rule type ', - name: 'juniper.srx.dst_nat_rule_type', - type: 'keyword', - }, - 'juniper.srx.dst_nat_rule_name': { - category: 'juniper', - description: 'dst nat rule name ', - name: 'juniper.srx.dst_nat_rule_name', - type: 'keyword', - }, - 'juniper.srx.protocol_id': { - category: 'juniper', - description: 'protocol id ', - name: 'juniper.srx.protocol_id', - type: 'keyword', - }, - 'juniper.srx.policy_name': { - category: 'juniper', - description: 'policy name ', - name: 'juniper.srx.policy_name', - type: 'keyword', - }, - 'juniper.srx.session_id_32': { - category: 'juniper', - description: 'session id 32 ', - name: 'juniper.srx.session_id_32', - type: 'keyword', - }, - 'juniper.srx.session_id': { - category: 'juniper', - description: 'session id ', - name: 'juniper.srx.session_id', - type: 'keyword', - }, - 'juniper.srx.outbound_packets': { - category: 'juniper', - description: 'packets from client ', - name: 'juniper.srx.outbound_packets', - type: 'integer', - }, - 'juniper.srx.outbound_bytes': { - category: 'juniper', - description: 'bytes from client ', - name: 'juniper.srx.outbound_bytes', - type: 'integer', - }, - 'juniper.srx.inbound_packets': { - category: 'juniper', - description: 'packets from server ', - name: 'juniper.srx.inbound_packets', - type: 'integer', - }, - 'juniper.srx.inbound_bytes': { - category: 'juniper', - description: 'bytes from server ', - name: 'juniper.srx.inbound_bytes', - type: 'integer', - }, - 'juniper.srx.elapsed_time': { - category: 'juniper', - description: 'elapsed time ', - name: 'juniper.srx.elapsed_time', - type: 'date', - }, - 'juniper.srx.application': { - category: 'juniper', - description: 'application ', - name: 'juniper.srx.application', - type: 'keyword', - }, - 'juniper.srx.nested_application': { - category: 'juniper', - description: 'nested application ', - name: 'juniper.srx.nested_application', - type: 'keyword', - }, - 'juniper.srx.username': { - category: 'juniper', - description: 'username ', - name: 'juniper.srx.username', - type: 'keyword', - }, - 'juniper.srx.roles': { - category: 'juniper', - description: 'roles ', - name: 'juniper.srx.roles', - type: 'keyword', - }, - 'juniper.srx.encrypted': { - category: 'juniper', - description: 'encrypted ', - name: 'juniper.srx.encrypted', - type: 'keyword', - }, - 'juniper.srx.application_category': { - category: 'juniper', - description: 'application category ', - name: 'juniper.srx.application_category', - type: 'keyword', - }, - 'juniper.srx.application_sub_category': { - category: 'juniper', - description: 'application sub category ', - name: 'juniper.srx.application_sub_category', - type: 'keyword', - }, - 'juniper.srx.application_characteristics': { - category: 'juniper', - description: 'application characteristics ', - name: 'juniper.srx.application_characteristics', - type: 'keyword', - }, - 'juniper.srx.secure_web_proxy_session_type': { - category: 'juniper', - description: 'secure web proxy session type ', - name: 'juniper.srx.secure_web_proxy_session_type', - type: 'keyword', - }, - 'juniper.srx.peer_session_id': { - category: 'juniper', - description: 'peer session id ', - name: 'juniper.srx.peer_session_id', - type: 'keyword', - }, - 'juniper.srx.peer_source_address': { - category: 'juniper', - description: 'peer source address ', - name: 'juniper.srx.peer_source_address', - type: 'ip', - }, - 'juniper.srx.peer_source_port': { - category: 'juniper', - description: 'peer source port ', - name: 'juniper.srx.peer_source_port', - type: 'integer', - }, - 'juniper.srx.peer_destination_address': { - category: 'juniper', - description: 'peer destination address ', - name: 'juniper.srx.peer_destination_address', - type: 'ip', - }, - 'juniper.srx.peer_destination_port': { - category: 'juniper', - description: 'peer destination port ', - name: 'juniper.srx.peer_destination_port', - type: 'integer', - }, - 'juniper.srx.hostname': { - category: 'juniper', - description: 'hostname ', - name: 'juniper.srx.hostname', - type: 'keyword', - }, - 'juniper.srx.src_vrf_grp': { - category: 'juniper', - description: 'src_vrf_grp ', - name: 'juniper.srx.src_vrf_grp', - type: 'keyword', - }, - 'juniper.srx.dst_vrf_grp': { - category: 'juniper', - description: 'dst_vrf_grp ', - name: 'juniper.srx.dst_vrf_grp', - type: 'keyword', - }, - 'juniper.srx.icmp_type': { - category: 'juniper', - description: 'icmp type ', - name: 'juniper.srx.icmp_type', - type: 'integer', - }, - 'juniper.srx.process': { - category: 'juniper', - description: 'process that generated the message ', - name: 'juniper.srx.process', - type: 'keyword', - }, - 'juniper.srx.apbr_rule_type': { - category: 'juniper', - description: 'apbr rule type ', - name: 'juniper.srx.apbr_rule_type', - type: 'keyword', - }, - 'juniper.srx.dscp_value': { - category: 'juniper', - description: 'apbr rule type ', - name: 'juniper.srx.dscp_value', - type: 'integer', - }, - 'juniper.srx.logical_system_name': { - category: 'juniper', - description: 'logical system name ', - name: 'juniper.srx.logical_system_name', - type: 'keyword', - }, - 'juniper.srx.profile_name': { - category: 'juniper', - description: 'profile name ', - name: 'juniper.srx.profile_name', - type: 'keyword', - }, - 'juniper.srx.routing_instance': { - category: 'juniper', - description: 'routing instance ', - name: 'juniper.srx.routing_instance', - type: 'keyword', - }, - 'juniper.srx.rule_name': { - category: 'juniper', - description: 'rule name ', - name: 'juniper.srx.rule_name', - type: 'keyword', - }, - 'juniper.srx.uplink_tx_bytes': { - category: 'juniper', - description: 'uplink tx bytes ', - name: 'juniper.srx.uplink_tx_bytes', - type: 'integer', - }, - 'juniper.srx.uplink_rx_bytes': { - category: 'juniper', - description: 'uplink rx bytes ', - name: 'juniper.srx.uplink_rx_bytes', - type: 'integer', - }, - 'juniper.srx.obj': { - category: 'juniper', - description: 'url path ', - name: 'juniper.srx.obj', - type: 'keyword', - }, - 'juniper.srx.url': { - category: 'juniper', - description: 'url domain ', - name: 'juniper.srx.url', - type: 'keyword', - }, - 'juniper.srx.profile': { - category: 'juniper', - description: 'filter profile ', - name: 'juniper.srx.profile', - type: 'keyword', - }, - 'juniper.srx.category': { - category: 'juniper', - description: 'filter category ', - name: 'juniper.srx.category', - type: 'keyword', - }, - 'juniper.srx.filename': { - category: 'juniper', - description: 'filename ', - name: 'juniper.srx.filename', - type: 'keyword', - }, - 'juniper.srx.temporary_filename': { - category: 'juniper', - description: 'temporary_filename ', - name: 'juniper.srx.temporary_filename', - type: 'keyword', - }, - 'juniper.srx.name': { - category: 'juniper', - description: 'name ', - name: 'juniper.srx.name', - type: 'keyword', - }, - 'juniper.srx.error_message': { - category: 'juniper', - description: 'error_message ', - name: 'juniper.srx.error_message', - type: 'keyword', - }, - 'juniper.srx.error_code': { - category: 'juniper', - description: 'error_code ', - name: 'juniper.srx.error_code', - type: 'keyword', - }, - 'juniper.srx.action': { - category: 'juniper', - description: 'action ', - name: 'juniper.srx.action', - type: 'keyword', - }, - 'juniper.srx.protocol': { - category: 'juniper', - description: 'protocol ', - name: 'juniper.srx.protocol', - type: 'keyword', - }, - 'juniper.srx.protocol_name': { - category: 'juniper', - description: 'protocol name ', - name: 'juniper.srx.protocol_name', - type: 'keyword', - }, - 'juniper.srx.type': { - category: 'juniper', - description: 'type ', - name: 'juniper.srx.type', - type: 'keyword', - }, - 'juniper.srx.repeat_count': { - category: 'juniper', - description: 'repeat count ', - name: 'juniper.srx.repeat_count', - type: 'integer', - }, - 'juniper.srx.alert': { - category: 'juniper', - description: 'repeat alert ', - name: 'juniper.srx.alert', - type: 'keyword', - }, - 'juniper.srx.message_type': { - category: 'juniper', - description: 'message type ', - name: 'juniper.srx.message_type', - type: 'keyword', - }, - 'juniper.srx.threat_severity': { - category: 'juniper', - description: 'threat severity ', - name: 'juniper.srx.threat_severity', - type: 'keyword', - }, - 'juniper.srx.application_name': { - category: 'juniper', - description: 'application name ', - name: 'juniper.srx.application_name', - type: 'keyword', - }, - 'juniper.srx.attack_name': { - category: 'juniper', - description: 'attack name ', - name: 'juniper.srx.attack_name', - type: 'keyword', - }, - 'juniper.srx.index': { - category: 'juniper', - description: 'index ', - name: 'juniper.srx.index', - type: 'keyword', - }, - 'juniper.srx.message': { - category: 'juniper', - description: 'mesagge ', - name: 'juniper.srx.message', - type: 'keyword', - }, - 'juniper.srx.epoch_time': { - category: 'juniper', - description: 'epoch time ', - name: 'juniper.srx.epoch_time', - type: 'date', - }, - 'juniper.srx.packet_log_id': { - category: 'juniper', - description: 'packet log id ', - name: 'juniper.srx.packet_log_id', - type: 'integer', - }, - 'juniper.srx.export_id': { - category: 'juniper', - description: 'packet log id ', - name: 'juniper.srx.export_id', - type: 'integer', - }, - 'juniper.srx.ddos_application_name': { - category: 'juniper', - description: 'ddos application name ', - name: 'juniper.srx.ddos_application_name', - type: 'keyword', - }, - 'juniper.srx.connection_hit_rate': { - category: 'juniper', - description: 'connection hit rate ', - name: 'juniper.srx.connection_hit_rate', - type: 'integer', - }, - 'juniper.srx.time_scope': { - category: 'juniper', - description: 'time scope ', - name: 'juniper.srx.time_scope', - type: 'keyword', - }, - 'juniper.srx.context_hit_rate': { - category: 'juniper', - description: 'context hit rate ', - name: 'juniper.srx.context_hit_rate', - type: 'integer', - }, - 'juniper.srx.context_value_hit_rate': { - category: 'juniper', - description: 'context value hit rate ', - name: 'juniper.srx.context_value_hit_rate', - type: 'integer', - }, - 'juniper.srx.time_count': { - category: 'juniper', - description: 'time count ', - name: 'juniper.srx.time_count', - type: 'integer', - }, - 'juniper.srx.time_period': { - category: 'juniper', - description: 'time period ', - name: 'juniper.srx.time_period', - type: 'integer', - }, - 'juniper.srx.context_value': { - category: 'juniper', - description: 'context value ', - name: 'juniper.srx.context_value', - type: 'keyword', - }, - 'juniper.srx.context_name': { - category: 'juniper', - description: 'context name ', - name: 'juniper.srx.context_name', - type: 'keyword', - }, - 'juniper.srx.ruleebase_name': { - category: 'juniper', - description: 'ruleebase name ', - name: 'juniper.srx.ruleebase_name', - type: 'keyword', - }, - 'juniper.srx.verdict_source': { - category: 'juniper', - description: 'verdict source ', - name: 'juniper.srx.verdict_source', - type: 'keyword', - }, - 'juniper.srx.verdict_number': { - category: 'juniper', - description: 'verdict number ', - name: 'juniper.srx.verdict_number', - type: 'integer', - }, - 'juniper.srx.file_category': { - category: 'juniper', - description: 'file category ', - name: 'juniper.srx.file_category', - type: 'keyword', - }, - 'juniper.srx.sample_sha256': { - category: 'juniper', - description: 'sample sha256 ', - name: 'juniper.srx.sample_sha256', - type: 'keyword', - }, - 'juniper.srx.malware_info': { - category: 'juniper', - description: 'malware info ', - name: 'juniper.srx.malware_info', - type: 'keyword', - }, - 'juniper.srx.client_ip': { - category: 'juniper', - description: 'client ip ', - name: 'juniper.srx.client_ip', - type: 'ip', - }, - 'juniper.srx.tenant_id': { - category: 'juniper', - description: 'tenant id ', - name: 'juniper.srx.tenant_id', - type: 'keyword', - }, - 'juniper.srx.timestamp': { - category: 'juniper', - description: 'timestamp ', - name: 'juniper.srx.timestamp', - type: 'date', - }, - 'juniper.srx.th': { - category: 'juniper', - description: 'th ', - name: 'juniper.srx.th', - type: 'keyword', - }, - 'juniper.srx.status': { - category: 'juniper', - description: 'status ', - name: 'juniper.srx.status', - type: 'keyword', - }, - 'juniper.srx.state': { - category: 'juniper', - description: 'state ', - name: 'juniper.srx.state', - type: 'keyword', - }, - 'juniper.srx.file_hash_lookup': { - category: 'juniper', - description: 'file hash lookup ', - name: 'juniper.srx.file_hash_lookup', - type: 'keyword', - }, - 'juniper.srx.file_name': { - category: 'juniper', - description: 'file name ', - name: 'juniper.srx.file_name', - type: 'keyword', - }, - 'juniper.srx.action_detail': { - category: 'juniper', - description: 'action detail ', - name: 'juniper.srx.action_detail', - type: 'keyword', - }, - 'juniper.srx.sub_category': { - category: 'juniper', - description: 'sub category ', - name: 'juniper.srx.sub_category', - type: 'keyword', - }, - 'juniper.srx.feed_name': { - category: 'juniper', - description: 'feed name ', - name: 'juniper.srx.feed_name', - type: 'keyword', - }, - 'juniper.srx.occur_count': { - category: 'juniper', - description: 'occur count ', - name: 'juniper.srx.occur_count', - type: 'integer', - }, - 'juniper.srx.tag': { - category: 'juniper', - description: 'system log message tag, which uniquely identifies the message. ', - name: 'juniper.srx.tag', - type: 'keyword', - }, - 'microsoft.defender_atp.lastUpdateTime': { - category: 'microsoft', - description: 'The date and time (in UTC) the alert was last updated. ', - name: 'microsoft.defender_atp.lastUpdateTime', - type: 'date', - }, - 'microsoft.defender_atp.resolvedTime': { - category: 'microsoft', - description: "The date and time in which the status of the alert was changed to 'Resolved'. ", - name: 'microsoft.defender_atp.resolvedTime', - type: 'date', - }, - 'microsoft.defender_atp.incidentId': { - category: 'microsoft', - description: 'The Incident ID of the Alert. ', - name: 'microsoft.defender_atp.incidentId', - type: 'keyword', - }, - 'microsoft.defender_atp.investigationId': { - category: 'microsoft', - description: 'The Investigation ID related to the Alert. ', - name: 'microsoft.defender_atp.investigationId', - type: 'keyword', - }, - 'microsoft.defender_atp.investigationState': { - category: 'microsoft', - description: 'The current state of the Investigation. ', - name: 'microsoft.defender_atp.investigationState', - type: 'keyword', - }, - 'microsoft.defender_atp.assignedTo': { - category: 'microsoft', - description: 'Owner of the alert. ', - name: 'microsoft.defender_atp.assignedTo', - type: 'keyword', - }, - 'microsoft.defender_atp.status': { - category: 'microsoft', - description: - "Specifies the current status of the alert. Possible values are: 'Unknown', 'New', 'InProgress' and 'Resolved'. ", - name: 'microsoft.defender_atp.status', - type: 'keyword', - }, - 'microsoft.defender_atp.classification': { - category: 'microsoft', - description: - "Specification of the alert. Possible values are: 'Unknown', 'FalsePositive', 'TruePositive'. ", - name: 'microsoft.defender_atp.classification', - type: 'keyword', - }, - 'microsoft.defender_atp.determination': { - category: 'microsoft', - description: - "Specifies the determination of the alert. Possible values are: 'NotAvailable', 'Apt', 'Malware', 'SecurityPersonnel', 'SecurityTesting', 'UnwantedSoftware', 'Other'. ", - name: 'microsoft.defender_atp.determination', - type: 'keyword', - }, - 'microsoft.defender_atp.threatFamilyName': { - category: 'microsoft', - description: 'Threat family. ', - name: 'microsoft.defender_atp.threatFamilyName', - type: 'keyword', - }, - 'microsoft.defender_atp.rbacGroupName': { - category: 'microsoft', - description: 'User group related to the alert ', - name: 'microsoft.defender_atp.rbacGroupName', - type: 'keyword', - }, - 'microsoft.defender_atp.evidence.domainName': { - category: 'microsoft', - description: 'Domain name related to the alert ', - name: 'microsoft.defender_atp.evidence.domainName', - type: 'keyword', - }, - 'microsoft.defender_atp.evidence.ipAddress': { - category: 'microsoft', - description: 'IP address involved in the alert ', - name: 'microsoft.defender_atp.evidence.ipAddress', - type: 'ip', - }, - 'microsoft.defender_atp.evidence.aadUserId': { - category: 'microsoft', - description: 'ID of the user involved in the alert ', - name: 'microsoft.defender_atp.evidence.aadUserId', - type: 'keyword', - }, - 'microsoft.defender_atp.evidence.accountName': { - category: 'microsoft', - description: 'Username of the user involved in the alert ', - name: 'microsoft.defender_atp.evidence.accountName', - type: 'keyword', - }, - 'microsoft.defender_atp.evidence.entityType': { - category: 'microsoft', - description: 'The type of evidence ', - name: 'microsoft.defender_atp.evidence.entityType', - type: 'keyword', - }, - 'microsoft.defender_atp.evidence.userPrincipalName': { - category: 'microsoft', - description: 'Principal name of the user involved in the alert ', - name: 'microsoft.defender_atp.evidence.userPrincipalName', - type: 'keyword', - }, - 'microsoft.m365_defender.incidentId': { - category: 'microsoft', - description: 'Unique identifier to represent the incident. ', - name: 'microsoft.m365_defender.incidentId', - type: 'keyword', - }, - 'microsoft.m365_defender.redirectIncidentId': { - category: 'microsoft', - description: - 'Only populated in case an incident is being grouped together with another incident, as part of the incident processing logic. ', - name: 'microsoft.m365_defender.redirectIncidentId', - type: 'keyword', - }, - 'microsoft.m365_defender.incidentName': { - category: 'microsoft', - description: 'Name of the Incident. ', - name: 'microsoft.m365_defender.incidentName', - type: 'keyword', - }, - 'microsoft.m365_defender.determination': { - category: 'microsoft', - description: - 'Specifies the determination of the incident. The property values are: NotAvailable, Apt, Malware, SecurityPersonnel, SecurityTesting, UnwantedSoftware, Other. ', - name: 'microsoft.m365_defender.determination', - type: 'keyword', - }, - 'microsoft.m365_defender.investigationState': { - category: 'microsoft', - description: 'The current state of the Investigation. ', - name: 'microsoft.m365_defender.investigationState', - type: 'keyword', - }, - 'microsoft.m365_defender.assignedTo': { - category: 'microsoft', - description: 'Owner of the alert. ', - name: 'microsoft.m365_defender.assignedTo', - type: 'keyword', - }, - 'microsoft.m365_defender.tags': { - category: 'microsoft', - description: - 'Array of custom tags associated with an incident, for example to flag a group of incidents with a common characteristic. ', - name: 'microsoft.m365_defender.tags', - type: 'keyword', - }, - 'microsoft.m365_defender.status': { - category: 'microsoft', - description: - "Specifies the current status of the alert. Possible values are: 'Unknown', 'New', 'InProgress' and 'Resolved'. ", - name: 'microsoft.m365_defender.status', - type: 'keyword', - }, - 'microsoft.m365_defender.classification': { - category: 'microsoft', - description: - "Specification of the alert. Possible values are: 'Unknown', 'FalsePositive', 'TruePositive'. ", - name: 'microsoft.m365_defender.classification', - type: 'keyword', - }, - 'microsoft.m365_defender.alerts.incidentId': { - category: 'microsoft', - description: 'Unique identifier to represent the incident this alert is associated with. ', - name: 'microsoft.m365_defender.alerts.incidentId', - type: 'keyword', - }, - 'microsoft.m365_defender.alerts.resolvedTime': { - category: 'microsoft', - description: 'Time when alert was resolved. ', - name: 'microsoft.m365_defender.alerts.resolvedTime', - type: 'date', - }, - 'microsoft.m365_defender.alerts.status': { - category: 'microsoft', - description: 'Categorize alerts (as New, Active, or Resolved). ', - name: 'microsoft.m365_defender.alerts.status', - type: 'keyword', - }, - 'microsoft.m365_defender.alerts.severity': { - category: 'microsoft', - description: 'The severity of the related alert. ', - name: 'microsoft.m365_defender.alerts.severity', - type: 'keyword', - }, - 'microsoft.m365_defender.alerts.creationTime': { - category: 'microsoft', - description: 'Time when alert was first created. ', - name: 'microsoft.m365_defender.alerts.creationTime', - type: 'date', - }, - 'microsoft.m365_defender.alerts.lastUpdatedTime': { - category: 'microsoft', - description: 'Time when alert was last updated. ', - name: 'microsoft.m365_defender.alerts.lastUpdatedTime', - type: 'date', - }, - 'microsoft.m365_defender.alerts.investigationId': { - category: 'microsoft', - description: 'The automated investigation id triggered by this alert. ', - name: 'microsoft.m365_defender.alerts.investigationId', - type: 'keyword', - }, - 'microsoft.m365_defender.alerts.userSid': { - category: 'microsoft', - description: 'The SID of the related user ', - name: 'microsoft.m365_defender.alerts.userSid', - type: 'keyword', - }, - 'microsoft.m365_defender.alerts.detectionSource': { - category: 'microsoft', - description: 'The service that initially detected the threat. ', - name: 'microsoft.m365_defender.alerts.detectionSource', - type: 'keyword', - }, - 'microsoft.m365_defender.alerts.classification': { - category: 'microsoft', - description: - 'The specification for the incident. The property values are: Unknown, FalsePositive, TruePositive or null. ', - name: 'microsoft.m365_defender.alerts.classification', - type: 'keyword', - }, - 'microsoft.m365_defender.alerts.investigationState': { - category: 'microsoft', - description: "Information on the investigation's current status. ", - name: 'microsoft.m365_defender.alerts.investigationState', - type: 'keyword', - }, - 'microsoft.m365_defender.alerts.determination': { - category: 'microsoft', - description: - 'Specifies the determination of the incident. The property values are: NotAvailable, Apt, Malware, SecurityPersonnel, SecurityTesting, UnwantedSoftware, Other or null ', - name: 'microsoft.m365_defender.alerts.determination', - type: 'keyword', - }, - 'microsoft.m365_defender.alerts.assignedTo': { - category: 'microsoft', - description: 'Owner of the incident, or null if no owner is assigned. ', - name: 'microsoft.m365_defender.alerts.assignedTo', - type: 'keyword', - }, - 'microsoft.m365_defender.alerts.actorName': { - category: 'microsoft', - description: 'The activity group, if any, the associated with this alert. ', - name: 'microsoft.m365_defender.alerts.actorName', - type: 'keyword', - }, - 'microsoft.m365_defender.alerts.threatFamilyName': { - category: 'microsoft', - description: 'Threat family associated with this alert. ', - name: 'microsoft.m365_defender.alerts.threatFamilyName', - type: 'keyword', - }, - 'microsoft.m365_defender.alerts.mitreTechniques': { - category: 'microsoft', - description: 'The attack techniques, as aligned with the MITRE ATT&CK™ framework. ', - name: 'microsoft.m365_defender.alerts.mitreTechniques', - type: 'keyword', - }, - 'microsoft.m365_defender.alerts.entities.entityType': { - category: 'microsoft', - description: - 'Entities that have been identified to be part of, or related to, a given alert. The properties values are: User, Ip, Url, File, Process, MailBox, MailMessage, MailCluster, Registry. ', - name: 'microsoft.m365_defender.alerts.entities.entityType', - type: 'keyword', - }, - 'microsoft.m365_defender.alerts.entities.accountName': { - category: 'microsoft', - description: 'Account name of the related user. ', - name: 'microsoft.m365_defender.alerts.entities.accountName', - type: 'keyword', - }, - 'microsoft.m365_defender.alerts.entities.mailboxDisplayName': { - category: 'microsoft', - description: 'The display name of the related mailbox. ', - name: 'microsoft.m365_defender.alerts.entities.mailboxDisplayName', - type: 'keyword', - }, - 'microsoft.m365_defender.alerts.entities.mailboxAddress': { - category: 'microsoft', - description: 'The mail address of the related mailbox. ', - name: 'microsoft.m365_defender.alerts.entities.mailboxAddress', - type: 'keyword', - }, - 'microsoft.m365_defender.alerts.entities.clusterBy': { - category: 'microsoft', - description: 'A list of metadata if the entityType is MailCluster. ', - name: 'microsoft.m365_defender.alerts.entities.clusterBy', - type: 'keyword', - }, - 'microsoft.m365_defender.alerts.entities.sender': { - category: 'microsoft', - description: 'The sender for the related email message. ', - name: 'microsoft.m365_defender.alerts.entities.sender', - type: 'keyword', - }, - 'microsoft.m365_defender.alerts.entities.recipient': { - category: 'microsoft', - description: 'The recipient for the related email message. ', - name: 'microsoft.m365_defender.alerts.entities.recipient', - type: 'keyword', - }, - 'microsoft.m365_defender.alerts.entities.subject': { - category: 'microsoft', - description: 'The subject for the related email message. ', - name: 'microsoft.m365_defender.alerts.entities.subject', - type: 'keyword', - }, - 'microsoft.m365_defender.alerts.entities.deliveryAction': { - category: 'microsoft', - description: 'The delivery status for the related email message. ', - name: 'microsoft.m365_defender.alerts.entities.deliveryAction', - type: 'keyword', - }, - 'microsoft.m365_defender.alerts.entities.securityGroupId': { - category: 'microsoft', - description: 'The Security Group ID for the user related to the email message. ', - name: 'microsoft.m365_defender.alerts.entities.securityGroupId', - type: 'keyword', - }, - 'microsoft.m365_defender.alerts.entities.securityGroupName': { - category: 'microsoft', - description: 'The Security Group Name for the user related to the email message. ', - name: 'microsoft.m365_defender.alerts.entities.securityGroupName', - type: 'keyword', - }, - 'microsoft.m365_defender.alerts.entities.registryHive': { - category: 'microsoft', - description: - 'Reference to which Hive in registry the event is related to, if eventType is registry. Example: HKEY_LOCAL_MACHINE. ', - name: 'microsoft.m365_defender.alerts.entities.registryHive', - type: 'keyword', - }, - 'microsoft.m365_defender.alerts.entities.registryKey': { - category: 'microsoft', - description: 'Reference to the related registry key to the event. ', - name: 'microsoft.m365_defender.alerts.entities.registryKey', - type: 'keyword', - }, - 'microsoft.m365_defender.alerts.entities.registryValueType': { - category: 'microsoft', - description: 'Value type of the registry key/value pair related to the event. ', - name: 'microsoft.m365_defender.alerts.entities.registryValueType', - type: 'keyword', - }, - 'microsoft.m365_defender.alerts.entities.deviceId': { - category: 'microsoft', - description: 'The unique ID of the device related to the event. ', - name: 'microsoft.m365_defender.alerts.entities.deviceId', - type: 'keyword', - }, - 'microsoft.m365_defender.alerts.entities.ipAddress': { - category: 'microsoft', - description: 'The related IP address to the event. ', - name: 'microsoft.m365_defender.alerts.entities.ipAddress', - type: 'keyword', - }, - 'microsoft.m365_defender.alerts.devices': { - category: 'microsoft', - description: 'The devices related to the investigation. ', - name: 'microsoft.m365_defender.alerts.devices', - type: 'flattened', - }, - 'misp.attack_pattern.id': { - category: 'misp', - description: 'Identifier of the threat indicator. ', - name: 'misp.attack_pattern.id', - type: 'keyword', - }, - 'misp.attack_pattern.name': { - category: 'misp', - description: 'Name of the attack pattern. ', - name: 'misp.attack_pattern.name', - type: 'keyword', - }, - 'misp.attack_pattern.description': { - category: 'misp', - description: 'Description of the attack pattern. ', - name: 'misp.attack_pattern.description', - type: 'text', - }, - 'misp.attack_pattern.kill_chain_phases': { - category: 'misp', - description: 'The kill chain phase(s) to which this attack pattern corresponds. ', - name: 'misp.attack_pattern.kill_chain_phases', - type: 'keyword', - }, - 'misp.campaign.id': { - category: 'misp', - description: 'Identifier of the campaign. ', - name: 'misp.campaign.id', - type: 'keyword', - }, - 'misp.campaign.name': { - category: 'misp', - description: 'Name of the campaign. ', - name: 'misp.campaign.name', - type: 'keyword', - }, - 'misp.campaign.description': { - category: 'misp', - description: 'Description of the campaign. ', - name: 'misp.campaign.description', - type: 'text', - }, - 'misp.campaign.aliases': { - category: 'misp', - description: 'Alternative names used to identify this campaign. ', - name: 'misp.campaign.aliases', - type: 'text', - }, - 'misp.campaign.first_seen': { - category: 'misp', - description: 'The time that this Campaign was first seen, in RFC3339 format. ', - name: 'misp.campaign.first_seen', - type: 'date', - }, - 'misp.campaign.last_seen': { - category: 'misp', - description: 'The time that this Campaign was last seen, in RFC3339 format. ', - name: 'misp.campaign.last_seen', - type: 'date', - }, - 'misp.campaign.objective': { - category: 'misp', - description: - "This field defines the Campaign's primary goal, objective, desired outcome, or intended effect. ", - name: 'misp.campaign.objective', - type: 'keyword', - }, - 'misp.course_of_action.id': { - category: 'misp', - description: 'Identifier of the Course of Action. ', - name: 'misp.course_of_action.id', - type: 'keyword', - }, - 'misp.course_of_action.name': { - category: 'misp', - description: 'The name used to identify the Course of Action. ', - name: 'misp.course_of_action.name', - type: 'keyword', - }, - 'misp.course_of_action.description': { - category: 'misp', - description: 'Description of the Course of Action. ', - name: 'misp.course_of_action.description', - type: 'text', - }, - 'misp.identity.id': { - category: 'misp', - description: 'Identifier of the Identity. ', - name: 'misp.identity.id', - type: 'keyword', - }, - 'misp.identity.name': { - category: 'misp', - description: 'The name used to identify the Identity. ', - name: 'misp.identity.name', - type: 'keyword', - }, - 'misp.identity.description': { - category: 'misp', - description: 'Description of the Identity. ', - name: 'misp.identity.description', - type: 'text', - }, - 'misp.identity.identity_class': { - category: 'misp', - description: - 'The type of entity that this Identity describes, e.g., an individual or organization. Open Vocab - identity-class-ov ', - name: 'misp.identity.identity_class', - type: 'keyword', - }, - 'misp.identity.labels': { - category: 'misp', - description: 'The list of roles that this Identity performs. ', - example: 'CEO\n', - name: 'misp.identity.labels', - type: 'keyword', - }, - 'misp.identity.sectors': { - category: 'misp', - description: - 'The list of sectors that this Identity belongs to. Open Vocab - industry-sector-ov ', - name: 'misp.identity.sectors', - type: 'keyword', - }, - 'misp.identity.contact_information': { - category: 'misp', - description: 'The contact information (e-mail, phone number, etc.) for this Identity. ', - name: 'misp.identity.contact_information', - type: 'text', - }, - 'misp.intrusion_set.id': { - category: 'misp', - description: 'Identifier of the Intrusion Set. ', - name: 'misp.intrusion_set.id', - type: 'keyword', - }, - 'misp.intrusion_set.name': { - category: 'misp', - description: 'The name used to identify the Intrusion Set. ', - name: 'misp.intrusion_set.name', - type: 'keyword', - }, - 'misp.intrusion_set.description': { - category: 'misp', - description: 'Description of the Intrusion Set. ', - name: 'misp.intrusion_set.description', - type: 'text', - }, - 'misp.intrusion_set.aliases': { - category: 'misp', - description: 'Alternative names used to identify the Intrusion Set. ', - name: 'misp.intrusion_set.aliases', - type: 'text', - }, - 'misp.intrusion_set.first_seen': { - category: 'misp', - description: 'The time that this Intrusion Set was first seen, in RFC3339 format. ', - name: 'misp.intrusion_set.first_seen', - type: 'date', - }, - 'misp.intrusion_set.last_seen': { - category: 'misp', - description: 'The time that this Intrusion Set was last seen, in RFC3339 format. ', - name: 'misp.intrusion_set.last_seen', - type: 'date', - }, - 'misp.intrusion_set.goals': { - category: 'misp', - description: 'The high level goals of this Intrusion Set, namely, what are they trying to do. ', - name: 'misp.intrusion_set.goals', - type: 'text', - }, - 'misp.intrusion_set.resource_level': { - category: 'misp', - description: - 'This defines the organizational level at which this Intrusion Set typically works. Open Vocab - attack-resource-level-ov ', - name: 'misp.intrusion_set.resource_level', - type: 'text', - }, - 'misp.intrusion_set.primary_motivation': { - category: 'misp', - description: - 'The primary reason, motivation, or purpose behind this Intrusion Set. Open Vocab - attack-motivation-ov ', - name: 'misp.intrusion_set.primary_motivation', - type: 'text', - }, - 'misp.intrusion_set.secondary_motivations': { - category: 'misp', - description: - 'The secondary reasons, motivations, or purposes behind this Intrusion Set. Open Vocab - attack-motivation-ov ', - name: 'misp.intrusion_set.secondary_motivations', - type: 'text', - }, - 'misp.malware.id': { - category: 'misp', - description: 'Identifier of the Malware. ', - name: 'misp.malware.id', - type: 'keyword', - }, - 'misp.malware.name': { - category: 'misp', - description: 'The name used to identify the Malware. ', - name: 'misp.malware.name', - type: 'keyword', - }, - 'misp.malware.description': { - category: 'misp', - description: 'Description of the Malware. ', - name: 'misp.malware.description', - type: 'text', - }, - 'misp.malware.labels': { - category: 'misp', - description: - 'The type of malware being described. Open Vocab - malware-label-ov. adware,backdoor,bot,ddos,dropper,exploit-kit,keylogger,ransomware, remote-access-trojan,resource-exploitation,rogue-security-software,rootkit, screen-capture,spyware,trojan,virus,worm ', - name: 'misp.malware.labels', - type: 'keyword', - }, - 'misp.malware.kill_chain_phases': { - category: 'misp', - description: 'The list of kill chain phases for which this Malware instance can be used. ', - name: 'misp.malware.kill_chain_phases', - type: 'keyword', - format: 'string', - }, - 'misp.note.id': { - category: 'misp', - description: 'Identifier of the Note. ', - name: 'misp.note.id', - type: 'keyword', - }, - 'misp.note.summary': { - category: 'misp', - description: 'A brief description used as a summary of the Note. ', - name: 'misp.note.summary', - type: 'keyword', - }, - 'misp.note.description': { - category: 'misp', - description: 'The content of the Note. ', - name: 'misp.note.description', - type: 'text', - }, - 'misp.note.authors': { - category: 'misp', - description: 'The name of the author(s) of this Note. ', - name: 'misp.note.authors', - type: 'keyword', - }, - 'misp.note.object_refs': { - category: 'misp', - description: 'The STIX Objects (SDOs and SROs) that the note is being applied to. ', - name: 'misp.note.object_refs', - type: 'keyword', - }, - 'misp.threat_indicator.labels': { - category: 'misp', - description: 'list of type open-vocab that specifies the type of indicator. ', - example: 'Domain Watchlist\n', - name: 'misp.threat_indicator.labels', - type: 'keyword', - }, - 'misp.threat_indicator.id': { - category: 'misp', - description: 'Identifier of the threat indicator. ', - name: 'misp.threat_indicator.id', - type: 'keyword', - }, - 'misp.threat_indicator.version': { - category: 'misp', - description: 'Version of the threat indicator. ', - name: 'misp.threat_indicator.version', - type: 'keyword', - }, - 'misp.threat_indicator.type': { - category: 'misp', - description: 'Type of the threat indicator. ', - name: 'misp.threat_indicator.type', - type: 'keyword', - }, - 'misp.threat_indicator.description': { - category: 'misp', - description: 'Description of the threat indicator. ', - name: 'misp.threat_indicator.description', - type: 'text', - }, - 'misp.threat_indicator.feed': { - category: 'misp', - description: 'Name of the threat feed. ', - name: 'misp.threat_indicator.feed', - type: 'text', - }, - 'misp.threat_indicator.valid_from': { - category: 'misp', - description: - 'The time from which this Indicator should be considered valuable intelligence, in RFC3339 format. ', - name: 'misp.threat_indicator.valid_from', - type: 'date', - }, - 'misp.threat_indicator.valid_until': { - category: 'misp', - description: - 'The time at which this Indicator should no longer be considered valuable intelligence. If the valid_until property is omitted, then there is no constraint on the latest time for which the indicator should be used, in RFC3339 format. ', - name: 'misp.threat_indicator.valid_until', - type: 'date', - }, - 'misp.threat_indicator.severity': { - category: 'misp', - description: 'Threat severity to which this indicator corresponds. ', - example: 'high', - name: 'misp.threat_indicator.severity', - type: 'keyword', - format: 'string', - }, - 'misp.threat_indicator.confidence': { - category: 'misp', - description: 'Confidence level to which this indicator corresponds. ', - example: 'high', - name: 'misp.threat_indicator.confidence', - type: 'keyword', - }, - 'misp.threat_indicator.kill_chain_phases': { - category: 'misp', - description: 'The kill chain phase(s) to which this indicator corresponds. ', - name: 'misp.threat_indicator.kill_chain_phases', - type: 'keyword', - format: 'string', - }, - 'misp.threat_indicator.mitre_tactic': { - category: 'misp', - description: 'MITRE tactics to which this indicator corresponds. ', - example: 'Initial Access', - name: 'misp.threat_indicator.mitre_tactic', - type: 'keyword', - format: 'string', - }, - 'misp.threat_indicator.mitre_technique': { - category: 'misp', - description: 'MITRE techniques to which this indicator corresponds. ', - example: 'Drive-by Compromise', - name: 'misp.threat_indicator.mitre_technique', - type: 'keyword', - format: 'string', - }, - 'misp.threat_indicator.attack_pattern': { - category: 'misp', - description: - 'The attack_pattern for this indicator is a STIX Pattern as specified in STIX Version 2.0 Part 5 - STIX Patterning. ', - example: "[destination:ip = '91.219.29.188/32']\n", - name: 'misp.threat_indicator.attack_pattern', - type: 'keyword', - }, - 'misp.threat_indicator.attack_pattern_kql': { - category: 'misp', - description: - 'The attack_pattern for this indicator is KQL query that matches the attack_pattern specified in the STIX Pattern format. ', - example: 'destination.ip: "91.219.29.188/32"\n', - name: 'misp.threat_indicator.attack_pattern_kql', - type: 'keyword', - }, - 'misp.threat_indicator.negate': { - category: 'misp', - description: 'When set to true, it specifies the absence of the attack_pattern. ', - name: 'misp.threat_indicator.negate', - type: 'boolean', - }, - 'misp.threat_indicator.intrusion_set': { - category: 'misp', - description: 'Name of the intrusion set if known. ', - name: 'misp.threat_indicator.intrusion_set', - type: 'keyword', - }, - 'misp.threat_indicator.campaign': { - category: 'misp', - description: 'Name of the attack campaign if known. ', - name: 'misp.threat_indicator.campaign', - type: 'keyword', - }, - 'misp.threat_indicator.threat_actor': { - category: 'misp', - description: 'Name of the threat actor if known. ', - name: 'misp.threat_indicator.threat_actor', - type: 'keyword', - }, - 'misp.observed_data.id': { - category: 'misp', - description: 'Identifier of the Observed Data. ', - name: 'misp.observed_data.id', - type: 'keyword', - }, - 'misp.observed_data.first_observed': { - category: 'misp', - description: 'The beginning of the time window that the data was observed, in RFC3339 format. ', - name: 'misp.observed_data.first_observed', - type: 'date', - }, - 'misp.observed_data.last_observed': { - category: 'misp', - description: 'The end of the time window that the data was observed, in RFC3339 format. ', - name: 'misp.observed_data.last_observed', - type: 'date', - }, - 'misp.observed_data.number_observed': { - category: 'misp', - description: - 'The number of times the data represented in the objects property was observed. This MUST be an integer between 1 and 999,999,999 inclusive. ', - name: 'misp.observed_data.number_observed', - type: 'integer', - }, - 'misp.observed_data.objects': { - category: 'misp', - description: - 'A dictionary of Cyber Observable Objects that describes the single fact that was observed. ', - name: 'misp.observed_data.objects', - type: 'keyword', - }, - 'misp.report.id': { - category: 'misp', - description: 'Identifier of the Report. ', - name: 'misp.report.id', - type: 'keyword', - }, - 'misp.report.labels': { - category: 'misp', - description: - 'This field is an Open Vocabulary that specifies the primary subject of this report. Open Vocab - report-label-ov. threat-report,attack-pattern,campaign,identity,indicator,malware,observed-data,threat-actor,tool,vulnerability ', - name: 'misp.report.labels', - type: 'keyword', - }, - 'misp.report.name': { - category: 'misp', - description: 'The name used to identify the Report. ', - name: 'misp.report.name', - type: 'keyword', - }, - 'misp.report.description': { - category: 'misp', - description: 'A description that provides more details and context about Report. ', - name: 'misp.report.description', - type: 'text', - }, - 'misp.report.published': { - category: 'misp', - description: - 'The date that this report object was officially published by the creator of this report, in RFC3339 format. ', - name: 'misp.report.published', - type: 'date', - }, - 'misp.report.object_refs': { - category: 'misp', - description: 'Specifies the STIX Objects that are referred to by this Report. ', - name: 'misp.report.object_refs', - type: 'text', - }, - 'misp.threat_actor.id': { - category: 'misp', - description: 'Identifier of the Threat Actor. ', - name: 'misp.threat_actor.id', - type: 'keyword', - }, - 'misp.threat_actor.labels': { - category: 'misp', - description: - 'This field specifies the type of threat actor. Open Vocab - threat-actor-label-ov. activist,competitor,crime-syndicate,criminal,hacker,insider-accidental,insider-disgruntled,nation-state,sensationalist,spy,terrorist ', - name: 'misp.threat_actor.labels', - type: 'keyword', - }, - 'misp.threat_actor.name': { - category: 'misp', - description: 'The name used to identify this Threat Actor or Threat Actor group. ', - name: 'misp.threat_actor.name', - type: 'keyword', - }, - 'misp.threat_actor.description': { - category: 'misp', - description: 'A description that provides more details and context about the Threat Actor. ', - name: 'misp.threat_actor.description', - type: 'text', - }, - 'misp.threat_actor.aliases': { - category: 'misp', - description: 'A list of other names that this Threat Actor is believed to use. ', - name: 'misp.threat_actor.aliases', - type: 'text', - }, - 'misp.threat_actor.roles': { - category: 'misp', - description: - 'This is a list of roles the Threat Actor plays. Open Vocab - threat-actor-role-ov. agent,director,independent,sponsor,infrastructure-operator,infrastructure-architect,malware-author ', - name: 'misp.threat_actor.roles', - type: 'text', - }, - 'misp.threat_actor.goals': { - category: 'misp', - description: 'The high level goals of this Threat Actor, namely, what are they trying to do. ', - name: 'misp.threat_actor.goals', - type: 'text', - }, - 'misp.threat_actor.sophistication': { - category: 'misp', - description: - 'The skill, specific knowledge, special training, or expertise a Threat Actor must have to perform the attack. Open Vocab - threat-actor-sophistication-ov. none,minimal,intermediate,advanced,strategic,expert,innovator ', - name: 'misp.threat_actor.sophistication', - type: 'text', - }, - 'misp.threat_actor.resource_level': { - category: 'misp', - description: - 'This defines the organizational level at which this Threat Actor typically works. Open Vocab - attack-resource-level-ov. individual,club,contest,team,organization,government ', - name: 'misp.threat_actor.resource_level', - type: 'text', - }, - 'misp.threat_actor.primary_motivation': { - category: 'misp', - description: - 'The primary reason, motivation, or purpose behind this Threat Actor. Open Vocab - attack-motivation-ov. accidental,coercion,dominance,ideology,notoriety,organizational-gain,personal-gain,personal-satisfaction,revenge,unpredictable ', - name: 'misp.threat_actor.primary_motivation', - type: 'text', - }, - 'misp.threat_actor.secondary_motivations': { - category: 'misp', - description: - 'The secondary reasons, motivations, or purposes behind this Threat Actor. Open Vocab - attack-motivation-ov. accidental,coercion,dominance,ideology,notoriety,organizational-gain,personal-gain,personal-satisfaction,revenge,unpredictable ', - name: 'misp.threat_actor.secondary_motivations', - type: 'text', - }, - 'misp.threat_actor.personal_motivations': { - category: 'misp', - description: - 'The personal reasons, motivations, or purposes of the Threat Actor regardless of organizational goals. Open Vocab - attack-motivation-ov. accidental,coercion,dominance,ideology,notoriety,organizational-gain,personal-gain,personal-satisfaction,revenge,unpredictable ', - name: 'misp.threat_actor.personal_motivations', - type: 'text', - }, - 'misp.tool.id': { - category: 'misp', - description: 'Identifier of the Tool. ', - name: 'misp.tool.id', - type: 'keyword', - }, - 'misp.tool.labels': { - category: 'misp', - description: - 'The kind(s) of tool(s) being described. Open Vocab - tool-label-ov. denial-of-service,exploitation,information-gathering,network-capture,credential-exploitation,remote-access,vulnerability-scanning ', - name: 'misp.tool.labels', - type: 'keyword', - }, - 'misp.tool.name': { - category: 'misp', - description: 'The name used to identify the Tool. ', - name: 'misp.tool.name', - type: 'keyword', - }, - 'misp.tool.description': { - category: 'misp', - description: 'A description that provides more details and context about the Tool. ', - name: 'misp.tool.description', - type: 'text', - }, - 'misp.tool.tool_version': { - category: 'misp', - description: 'The version identifier associated with the Tool. ', - name: 'misp.tool.tool_version', - type: 'keyword', - }, - 'misp.tool.kill_chain_phases': { - category: 'misp', - description: 'The list of kill chain phases for which this Tool instance can be used. ', - name: 'misp.tool.kill_chain_phases', - type: 'text', - }, - 'misp.vulnerability.id': { - category: 'misp', - description: 'Identifier of the Vulnerability. ', - name: 'misp.vulnerability.id', - type: 'keyword', - }, - 'misp.vulnerability.name': { - category: 'misp', - description: 'The name used to identify the Vulnerability. ', - name: 'misp.vulnerability.name', - type: 'keyword', - }, - 'misp.vulnerability.description': { - category: 'misp', - description: 'A description that provides more details and context about the Vulnerability. ', - name: 'misp.vulnerability.description', - type: 'text', - }, - 'mssql.log.origin': { - category: 'mssql', - description: 'Origin of the message, usually the server but it can also be a recovery process', - name: 'mssql.log.origin', - type: 'keyword', - }, - 'mysqlenterprise.audit.class': { - category: 'mysqlenterprise', - description: - 'A string representing the event class. The class defines the type of event, when taken together with the event item that specifies the event subclass. ', - name: 'mysqlenterprise.audit.class', - type: 'keyword', - }, - 'mysqlenterprise.audit.connection_id': { - category: 'mysqlenterprise', - description: - 'An integer representing the client connection identifier. This is the same as the value returned by the CONNECTION_ID() function within the session. ', - name: 'mysqlenterprise.audit.connection_id', - type: 'keyword', - }, - 'mysqlenterprise.audit.id': { - category: 'mysqlenterprise', - description: 'An unsigned integer representing an event ID. ', - name: 'mysqlenterprise.audit.id', - type: 'keyword', - }, - 'mysqlenterprise.audit.connection_data.connection_type': { - category: 'mysqlenterprise', - description: - 'The security state of the connection to the server. Permitted values are tcp/ip (TCP/IP connection established without encryption), ssl (TCP/IP connection established with encryption), socket (Unix socket file connection), named_pipe (Windows named pipe connection), and shared_memory (Windows shared memory connection). ', - name: 'mysqlenterprise.audit.connection_data.connection_type', - type: 'keyword', - }, - 'mysqlenterprise.audit.connection_data.status': { - category: 'mysqlenterprise', - description: - 'An integer representing the command status: 0 for success, nonzero if an error occurred. ', - name: 'mysqlenterprise.audit.connection_data.status', - type: 'long', - }, - 'mysqlenterprise.audit.connection_data.db': { - category: 'mysqlenterprise', - description: - 'A string representing a database name. For connection_data, it is the default database. For table_access_data, it is the table database. ', - name: 'mysqlenterprise.audit.connection_data.db', - type: 'keyword', - }, - 'mysqlenterprise.audit.connection_data.connection_attributes': { - category: 'mysqlenterprise', - description: 'Connection attributes that might be passed by different MySQL Clients. ', - name: 'mysqlenterprise.audit.connection_data.connection_attributes', - type: 'flattened', - }, - 'mysqlenterprise.audit.general_data.command': { - category: 'mysqlenterprise', - description: - 'A string representing the type of instruction that generated the audit event, such as a command that the server received from a client. ', - name: 'mysqlenterprise.audit.general_data.command', - type: 'keyword', - }, - 'mysqlenterprise.audit.general_data.sql_command': { - category: 'mysqlenterprise', - description: 'A string that indicates the SQL statement type. ', - name: 'mysqlenterprise.audit.general_data.sql_command', - type: 'keyword', - }, - 'mysqlenterprise.audit.general_data.query': { - category: 'mysqlenterprise', - description: - 'A string representing the text of an SQL statement. The value can be empty. Long values may be truncated. The string, like the audit log file itself, is written using UTF-8 (up to 4 bytes per character), so the value may be the result of conversion. ', - name: 'mysqlenterprise.audit.general_data.query', - type: 'keyword', - }, - 'mysqlenterprise.audit.general_data.status': { - category: 'mysqlenterprise', - description: - 'An integer representing the command status: 0 for success, nonzero if an error occurred. This is the same as the value of the mysql_errno() C API function. ', - name: 'mysqlenterprise.audit.general_data.status', - type: 'long', - }, - 'mysqlenterprise.audit.login.user': { - category: 'mysqlenterprise', - description: - 'A string representing the information indicating how a client connected to the server. ', - name: 'mysqlenterprise.audit.login.user', - type: 'keyword', - }, - 'mysqlenterprise.audit.login.proxy': { - category: 'mysqlenterprise', - description: - 'A string representing the proxy user. The value is empty if user proxying is not in effect. ', - name: 'mysqlenterprise.audit.login.proxy', - type: 'keyword', - }, - 'mysqlenterprise.audit.shutdown_data.server_id': { - category: 'mysqlenterprise', - description: - 'An integer representing the server ID. This is the same as the value of the server_id system variable. ', - name: 'mysqlenterprise.audit.shutdown_data.server_id', - type: 'keyword', - }, - 'mysqlenterprise.audit.startup_data.server_id': { - category: 'mysqlenterprise', - description: - 'An integer representing the server ID. This is the same as the value of the server_id system variable. ', - name: 'mysqlenterprise.audit.startup_data.server_id', - type: 'keyword', - }, - 'mysqlenterprise.audit.startup_data.mysql_version': { - category: 'mysqlenterprise', - description: - 'An integer representing the server ID. This is the same as the value of the server_id system variable. ', - name: 'mysqlenterprise.audit.startup_data.mysql_version', - type: 'keyword', - }, - 'mysqlenterprise.audit.table_access_data.db': { - category: 'mysqlenterprise', - description: - 'A string representing a database name. For connection_data, it is the default database. For table_access_data, it is the table database. ', - name: 'mysqlenterprise.audit.table_access_data.db', - type: 'keyword', - }, - 'mysqlenterprise.audit.table_access_data.table': { - category: 'mysqlenterprise', - description: 'A string representing a table name. ', - name: 'mysqlenterprise.audit.table_access_data.table', - type: 'keyword', - }, - 'mysqlenterprise.audit.table_access_data.query': { - category: 'mysqlenterprise', - description: - 'A string representing the text of an SQL statement. The value can be empty. Long values may be truncated. The string, like the audit log file itself, is written using UTF-8 (up to 4 bytes per character), so the value may be the result of conversion. ', - name: 'mysqlenterprise.audit.table_access_data.query', - type: 'keyword', - }, - 'mysqlenterprise.audit.table_access_data.sql_command': { - category: 'mysqlenterprise', - description: 'A string that indicates the SQL statement type. ', - name: 'mysqlenterprise.audit.table_access_data.sql_command', - type: 'keyword', - }, - 'mysqlenterprise.audit.account.user': { - category: 'mysqlenterprise', - description: - 'A string representing the user that the server authenticated the client as. This is the user name that the server uses for privilege checking. ', - name: 'mysqlenterprise.audit.account.user', - type: 'keyword', - }, - 'mysqlenterprise.audit.account.host': { - category: 'mysqlenterprise', - description: 'A string representing the client host name. ', - name: 'mysqlenterprise.audit.account.host', - type: 'keyword', - }, - 'mysqlenterprise.audit.login.os': { - category: 'mysqlenterprise', - description: - 'A string representing the external user name used during the authentication process, as set by the plugin used to authenticate the client. ', - name: 'mysqlenterprise.audit.login.os', - type: 'keyword', - }, - 'o365.audit.AADGroupId': { - category: 'o365', - name: 'o365.audit.AADGroupId', - type: 'keyword', - }, - 'o365.audit.Actor.ID': { - category: 'o365', - name: 'o365.audit.Actor.ID', - type: 'keyword', - }, - 'o365.audit.Actor.Type': { - category: 'o365', - name: 'o365.audit.Actor.Type', - type: 'keyword', - }, - 'o365.audit.ActorContextId': { - category: 'o365', - name: 'o365.audit.ActorContextId', - type: 'keyword', - }, - 'o365.audit.ActorIpAddress': { - category: 'o365', - name: 'o365.audit.ActorIpAddress', - type: 'keyword', - }, - 'o365.audit.ActorUserId': { - category: 'o365', - name: 'o365.audit.ActorUserId', - type: 'keyword', - }, - 'o365.audit.ActorYammerUserId': { - category: 'o365', - name: 'o365.audit.ActorYammerUserId', - type: 'keyword', - }, - 'o365.audit.AlertEntityId': { - category: 'o365', - name: 'o365.audit.AlertEntityId', - type: 'keyword', - }, - 'o365.audit.AlertId': { - category: 'o365', - name: 'o365.audit.AlertId', - type: 'keyword', - }, - 'o365.audit.AlertLinks': { - category: 'o365', - name: 'o365.audit.AlertLinks', - type: 'array', - }, - 'o365.audit.AlertType': { - category: 'o365', - name: 'o365.audit.AlertType', - type: 'keyword', - }, - 'o365.audit.AppId': { - category: 'o365', - name: 'o365.audit.AppId', - type: 'keyword', - }, - 'o365.audit.ApplicationDisplayName': { - category: 'o365', - name: 'o365.audit.ApplicationDisplayName', - type: 'keyword', - }, - 'o365.audit.ApplicationId': { - category: 'o365', - name: 'o365.audit.ApplicationId', - type: 'keyword', - }, - 'o365.audit.AzureActiveDirectoryEventType': { - category: 'o365', - name: 'o365.audit.AzureActiveDirectoryEventType', - type: 'keyword', - }, - 'o365.audit.ExchangeMetaData.*': { - category: 'o365', - name: 'o365.audit.ExchangeMetaData.*', - type: 'object', - }, - 'o365.audit.Category': { - category: 'o365', - name: 'o365.audit.Category', - type: 'keyword', - }, - 'o365.audit.ClientAppId': { - category: 'o365', - name: 'o365.audit.ClientAppId', - type: 'keyword', - }, - 'o365.audit.ClientInfoString': { - category: 'o365', - name: 'o365.audit.ClientInfoString', - type: 'keyword', - }, - 'o365.audit.ClientIP': { - category: 'o365', - name: 'o365.audit.ClientIP', - type: 'keyword', - }, - 'o365.audit.ClientIPAddress': { - category: 'o365', - name: 'o365.audit.ClientIPAddress', - type: 'keyword', - }, - 'o365.audit.Comments': { - category: 'o365', - name: 'o365.audit.Comments', - type: 'text', - }, - 'o365.audit.CommunicationType': { - category: 'o365', - name: 'o365.audit.CommunicationType', - type: 'keyword', - }, - 'o365.audit.CorrelationId': { - category: 'o365', - name: 'o365.audit.CorrelationId', - type: 'keyword', - }, - 'o365.audit.CreationTime': { - category: 'o365', - name: 'o365.audit.CreationTime', - type: 'keyword', - }, - 'o365.audit.CustomUniqueId': { - category: 'o365', - name: 'o365.audit.CustomUniqueId', - type: 'keyword', - }, - 'o365.audit.Data': { - category: 'o365', - name: 'o365.audit.Data', - type: 'keyword', - }, - 'o365.audit.DataType': { - category: 'o365', - name: 'o365.audit.DataType', - type: 'keyword', - }, - 'o365.audit.DoNotDistributeEvent': { - category: 'o365', - name: 'o365.audit.DoNotDistributeEvent', - type: 'boolean', - }, - 'o365.audit.EntityType': { - category: 'o365', - name: 'o365.audit.EntityType', - type: 'keyword', - }, - 'o365.audit.ErrorNumber': { - category: 'o365', - name: 'o365.audit.ErrorNumber', - type: 'keyword', - }, - 'o365.audit.EventData': { - category: 'o365', - name: 'o365.audit.EventData', - type: 'keyword', - }, - 'o365.audit.EventSource': { - category: 'o365', - name: 'o365.audit.EventSource', - type: 'keyword', - }, - 'o365.audit.ExceptionInfo.*': { - category: 'o365', - name: 'o365.audit.ExceptionInfo.*', - type: 'object', - }, - 'o365.audit.ExtendedProperties.*': { - category: 'o365', - name: 'o365.audit.ExtendedProperties.*', - type: 'object', - }, - 'o365.audit.ExternalAccess': { - category: 'o365', - name: 'o365.audit.ExternalAccess', - type: 'keyword', - }, - 'o365.audit.FromApp': { - category: 'o365', - name: 'o365.audit.FromApp', - type: 'boolean', - }, - 'o365.audit.GroupName': { - category: 'o365', - name: 'o365.audit.GroupName', - type: 'keyword', - }, - 'o365.audit.Id': { - category: 'o365', - name: 'o365.audit.Id', - type: 'keyword', - }, - 'o365.audit.ImplicitShare': { - category: 'o365', - name: 'o365.audit.ImplicitShare', - type: 'keyword', - }, - 'o365.audit.IncidentId': { - category: 'o365', - name: 'o365.audit.IncidentId', - type: 'keyword', - }, - 'o365.audit.InternalLogonType': { - category: 'o365', - name: 'o365.audit.InternalLogonType', - type: 'keyword', - }, - 'o365.audit.InterSystemsId': { - category: 'o365', - name: 'o365.audit.InterSystemsId', - type: 'keyword', - }, - 'o365.audit.IntraSystemId': { - category: 'o365', - name: 'o365.audit.IntraSystemId', - type: 'keyword', - }, - 'o365.audit.IsDocLib': { - category: 'o365', - name: 'o365.audit.IsDocLib', - type: 'boolean', - }, - 'o365.audit.Item.*': { - category: 'o365', - name: 'o365.audit.Item.*', - type: 'object', - }, - 'o365.audit.Item.*.*': { - category: 'o365', - name: 'o365.audit.Item.*.*', - type: 'object', - }, - 'o365.audit.ItemCount': { - category: 'o365', - name: 'o365.audit.ItemCount', - type: 'long', - }, - 'o365.audit.ItemName': { - category: 'o365', - name: 'o365.audit.ItemName', - type: 'keyword', - }, - 'o365.audit.ItemType': { - category: 'o365', - name: 'o365.audit.ItemType', - type: 'keyword', - }, - 'o365.audit.ListBaseTemplateType': { - category: 'o365', - name: 'o365.audit.ListBaseTemplateType', - type: 'keyword', - }, - 'o365.audit.ListBaseType': { - category: 'o365', - name: 'o365.audit.ListBaseType', - type: 'keyword', - }, - 'o365.audit.ListColor': { - category: 'o365', - name: 'o365.audit.ListColor', - type: 'keyword', - }, - 'o365.audit.ListIcon': { - category: 'o365', - name: 'o365.audit.ListIcon', - type: 'keyword', - }, - 'o365.audit.ListId': { - category: 'o365', - name: 'o365.audit.ListId', - type: 'keyword', - }, - 'o365.audit.ListTitle': { - category: 'o365', - name: 'o365.audit.ListTitle', - type: 'keyword', - }, - 'o365.audit.ListItemUniqueId': { - category: 'o365', - name: 'o365.audit.ListItemUniqueId', - type: 'keyword', - }, - 'o365.audit.LogonError': { - category: 'o365', - name: 'o365.audit.LogonError', - type: 'keyword', - }, - 'o365.audit.LogonType': { - category: 'o365', - name: 'o365.audit.LogonType', - type: 'keyword', - }, - 'o365.audit.LogonUserSid': { - category: 'o365', - name: 'o365.audit.LogonUserSid', - type: 'keyword', - }, - 'o365.audit.MailboxGuid': { - category: 'o365', - name: 'o365.audit.MailboxGuid', - type: 'keyword', - }, - 'o365.audit.MailboxOwnerMasterAccountSid': { - category: 'o365', - name: 'o365.audit.MailboxOwnerMasterAccountSid', - type: 'keyword', - }, - 'o365.audit.MailboxOwnerSid': { - category: 'o365', - name: 'o365.audit.MailboxOwnerSid', - type: 'keyword', - }, - 'o365.audit.MailboxOwnerUPN': { - category: 'o365', - name: 'o365.audit.MailboxOwnerUPN', - type: 'keyword', - }, - 'o365.audit.Members': { - category: 'o365', - name: 'o365.audit.Members', - type: 'array', - }, - 'o365.audit.Members.*': { - category: 'o365', - name: 'o365.audit.Members.*', - type: 'object', - }, - 'o365.audit.ModifiedProperties.*.*': { - category: 'o365', - name: 'o365.audit.ModifiedProperties.*.*', - type: 'object', - }, - 'o365.audit.Name': { - category: 'o365', - name: 'o365.audit.Name', - type: 'keyword', - }, - 'o365.audit.ObjectId': { - category: 'o365', - name: 'o365.audit.ObjectId', - type: 'keyword', - }, - 'o365.audit.Operation': { - category: 'o365', - name: 'o365.audit.Operation', - type: 'keyword', - }, - 'o365.audit.OrganizationId': { - category: 'o365', - name: 'o365.audit.OrganizationId', - type: 'keyword', - }, - 'o365.audit.OrganizationName': { - category: 'o365', - name: 'o365.audit.OrganizationName', - type: 'keyword', - }, - 'o365.audit.OriginatingServer': { - category: 'o365', - name: 'o365.audit.OriginatingServer', - type: 'keyword', - }, - 'o365.audit.Parameters.*': { - category: 'o365', - name: 'o365.audit.Parameters.*', - type: 'object', - }, - 'o365.audit.PolicyDetails': { - category: 'o365', - name: 'o365.audit.PolicyDetails', - type: 'array', - }, - 'o365.audit.PolicyId': { - category: 'o365', - name: 'o365.audit.PolicyId', - type: 'keyword', - }, - 'o365.audit.RecordType': { - category: 'o365', - name: 'o365.audit.RecordType', - type: 'keyword', - }, - 'o365.audit.ResultStatus': { - category: 'o365', - name: 'o365.audit.ResultStatus', - type: 'keyword', - }, - 'o365.audit.SensitiveInfoDetectionIsIncluded': { - category: 'o365', - name: 'o365.audit.SensitiveInfoDetectionIsIncluded', - type: 'keyword', - }, - 'o365.audit.SharePointMetaData.*': { - category: 'o365', - name: 'o365.audit.SharePointMetaData.*', - type: 'object', - }, - 'o365.audit.SessionId': { - category: 'o365', - name: 'o365.audit.SessionId', - type: 'keyword', - }, - 'o365.audit.Severity': { - category: 'o365', - name: 'o365.audit.Severity', - type: 'keyword', - }, - 'o365.audit.Site': { - category: 'o365', - name: 'o365.audit.Site', - type: 'keyword', - }, - 'o365.audit.SiteUrl': { - category: 'o365', - name: 'o365.audit.SiteUrl', - type: 'keyword', - }, - 'o365.audit.Source': { - category: 'o365', - name: 'o365.audit.Source', - type: 'keyword', - }, - 'o365.audit.SourceFileExtension': { - category: 'o365', - name: 'o365.audit.SourceFileExtension', - type: 'keyword', - }, - 'o365.audit.SourceFileName': { - category: 'o365', - name: 'o365.audit.SourceFileName', - type: 'keyword', - }, - 'o365.audit.SourceRelativeUrl': { - category: 'o365', - name: 'o365.audit.SourceRelativeUrl', - type: 'keyword', - }, - 'o365.audit.Status': { - category: 'o365', - name: 'o365.audit.Status', - type: 'keyword', - }, - 'o365.audit.SupportTicketId': { - category: 'o365', - name: 'o365.audit.SupportTicketId', - type: 'keyword', - }, - 'o365.audit.Target.ID': { - category: 'o365', - name: 'o365.audit.Target.ID', - type: 'keyword', - }, - 'o365.audit.Target.Type': { - category: 'o365', - name: 'o365.audit.Target.Type', - type: 'keyword', - }, - 'o365.audit.TargetContextId': { - category: 'o365', - name: 'o365.audit.TargetContextId', - type: 'keyword', - }, - 'o365.audit.TargetUserOrGroupName': { - category: 'o365', - name: 'o365.audit.TargetUserOrGroupName', - type: 'keyword', - }, - 'o365.audit.TargetUserOrGroupType': { - category: 'o365', - name: 'o365.audit.TargetUserOrGroupType', - type: 'keyword', - }, - 'o365.audit.TeamName': { - category: 'o365', - name: 'o365.audit.TeamName', - type: 'keyword', - }, - 'o365.audit.TeamGuid': { - category: 'o365', - name: 'o365.audit.TeamGuid', - type: 'keyword', - }, - 'o365.audit.TemplateTypeId': { - category: 'o365', - name: 'o365.audit.TemplateTypeId', - type: 'keyword', - }, - 'o365.audit.UniqueSharingId': { - category: 'o365', - name: 'o365.audit.UniqueSharingId', - type: 'keyword', - }, - 'o365.audit.UserAgent': { - category: 'o365', - name: 'o365.audit.UserAgent', - type: 'keyword', - }, - 'o365.audit.UserId': { - category: 'o365', - name: 'o365.audit.UserId', - type: 'keyword', - }, - 'o365.audit.UserKey': { - category: 'o365', - name: 'o365.audit.UserKey', - type: 'keyword', - }, - 'o365.audit.UserType': { - category: 'o365', - name: 'o365.audit.UserType', - type: 'keyword', - }, - 'o365.audit.Version': { - category: 'o365', - name: 'o365.audit.Version', - type: 'keyword', - }, - 'o365.audit.WebId': { - category: 'o365', - name: 'o365.audit.WebId', - type: 'keyword', - }, - 'o365.audit.Workload': { - category: 'o365', - name: 'o365.audit.Workload', - type: 'keyword', - }, - 'o365.audit.YammerNetworkId': { - category: 'o365', - name: 'o365.audit.YammerNetworkId', - type: 'keyword', - }, - 'okta.uuid': { - category: 'okta', - description: 'The unique identifier of the Okta LogEvent. ', - name: 'okta.uuid', - type: 'keyword', - }, - 'okta.event_type': { - category: 'okta', - description: 'The type of the LogEvent. ', - name: 'okta.event_type', - type: 'keyword', - }, - 'okta.version': { - category: 'okta', - description: 'The version of the LogEvent. ', - name: 'okta.version', - type: 'keyword', - }, - 'okta.severity': { - category: 'okta', - description: 'The severity of the LogEvent. Must be one of DEBUG, INFO, WARN, or ERROR. ', - name: 'okta.severity', - type: 'keyword', - }, - 'okta.display_message': { - category: 'okta', - description: 'The display message of the LogEvent. ', - name: 'okta.display_message', - type: 'keyword', - }, - 'okta.actor.id': { - category: 'okta', - description: 'Identifier of the actor. ', - name: 'okta.actor.id', - type: 'keyword', - }, - 'okta.actor.type': { - category: 'okta', - description: 'Type of the actor. ', - name: 'okta.actor.type', - type: 'keyword', - }, - 'okta.actor.alternate_id': { - category: 'okta', - description: 'Alternate identifier of the actor. ', - name: 'okta.actor.alternate_id', - type: 'keyword', - }, - 'okta.actor.display_name': { - category: 'okta', - description: 'Display name of the actor. ', - name: 'okta.actor.display_name', - type: 'keyword', - }, - 'okta.client.ip': { - category: 'okta', - description: 'The IP address of the client. ', - name: 'okta.client.ip', - type: 'ip', - }, - 'okta.client.user_agent.raw_user_agent': { - category: 'okta', - description: 'The raw informaton of the user agent. ', - name: 'okta.client.user_agent.raw_user_agent', - type: 'keyword', - }, - 'okta.client.user_agent.os': { - category: 'okta', - description: 'The OS informaton. ', - name: 'okta.client.user_agent.os', - type: 'keyword', - }, - 'okta.client.user_agent.browser': { - category: 'okta', - description: 'The browser informaton of the client. ', - name: 'okta.client.user_agent.browser', - type: 'keyword', - }, - 'okta.client.zone': { - category: 'okta', - description: 'The zone information of the client. ', - name: 'okta.client.zone', - type: 'keyword', - }, - 'okta.client.device': { - category: 'okta', - description: 'The information of the client device. ', - name: 'okta.client.device', - type: 'keyword', - }, - 'okta.client.id': { - category: 'okta', - description: 'The identifier of the client. ', - name: 'okta.client.id', - type: 'keyword', - }, - 'okta.outcome.reason': { - category: 'okta', - description: 'The reason of the outcome. ', - name: 'okta.outcome.reason', - type: 'keyword', - }, - 'okta.outcome.result': { - category: 'okta', - description: - 'The result of the outcome. Must be one of: SUCCESS, FAILURE, SKIPPED, ALLOW, DENY, CHALLENGE, UNKNOWN. ', - name: 'okta.outcome.result', - type: 'keyword', - }, - 'okta.target.id': { - category: 'okta', - description: 'Identifier of the actor. ', - name: 'okta.target.id', - type: 'keyword', - }, - 'okta.target.type': { - category: 'okta', - description: 'Type of the actor. ', - name: 'okta.target.type', - type: 'keyword', - }, - 'okta.target.alternate_id': { - category: 'okta', - description: 'Alternate identifier of the actor. ', - name: 'okta.target.alternate_id', - type: 'keyword', - }, - 'okta.target.display_name': { - category: 'okta', - description: 'Display name of the actor. ', - name: 'okta.target.display_name', - type: 'keyword', - }, - 'okta.transaction.id': { - category: 'okta', - description: 'Identifier of the transaction. ', - name: 'okta.transaction.id', - type: 'keyword', - }, - 'okta.transaction.type': { - category: 'okta', - description: 'The type of transaction. Must be one of "WEB", "JOB". ', - name: 'okta.transaction.type', - type: 'keyword', - }, - 'okta.debug_context.debug_data.device_fingerprint': { - category: 'okta', - description: 'The fingerprint of the device. ', - name: 'okta.debug_context.debug_data.device_fingerprint', - type: 'keyword', - }, - 'okta.debug_context.debug_data.request_id': { - category: 'okta', - description: 'The identifier of the request. ', - name: 'okta.debug_context.debug_data.request_id', - type: 'keyword', - }, - 'okta.debug_context.debug_data.request_uri': { - category: 'okta', - description: 'The request URI. ', - name: 'okta.debug_context.debug_data.request_uri', - type: 'keyword', - }, - 'okta.debug_context.debug_data.threat_suspected': { - category: 'okta', - description: 'Threat suspected. ', - name: 'okta.debug_context.debug_data.threat_suspected', - type: 'keyword', - }, - 'okta.debug_context.debug_data.url': { - category: 'okta', - description: 'The URL. ', - name: 'okta.debug_context.debug_data.url', - type: 'keyword', - }, - 'okta.debug_context.debug_data.suspicious_activity.browser': { - category: 'okta', - description: 'The browser used. ', - name: 'okta.debug_context.debug_data.suspicious_activity.browser', - type: 'keyword', - }, - 'okta.debug_context.debug_data.suspicious_activity.event_city': { - category: 'okta', - description: 'The city where the suspicious activity took place. ', - name: 'okta.debug_context.debug_data.suspicious_activity.event_city', - type: 'keyword', - }, - 'okta.debug_context.debug_data.suspicious_activity.event_country': { - category: 'okta', - description: 'The country where the suspicious activity took place. ', - name: 'okta.debug_context.debug_data.suspicious_activity.event_country', - type: 'keyword', - }, - 'okta.debug_context.debug_data.suspicious_activity.event_id': { - category: 'okta', - description: 'The event ID. ', - name: 'okta.debug_context.debug_data.suspicious_activity.event_id', - type: 'keyword', - }, - 'okta.debug_context.debug_data.suspicious_activity.event_ip': { - category: 'okta', - description: 'The IP of the suspicious event. ', - name: 'okta.debug_context.debug_data.suspicious_activity.event_ip', - type: 'ip', - }, - 'okta.debug_context.debug_data.suspicious_activity.event_latitude': { - category: 'okta', - description: 'The latitude where the suspicious activity took place. ', - name: 'okta.debug_context.debug_data.suspicious_activity.event_latitude', - type: 'float', - }, - 'okta.debug_context.debug_data.suspicious_activity.event_longitude': { - category: 'okta', - description: 'The longitude where the suspicious activity took place. ', - name: 'okta.debug_context.debug_data.suspicious_activity.event_longitude', - type: 'float', - }, - 'okta.debug_context.debug_data.suspicious_activity.event_state': { - category: 'okta', - description: 'The state where the suspicious activity took place. ', - name: 'okta.debug_context.debug_data.suspicious_activity.event_state', - type: 'keyword', - }, - 'okta.debug_context.debug_data.suspicious_activity.event_transaction_id': { - category: 'okta', - description: 'The event transaction ID. ', - name: 'okta.debug_context.debug_data.suspicious_activity.event_transaction_id', - type: 'keyword', - }, - 'okta.debug_context.debug_data.suspicious_activity.event_type': { - category: 'okta', - description: 'The event type. ', - name: 'okta.debug_context.debug_data.suspicious_activity.event_type', - type: 'keyword', - }, - 'okta.debug_context.debug_data.suspicious_activity.os': { - category: 'okta', - description: 'The OS of the system from where the suspicious activity occured. ', - name: 'okta.debug_context.debug_data.suspicious_activity.os', - type: 'keyword', - }, - 'okta.debug_context.debug_data.suspicious_activity.timestamp': { - category: 'okta', - description: 'The timestamp of when the activity occurred. ', - name: 'okta.debug_context.debug_data.suspicious_activity.timestamp', - type: 'date', - }, - 'okta.authentication_context.authentication_provider': { - category: 'okta', - description: - 'The information about the authentication provider. Must be one of OKTA_AUTHENTICATION_PROVIDER, ACTIVE_DIRECTORY, LDAP, FEDERATION, SOCIAL, FACTOR_PROVIDER. ', - name: 'okta.authentication_context.authentication_provider', - type: 'keyword', - }, - 'okta.authentication_context.authentication_step': { - category: 'okta', - description: 'The authentication step. ', - name: 'okta.authentication_context.authentication_step', - type: 'integer', - }, - 'okta.authentication_context.credential_provider': { - category: 'okta', - description: - 'The information about credential provider. Must be one of OKTA_CREDENTIAL_PROVIDER, RSA, SYMANTEC, GOOGLE, DUO, YUBIKEY. ', - name: 'okta.authentication_context.credential_provider', - type: 'keyword', - }, - 'okta.authentication_context.credential_type': { - category: 'okta', - description: - 'The information about credential type. Must be one of OTP, SMS, PASSWORD, ASSERTION, IWA, EMAIL, OAUTH2, JWT, CERTIFICATE, PRE_SHARED_SYMMETRIC_KEY, OKTA_CLIENT_SESSION, DEVICE_UDID. ', - name: 'okta.authentication_context.credential_type', - type: 'keyword', - }, - 'okta.authentication_context.issuer.id': { - category: 'okta', - description: 'The identifier of the issuer. ', - name: 'okta.authentication_context.issuer.id', - type: 'keyword', - }, - 'okta.authentication_context.issuer.type': { - category: 'okta', - description: 'The type of the issuer. ', - name: 'okta.authentication_context.issuer.type', - type: 'keyword', - }, - 'okta.authentication_context.external_session_id': { - category: 'okta', - description: 'The session identifer of the external session if any. ', - name: 'okta.authentication_context.external_session_id', - type: 'keyword', - }, - 'okta.authentication_context.interface': { - category: 'okta', - description: 'The interface used. e.g., Outlook, Office365, wsTrust ', - name: 'okta.authentication_context.interface', - type: 'keyword', - }, - 'okta.security_context.as.number': { - category: 'okta', - description: 'The AS number. ', - name: 'okta.security_context.as.number', - type: 'integer', - }, - 'okta.security_context.as.organization.name': { - category: 'okta', - description: 'The organization name. ', - name: 'okta.security_context.as.organization.name', - type: 'keyword', - }, - 'okta.security_context.isp': { - category: 'okta', - description: 'The Internet Service Provider. ', - name: 'okta.security_context.isp', - type: 'keyword', - }, - 'okta.security_context.domain': { - category: 'okta', - description: 'The domain name. ', - name: 'okta.security_context.domain', - type: 'keyword', - }, - 'okta.security_context.is_proxy': { - category: 'okta', - description: 'Whether it is a proxy or not. ', - name: 'okta.security_context.is_proxy', - type: 'boolean', - }, - 'okta.request.ip_chain.ip': { - category: 'okta', - description: 'IP address. ', - name: 'okta.request.ip_chain.ip', - type: 'ip', - }, - 'okta.request.ip_chain.version': { - category: 'okta', - description: 'IP version. Must be one of V4, V6. ', - name: 'okta.request.ip_chain.version', - type: 'keyword', - }, - 'okta.request.ip_chain.source': { - category: 'okta', - description: 'Source information. ', - name: 'okta.request.ip_chain.source', - type: 'keyword', - }, - 'okta.request.ip_chain.geographical_context.city': { - category: 'okta', - description: 'The city.', - name: 'okta.request.ip_chain.geographical_context.city', - type: 'keyword', - }, - 'okta.request.ip_chain.geographical_context.state': { - category: 'okta', - description: 'The state.', - name: 'okta.request.ip_chain.geographical_context.state', - type: 'keyword', - }, - 'okta.request.ip_chain.geographical_context.postal_code': { - category: 'okta', - description: 'The postal code.', - name: 'okta.request.ip_chain.geographical_context.postal_code', - type: 'keyword', - }, - 'okta.request.ip_chain.geographical_context.country': { - category: 'okta', - description: 'The country.', - name: 'okta.request.ip_chain.geographical_context.country', - type: 'keyword', - }, - 'okta.request.ip_chain.geographical_context.geolocation': { - category: 'okta', - description: 'Geolocation information. ', - name: 'okta.request.ip_chain.geographical_context.geolocation', - type: 'geo_point', - }, - 'oracle.database_audit.status': { - category: 'oracle', - description: 'Database Audit Status. ', - name: 'oracle.database_audit.status', - type: 'keyword', - }, - 'oracle.database_audit.session_id': { - category: 'oracle', - description: 'Indicates the audit session ID number. ', - name: 'oracle.database_audit.session_id', - type: 'keyword', - }, - 'oracle.database_audit.client.terminal': { - category: 'oracle', - description: 'If available, the client terminal type, for example "pty". ', - name: 'oracle.database_audit.client.terminal', - type: 'keyword', - }, - 'oracle.database_audit.client.address': { - category: 'oracle', - description: 'The IP Address or Domain used by the client. ', - name: 'oracle.database_audit.client.address', - type: 'keyword', - }, - 'oracle.database_audit.client.user': { - category: 'oracle', - description: 'The user running the client or connection to the database. ', - name: 'oracle.database_audit.client.user', - type: 'keyword', - }, - 'oracle.database_audit.database.user': { - category: 'oracle', - description: 'The database user used to authenticate. ', - name: 'oracle.database_audit.database.user', - type: 'keyword', - }, - 'oracle.database_audit.privilege': { - category: 'oracle', - description: 'The privilege group related to the database user. ', - name: 'oracle.database_audit.privilege', - type: 'keyword', - }, - 'oracle.database_audit.entry.id': { - category: 'oracle', - description: - 'Indicates the current audit entry number, assigned to each audit trail record. The audit entry.id sequence number is shared between fine-grained audit records and regular audit records. ', - name: 'oracle.database_audit.entry.id', - type: 'keyword', - }, - 'oracle.database_audit.database.host': { - category: 'oracle', - description: 'Client host machine name. ', - name: 'oracle.database_audit.database.host', - type: 'keyword', - }, - 'oracle.database_audit.action': { - category: 'oracle', - description: - 'The action performed during the audit event. This could for example be the raw query. ', - name: 'oracle.database_audit.action', - type: 'keyword', - }, - 'oracle.database_audit.action_number': { - category: 'oracle', - description: - 'Action is a numeric value representing the action the user performed. The corresponding name of the action type is in the AUDIT_ACTIONS table. For example, action 100 refers to LOGON. ', - name: 'oracle.database_audit.action_number', - type: 'keyword', - }, - 'oracle.database_audit.database.id': { - category: 'oracle', - description: - 'Database identifier calculated when the database is created. It corresponds to the DBID column of the V$DATABASE data dictionary view. ', - name: 'oracle.database_audit.database.id', - type: 'keyword', - }, - 'oracle.database_audit.length': { - category: 'oracle', - description: - 'Refers to the total number of bytes used in this audit record. This number includes the trailing newline bytes (\\n), if any, at the end of the audit record. ', - name: 'oracle.database_audit.length', - type: 'long', - }, - 'panw.panos.ruleset': { - category: 'panw', - description: 'Name of the rule that matched this session. ', - name: 'panw.panos.ruleset', - type: 'keyword', - }, - 'panw.panos.source.zone': { - category: 'panw', - description: 'Source zone for this session. ', - name: 'panw.panos.source.zone', - type: 'keyword', - }, - 'panw.panos.source.interface': { - category: 'panw', - description: 'Source interface for this session. ', - name: 'panw.panos.source.interface', - type: 'keyword', - }, - 'panw.panos.source.nat.ip': { - category: 'panw', - description: 'Post-NAT source IP. ', - name: 'panw.panos.source.nat.ip', - type: 'ip', - }, - 'panw.panos.source.nat.port': { - category: 'panw', - description: 'Post-NAT source port. ', - name: 'panw.panos.source.nat.port', - type: 'long', - }, - 'panw.panos.destination.zone': { - category: 'panw', - description: 'Destination zone for this session. ', - name: 'panw.panos.destination.zone', - type: 'keyword', - }, - 'panw.panos.destination.interface': { - category: 'panw', - description: 'Destination interface for this session. ', - name: 'panw.panos.destination.interface', - type: 'keyword', - }, - 'panw.panos.destination.nat.ip': { - category: 'panw', - description: 'Post-NAT destination IP. ', - name: 'panw.panos.destination.nat.ip', - type: 'ip', - }, - 'panw.panos.destination.nat.port': { - category: 'panw', - description: 'Post-NAT destination port. ', - name: 'panw.panos.destination.nat.port', - type: 'long', - }, - 'panw.panos.endreason': { - category: 'panw', - description: 'The reason a session terminated. ', - name: 'panw.panos.endreason', - type: 'keyword', - }, - 'panw.panos.network.pcap_id': { - category: 'panw', - description: 'Packet capture ID for a threat. ', - name: 'panw.panos.network.pcap_id', - type: 'keyword', - }, - 'panw.panos.network.nat.community_id': { - category: 'panw', - description: 'Community ID flow-hash for the NAT 5-tuple. ', - name: 'panw.panos.network.nat.community_id', - type: 'keyword', - }, - 'panw.panos.file.hash': { - category: 'panw', - description: 'Binary hash for a threat file sent to be analyzed by the WildFire service. ', - name: 'panw.panos.file.hash', - type: 'keyword', - }, - 'panw.panos.url.category': { - category: 'panw', - description: - "For threat URLs, it's the URL category. For WildFire, the verdict on the file and is either 'malicious', 'grayware', or 'benign'. ", - name: 'panw.panos.url.category', - type: 'keyword', - }, - 'panw.panos.flow_id': { - category: 'panw', - description: 'Internal numeric identifier for each session. ', - name: 'panw.panos.flow_id', - type: 'keyword', - }, - 'panw.panos.sequence_number': { - category: 'panw', - description: - 'Log entry identifier that is incremented sequentially. Unique for each log type. ', - name: 'panw.panos.sequence_number', - type: 'long', - }, - 'panw.panos.threat.resource': { - category: 'panw', - description: 'URL or file name for a threat. ', - name: 'panw.panos.threat.resource', - type: 'keyword', - }, - 'panw.panos.threat.id': { - category: 'panw', - description: 'Palo Alto Networks identifier for the threat. ', - name: 'panw.panos.threat.id', - type: 'keyword', - }, - 'panw.panos.threat.name': { - category: 'panw', - description: 'Palo Alto Networks name for the threat. ', - name: 'panw.panos.threat.name', - type: 'keyword', - }, - 'panw.panos.action': { - category: 'panw', - description: 'Action taken for the session.', - name: 'panw.panos.action', - type: 'keyword', - }, - 'panw.panos.type': { - category: 'panw', - description: 'Specifies the type of the log', - name: 'panw.panos.type', - }, - 'panw.panos.sub_type': { - category: 'panw', - description: 'Specifies the sub type of the log', - name: 'panw.panos.sub_type', - }, - 'panw.panos.virtual_sys': { - category: 'panw', - description: 'Virtual system instance ', - name: 'panw.panos.virtual_sys', - type: 'keyword', - }, - 'panw.panos.client_os_ver': { - category: 'panw', - description: 'The client device’s OS version. ', - name: 'panw.panos.client_os_ver', - type: 'keyword', - }, - 'panw.panos.client_os': { - category: 'panw', - description: 'The client device’s OS version. ', - name: 'panw.panos.client_os', - type: 'keyword', - }, - 'panw.panos.client_ver': { - category: 'panw', - description: 'The client’s GlobalProtect app version. ', - name: 'panw.panos.client_ver', - type: 'keyword', - }, - 'panw.panos.stage': { - category: 'panw', - description: 'A string showing the stage of the connection ', - example: 'before-login', - name: 'panw.panos.stage', - type: 'keyword', - }, - 'panw.panos.actionflags': { - category: 'panw', - description: 'A bit field indicating if the log was forwarded to Panorama. ', - name: 'panw.panos.actionflags', - type: 'keyword', - }, - 'panw.panos.error': { - category: 'panw', - description: 'A string showing that error that has occurred in any event. ', - name: 'panw.panos.error', - type: 'keyword', - }, - 'panw.panos.error_code': { - category: 'panw', - description: 'An integer associated with any errors that occurred. ', - name: 'panw.panos.error_code', - type: 'integer', - }, - 'panw.panos.repeatcnt': { - category: 'panw', - description: - 'The number of sessions with the same source IP address, destination IP address, application, and subtype that GlobalProtect has detected within the last five seconds.An integer associated with any errors that occurred. ', - name: 'panw.panos.repeatcnt', - type: 'integer', - }, - 'panw.panos.serial_number': { - category: 'panw', - description: 'The serial number of the user’s machine or device. ', - name: 'panw.panos.serial_number', - type: 'keyword', - }, - 'panw.panos.auth_method': { - category: 'panw', - description: 'A string showing the authentication type ', - example: 'LDAP', - name: 'panw.panos.auth_method', - type: 'keyword', - }, - 'panw.panos.datasource': { - category: 'panw', - description: 'Source from which mapping information is collected. ', - name: 'panw.panos.datasource', - type: 'keyword', - }, - 'panw.panos.datasourcetype': { - category: 'panw', - description: 'Mechanism used to identify the IP/User mappings within a data source. ', - name: 'panw.panos.datasourcetype', - type: 'keyword', - }, - 'panw.panos.datasourcename': { - category: 'panw', - description: 'User-ID source that sends the IP (Port)-User Mapping. ', - name: 'panw.panos.datasourcename', - type: 'keyword', - }, - 'panw.panos.factorno': { - category: 'panw', - description: 'Indicates the use of primary authentication (1) or additional factors (2, 3). ', - name: 'panw.panos.factorno', - type: 'integer', - }, - 'panw.panos.factortype': { - category: 'panw', - description: 'Vendor used to authenticate a user when Multi Factor authentication is present. ', - name: 'panw.panos.factortype', - type: 'keyword', - }, - 'panw.panos.factorcompletiontime': { - category: 'panw', - description: 'Time the authentication was completed. ', - name: 'panw.panos.factorcompletiontime', - type: 'date', - }, - 'panw.panos.ugflags': { - category: 'panw', - description: - 'Displays whether the user group that was found during user group mapping. Supported values are: User Group Found—Indicates whether the user could be mapped to a group. Duplicate User—Indicates whether duplicate users were found in a user group. Displays N/A if no user group is found. ', - name: 'panw.panos.ugflags', - type: 'keyword', - }, - 'panw.panos.device_group_hierarchy.level_1': { - category: 'panw', - description: - 'A sequence of identification numbers that indicate the device group’s location within a device group hierarchy. The firewall (or virtual system) generating the log includes the identification number of each ancestor in its device group hierarchy. The shared device group (level 0) is not included in this structure. If the log values are 12, 34, 45, 0, it means that the log was generated by a firewall (or virtual system) that belongs to device group 45, and its ancestors are 34, and 12. ', - name: 'panw.panos.device_group_hierarchy.level_1', - type: 'keyword', - }, - 'panw.panos.device_group_hierarchy.level_2': { - category: 'panw', - description: - 'A sequence of identification numbers that indicate the device group’s location within a device group hierarchy. The firewall (or virtual system) generating the log includes the identification number of each ancestor in its device group hierarchy. The shared device group (level 0) is not included in this structure. If the log values are 12, 34, 45, 0, it means that the log was generated by a firewall (or virtual system) that belongs to device group 45, and its ancestors are 34, and 12. ', - name: 'panw.panos.device_group_hierarchy.level_2', - type: 'keyword', - }, - 'panw.panos.device_group_hierarchy.level_3': { - category: 'panw', - description: - 'A sequence of identification numbers that indicate the device group’s location within a device group hierarchy. The firewall (or virtual system) generating the log includes the identification number of each ancestor in its device group hierarchy. The shared device group (level 0) is not included in this structure. If the log values are 12, 34, 45, 0, it means that the log was generated by a firewall (or virtual system) that belongs to device group 45, and its ancestors are 34, and 12. ', - name: 'panw.panos.device_group_hierarchy.level_3', - type: 'keyword', - }, - 'panw.panos.device_group_hierarchy.level_4': { - category: 'panw', - description: - 'A sequence of identification numbers that indicate the device group’s location within a device group hierarchy. The firewall (or virtual system) generating the log includes the identification number of each ancestor in its device group hierarchy. The shared device group (level 0) is not included in this structure. If the log values are 12, 34, 45, 0, it means that the log was generated by a firewall (or virtual system) that belongs to device group 45, and its ancestors are 34, and 12. ', - name: 'panw.panos.device_group_hierarchy.level_4', - type: 'keyword', - }, - 'panw.panos.timeout': { - category: 'panw', - description: 'Timeout after which the IP/User Mappings are cleared. ', - name: 'panw.panos.timeout', - type: 'integer', - }, - 'panw.panos.vsys_id': { - category: 'panw', - description: 'A unique identifier for a virtual system on a Palo Alto Networks firewall. ', - name: 'panw.panos.vsys_id', - type: 'keyword', - }, - 'panw.panos.vsys_name': { - category: 'panw', - description: - 'The name of the virtual system associated with the session; only valid on firewalls enabled for multiple virtual systems. ', - name: 'panw.panos.vsys_name', - type: 'keyword', - }, - 'panw.panos.description': { - category: 'panw', - description: 'Additional information for any event that has occurred. ', - name: 'panw.panos.description', - type: 'keyword', - }, - 'panw.panos.tunnel_type': { - category: 'panw', - description: 'The type of tunnel (either SSLVPN or IPSec). ', - name: 'panw.panos.tunnel_type', - type: 'keyword', - }, - 'panw.panos.connect_method': { - category: 'panw', - description: 'A string showing the how the GlobalProtect app connects to Gateway ', - name: 'panw.panos.connect_method', - type: 'keyword', - }, - 'panw.panos.matchname': { - category: 'panw', - description: 'Name of the HIP object or profile. ', - name: 'panw.panos.matchname', - type: 'keyword', - }, - 'panw.panos.matchtype': { - category: 'panw', - description: 'Whether the hip field represents a HIP object or a HIP profile. ', - name: 'panw.panos.matchtype', - type: 'keyword', - }, - 'panw.panos.priority': { - category: 'panw', - description: - 'The priority order of the gateway that is based on highest (1), high (2), medium (3), low (4), or lowest (5) to which the GlobalProtect app can connect. ', - name: 'panw.panos.priority', - type: 'keyword', - }, - 'panw.panos.response_time': { - category: 'panw', - description: - 'The SSL response time of the selected gateway that is measured in milliseconds on the endpoint during tunnel setup. ', - name: 'panw.panos.response_time', - type: 'keyword', - }, - 'panw.panos.attempted_gateways': { - category: 'panw', - description: - 'The fields that are collected for each gateway connection attempt with the gateway name, SSL response time, and priority ', - name: 'panw.panos.attempted_gateways', - type: 'keyword', - }, - 'panw.panos.gateway': { - category: 'panw', - description: 'The name of the gateway that is specified on the portal configuration. ', - name: 'panw.panos.gateway', - type: 'keyword', - }, - 'panw.panos.selection_type': { - category: 'panw', - description: 'The connection method that is selected to connect to the gateway. ', - name: 'panw.panos.selection_type', - type: 'keyword', - }, - 'rabbitmq.log.pid': { - category: 'rabbitmq', - description: 'The Erlang process id', - example: '<0.222.0>', - name: 'rabbitmq.log.pid', - type: 'keyword', - }, - 'snyk.projects': { - category: 'snyk', - description: 'Array with all related projects objects. ', - name: 'snyk.projects', - type: 'flattened', - }, - 'snyk.related.projects': { - category: 'snyk', - description: "Array of all the related project ID's. ", - name: 'snyk.related.projects', - type: 'keyword', - }, - 'snyk.audit.org_id': { - category: 'snyk', - description: 'ID of the related Organization related to the event. ', - name: 'snyk.audit.org_id', - type: 'keyword', - }, - 'snyk.audit.project_id': { - category: 'snyk', - description: 'ID of the project related to the event. ', - name: 'snyk.audit.project_id', - type: 'keyword', - }, - 'snyk.audit.content': { - category: 'snyk', - description: 'Overview of the content that was changed, both old and new values. ', - name: 'snyk.audit.content', - type: 'flattened', - }, - 'snyk.vulnerabilities.cvss3': { - category: 'snyk', - description: 'CSSv3 scores. ', - name: 'snyk.vulnerabilities.cvss3', - type: 'keyword', - }, - 'snyk.vulnerabilities.disclosure_time': { - category: 'snyk', - description: - 'The time this vulnerability was originally disclosed to the package maintainers. ', - name: 'snyk.vulnerabilities.disclosure_time', - type: 'date', - }, - 'snyk.vulnerabilities.exploit_maturity': { - category: 'snyk', - description: 'The Snyk exploit maturity level. ', - name: 'snyk.vulnerabilities.exploit_maturity', - type: 'keyword', - }, - 'snyk.vulnerabilities.id': { - category: 'snyk', - description: 'The vulnerability reference ID. ', - name: 'snyk.vulnerabilities.id', - type: 'keyword', - }, - 'snyk.vulnerabilities.is_ignored': { - category: 'snyk', - description: 'If the vulnerability report has been ignored. ', - name: 'snyk.vulnerabilities.is_ignored', - type: 'boolean', - }, - 'snyk.vulnerabilities.is_patchable': { - category: 'snyk', - description: 'If vulnerability is fixable by using a Snyk supplied patch. ', - name: 'snyk.vulnerabilities.is_patchable', - type: 'boolean', - }, - 'snyk.vulnerabilities.is_patched': { - category: 'snyk', - description: 'If the vulnerability has been patched. ', - name: 'snyk.vulnerabilities.is_patched', - type: 'boolean', - }, - 'snyk.vulnerabilities.is_pinnable': { - category: 'snyk', - description: 'If the vulnerability is fixable by pinning a transitive dependency. ', - name: 'snyk.vulnerabilities.is_pinnable', - type: 'boolean', - }, - 'snyk.vulnerabilities.is_upgradable': { - category: 'snyk', - description: 'If the vulnerability fixable by upgrading a dependency. ', - name: 'snyk.vulnerabilities.is_upgradable', - type: 'boolean', - }, - 'snyk.vulnerabilities.language': { - category: 'snyk', - description: "The package's programming language. ", - name: 'snyk.vulnerabilities.language', - type: 'keyword', - }, - 'snyk.vulnerabilities.package': { - category: 'snyk', - description: 'The package identifier according to its package manager. ', - name: 'snyk.vulnerabilities.package', - type: 'keyword', - }, - 'snyk.vulnerabilities.package_manager': { - category: 'snyk', - description: 'The package manager. ', - name: 'snyk.vulnerabilities.package_manager', - type: 'keyword', - }, - 'snyk.vulnerabilities.patches': { - category: 'snyk', - description: 'Patches required to resolve the issue created by Snyk. ', - name: 'snyk.vulnerabilities.patches', - type: 'flattened', - }, - 'snyk.vulnerabilities.priority_score': { - category: 'snyk', - description: 'The CVS priority score. ', - name: 'snyk.vulnerabilities.priority_score', - type: 'long', - }, - 'snyk.vulnerabilities.publication_time': { - category: 'snyk', - description: 'The vulnerability publication time. ', - name: 'snyk.vulnerabilities.publication_time', - type: 'date', - }, - 'snyk.vulnerabilities.jira_issue_url': { - category: 'snyk', - description: 'Link to the related Jira issue. ', - name: 'snyk.vulnerabilities.jira_issue_url', - type: 'keyword', - }, - 'snyk.vulnerabilities.original_severity': { - category: 'snyk', - description: 'The original severity of the vulnerability. ', - name: 'snyk.vulnerabilities.original_severity', - type: 'long', - }, - 'snyk.vulnerabilities.reachability': { - category: 'snyk', - description: - 'If the vulnerable function from the library is used in the code scanned. Can either be No Info, Potentially reachable and Reachable. ', - name: 'snyk.vulnerabilities.reachability', - type: 'keyword', - }, - 'snyk.vulnerabilities.title': { - category: 'snyk', - description: 'The issue title. ', - name: 'snyk.vulnerabilities.title', - type: 'keyword', - }, - 'snyk.vulnerabilities.type': { - category: 'snyk', - description: 'The issue type. Can be either "license" or "vulnerability". ', - name: 'snyk.vulnerabilities.type', - type: 'keyword', - }, - 'snyk.vulnerabilities.unique_severities_list': { - category: 'snyk', - description: 'A list of related unique severities. ', - name: 'snyk.vulnerabilities.unique_severities_list', - type: 'keyword', - }, - 'snyk.vulnerabilities.version': { - category: 'snyk', - description: 'The package version this issue is applicable to. ', - name: 'snyk.vulnerabilities.version', - type: 'keyword', - }, - 'snyk.vulnerabilities.introduced_date': { - category: 'snyk', - description: 'The date the vulnerability was initially found. ', - name: 'snyk.vulnerabilities.introduced_date', - type: 'date', - }, - 'snyk.vulnerabilities.is_fixed': { - category: 'snyk', - description: 'If the related vulnerability has been resolved. ', - name: 'snyk.vulnerabilities.is_fixed', - type: 'boolean', - }, - 'snyk.vulnerabilities.credit': { - category: 'snyk', - description: 'Reference to the person that original found the vulnerability. ', - name: 'snyk.vulnerabilities.credit', - type: 'keyword', - }, - 'snyk.vulnerabilities.semver': { - category: 'snyk', - description: - 'One or more semver ranges this issue is applicable to. The format varies according to package manager. ', - name: 'snyk.vulnerabilities.semver', - type: 'flattened', - }, - 'snyk.vulnerabilities.identifiers.alternative': { - category: 'snyk', - description: 'Additional vulnerability identifiers. ', - name: 'snyk.vulnerabilities.identifiers.alternative', - type: 'keyword', - }, - 'snyk.vulnerabilities.identifiers.cwe': { - category: 'snyk', - description: 'CWE vulnerability identifiers. ', - name: 'snyk.vulnerabilities.identifiers.cwe', - type: 'keyword', - }, - 'sophos.xg.device': { - category: 'sophos', - description: 'device ', - name: 'sophos.xg.device', - type: 'keyword', - }, - 'sophos.xg.date': { - category: 'sophos', - description: 'Date (yyyy-mm-dd) when the event occurred ', - name: 'sophos.xg.date', - type: 'date', - }, - 'sophos.xg.timezone': { - category: 'sophos', - description: 'Time (hh:mm:ss) when the event occurred ', - name: 'sophos.xg.timezone', - type: 'keyword', - }, - 'sophos.xg.device_name': { - category: 'sophos', - description: 'Model number of the device ', - name: 'sophos.xg.device_name', - type: 'keyword', - }, - 'sophos.xg.device_id': { - category: 'sophos', - description: 'Serial number of the device ', - name: 'sophos.xg.device_id', - type: 'keyword', - }, - 'sophos.xg.log_id': { - category: 'sophos', - description: 'Unique 12 characters code (0101011) ', - name: 'sophos.xg.log_id', - type: 'keyword', - }, - 'sophos.xg.log_type': { - category: 'sophos', - description: 'Type of event e.g. firewall event ', - name: 'sophos.xg.log_type', - type: 'keyword', - }, - 'sophos.xg.log_component': { - category: 'sophos', - description: 'Component responsible for logging e.g. Firewall rule ', - name: 'sophos.xg.log_component', - type: 'keyword', - }, - 'sophos.xg.log_subtype': { - category: 'sophos', - description: 'Sub type of event ', - name: 'sophos.xg.log_subtype', - type: 'keyword', - }, - 'sophos.xg.hb_health': { - category: 'sophos', - description: 'Heartbeat status ', - name: 'sophos.xg.hb_health', - type: 'keyword', - }, - 'sophos.xg.priority': { - category: 'sophos', - description: 'Severity level of traffic ', - name: 'sophos.xg.priority', - type: 'keyword', - }, - 'sophos.xg.status': { - category: 'sophos', - description: 'Ultimate status of traffic – Allowed or Denied ', - name: 'sophos.xg.status', - type: 'keyword', - }, - 'sophos.xg.duration': { - category: 'sophos', - description: 'Durability of traffic (seconds) ', - name: 'sophos.xg.duration', - type: 'long', - }, - 'sophos.xg.fw_rule_id': { - category: 'sophos', - description: 'Firewall Rule ID which is applied on the traffic ', - name: 'sophos.xg.fw_rule_id', - type: 'integer', - }, - 'sophos.xg.user_name': { - category: 'sophos', - description: 'user_name ', - name: 'sophos.xg.user_name', - type: 'keyword', - }, - 'sophos.xg.user_group': { - category: 'sophos', - description: 'Group name to which the user belongs ', - name: 'sophos.xg.user_group', - type: 'keyword', - }, - 'sophos.xg.iap': { - category: 'sophos', - description: 'Internet Access policy ID applied on the traffic ', - name: 'sophos.xg.iap', - type: 'keyword', - }, - 'sophos.xg.ips_policy_id': { - category: 'sophos', - description: 'IPS policy ID applied on the traffic ', - name: 'sophos.xg.ips_policy_id', - type: 'integer', - }, - 'sophos.xg.policy_type': { - category: 'sophos', - description: 'Policy type applied to the traffic ', - name: 'sophos.xg.policy_type', - type: 'keyword', - }, - 'sophos.xg.appfilter_policy_id': { - category: 'sophos', - description: 'Application Filter policy applied on the traffic ', - name: 'sophos.xg.appfilter_policy_id', - type: 'integer', - }, - 'sophos.xg.application_filter_policy': { - category: 'sophos', - description: 'Application Filter policy applied on the traffic ', - name: 'sophos.xg.application_filter_policy', - type: 'integer', - }, - 'sophos.xg.application': { - category: 'sophos', - description: 'Application name ', - name: 'sophos.xg.application', - type: 'keyword', - }, - 'sophos.xg.application_name': { - category: 'sophos', - description: 'Application name ', - name: 'sophos.xg.application_name', - type: 'keyword', - }, - 'sophos.xg.application_risk': { - category: 'sophos', - description: 'Risk level assigned to the application ', - name: 'sophos.xg.application_risk', - type: 'keyword', - }, - 'sophos.xg.application_technology': { - category: 'sophos', - description: 'Technology of the application ', - name: 'sophos.xg.application_technology', - type: 'keyword', - }, - 'sophos.xg.application_category': { - category: 'sophos', - description: 'Application is resolved by signature or synchronized application ', - name: 'sophos.xg.application_category', - type: 'keyword', - }, - 'sophos.xg.appresolvedby': { - category: 'sophos', - description: 'Technology of the application ', - name: 'sophos.xg.appresolvedby', - type: 'keyword', - }, - 'sophos.xg.app_is_cloud': { - category: 'sophos', - description: 'Application is Cloud ', - name: 'sophos.xg.app_is_cloud', - type: 'keyword', - }, - 'sophos.xg.in_interface': { - category: 'sophos', - description: 'Interface for incoming traffic, e.g., Port A ', - name: 'sophos.xg.in_interface', - type: 'keyword', - }, - 'sophos.xg.out_interface': { - category: 'sophos', - description: 'Interface for outgoing traffic, e.g., Port B ', - name: 'sophos.xg.out_interface', - type: 'keyword', - }, - 'sophos.xg.src_ip': { - category: 'sophos', - description: 'Original source IP address of traffic ', - name: 'sophos.xg.src_ip', - type: 'ip', - }, - 'sophos.xg.src_mac': { - category: 'sophos', - description: 'Original source MAC address of traffic ', - name: 'sophos.xg.src_mac', - type: 'keyword', - }, - 'sophos.xg.src_country_code': { - category: 'sophos', - description: 'Code of the country to which the source IP belongs ', - name: 'sophos.xg.src_country_code', - type: 'keyword', - }, - 'sophos.xg.dst_ip': { - category: 'sophos', - description: 'Original destination IP address of traffic ', - name: 'sophos.xg.dst_ip', - type: 'ip', - }, - 'sophos.xg.dst_country_code': { - category: 'sophos', - description: 'Code of the country to which the destination IP belongs ', - name: 'sophos.xg.dst_country_code', - type: 'keyword', - }, - 'sophos.xg.protocol': { - category: 'sophos', - description: 'Protocol number of traffic ', - name: 'sophos.xg.protocol', - type: 'keyword', - }, - 'sophos.xg.src_port': { - category: 'sophos', - description: 'Original source port of TCP and UDP traffic ', - name: 'sophos.xg.src_port', - type: 'integer', - }, - 'sophos.xg.dst_port': { - category: 'sophos', - description: 'Original destination port of TCP and UDP traffic ', - name: 'sophos.xg.dst_port', - type: 'integer', - }, - 'sophos.xg.icmp_type': { - category: 'sophos', - description: 'ICMP type of ICMP traffic ', - name: 'sophos.xg.icmp_type', - type: 'keyword', - }, - 'sophos.xg.icmp_code': { - category: 'sophos', - description: 'ICMP code of ICMP traffic ', - name: 'sophos.xg.icmp_code', - type: 'keyword', - }, - 'sophos.xg.sent_pkts': { - category: 'sophos', - description: 'Total number of packets sent ', - name: 'sophos.xg.sent_pkts', - type: 'long', - }, - 'sophos.xg.received_pkts': { - category: 'sophos', - description: 'Total number of packets received ', - name: 'sophos.xg.received_pkts', - type: 'long', - }, - 'sophos.xg.sent_bytes': { - category: 'sophos', - description: 'Total number of bytes sent ', - name: 'sophos.xg.sent_bytes', - type: 'long', - }, - 'sophos.xg.recv_bytes': { - category: 'sophos', - description: 'Total number of bytes received ', - name: 'sophos.xg.recv_bytes', - type: 'long', - }, - 'sophos.xg.trans_src_ip': { - category: 'sophos', - description: 'Translated source IP address for outgoing traffic ', - name: 'sophos.xg.trans_src_ip', - type: 'ip', - }, - 'sophos.xg.trans_src_port': { - category: 'sophos', - description: 'Translated source port for outgoing traffic ', - name: 'sophos.xg.trans_src_port', - type: 'integer', - }, - 'sophos.xg.trans_dst_ip': { - category: 'sophos', - description: 'Translated destination IP address for outgoing traffic ', - name: 'sophos.xg.trans_dst_ip', - type: 'ip', - }, - 'sophos.xg.trans_dst_port': { - category: 'sophos', - description: 'Translated destination port for outgoing traffic ', - name: 'sophos.xg.trans_dst_port', - type: 'integer', - }, - 'sophos.xg.srczonetype': { - category: 'sophos', - description: 'Type of source zone, e.g., LAN ', - name: 'sophos.xg.srczonetype', - type: 'keyword', - }, - 'sophos.xg.srczone': { - category: 'sophos', - description: 'Name of source zone ', - name: 'sophos.xg.srczone', - type: 'keyword', - }, - 'sophos.xg.dstzonetype': { - category: 'sophos', - description: 'Type of destination zone, e.g., WAN ', - name: 'sophos.xg.dstzonetype', - type: 'keyword', - }, - 'sophos.xg.dstzone': { - category: 'sophos', - description: 'Name of destination zone ', - name: 'sophos.xg.dstzone', - type: 'keyword', - }, - 'sophos.xg.dir_disp': { - category: 'sophos', - description: 'TPacket direction. Possible values:“org”, “reply”, “” ', - name: 'sophos.xg.dir_disp', - type: 'keyword', - }, - 'sophos.xg.connevent': { - category: 'sophos', - description: 'Event on which this log is generated ', - name: 'sophos.xg.connevent', - type: 'keyword', - }, - 'sophos.xg.conn_id': { - category: 'sophos', - description: 'Unique identifier of connection ', - name: 'sophos.xg.conn_id', - type: 'integer', - }, - 'sophos.xg.vconn_id': { - category: 'sophos', - description: 'Connection ID of the master connection ', - name: 'sophos.xg.vconn_id', - type: 'integer', - }, - 'sophos.xg.idp_policy_id': { - category: 'sophos', - description: 'IPS policy ID which is applied on the traffic ', - name: 'sophos.xg.idp_policy_id', - type: 'integer', - }, - 'sophos.xg.idp_policy_name': { - category: 'sophos', - description: 'IPS policy name i.e. IPS policy name which is applied on the traffic ', - name: 'sophos.xg.idp_policy_name', - type: 'keyword', - }, - 'sophos.xg.signature_id': { - category: 'sophos', - description: 'Signature ID ', - name: 'sophos.xg.signature_id', - type: 'keyword', - }, - 'sophos.xg.signature_msg': { - category: 'sophos', - description: 'Signature messsage ', - name: 'sophos.xg.signature_msg', - type: 'keyword', - }, - 'sophos.xg.classification': { - category: 'sophos', - description: 'Signature classification ', - name: 'sophos.xg.classification', - type: 'keyword', - }, - 'sophos.xg.rule_priority': { - category: 'sophos', - description: 'Priority of IPS policy ', - name: 'sophos.xg.rule_priority', - type: 'keyword', - }, - 'sophos.xg.platform': { - category: 'sophos', - description: 'Platform of the traffic. ', - name: 'sophos.xg.platform', - type: 'keyword', - }, - 'sophos.xg.category': { - category: 'sophos', - description: 'IPS signature category. ', - name: 'sophos.xg.category', - type: 'keyword', - }, - 'sophos.xg.target': { - category: 'sophos', - description: 'Platform of the traffic. ', - name: 'sophos.xg.target', - type: 'keyword', - }, - 'sophos.xg.eventid': { - category: 'sophos', - description: 'ATP Evenet ID ', - name: 'sophos.xg.eventid', - type: 'keyword', - }, - 'sophos.xg.ep_uuid': { - category: 'sophos', - description: 'Endpoint UUID ', - name: 'sophos.xg.ep_uuid', - type: 'keyword', - }, - 'sophos.xg.threatname': { - category: 'sophos', - description: 'ATP threatname ', - name: 'sophos.xg.threatname', - type: 'keyword', - }, - 'sophos.xg.sourceip': { - category: 'sophos', - description: 'Original source IP address of traffic ', - name: 'sophos.xg.sourceip', - type: 'ip', - }, - 'sophos.xg.destinationip': { - category: 'sophos', - description: 'Original destination IP address of traffic ', - name: 'sophos.xg.destinationip', - type: 'ip', - }, - 'sophos.xg.login_user': { - category: 'sophos', - description: 'ATP login user ', - name: 'sophos.xg.login_user', - type: 'keyword', - }, - 'sophos.xg.eventtype': { - category: 'sophos', - description: 'ATP event type ', - name: 'sophos.xg.eventtype', - type: 'keyword', - }, - 'sophos.xg.execution_path': { - category: 'sophos', - description: 'ATP execution path ', - name: 'sophos.xg.execution_path', - type: 'keyword', - }, - 'sophos.xg.av_policy_name': { - category: 'sophos', - description: 'Malware scanning policy name which is applied on the traffic ', - name: 'sophos.xg.av_policy_name', - type: 'keyword', - }, - 'sophos.xg.from_email_address': { - category: 'sophos', - description: 'Sender email address ', - name: 'sophos.xg.from_email_address', - type: 'keyword', - }, - 'sophos.xg.to_email_address': { - category: 'sophos', - description: 'Receipeint email address ', - name: 'sophos.xg.to_email_address', - type: 'keyword', - }, - 'sophos.xg.subject': { - category: 'sophos', - description: 'Email subject ', - name: 'sophos.xg.subject', - type: 'keyword', - }, - 'sophos.xg.mailsize': { - category: 'sophos', - description: 'mailsize ', - name: 'sophos.xg.mailsize', - type: 'integer', - }, - 'sophos.xg.virus': { - category: 'sophos', - description: 'virus name ', - name: 'sophos.xg.virus', - type: 'keyword', - }, - 'sophos.xg.ftp_url': { - category: 'sophos', - description: 'FTP URL from which virus was downloaded ', - name: 'sophos.xg.ftp_url', - type: 'keyword', - }, - 'sophos.xg.ftp_direction': { - category: 'sophos', - description: 'Direction of FTP transfer: Upload or Download ', - name: 'sophos.xg.ftp_direction', - type: 'keyword', - }, - 'sophos.xg.filesize': { - category: 'sophos', - description: 'Size of the file that contained virus ', - name: 'sophos.xg.filesize', - type: 'integer', - }, - 'sophos.xg.filepath': { - category: 'sophos', - description: 'Path of the file containing virus ', - name: 'sophos.xg.filepath', - type: 'keyword', - }, - 'sophos.xg.filename': { - category: 'sophos', - description: 'File name associated with the event ', - name: 'sophos.xg.filename', - type: 'keyword', - }, - 'sophos.xg.ftpcommand': { - category: 'sophos', - description: 'FTP command used when virus was found ', - name: 'sophos.xg.ftpcommand', - type: 'keyword', - }, - 'sophos.xg.url': { - category: 'sophos', - description: 'URL from which virus was downloaded ', - name: 'sophos.xg.url', - type: 'keyword', - }, - 'sophos.xg.domainname': { - category: 'sophos', - description: 'Domain from which virus was downloaded ', - name: 'sophos.xg.domainname', - type: 'keyword', - }, - 'sophos.xg.quarantine': { - category: 'sophos', - description: 'Path and filename of the file quarantined ', - name: 'sophos.xg.quarantine', - type: 'keyword', - }, - 'sophos.xg.src_domainname': { - category: 'sophos', - description: 'Sender domain name ', - name: 'sophos.xg.src_domainname', - type: 'keyword', - }, - 'sophos.xg.dst_domainname': { - category: 'sophos', - description: 'Receiver domain name ', - name: 'sophos.xg.dst_domainname', - type: 'keyword', - }, - 'sophos.xg.reason': { - category: 'sophos', - description: 'Reason why the record was detected as spam/malicious ', - name: 'sophos.xg.reason', - type: 'keyword', - }, - 'sophos.xg.referer': { - category: 'sophos', - description: 'Referer ', - name: 'sophos.xg.referer', - type: 'keyword', - }, - 'sophos.xg.spamaction': { - category: 'sophos', - description: 'Spam Action ', - name: 'sophos.xg.spamaction', - type: 'keyword', - }, - 'sophos.xg.mailid': { - category: 'sophos', - description: 'mailid ', - name: 'sophos.xg.mailid', - type: 'keyword', - }, - 'sophos.xg.quarantine_reason': { - category: 'sophos', - description: 'Quarantine reason ', - name: 'sophos.xg.quarantine_reason', - type: 'keyword', - }, - 'sophos.xg.status_code': { - category: 'sophos', - description: 'Status code ', - name: 'sophos.xg.status_code', - type: 'keyword', - }, - 'sophos.xg.override_token': { - category: 'sophos', - description: 'Override token ', - name: 'sophos.xg.override_token', - type: 'keyword', - }, - 'sophos.xg.con_id': { - category: 'sophos', - description: 'Unique identifier of connection ', - name: 'sophos.xg.con_id', - type: 'integer', - }, - 'sophos.xg.override_authorizer': { - category: 'sophos', - description: 'Override authorizer ', - name: 'sophos.xg.override_authorizer', - type: 'keyword', - }, - 'sophos.xg.transactionid': { - category: 'sophos', - description: 'Transaction ID of the AV scan. ', - name: 'sophos.xg.transactionid', - type: 'keyword', - }, - 'sophos.xg.upload_file_type': { - category: 'sophos', - description: 'Upload file type ', - name: 'sophos.xg.upload_file_type', - type: 'keyword', - }, - 'sophos.xg.upload_file_name': { - category: 'sophos', - description: 'Upload file name ', - name: 'sophos.xg.upload_file_name', - type: 'keyword', - }, - 'sophos.xg.httpresponsecode': { - category: 'sophos', - description: 'code of HTTP response ', - name: 'sophos.xg.httpresponsecode', - type: 'long', - }, - 'sophos.xg.user_gp': { - category: 'sophos', - description: 'Group name to which the user belongs. ', - name: 'sophos.xg.user_gp', - type: 'keyword', - }, - 'sophos.xg.category_type': { - category: 'sophos', - description: 'Type of category under which website falls ', - name: 'sophos.xg.category_type', - type: 'keyword', - }, - 'sophos.xg.download_file_type': { - category: 'sophos', - description: 'Download file type ', - name: 'sophos.xg.download_file_type', - type: 'keyword', - }, - 'sophos.xg.exceptions': { - category: 'sophos', - description: 'List of the checks excluded by web exceptions. ', - name: 'sophos.xg.exceptions', - type: 'keyword', - }, - 'sophos.xg.contenttype': { - category: 'sophos', - description: 'Type of the content ', - name: 'sophos.xg.contenttype', - type: 'keyword', - }, - 'sophos.xg.override_name': { - category: 'sophos', - description: 'Override name ', - name: 'sophos.xg.override_name', - type: 'keyword', - }, - 'sophos.xg.activityname': { - category: 'sophos', - description: 'Web policy activity that matched and caused the policy result. ', - name: 'sophos.xg.activityname', - type: 'keyword', - }, - 'sophos.xg.download_file_name': { - category: 'sophos', - description: 'Download file name ', - name: 'sophos.xg.download_file_name', - type: 'keyword', - }, - 'sophos.xg.sha1sum': { - category: 'sophos', - description: 'SHA1 checksum of the item being analyzed ', - name: 'sophos.xg.sha1sum', - type: 'keyword', - }, - 'sophos.xg.message_id': { - category: 'sophos', - description: 'Message ID ', - name: 'sophos.xg.message_id', - type: 'keyword', - }, - 'sophos.xg.connid': { - category: 'sophos', - description: 'Connection ID ', - name: 'sophos.xg.connid', - type: 'keyword', - }, - 'sophos.xg.message': { - category: 'sophos', - description: 'Message ', - name: 'sophos.xg.message', - type: 'keyword', - }, - 'sophos.xg.email_subject': { - category: 'sophos', - description: 'Email Subject ', - name: 'sophos.xg.email_subject', - type: 'keyword', - }, - 'sophos.xg.file_path': { - category: 'sophos', - description: 'File path ', - name: 'sophos.xg.file_path', - type: 'keyword', - }, - 'sophos.xg.dstdomain': { - category: 'sophos', - description: 'Destination Domain ', - name: 'sophos.xg.dstdomain', - type: 'keyword', - }, - 'sophos.xg.file_size': { - category: 'sophos', - description: 'File Size ', - name: 'sophos.xg.file_size', - type: 'integer', - }, - 'sophos.xg.transaction_id': { - category: 'sophos', - description: 'Transaction ID ', - name: 'sophos.xg.transaction_id', - type: 'keyword', - }, - 'sophos.xg.website': { - category: 'sophos', - description: 'Website ', - name: 'sophos.xg.website', - type: 'keyword', - }, - 'sophos.xg.file_name': { - category: 'sophos', - description: 'Filename ', - name: 'sophos.xg.file_name', - type: 'keyword', - }, - 'sophos.xg.context_prefix': { - category: 'sophos', - description: 'Content Prefix ', - name: 'sophos.xg.context_prefix', - type: 'keyword', - }, - 'sophos.xg.site_category': { - category: 'sophos', - description: 'Site Category ', - name: 'sophos.xg.site_category', - type: 'keyword', - }, - 'sophos.xg.context_suffix': { - category: 'sophos', - description: 'Context Suffix ', - name: 'sophos.xg.context_suffix', - type: 'keyword', - }, - 'sophos.xg.dictionary_name': { - category: 'sophos', - description: 'Dictionary Name ', - name: 'sophos.xg.dictionary_name', - type: 'keyword', - }, - 'sophos.xg.action': { - category: 'sophos', - description: 'Event Action ', - name: 'sophos.xg.action', - type: 'keyword', - }, - 'sophos.xg.user': { - category: 'sophos', - description: 'User ', - name: 'sophos.xg.user', - type: 'keyword', - }, - 'sophos.xg.context_match': { - category: 'sophos', - description: 'Context Match ', - name: 'sophos.xg.context_match', - type: 'keyword', - }, - 'sophos.xg.direction': { - category: 'sophos', - description: 'Direction ', - name: 'sophos.xg.direction', - type: 'keyword', - }, - 'sophos.xg.auth_client': { - category: 'sophos', - description: 'Auth Client ', - name: 'sophos.xg.auth_client', - type: 'keyword', - }, - 'sophos.xg.auth_mechanism': { - category: 'sophos', - description: 'Auth mechanism ', - name: 'sophos.xg.auth_mechanism', - type: 'keyword', - }, - 'sophos.xg.connectionname': { - category: 'sophos', - description: 'Connectionname ', - name: 'sophos.xg.connectionname', - type: 'keyword', - }, - 'sophos.xg.remotenetwork': { - category: 'sophos', - description: 'remotenetwork ', - name: 'sophos.xg.remotenetwork', - type: 'keyword', - }, - 'sophos.xg.localgateway': { - category: 'sophos', - description: 'Localgateway ', - name: 'sophos.xg.localgateway', - type: 'keyword', - }, - 'sophos.xg.localnetwork': { - category: 'sophos', - description: 'Localnetwork ', - name: 'sophos.xg.localnetwork', - type: 'keyword', - }, - 'sophos.xg.connectiontype': { - category: 'sophos', - description: 'Connectiontype ', - name: 'sophos.xg.connectiontype', - type: 'keyword', - }, - 'sophos.xg.oldversion': { - category: 'sophos', - description: 'Oldversion ', - name: 'sophos.xg.oldversion', - type: 'keyword', - }, - 'sophos.xg.newversion': { - category: 'sophos', - description: 'Newversion ', - name: 'sophos.xg.newversion', - type: 'keyword', - }, - 'sophos.xg.ipaddress': { - category: 'sophos', - description: 'Ipaddress ', - name: 'sophos.xg.ipaddress', - type: 'keyword', - }, - 'sophos.xg.client_physical_address': { - category: 'sophos', - description: 'Client physical address ', - name: 'sophos.xg.client_physical_address', - type: 'keyword', - }, - 'sophos.xg.client_host_name': { - category: 'sophos', - description: 'Client host name ', - name: 'sophos.xg.client_host_name', - type: 'keyword', - }, - 'sophos.xg.raw_data': { - category: 'sophos', - description: 'Raw data ', - name: 'sophos.xg.raw_data', - type: 'keyword', - }, - 'sophos.xg.Mode': { - category: 'sophos', - description: 'Mode ', - name: 'sophos.xg.Mode', - type: 'keyword', - }, - 'sophos.xg.sessionid': { - category: 'sophos', - description: 'Sessionid ', - name: 'sophos.xg.sessionid', - type: 'keyword', - }, - 'sophos.xg.starttime': { - category: 'sophos', - description: 'Starttime ', - name: 'sophos.xg.starttime', - type: 'date', - }, - 'sophos.xg.remote_ip': { - category: 'sophos', - description: 'Remote IP ', - name: 'sophos.xg.remote_ip', - type: 'ip', - }, - 'sophos.xg.timestamp': { - category: 'sophos', - description: 'timestamp ', - name: 'sophos.xg.timestamp', - type: 'date', - }, - 'sophos.xg.SysLog_SERVER_NAME': { - category: 'sophos', - description: 'SysLog SERVER NAME ', - name: 'sophos.xg.SysLog_SERVER_NAME', - type: 'keyword', - }, - 'sophos.xg.backup_mode': { - category: 'sophos', - description: 'Backup mode ', - name: 'sophos.xg.backup_mode', - type: 'keyword', - }, - 'sophos.xg.source': { - category: 'sophos', - description: 'Source ', - name: 'sophos.xg.source', - type: 'keyword', - }, - 'sophos.xg.server': { - category: 'sophos', - description: 'Server ', - name: 'sophos.xg.server', - type: 'keyword', - }, - 'sophos.xg.host': { - category: 'sophos', - description: 'Host ', - name: 'sophos.xg.host', - type: 'keyword', - }, - 'sophos.xg.responsetime': { - category: 'sophos', - description: 'Responsetime ', - name: 'sophos.xg.responsetime', - type: 'long', - }, - 'sophos.xg.cookie': { - category: 'sophos', - description: 'cookie ', - name: 'sophos.xg.cookie', - type: 'keyword', - }, - 'sophos.xg.querystring': { - category: 'sophos', - description: 'querystring ', - name: 'sophos.xg.querystring', - type: 'keyword', - }, - 'sophos.xg.extra': { - category: 'sophos', - description: 'extra ', - name: 'sophos.xg.extra', - type: 'keyword', - }, - 'sophos.xg.PHPSESSID': { - category: 'sophos', - description: 'PHPSESSID ', - name: 'sophos.xg.PHPSESSID', - type: 'keyword', - }, - 'sophos.xg.start_time': { - category: 'sophos', - description: 'Start time ', - name: 'sophos.xg.start_time', - type: 'date', - }, - 'sophos.xg.eventtime': { - category: 'sophos', - description: 'Event time ', - name: 'sophos.xg.eventtime', - type: 'date', - }, - 'sophos.xg.red_id': { - category: 'sophos', - description: 'RED ID ', - name: 'sophos.xg.red_id', - type: 'keyword', - }, - 'sophos.xg.branch_name': { - category: 'sophos', - description: 'Branch Name ', - name: 'sophos.xg.branch_name', - type: 'keyword', - }, - 'sophos.xg.updatedip': { - category: 'sophos', - description: 'updatedip ', - name: 'sophos.xg.updatedip', - type: 'ip', - }, - 'sophos.xg.idle_cpu': { - category: 'sophos', - description: 'idle ## ', - name: 'sophos.xg.idle_cpu', - type: 'float', - }, - 'sophos.xg.system_cpu': { - category: 'sophos', - description: 'system ', - name: 'sophos.xg.system_cpu', - type: 'float', - }, - 'sophos.xg.user_cpu': { - category: 'sophos', - description: 'system ', - name: 'sophos.xg.user_cpu', - type: 'float', - }, - 'sophos.xg.used': { - category: 'sophos', - description: 'used ', - name: 'sophos.xg.used', - type: 'integer', - }, - 'sophos.xg.unit': { - category: 'sophos', - description: 'unit ', - name: 'sophos.xg.unit', - type: 'keyword', - }, - 'sophos.xg.total_memory': { - category: 'sophos', - description: 'Total Memory ', - name: 'sophos.xg.total_memory', - type: 'integer', - }, - 'sophos.xg.free': { - category: 'sophos', - description: 'free ', - name: 'sophos.xg.free', - type: 'integer', - }, - 'sophos.xg.transmittederrors': { - category: 'sophos', - description: 'transmitted errors ', - name: 'sophos.xg.transmittederrors', - type: 'keyword', - }, - 'sophos.xg.receivederrors': { - category: 'sophos', - description: 'received errors ', - name: 'sophos.xg.receivederrors', - type: 'keyword', - }, - 'sophos.xg.receivedkbits': { - category: 'sophos', - description: 'received kbits ', - name: 'sophos.xg.receivedkbits', - type: 'long', - }, - 'sophos.xg.transmittedkbits': { - category: 'sophos', - description: 'transmitted kbits ', - name: 'sophos.xg.transmittedkbits', - type: 'long', - }, - 'sophos.xg.transmitteddrops': { - category: 'sophos', - description: 'transmitted drops ', - name: 'sophos.xg.transmitteddrops', - type: 'long', - }, - 'sophos.xg.receiveddrops': { - category: 'sophos', - description: 'received drops ', - name: 'sophos.xg.receiveddrops', - type: 'long', - }, - 'sophos.xg.collisions': { - category: 'sophos', - description: 'collisions ', - name: 'sophos.xg.collisions', - type: 'long', - }, - 'sophos.xg.interface': { - category: 'sophos', - description: 'interface ', - name: 'sophos.xg.interface', - type: 'keyword', - }, - 'sophos.xg.Configuration': { - category: 'sophos', - description: 'Configuration ', - name: 'sophos.xg.Configuration', - type: 'float', - }, - 'sophos.xg.Reports': { - category: 'sophos', - description: 'Reports ', - name: 'sophos.xg.Reports', - type: 'float', - }, - 'sophos.xg.Signature': { - category: 'sophos', - description: 'Signature ', - name: 'sophos.xg.Signature', - type: 'float', - }, - 'sophos.xg.Temp': { - category: 'sophos', - description: 'Temp ', - name: 'sophos.xg.Temp', - type: 'float', - }, - 'sophos.xg.users': { - category: 'sophos', - description: 'users ', - name: 'sophos.xg.users', - type: 'keyword', - }, - 'sophos.xg.ssid': { - category: 'sophos', - description: 'ssid ', - name: 'sophos.xg.ssid', - type: 'keyword', - }, - 'sophos.xg.ap': { - category: 'sophos', - description: 'ap ', - name: 'sophos.xg.ap', - type: 'keyword', - }, - 'sophos.xg.clients_conn_ssid': { - category: 'sophos', - description: 'clients connection ssid ', - name: 'sophos.xg.clients_conn_ssid', - type: 'keyword', - }, - 'sophos.xg.sqli': { - category: 'sophos', - description: 'The related SQLI caught by the WAF ', - name: 'sophos.xg.sqli', - type: 'keyword', - }, - 'sophos.xg.xss': { - category: 'sophos', - description: 'The related XSS caught by the WAF ', - name: 'sophos.xg.xss', - type: 'keyword', - }, - 'suricata.eve.event_type': { - category: 'suricata', - name: 'suricata.eve.event_type', - type: 'keyword', - }, - 'suricata.eve.app_proto_orig': { - category: 'suricata', - name: 'suricata.eve.app_proto_orig', - type: 'keyword', - }, - 'suricata.eve.tcp.tcp_flags': { - category: 'suricata', - name: 'suricata.eve.tcp.tcp_flags', - type: 'keyword', - }, - 'suricata.eve.tcp.psh': { - category: 'suricata', - name: 'suricata.eve.tcp.psh', - type: 'boolean', - }, - 'suricata.eve.tcp.tcp_flags_tc': { - category: 'suricata', - name: 'suricata.eve.tcp.tcp_flags_tc', - type: 'keyword', - }, - 'suricata.eve.tcp.ack': { - category: 'suricata', - name: 'suricata.eve.tcp.ack', - type: 'boolean', - }, - 'suricata.eve.tcp.syn': { - category: 'suricata', - name: 'suricata.eve.tcp.syn', - type: 'boolean', - }, - 'suricata.eve.tcp.state': { - category: 'suricata', - name: 'suricata.eve.tcp.state', - type: 'keyword', - }, - 'suricata.eve.tcp.tcp_flags_ts': { - category: 'suricata', - name: 'suricata.eve.tcp.tcp_flags_ts', - type: 'keyword', - }, - 'suricata.eve.tcp.rst': { - category: 'suricata', - name: 'suricata.eve.tcp.rst', - type: 'boolean', - }, - 'suricata.eve.tcp.fin': { - category: 'suricata', - name: 'suricata.eve.tcp.fin', - type: 'boolean', - }, - 'suricata.eve.fileinfo.sha1': { - category: 'suricata', - name: 'suricata.eve.fileinfo.sha1', - type: 'keyword', - }, - 'suricata.eve.fileinfo.filename': { - category: 'suricata', - name: 'suricata.eve.fileinfo.filename', - type: 'alias', - }, - 'suricata.eve.fileinfo.tx_id': { - category: 'suricata', - name: 'suricata.eve.fileinfo.tx_id', - type: 'long', - }, - 'suricata.eve.fileinfo.state': { - category: 'suricata', - name: 'suricata.eve.fileinfo.state', - type: 'keyword', - }, - 'suricata.eve.fileinfo.stored': { - category: 'suricata', - name: 'suricata.eve.fileinfo.stored', - type: 'boolean', - }, - 'suricata.eve.fileinfo.gaps': { - category: 'suricata', - name: 'suricata.eve.fileinfo.gaps', - type: 'boolean', - }, - 'suricata.eve.fileinfo.sha256': { - category: 'suricata', - name: 'suricata.eve.fileinfo.sha256', - type: 'keyword', - }, - 'suricata.eve.fileinfo.md5': { - category: 'suricata', - name: 'suricata.eve.fileinfo.md5', - type: 'keyword', - }, - 'suricata.eve.fileinfo.size': { - category: 'suricata', - name: 'suricata.eve.fileinfo.size', - type: 'alias', - }, - 'suricata.eve.icmp_type': { - category: 'suricata', - name: 'suricata.eve.icmp_type', - type: 'long', - }, - 'suricata.eve.dest_port': { - category: 'suricata', - name: 'suricata.eve.dest_port', - type: 'alias', - }, - 'suricata.eve.src_port': { - category: 'suricata', - name: 'suricata.eve.src_port', - type: 'alias', - }, - 'suricata.eve.proto': { - category: 'suricata', - name: 'suricata.eve.proto', - type: 'alias', - }, - 'suricata.eve.pcap_cnt': { - category: 'suricata', - name: 'suricata.eve.pcap_cnt', - type: 'long', - }, - 'suricata.eve.src_ip': { - category: 'suricata', - name: 'suricata.eve.src_ip', - type: 'alias', - }, - 'suricata.eve.dns.type': { - category: 'suricata', - name: 'suricata.eve.dns.type', - type: 'keyword', - }, - 'suricata.eve.dns.rrtype': { - category: 'suricata', - name: 'suricata.eve.dns.rrtype', - type: 'keyword', - }, - 'suricata.eve.dns.rrname': { - category: 'suricata', - name: 'suricata.eve.dns.rrname', - type: 'keyword', - }, - 'suricata.eve.dns.rdata': { - category: 'suricata', - name: 'suricata.eve.dns.rdata', - type: 'keyword', - }, - 'suricata.eve.dns.tx_id': { - category: 'suricata', - name: 'suricata.eve.dns.tx_id', - type: 'long', - }, - 'suricata.eve.dns.ttl': { - category: 'suricata', - name: 'suricata.eve.dns.ttl', - type: 'long', - }, - 'suricata.eve.dns.rcode': { - category: 'suricata', - name: 'suricata.eve.dns.rcode', - type: 'keyword', - }, - 'suricata.eve.dns.id': { - category: 'suricata', - name: 'suricata.eve.dns.id', - type: 'long', - }, - 'suricata.eve.flow_id': { - category: 'suricata', - name: 'suricata.eve.flow_id', - type: 'keyword', - }, - 'suricata.eve.email.status': { - category: 'suricata', - name: 'suricata.eve.email.status', - type: 'keyword', - }, - 'suricata.eve.dest_ip': { - category: 'suricata', - name: 'suricata.eve.dest_ip', - type: 'alias', - }, - 'suricata.eve.icmp_code': { - category: 'suricata', - name: 'suricata.eve.icmp_code', - type: 'long', - }, - 'suricata.eve.http.status': { - category: 'suricata', - name: 'suricata.eve.http.status', - type: 'alias', - }, - 'suricata.eve.http.redirect': { - category: 'suricata', - name: 'suricata.eve.http.redirect', - type: 'keyword', - }, - 'suricata.eve.http.http_user_agent': { - category: 'suricata', - name: 'suricata.eve.http.http_user_agent', - type: 'alias', - }, - 'suricata.eve.http.protocol': { - category: 'suricata', - name: 'suricata.eve.http.protocol', - type: 'keyword', - }, - 'suricata.eve.http.http_refer': { - category: 'suricata', - name: 'suricata.eve.http.http_refer', - type: 'alias', - }, - 'suricata.eve.http.url': { - category: 'suricata', - name: 'suricata.eve.http.url', - type: 'alias', - }, - 'suricata.eve.http.hostname': { - category: 'suricata', - name: 'suricata.eve.http.hostname', - type: 'alias', - }, - 'suricata.eve.http.length': { - category: 'suricata', - name: 'suricata.eve.http.length', - type: 'alias', - }, - 'suricata.eve.http.http_method': { - category: 'suricata', - name: 'suricata.eve.http.http_method', - type: 'alias', - }, - 'suricata.eve.http.http_content_type': { - category: 'suricata', - name: 'suricata.eve.http.http_content_type', - type: 'keyword', - }, - 'suricata.eve.in_iface': { - category: 'suricata', - name: 'suricata.eve.in_iface', - type: 'keyword', - }, - 'suricata.eve.alert.metadata': { - category: 'suricata', - description: 'Metadata about the alert.', - name: 'suricata.eve.alert.metadata', - type: 'flattened', - }, - 'suricata.eve.alert.category': { - category: 'suricata', - name: 'suricata.eve.alert.category', - type: 'keyword', - }, - 'suricata.eve.alert.severity': { - category: 'suricata', - name: 'suricata.eve.alert.severity', - type: 'alias', - }, - 'suricata.eve.alert.rev': { - category: 'suricata', - name: 'suricata.eve.alert.rev', - type: 'long', - }, - 'suricata.eve.alert.gid': { - category: 'suricata', - name: 'suricata.eve.alert.gid', - type: 'long', - }, - 'suricata.eve.alert.signature': { - category: 'suricata', - name: 'suricata.eve.alert.signature', - type: 'keyword', - }, - 'suricata.eve.alert.action': { - category: 'suricata', - name: 'suricata.eve.alert.action', - type: 'alias', - }, - 'suricata.eve.alert.signature_id': { - category: 'suricata', - name: 'suricata.eve.alert.signature_id', - type: 'long', - }, - 'suricata.eve.alert.protocols': { - category: 'suricata', - name: 'suricata.eve.alert.protocols', - type: 'keyword', - }, - 'suricata.eve.alert.attack_target': { - category: 'suricata', - name: 'suricata.eve.alert.attack_target', - type: 'keyword', - }, - 'suricata.eve.alert.capec_id': { - category: 'suricata', - name: 'suricata.eve.alert.capec_id', - type: 'keyword', - }, - 'suricata.eve.alert.cwe_id': { - category: 'suricata', - name: 'suricata.eve.alert.cwe_id', - type: 'keyword', - }, - 'suricata.eve.alert.malware': { - category: 'suricata', - name: 'suricata.eve.alert.malware', - type: 'keyword', - }, - 'suricata.eve.alert.cve': { - category: 'suricata', - name: 'suricata.eve.alert.cve', - type: 'keyword', - }, - 'suricata.eve.alert.cvss_v2_base': { - category: 'suricata', - name: 'suricata.eve.alert.cvss_v2_base', - type: 'keyword', - }, - 'suricata.eve.alert.cvss_v2_temporal': { - category: 'suricata', - name: 'suricata.eve.alert.cvss_v2_temporal', - type: 'keyword', - }, - 'suricata.eve.alert.cvss_v3_base': { - category: 'suricata', - name: 'suricata.eve.alert.cvss_v3_base', - type: 'keyword', - }, - 'suricata.eve.alert.cvss_v3_temporal': { - category: 'suricata', - name: 'suricata.eve.alert.cvss_v3_temporal', - type: 'keyword', - }, - 'suricata.eve.alert.priority': { - category: 'suricata', - name: 'suricata.eve.alert.priority', - type: 'keyword', - }, - 'suricata.eve.alert.hostile': { - category: 'suricata', - name: 'suricata.eve.alert.hostile', - type: 'keyword', - }, - 'suricata.eve.alert.infected': { - category: 'suricata', - name: 'suricata.eve.alert.infected', - type: 'keyword', - }, - 'suricata.eve.alert.created_at': { - category: 'suricata', - name: 'suricata.eve.alert.created_at', - type: 'date', - }, - 'suricata.eve.alert.updated_at': { - category: 'suricata', - name: 'suricata.eve.alert.updated_at', - type: 'date', - }, - 'suricata.eve.alert.classtype': { - category: 'suricata', - name: 'suricata.eve.alert.classtype', - type: 'keyword', - }, - 'suricata.eve.alert.rule_source': { - category: 'suricata', - name: 'suricata.eve.alert.rule_source', - type: 'keyword', - }, - 'suricata.eve.alert.sid': { - category: 'suricata', - name: 'suricata.eve.alert.sid', - type: 'keyword', - }, - 'suricata.eve.alert.affected_product': { - category: 'suricata', - name: 'suricata.eve.alert.affected_product', - type: 'keyword', - }, - 'suricata.eve.alert.deployment': { - category: 'suricata', - name: 'suricata.eve.alert.deployment', - type: 'keyword', - }, - 'suricata.eve.alert.former_category': { - category: 'suricata', - name: 'suricata.eve.alert.former_category', - type: 'keyword', - }, - 'suricata.eve.alert.mitre_tool_id': { - category: 'suricata', - name: 'suricata.eve.alert.mitre_tool_id', - type: 'keyword', - }, - 'suricata.eve.alert.performance_impact': { - category: 'suricata', - name: 'suricata.eve.alert.performance_impact', - type: 'keyword', - }, - 'suricata.eve.alert.signature_severity': { - category: 'suricata', - name: 'suricata.eve.alert.signature_severity', - type: 'keyword', - }, - 'suricata.eve.alert.tag': { - category: 'suricata', - name: 'suricata.eve.alert.tag', - type: 'keyword', - }, - 'suricata.eve.ssh.client.proto_version': { - category: 'suricata', - name: 'suricata.eve.ssh.client.proto_version', - type: 'keyword', - }, - 'suricata.eve.ssh.client.software_version': { - category: 'suricata', - name: 'suricata.eve.ssh.client.software_version', - type: 'keyword', - }, - 'suricata.eve.ssh.server.proto_version': { - category: 'suricata', - name: 'suricata.eve.ssh.server.proto_version', - type: 'keyword', - }, - 'suricata.eve.ssh.server.software_version': { - category: 'suricata', - name: 'suricata.eve.ssh.server.software_version', - type: 'keyword', - }, - 'suricata.eve.stats.capture.kernel_packets': { - category: 'suricata', - name: 'suricata.eve.stats.capture.kernel_packets', - type: 'long', - }, - 'suricata.eve.stats.capture.kernel_drops': { - category: 'suricata', - name: 'suricata.eve.stats.capture.kernel_drops', - type: 'long', - }, - 'suricata.eve.stats.capture.kernel_ifdrops': { - category: 'suricata', - name: 'suricata.eve.stats.capture.kernel_ifdrops', - type: 'long', - }, - 'suricata.eve.stats.uptime': { - category: 'suricata', - name: 'suricata.eve.stats.uptime', - type: 'long', - }, - 'suricata.eve.stats.detect.alert': { - category: 'suricata', - name: 'suricata.eve.stats.detect.alert', - type: 'long', - }, - 'suricata.eve.stats.http.memcap': { - category: 'suricata', - name: 'suricata.eve.stats.http.memcap', - type: 'long', - }, - 'suricata.eve.stats.http.memuse': { - category: 'suricata', - name: 'suricata.eve.stats.http.memuse', - type: 'long', - }, - 'suricata.eve.stats.file_store.open_files': { - category: 'suricata', - name: 'suricata.eve.stats.file_store.open_files', - type: 'long', - }, - 'suricata.eve.stats.defrag.max_frag_hits': { - category: 'suricata', - name: 'suricata.eve.stats.defrag.max_frag_hits', - type: 'long', - }, - 'suricata.eve.stats.defrag.ipv4.timeouts': { - category: 'suricata', - name: 'suricata.eve.stats.defrag.ipv4.timeouts', - type: 'long', - }, - 'suricata.eve.stats.defrag.ipv4.fragments': { - category: 'suricata', - name: 'suricata.eve.stats.defrag.ipv4.fragments', - type: 'long', - }, - 'suricata.eve.stats.defrag.ipv4.reassembled': { - category: 'suricata', - name: 'suricata.eve.stats.defrag.ipv4.reassembled', - type: 'long', - }, - 'suricata.eve.stats.defrag.ipv6.timeouts': { - category: 'suricata', - name: 'suricata.eve.stats.defrag.ipv6.timeouts', - type: 'long', - }, - 'suricata.eve.stats.defrag.ipv6.fragments': { - category: 'suricata', - name: 'suricata.eve.stats.defrag.ipv6.fragments', - type: 'long', - }, - 'suricata.eve.stats.defrag.ipv6.reassembled': { - category: 'suricata', - name: 'suricata.eve.stats.defrag.ipv6.reassembled', - type: 'long', - }, - 'suricata.eve.stats.flow.tcp_reuse': { - category: 'suricata', - name: 'suricata.eve.stats.flow.tcp_reuse', - type: 'long', - }, - 'suricata.eve.stats.flow.udp': { - category: 'suricata', - name: 'suricata.eve.stats.flow.udp', - type: 'long', - }, - 'suricata.eve.stats.flow.memcap': { - category: 'suricata', - name: 'suricata.eve.stats.flow.memcap', - type: 'long', - }, - 'suricata.eve.stats.flow.emerg_mode_entered': { - category: 'suricata', - name: 'suricata.eve.stats.flow.emerg_mode_entered', - type: 'long', - }, - 'suricata.eve.stats.flow.emerg_mode_over': { - category: 'suricata', - name: 'suricata.eve.stats.flow.emerg_mode_over', - type: 'long', - }, - 'suricata.eve.stats.flow.tcp': { - category: 'suricata', - name: 'suricata.eve.stats.flow.tcp', - type: 'long', - }, - 'suricata.eve.stats.flow.icmpv6': { - category: 'suricata', - name: 'suricata.eve.stats.flow.icmpv6', - type: 'long', - }, - 'suricata.eve.stats.flow.icmpv4': { - category: 'suricata', - name: 'suricata.eve.stats.flow.icmpv4', - type: 'long', - }, - 'suricata.eve.stats.flow.spare': { - category: 'suricata', - name: 'suricata.eve.stats.flow.spare', - type: 'long', - }, - 'suricata.eve.stats.flow.memuse': { - category: 'suricata', - name: 'suricata.eve.stats.flow.memuse', - type: 'long', - }, - 'suricata.eve.stats.tcp.pseudo_failed': { - category: 'suricata', - name: 'suricata.eve.stats.tcp.pseudo_failed', - type: 'long', - }, - 'suricata.eve.stats.tcp.ssn_memcap_drop': { - category: 'suricata', - name: 'suricata.eve.stats.tcp.ssn_memcap_drop', - type: 'long', - }, - 'suricata.eve.stats.tcp.insert_data_overlap_fail': { - category: 'suricata', - name: 'suricata.eve.stats.tcp.insert_data_overlap_fail', - type: 'long', - }, - 'suricata.eve.stats.tcp.sessions': { - category: 'suricata', - name: 'suricata.eve.stats.tcp.sessions', - type: 'long', - }, - 'suricata.eve.stats.tcp.pseudo': { - category: 'suricata', - name: 'suricata.eve.stats.tcp.pseudo', - type: 'long', - }, - 'suricata.eve.stats.tcp.synack': { - category: 'suricata', - name: 'suricata.eve.stats.tcp.synack', - type: 'long', - }, - 'suricata.eve.stats.tcp.insert_data_normal_fail': { - category: 'suricata', - name: 'suricata.eve.stats.tcp.insert_data_normal_fail', - type: 'long', - }, - 'suricata.eve.stats.tcp.syn': { - category: 'suricata', - name: 'suricata.eve.stats.tcp.syn', - type: 'long', - }, - 'suricata.eve.stats.tcp.memuse': { - category: 'suricata', - name: 'suricata.eve.stats.tcp.memuse', - type: 'long', - }, - 'suricata.eve.stats.tcp.invalid_checksum': { - category: 'suricata', - name: 'suricata.eve.stats.tcp.invalid_checksum', - type: 'long', - }, - 'suricata.eve.stats.tcp.segment_memcap_drop': { - category: 'suricata', - name: 'suricata.eve.stats.tcp.segment_memcap_drop', - type: 'long', - }, - 'suricata.eve.stats.tcp.overlap': { - category: 'suricata', - name: 'suricata.eve.stats.tcp.overlap', - type: 'long', - }, - 'suricata.eve.stats.tcp.insert_list_fail': { - category: 'suricata', - name: 'suricata.eve.stats.tcp.insert_list_fail', - type: 'long', - }, - 'suricata.eve.stats.tcp.rst': { - category: 'suricata', - name: 'suricata.eve.stats.tcp.rst', - type: 'long', - }, - 'suricata.eve.stats.tcp.stream_depth_reached': { - category: 'suricata', - name: 'suricata.eve.stats.tcp.stream_depth_reached', - type: 'long', - }, - 'suricata.eve.stats.tcp.reassembly_memuse': { - category: 'suricata', - name: 'suricata.eve.stats.tcp.reassembly_memuse', - type: 'long', - }, - 'suricata.eve.stats.tcp.reassembly_gap': { - category: 'suricata', - name: 'suricata.eve.stats.tcp.reassembly_gap', - type: 'long', - }, - 'suricata.eve.stats.tcp.overlap_diff_data': { - category: 'suricata', - name: 'suricata.eve.stats.tcp.overlap_diff_data', - type: 'long', - }, - 'suricata.eve.stats.tcp.no_flow': { - category: 'suricata', - name: 'suricata.eve.stats.tcp.no_flow', - type: 'long', - }, - 'suricata.eve.stats.decoder.avg_pkt_size': { - category: 'suricata', - name: 'suricata.eve.stats.decoder.avg_pkt_size', - type: 'long', - }, - 'suricata.eve.stats.decoder.bytes': { - category: 'suricata', - name: 'suricata.eve.stats.decoder.bytes', - type: 'long', - }, - 'suricata.eve.stats.decoder.tcp': { - category: 'suricata', - name: 'suricata.eve.stats.decoder.tcp', - type: 'long', - }, - 'suricata.eve.stats.decoder.raw': { - category: 'suricata', - name: 'suricata.eve.stats.decoder.raw', - type: 'long', - }, - 'suricata.eve.stats.decoder.ppp': { - category: 'suricata', - name: 'suricata.eve.stats.decoder.ppp', - type: 'long', - }, - 'suricata.eve.stats.decoder.vlan_qinq': { - category: 'suricata', - name: 'suricata.eve.stats.decoder.vlan_qinq', - type: 'long', - }, - 'suricata.eve.stats.decoder.null': { - category: 'suricata', - name: 'suricata.eve.stats.decoder.null', - type: 'long', - }, - 'suricata.eve.stats.decoder.ltnull.unsupported_type': { - category: 'suricata', - name: 'suricata.eve.stats.decoder.ltnull.unsupported_type', - type: 'long', - }, - 'suricata.eve.stats.decoder.ltnull.pkt_too_small': { - category: 'suricata', - name: 'suricata.eve.stats.decoder.ltnull.pkt_too_small', - type: 'long', - }, - 'suricata.eve.stats.decoder.invalid': { - category: 'suricata', - name: 'suricata.eve.stats.decoder.invalid', - type: 'long', - }, - 'suricata.eve.stats.decoder.gre': { - category: 'suricata', - name: 'suricata.eve.stats.decoder.gre', - type: 'long', - }, - 'suricata.eve.stats.decoder.ipv4': { - category: 'suricata', - name: 'suricata.eve.stats.decoder.ipv4', - type: 'long', - }, - 'suricata.eve.stats.decoder.ipv6': { - category: 'suricata', - name: 'suricata.eve.stats.decoder.ipv6', - type: 'long', - }, - 'suricata.eve.stats.decoder.pkts': { - category: 'suricata', - name: 'suricata.eve.stats.decoder.pkts', - type: 'long', - }, - 'suricata.eve.stats.decoder.ipv6_in_ipv6': { - category: 'suricata', - name: 'suricata.eve.stats.decoder.ipv6_in_ipv6', - type: 'long', - }, - 'suricata.eve.stats.decoder.ipraw.invalid_ip_version': { - category: 'suricata', - name: 'suricata.eve.stats.decoder.ipraw.invalid_ip_version', - type: 'long', - }, - 'suricata.eve.stats.decoder.pppoe': { - category: 'suricata', - name: 'suricata.eve.stats.decoder.pppoe', - type: 'long', - }, - 'suricata.eve.stats.decoder.udp': { - category: 'suricata', - name: 'suricata.eve.stats.decoder.udp', - type: 'long', - }, - 'suricata.eve.stats.decoder.dce.pkt_too_small': { - category: 'suricata', - name: 'suricata.eve.stats.decoder.dce.pkt_too_small', - type: 'long', - }, - 'suricata.eve.stats.decoder.vlan': { - category: 'suricata', - name: 'suricata.eve.stats.decoder.vlan', - type: 'long', - }, - 'suricata.eve.stats.decoder.sctp': { - category: 'suricata', - name: 'suricata.eve.stats.decoder.sctp', - type: 'long', - }, - 'suricata.eve.stats.decoder.max_pkt_size': { - category: 'suricata', - name: 'suricata.eve.stats.decoder.max_pkt_size', - type: 'long', - }, - 'suricata.eve.stats.decoder.teredo': { - category: 'suricata', - name: 'suricata.eve.stats.decoder.teredo', - type: 'long', - }, - 'suricata.eve.stats.decoder.mpls': { - category: 'suricata', - name: 'suricata.eve.stats.decoder.mpls', - type: 'long', - }, - 'suricata.eve.stats.decoder.sll': { - category: 'suricata', - name: 'suricata.eve.stats.decoder.sll', - type: 'long', - }, - 'suricata.eve.stats.decoder.icmpv6': { - category: 'suricata', - name: 'suricata.eve.stats.decoder.icmpv6', - type: 'long', - }, - 'suricata.eve.stats.decoder.icmpv4': { - category: 'suricata', - name: 'suricata.eve.stats.decoder.icmpv4', - type: 'long', - }, - 'suricata.eve.stats.decoder.erspan': { - category: 'suricata', - name: 'suricata.eve.stats.decoder.erspan', - type: 'long', - }, - 'suricata.eve.stats.decoder.ethernet': { - category: 'suricata', - name: 'suricata.eve.stats.decoder.ethernet', - type: 'long', - }, - 'suricata.eve.stats.decoder.ipv4_in_ipv6': { - category: 'suricata', - name: 'suricata.eve.stats.decoder.ipv4_in_ipv6', - type: 'long', - }, - 'suricata.eve.stats.decoder.ieee8021ah': { - category: 'suricata', - name: 'suricata.eve.stats.decoder.ieee8021ah', - type: 'long', - }, - 'suricata.eve.stats.dns.memcap_global': { - category: 'suricata', - name: 'suricata.eve.stats.dns.memcap_global', - type: 'long', - }, - 'suricata.eve.stats.dns.memcap_state': { - category: 'suricata', - name: 'suricata.eve.stats.dns.memcap_state', - type: 'long', - }, - 'suricata.eve.stats.dns.memuse': { - category: 'suricata', - name: 'suricata.eve.stats.dns.memuse', - type: 'long', - }, - 'suricata.eve.stats.flow_mgr.rows_busy': { - category: 'suricata', - name: 'suricata.eve.stats.flow_mgr.rows_busy', - type: 'long', - }, - 'suricata.eve.stats.flow_mgr.flows_timeout': { - category: 'suricata', - name: 'suricata.eve.stats.flow_mgr.flows_timeout', - type: 'long', - }, - 'suricata.eve.stats.flow_mgr.flows_notimeout': { - category: 'suricata', - name: 'suricata.eve.stats.flow_mgr.flows_notimeout', - type: 'long', - }, - 'suricata.eve.stats.flow_mgr.rows_skipped': { - category: 'suricata', - name: 'suricata.eve.stats.flow_mgr.rows_skipped', - type: 'long', - }, - 'suricata.eve.stats.flow_mgr.closed_pruned': { - category: 'suricata', - name: 'suricata.eve.stats.flow_mgr.closed_pruned', - type: 'long', - }, - 'suricata.eve.stats.flow_mgr.new_pruned': { - category: 'suricata', - name: 'suricata.eve.stats.flow_mgr.new_pruned', - type: 'long', - }, - 'suricata.eve.stats.flow_mgr.flows_removed': { - category: 'suricata', - name: 'suricata.eve.stats.flow_mgr.flows_removed', - type: 'long', - }, - 'suricata.eve.stats.flow_mgr.bypassed_pruned': { - category: 'suricata', - name: 'suricata.eve.stats.flow_mgr.bypassed_pruned', - type: 'long', - }, - 'suricata.eve.stats.flow_mgr.est_pruned': { - category: 'suricata', - name: 'suricata.eve.stats.flow_mgr.est_pruned', - type: 'long', - }, - 'suricata.eve.stats.flow_mgr.flows_timeout_inuse': { - category: 'suricata', - name: 'suricata.eve.stats.flow_mgr.flows_timeout_inuse', - type: 'long', - }, - 'suricata.eve.stats.flow_mgr.flows_checked': { - category: 'suricata', - name: 'suricata.eve.stats.flow_mgr.flows_checked', - type: 'long', - }, - 'suricata.eve.stats.flow_mgr.rows_maxlen': { - category: 'suricata', - name: 'suricata.eve.stats.flow_mgr.rows_maxlen', - type: 'long', - }, - 'suricata.eve.stats.flow_mgr.rows_checked': { - category: 'suricata', - name: 'suricata.eve.stats.flow_mgr.rows_checked', - type: 'long', - }, - 'suricata.eve.stats.flow_mgr.rows_empty': { - category: 'suricata', - name: 'suricata.eve.stats.flow_mgr.rows_empty', - type: 'long', - }, - 'suricata.eve.stats.app_layer.flow.tls': { - category: 'suricata', - name: 'suricata.eve.stats.app_layer.flow.tls', - type: 'long', - }, - 'suricata.eve.stats.app_layer.flow.ftp': { - category: 'suricata', - name: 'suricata.eve.stats.app_layer.flow.ftp', - type: 'long', - }, - 'suricata.eve.stats.app_layer.flow.http': { - category: 'suricata', - name: 'suricata.eve.stats.app_layer.flow.http', - type: 'long', - }, - 'suricata.eve.stats.app_layer.flow.failed_udp': { - category: 'suricata', - name: 'suricata.eve.stats.app_layer.flow.failed_udp', - type: 'long', - }, - 'suricata.eve.stats.app_layer.flow.dns_udp': { - category: 'suricata', - name: 'suricata.eve.stats.app_layer.flow.dns_udp', - type: 'long', - }, - 'suricata.eve.stats.app_layer.flow.dns_tcp': { - category: 'suricata', - name: 'suricata.eve.stats.app_layer.flow.dns_tcp', - type: 'long', - }, - 'suricata.eve.stats.app_layer.flow.smtp': { - category: 'suricata', - name: 'suricata.eve.stats.app_layer.flow.smtp', - type: 'long', - }, - 'suricata.eve.stats.app_layer.flow.failed_tcp': { - category: 'suricata', - name: 'suricata.eve.stats.app_layer.flow.failed_tcp', - type: 'long', - }, - 'suricata.eve.stats.app_layer.flow.msn': { - category: 'suricata', - name: 'suricata.eve.stats.app_layer.flow.msn', - type: 'long', - }, - 'suricata.eve.stats.app_layer.flow.ssh': { - category: 'suricata', - name: 'suricata.eve.stats.app_layer.flow.ssh', - type: 'long', - }, - 'suricata.eve.stats.app_layer.flow.imap': { - category: 'suricata', - name: 'suricata.eve.stats.app_layer.flow.imap', - type: 'long', - }, - 'suricata.eve.stats.app_layer.flow.dcerpc_udp': { - category: 'suricata', - name: 'suricata.eve.stats.app_layer.flow.dcerpc_udp', - type: 'long', - }, - 'suricata.eve.stats.app_layer.flow.dcerpc_tcp': { - category: 'suricata', - name: 'suricata.eve.stats.app_layer.flow.dcerpc_tcp', - type: 'long', - }, - 'suricata.eve.stats.app_layer.flow.smb': { - category: 'suricata', - name: 'suricata.eve.stats.app_layer.flow.smb', - type: 'long', - }, - 'suricata.eve.stats.app_layer.tx.tls': { - category: 'suricata', - name: 'suricata.eve.stats.app_layer.tx.tls', - type: 'long', - }, - 'suricata.eve.stats.app_layer.tx.ftp': { - category: 'suricata', - name: 'suricata.eve.stats.app_layer.tx.ftp', - type: 'long', - }, - 'suricata.eve.stats.app_layer.tx.http': { - category: 'suricata', - name: 'suricata.eve.stats.app_layer.tx.http', - type: 'long', - }, - 'suricata.eve.stats.app_layer.tx.dns_udp': { - category: 'suricata', - name: 'suricata.eve.stats.app_layer.tx.dns_udp', - type: 'long', - }, - 'suricata.eve.stats.app_layer.tx.dns_tcp': { - category: 'suricata', - name: 'suricata.eve.stats.app_layer.tx.dns_tcp', - type: 'long', - }, - 'suricata.eve.stats.app_layer.tx.smtp': { - category: 'suricata', - name: 'suricata.eve.stats.app_layer.tx.smtp', - type: 'long', - }, - 'suricata.eve.stats.app_layer.tx.ssh': { - category: 'suricata', - name: 'suricata.eve.stats.app_layer.tx.ssh', - type: 'long', - }, - 'suricata.eve.stats.app_layer.tx.dcerpc_udp': { - category: 'suricata', - name: 'suricata.eve.stats.app_layer.tx.dcerpc_udp', - type: 'long', - }, - 'suricata.eve.stats.app_layer.tx.dcerpc_tcp': { - category: 'suricata', - name: 'suricata.eve.stats.app_layer.tx.dcerpc_tcp', - type: 'long', - }, - 'suricata.eve.stats.app_layer.tx.smb': { - category: 'suricata', - name: 'suricata.eve.stats.app_layer.tx.smb', - type: 'long', - }, - 'suricata.eve.tls.notbefore': { - category: 'suricata', - name: 'suricata.eve.tls.notbefore', - type: 'date', - }, - 'suricata.eve.tls.issuerdn': { - category: 'suricata', - name: 'suricata.eve.tls.issuerdn', - type: 'keyword', - }, - 'suricata.eve.tls.sni': { - category: 'suricata', - name: 'suricata.eve.tls.sni', - type: 'keyword', - }, - 'suricata.eve.tls.version': { - category: 'suricata', - name: 'suricata.eve.tls.version', - type: 'keyword', - }, - 'suricata.eve.tls.session_resumed': { - category: 'suricata', - name: 'suricata.eve.tls.session_resumed', - type: 'boolean', - }, - 'suricata.eve.tls.fingerprint': { - category: 'suricata', - name: 'suricata.eve.tls.fingerprint', - type: 'keyword', - }, - 'suricata.eve.tls.serial': { - category: 'suricata', - name: 'suricata.eve.tls.serial', - type: 'keyword', - }, - 'suricata.eve.tls.notafter': { - category: 'suricata', - name: 'suricata.eve.tls.notafter', - type: 'date', - }, - 'suricata.eve.tls.subject': { - category: 'suricata', - name: 'suricata.eve.tls.subject', - type: 'keyword', - }, - 'suricata.eve.tls.ja3s.string': { - category: 'suricata', - name: 'suricata.eve.tls.ja3s.string', - type: 'keyword', - }, - 'suricata.eve.tls.ja3s.hash': { - category: 'suricata', - name: 'suricata.eve.tls.ja3s.hash', - type: 'keyword', - }, - 'suricata.eve.tls.ja3.string': { - category: 'suricata', - name: 'suricata.eve.tls.ja3.string', - type: 'keyword', - }, - 'suricata.eve.tls.ja3.hash': { - category: 'suricata', - name: 'suricata.eve.tls.ja3.hash', - type: 'keyword', - }, - 'suricata.eve.app_proto_ts': { - category: 'suricata', - name: 'suricata.eve.app_proto_ts', - type: 'keyword', - }, - 'suricata.eve.flow.bytes_toclient': { - category: 'suricata', - name: 'suricata.eve.flow.bytes_toclient', - type: 'alias', - }, - 'suricata.eve.flow.start': { - category: 'suricata', - name: 'suricata.eve.flow.start', - type: 'alias', - }, - 'suricata.eve.flow.pkts_toclient': { - category: 'suricata', - name: 'suricata.eve.flow.pkts_toclient', - type: 'alias', - }, - 'suricata.eve.flow.age': { - category: 'suricata', - name: 'suricata.eve.flow.age', - type: 'long', - }, - 'suricata.eve.flow.state': { - category: 'suricata', - name: 'suricata.eve.flow.state', - type: 'keyword', - }, - 'suricata.eve.flow.bytes_toserver': { - category: 'suricata', - name: 'suricata.eve.flow.bytes_toserver', - type: 'alias', - }, - 'suricata.eve.flow.reason': { - category: 'suricata', - name: 'suricata.eve.flow.reason', - type: 'keyword', - }, - 'suricata.eve.flow.pkts_toserver': { - category: 'suricata', - name: 'suricata.eve.flow.pkts_toserver', - type: 'alias', - }, - 'suricata.eve.flow.alerted': { - category: 'suricata', - name: 'suricata.eve.flow.alerted', - type: 'boolean', - }, - 'suricata.eve.app_proto': { - category: 'suricata', - name: 'suricata.eve.app_proto', - type: 'alias', - }, - 'suricata.eve.tx_id': { - category: 'suricata', - name: 'suricata.eve.tx_id', - type: 'long', - }, - 'suricata.eve.app_proto_tc': { - category: 'suricata', - name: 'suricata.eve.app_proto_tc', - type: 'keyword', - }, - 'suricata.eve.smtp.rcpt_to': { - category: 'suricata', - name: 'suricata.eve.smtp.rcpt_to', - type: 'keyword', - }, - 'suricata.eve.smtp.mail_from': { - category: 'suricata', - name: 'suricata.eve.smtp.mail_from', - type: 'keyword', - }, - 'suricata.eve.smtp.helo': { - category: 'suricata', - name: 'suricata.eve.smtp.helo', - type: 'keyword', - }, - 'suricata.eve.app_proto_expected': { - category: 'suricata', - name: 'suricata.eve.app_proto_expected', - type: 'keyword', - }, - 'suricata.eve.flags': { - category: 'suricata', - name: 'suricata.eve.flags', - type: 'group', - }, - 'threatintel.indicator.first_seen': { - category: 'threatintel', - description: - 'The date and time when intelligence source first reported sighting this indicator. ', - name: 'threatintel.indicator.first_seen', - type: 'date', - }, - 'threatintel.indicator.last_seen': { - category: 'threatintel', - description: - 'The date and time when intelligence source last reported sighting this indicator. ', - name: 'threatintel.indicator.last_seen', - type: 'date', - }, - 'threatintel.indicator.sightings': { - category: 'threatintel', - description: 'Number of times this indicator was observed conducting threat activity. ', - name: 'threatintel.indicator.sightings', - type: 'long', - }, - 'threatintel.indicator.type': { - category: 'threatintel', - description: - 'Type of indicator as represented by Cyber Observable in STIX 2.0. Expected values * autonomous-system * artifact * directory * domain-name * email-addr * file * ipv4-addr * ipv6-addr * mac-addr * mutex * process * software * url * user-account * windows-registry-key * x-509-certificate ', - name: 'threatintel.indicator.type', - type: 'keyword', - }, - 'threatintel.indicator.description': { - category: 'threatintel', - description: 'Describes the type of action conducted by the threat. ', - name: 'threatintel.indicator.description', - type: 'keyword', - }, - 'threatintel.indicator.scanner_stats': { - category: 'threatintel', - description: 'Count of AV/EDR vendors that successfully detected malicious file or URL. ', - name: 'threatintel.indicator.scanner_stats', - type: 'long', - }, - 'threatintel.indicator.provider': { - category: 'threatintel', - description: 'Identifies the name of the intelligence provider. ', - name: 'threatintel.indicator.provider', - type: 'keyword', - }, - 'threatintel.indicator.confidence': { - category: 'threatintel', - description: - 'Identifies the confidence rating assigned by the provider using STIX confidence scales. Expected values * Not Specified, None, Low, Medium, High * 0-10 * Admirality Scale (1-6) * DNI Scale (5-95) * WEP Scale (Impossible - Certain) ', - name: 'threatintel.indicator.confidence', - type: 'keyword', - }, - 'threatintel.indicator.module': { - category: 'threatintel', - description: 'Identifies the name of specific module this data is coming from. ', - name: 'threatintel.indicator.module', - type: 'keyword', - }, - 'threatintel.indicator.dataset': { - category: 'threatintel', - description: 'Identifies the name of specific dataset from the intelligence source. ', - name: 'threatintel.indicator.dataset', - type: 'keyword', - }, - 'threatintel.indicator.ip': { - category: 'threatintel', - description: 'Identifies a threat indicator as an IP address (irrespective of direction). ', - name: 'threatintel.indicator.ip', - type: 'ip', - }, - 'threatintel.indicator.domain': { - category: 'threatintel', - description: 'Identifies a threat indicator as a domain (irrespective of direction). ', - name: 'threatintel.indicator.domain', - type: 'keyword', - }, - 'threatintel.indicator.port': { - category: 'threatintel', - description: 'Identifies a threat indicator as a port number (irrespective of direction). ', - name: 'threatintel.indicator.port', - type: 'long', - }, - 'threatintel.indicator.email.address': { - category: 'threatintel', - description: 'Identifies a threat indicator as an email address (irrespective of direction). ', - name: 'threatintel.indicator.email.address', - type: 'keyword', - }, - 'threatintel.indicator.marking.tlp': { - category: 'threatintel', - description: - 'Traffic Light Protocol sharing markings. Expected values are: * White * Green * Amber * Red ', - name: 'threatintel.indicator.marking.tlp', - type: 'keyword', - }, - 'threatintel.indicator.matched.atomic': { - category: 'threatintel', - description: - 'Identifies the atomic indicator that matched a local environment endpoint or network event. ', - name: 'threatintel.indicator.matched.atomic', - type: 'keyword', - }, - 'threatintel.indicator.matched.field': { - category: 'threatintel', - description: - 'Identifies the field of the atomic indicator that matched a local environment endpoint or network event. ', - name: 'threatintel.indicator.matched.field', - type: 'keyword', - }, - 'threatintel.indicator.matched.type': { - category: 'threatintel', - description: - 'Identifies the type of the atomic indicator that matched a local environment endpoint or network event. ', - name: 'threatintel.indicator.matched.type', - type: 'keyword', - }, - 'threatintel.indicator.as.number': { - category: 'threatintel', - description: - 'Unique number allocated to the autonomous system. The autonomous system number (ASN) uniquely identifies each network on the Internet.', - example: 15169, - name: 'threatintel.indicator.as.number', - type: 'long', - }, - 'threatintel.indicator.as.organization.name': { - category: 'threatintel', - description: 'Organization name.', - example: 'Google LLC', - name: 'threatintel.indicator.as.organization.name', - type: 'keyword', - }, - 'threatintel.indicator.registry.data.strings': { - category: 'threatintel', - description: - 'Content when writing string types. Populated as an array when writing string data to the registry. For single string registry types (REG_SZ, REG_EXPAND_SZ), this should be an array with one string. For sequences of string with REG_MULTI_SZ, this array will be variable length. For numeric data, such as REG_DWORD and REG_QWORD, this should be populated with the decimal representation (e.g `"1"`). ', - example: '["C:\\rta\\red_ttp\\bin\\myapp.exe"]', - name: 'threatintel.indicator.registry.data.strings', - type: 'keyword', - }, - 'threatintel.indicator.registry.path': { - category: 'threatintel', - description: 'Full path, including hive, key and value', - example: - 'HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\winword.exe\\Debugger', - name: 'threatintel.indicator.registry.path', - type: 'keyword', - }, - 'threatintel.indicator.registry.value': { - category: 'threatintel', - description: 'Name of the value written.', - example: 'Debugger', - name: 'threatintel.indicator.registry.value', - type: 'keyword', - }, - 'threatintel.indicator.registry.key': { - category: 'threatintel', - description: 'Registry key value', - name: 'threatintel.indicator.registry.key', - type: 'keyword', - }, - 'threatintel.indicator.geo.city_name': { - category: 'threatintel', - description: 'City name.', - example: 'Montreal', - name: 'threatintel.indicator.geo.city_name', - type: 'keyword', - }, - 'threatintel.indicator.geo.continent_name': { - category: 'threatintel', - description: 'Name of the continent.', - example: 'North America', - name: 'threatintel.indicator.geo.continent_name', - type: 'keyword', - }, - 'threatintel.indicator.geo.country_iso_code': { - category: 'threatintel', - description: 'Country ISO code.', - example: 'CA', - name: 'threatintel.indicator.geo.country_iso_code', - type: 'keyword', - }, - 'threatintel.indicator.geo.country_name': { - category: 'threatintel', - description: 'Country name.', - example: 'Canada', - name: 'threatintel.indicator.geo.country_name', - type: 'keyword', - }, - 'threatintel.indicator.geo.location': { - category: 'threatintel', - description: 'Longitude and latitude.', - example: '{ "lon": -73.614830, "lat": 45.505918 }', - name: 'threatintel.indicator.geo.location', - type: 'geo_point', - }, - 'threatintel.indicator.geo.region_iso_code': { - category: 'threatintel', - description: 'Region ISO code.', - example: 'CA-QC', - name: 'threatintel.indicator.geo.region_iso_code', - type: 'keyword', - }, - 'threatintel.indicator.geo.region_name': { - category: 'threatintel', - description: 'Region name.', - example: 'Quebec', - name: 'threatintel.indicator.geo.region_name', - type: 'keyword', - }, - 'threatintel.indicator.file.pe.imphash': { - category: 'threatintel', - description: - 'A hash of the imports in a PE file. An imphash -- or import hash -- can be used to fingerprint binaries even after recompilation or other code-level transformations have occurred, which would change more traditional hash values. Learn more at https://www.fireeye.com/blog/threat-research/2014/01/tracking-malware-import-hashing.html.', - example: '0c6803c4e922103c4dca5963aad36ddf', - name: 'threatintel.indicator.file.pe.imphash', - type: 'keyword', - }, - 'threatintel.indicator.file.hash.tlsh': { - category: 'threatintel', - description: "The file's import tlsh, if available. ", - name: 'threatintel.indicator.file.hash.tlsh', - type: 'keyword', - }, - 'threatintel.indicator.file.hash.ssdeep': { - category: 'threatintel', - description: "The file's ssdeep hash, if available. ", - name: 'threatintel.indicator.file.hash.ssdeep', - type: 'keyword', - }, - 'threatintel.indicator.file.hash.md5': { - category: 'threatintel', - description: "The file's md5 hash, if available. ", - name: 'threatintel.indicator.file.hash.md5', - type: 'keyword', - }, - 'threatintel.indicator.file.hash.sha1': { - category: 'threatintel', - description: "The file's sha1 hash, if available. ", - name: 'threatintel.indicator.file.hash.sha1', - type: 'keyword', - }, - 'threatintel.indicator.file.hash.sha256': { - category: 'threatintel', - description: "The file's sha256 hash, if available. ", - name: 'threatintel.indicator.file.hash.sha256', - type: 'keyword', - }, - 'threatintel.indicator.file.hash.sha384': { - category: 'threatintel', - description: "The file's sha384 hash, if available. ", - name: 'threatintel.indicator.file.hash.sha384', - type: 'keyword', - }, - 'threatintel.indicator.file.hash.sha512': { - category: 'threatintel', - description: "The file's sha512 hash, if available. ", - name: 'threatintel.indicator.file.hash.sha512', - type: 'keyword', - }, - 'threatintel.indicator.file.type': { - category: 'threatintel', - description: 'The file type. ', - name: 'threatintel.indicator.file.type', - type: 'keyword', - }, - 'threatintel.indicator.file.size': { - category: 'threatintel', - description: "The file's total size. ", - name: 'threatintel.indicator.file.size', - type: 'long', - }, - 'threatintel.indicator.file.name': { - category: 'threatintel', - description: "The file's name. ", - name: 'threatintel.indicator.file.name', - type: 'keyword', - }, - 'threatintel.indicator.file.extension': { - category: 'threatintel', - description: "The file's extension. ", - name: 'threatintel.indicator.file.extension', - type: 'keyword', - }, - 'threatintel.indicator.file.mime_type': { - category: 'threatintel', - description: "The file's MIME type. ", - name: 'threatintel.indicator.file.mime_type', - type: 'keyword', - }, - 'threatintel.indicator.url.domain': { - category: 'threatintel', - description: 'Domain of the url, such as "www.elastic.co". ', - name: 'threatintel.indicator.url.domain', - type: 'keyword', - }, - 'threatintel.indicator.url.extension': { - category: 'threatintel', - description: 'The field contains the file extension from the original request ', - name: 'threatintel.indicator.url.extension', - type: 'keyword', - }, - 'threatintel.indicator.url.fragment': { - category: 'threatintel', - description: 'Portion of the url after the `#`, such as "top". ', - name: 'threatintel.indicator.url.fragment', - type: 'keyword', - }, - 'threatintel.indicator.url.full': { - category: 'threatintel', - description: - 'If full URLs are important to your use case, they should be stored in `url.full`, whether this field is reconstructed or present in the event source. ', - name: 'threatintel.indicator.url.full', - type: 'keyword', - }, - 'threatintel.indicator.url.original': { - category: 'threatintel', - description: - 'Unmodified original url as seen in the event source. Note that in network monitoring, the observed URL may be a full URL, whereas in access logs, the URL is often just represented as a path. This field is meant to represent the URL as it was observed, complete or not. ', - name: 'threatintel.indicator.url.original', - type: 'keyword', - }, - 'threatintel.indicator.url.password': { - category: 'threatintel', - description: 'Password of the request. ', - name: 'threatintel.indicator.url.password', - type: 'keyword', - }, - 'threatintel.indicator.url.path': { - category: 'threatintel', - description: 'Path of the request, such as "/search". ', - name: 'threatintel.indicator.url.path', - type: 'keyword', - }, - 'threatintel.indicator.url.port': { - category: 'threatintel', - description: 'Port of the request, such as 443. ', - name: 'threatintel.indicator.url.port', - type: 'long', - format: 'string', - }, - 'threatintel.indicator.url.query': { - category: 'threatintel', - description: - 'The query field describes the query string of the request, such as "q=elasticsearch". The `?` is excluded from the query string. If a URL contains no `?`, there is no query field. If there is a `?` but no query, the query field exists with an empty string. The `exists` query can be used to differentiate between the two cases. ', - name: 'threatintel.indicator.url.query', - type: 'keyword', - }, - 'threatintel.indicator.url.registered_domain': { - category: 'threatintel', - description: - 'The highest registered url domain, stripped of the subdomain. For example, the registered domain for "foo.example.com" is "example.com". This value can be determined precisely with a list like the public suffix list (http://publicsuffix.org). Trying to approximate this by simply taking the last two labels will not work well for TLDs such as "co.uk". ', - name: 'threatintel.indicator.url.registered_domain', - type: 'keyword', - }, - 'threatintel.indicator.url.scheme': { - category: 'threatintel', - description: 'Scheme of the request, such as "https". ', - name: 'threatintel.indicator.url.scheme', - type: 'keyword', - }, - 'threatintel.indicator.url.subdomain': { - category: 'threatintel', - description: - 'The subdomain portion of a fully qualified domain name includes all of the names except the host name under the registered_domain. In a partially qualified domain, or if the the qualification level of the full name cannot be determined, subdomain contains all of the names below the registered domain. For example the subdomain portion of "www.east.mydomain.co.uk" is "east". If the domain has multiple levels of subdomain, such as "sub2.sub1.example.com", the subdomain field should contain "sub2.sub1", with no trailing period. ', - name: 'threatintel.indicator.url.subdomain', - type: 'keyword', - }, - 'threatintel.indicator.url.top_level_domain': { - category: 'threatintel', - description: - 'The effective top level domain (eTLD), also known as the domain suffix, is the last part of the domain name. For example, the top level domain for example.com is "com". This value can be determined precisely with a list like the public suffix list (http://publicsuffix.org). Trying to approximate this by simply taking the last label will not work well for effective TLDs such as "co.uk". ', - name: 'threatintel.indicator.url.top_level_domain', - type: 'keyword', - }, - 'threatintel.indicator.url.username': { - category: 'threatintel', - description: 'Username of the request. ', - name: 'threatintel.indicator.url.username', - type: 'keyword', - }, - 'threatintel.indicator.x509.serial_number': { - category: 'threatintel', - description: - 'Unique serial number issued by the certificate authority. For consistency, if this value is alphanumeric, it should be formatted without colons and uppercase characters.', - example: '55FBB9C7DEBF09809D12CCAA', - name: 'threatintel.indicator.x509.serial_number', - type: 'keyword', - }, - 'threatintel.indicator.x509.issuer': { - category: 'threatintel', - description: - 'Name of issuing certificate authority. Could be either Distinguished Name (DN) or Common Name (CN), depending on source.', - example: 'C=US, O=Example Inc, OU=www.example.com, CN=Example SHA2 High Assurance Server CA', - name: 'threatintel.indicator.x509.issuer', - type: 'keyword', - }, - 'threatintel.indicator.x509.subject': { - category: 'threatintel', - description: - 'Name of the certificate subject entity. Could be either Distinguished Name (DN) or Common Name (CN), depending on source.', - example: 'C=US, ST=California, L=San Francisco, O=Example, Inc., CN=shared.global.example.net', - name: 'threatintel.indicator.x509.subject', - type: 'keyword', - }, - 'threatintel.indicator.x509.alternative_names': { - category: 'threatintel', - description: - 'List of subject alternative names (SAN). Name types vary by certificate authority and certificate type but commonly contain IP addresses, DNS names (and wildcards), and email addresses.', - example: '*.elastic.co', - name: 'threatintel.indicator.x509.alternative_names', - type: 'keyword', - }, - 'threatintel.indicator.signature': { - category: 'threatintel', - description: 'Malware family of sample (if available). ', - name: 'threatintel.indicator.signature', - type: 'keyword', - }, - 'threatintel.abusemalware.file_type': { - category: 'threatintel', - description: 'File type guessed by URLhaus. ', - name: 'threatintel.abusemalware.file_type', - type: 'keyword', - }, - 'threatintel.abusemalware.signature': { - category: 'threatintel', - description: 'Malware familiy. ', - name: 'threatintel.abusemalware.signature', - type: 'keyword', - }, - 'threatintel.abusemalware.urlhaus_download': { - category: 'threatintel', - description: 'Location (URL) where you can download a copy of this file. ', - name: 'threatintel.abusemalware.urlhaus_download', - type: 'keyword', - }, - 'threatintel.abusemalware.virustotal.result': { - category: 'threatintel', - description: 'AV detection ration. ', - name: 'threatintel.abusemalware.virustotal.result', - type: 'keyword', - }, - 'threatintel.abusemalware.virustotal.percent': { - category: 'threatintel', - description: 'AV detection in percent. ', - name: 'threatintel.abusemalware.virustotal.percent', - type: 'float', - }, - 'threatintel.abusemalware.virustotal.link': { - category: 'threatintel', - description: 'Link to the Virustotal report. ', - name: 'threatintel.abusemalware.virustotal.link', - type: 'keyword', - }, - 'threatintel.abuseurl.id': { - category: 'threatintel', - description: 'The ID of the url. ', - name: 'threatintel.abuseurl.id', - type: 'keyword', - }, - 'threatintel.abuseurl.urlhaus_reference': { - category: 'threatintel', - description: 'Link to URLhaus entry. ', - name: 'threatintel.abuseurl.urlhaus_reference', - type: 'keyword', - }, - 'threatintel.abuseurl.url_status': { - category: 'threatintel', - description: - 'The current status of the URL. Possible values are: online, offline and unknown. ', - name: 'threatintel.abuseurl.url_status', - type: 'keyword', - }, - 'threatintel.abuseurl.threat': { - category: 'threatintel', - description: 'The threat corresponding to this malware URL. ', - name: 'threatintel.abuseurl.threat', - type: 'keyword', - }, - 'threatintel.abuseurl.blacklists.surbl': { - category: 'threatintel', - description: 'SURBL blacklist status. Possible values are: listed and not_listed ', - name: 'threatintel.abuseurl.blacklists.surbl', - type: 'keyword', - }, - 'threatintel.abuseurl.blacklists.spamhaus_dbl': { - category: 'threatintel', - description: 'Spamhaus DBL blacklist status. ', - name: 'threatintel.abuseurl.blacklists.spamhaus_dbl', - type: 'keyword', - }, - 'threatintel.abuseurl.reporter': { - category: 'threatintel', - description: - 'The Twitter handle of the reporter that has reported this malware URL (or anonymous). ', - name: 'threatintel.abuseurl.reporter', - type: 'keyword', - }, - 'threatintel.abuseurl.larted': { - category: 'threatintel', - description: - 'Indicates whether the malware URL has been reported to the hosting provider (true or false) ', - name: 'threatintel.abuseurl.larted', - type: 'boolean', - }, - 'threatintel.abuseurl.tags': { - category: 'threatintel', - description: 'A list of tags associated with the queried malware URL ', - name: 'threatintel.abuseurl.tags', - type: 'keyword', - }, - 'threatintel.anomali.id': { - category: 'threatintel', - description: 'The ID of the indicator. ', - name: 'threatintel.anomali.id', - type: 'keyword', - }, - 'threatintel.anomali.name': { - category: 'threatintel', - description: 'The name of the indicator. ', - name: 'threatintel.anomali.name', - type: 'keyword', - }, - 'threatintel.anomali.pattern': { - category: 'threatintel', - description: 'The pattern ID of the indicator. ', - name: 'threatintel.anomali.pattern', - type: 'keyword', - }, - 'threatintel.anomali.valid_from': { - category: 'threatintel', - description: 'When the indicator was first found or is considered valid. ', - name: 'threatintel.anomali.valid_from', - type: 'date', - }, - 'threatintel.anomali.modified': { - category: 'threatintel', - description: 'When the indicator was last modified ', - name: 'threatintel.anomali.modified', - type: 'date', - }, - 'threatintel.anomali.labels': { - category: 'threatintel', - description: 'The labels related to the indicator ', - name: 'threatintel.anomali.labels', - type: 'keyword', - }, - 'threatintel.anomali.indicator': { - category: 'threatintel', - description: - 'The value of the indicator, for example if the type is domain, this would be the value. ', - name: 'threatintel.anomali.indicator', - type: 'keyword', - }, - 'threatintel.anomali.description': { - category: 'threatintel', - description: 'A description of the indicator. ', - name: 'threatintel.anomali.description', - type: 'keyword', - }, - 'threatintel.anomali.title': { - category: 'threatintel', - description: 'Title describing the indicator. ', - name: 'threatintel.anomali.title', - type: 'keyword', - }, - 'threatintel.anomali.content': { - category: 'threatintel', - description: 'Extra text or descriptive content related to the indicator. ', - name: 'threatintel.anomali.content', - type: 'keyword', - }, - 'threatintel.anomali.type': { - category: 'threatintel', - description: 'The indicator type, can for example be "domain, email, FileHash-SHA256". ', - name: 'threatintel.anomali.type', - type: 'keyword', - }, - 'threatintel.anomali.object_marking_refs': { - category: 'threatintel', - description: 'The STIX reference object. ', - name: 'threatintel.anomali.object_marking_refs', - type: 'keyword', - }, - 'threatintel.anomalithreatstream.classification': { - category: 'threatintel', - description: - 'Indicates whether an indicator is private or from a public feed and available publicly. Possible values: private, public. ', - example: 'private', - name: 'threatintel.anomalithreatstream.classification', - type: 'keyword', - }, - 'threatintel.anomalithreatstream.confidence': { - category: 'threatintel', - description: - "The measure of the accuracy (from 0 to 100) assigned by ThreatStream's predictive analytics technology to indicators. ", - name: 'threatintel.anomalithreatstream.confidence', - type: 'short', - }, - 'threatintel.anomalithreatstream.detail2': { - category: 'threatintel', - description: 'Detail text for indicator. ', - example: 'Imported by user 42.', - name: 'threatintel.anomalithreatstream.detail2', - type: 'text', - }, - 'threatintel.anomalithreatstream.id': { - category: 'threatintel', - description: 'The ID of the indicator. ', - name: 'threatintel.anomalithreatstream.id', - type: 'keyword', - }, - 'threatintel.anomalithreatstream.import_session_id': { - category: 'threatintel', - description: 'ID of the import session that created the indicator on ThreatStream. ', - name: 'threatintel.anomalithreatstream.import_session_id', - type: 'keyword', - }, - 'threatintel.anomalithreatstream.itype': { - category: 'threatintel', - description: - 'Indicator type. Possible values: "apt_domain", "apt_email", "apt_ip", "apt_url", "bot_ip", "c2_domain", "c2_ip", "c2_url", "i2p_ip", "mal_domain", "mal_email", "mal_ip", "mal_md5", "mal_url", "parked_ip", "phish_email", "phish_ip", "phish_url", "scan_ip", "spam_domain", "ssh_ip", "suspicious_domain", "tor_ip" and "torrent_tracker_url". ', - name: 'threatintel.anomalithreatstream.itype', - type: 'keyword', - }, - 'threatintel.anomalithreatstream.maltype': { - category: 'threatintel', - description: - 'Information regarding a malware family, a CVE ID, or another attack or threat, associated with the indicator. ', - name: 'threatintel.anomalithreatstream.maltype', - type: 'wildcard', - }, - 'threatintel.anomalithreatstream.md5': { - category: 'threatintel', - description: 'Hash for the indicator. ', - name: 'threatintel.anomalithreatstream.md5', - type: 'keyword', - }, - 'threatintel.anomalithreatstream.resource_uri': { - category: 'threatintel', - description: 'Relative URI for the indicator details. ', - name: 'threatintel.anomalithreatstream.resource_uri', - type: 'keyword', - }, - 'threatintel.anomalithreatstream.severity': { - category: 'threatintel', - description: - 'Criticality associated with the threat feed that supplied the indicator. Possible values: low, medium, high, very-high. ', - name: 'threatintel.anomalithreatstream.severity', - type: 'keyword', - }, - 'threatintel.anomalithreatstream.source': { - category: 'threatintel', - description: 'Source for the indicator. ', - example: 'Analyst', - name: 'threatintel.anomalithreatstream.source', - type: 'keyword', - }, - 'threatintel.anomalithreatstream.source_feed_id': { - category: 'threatintel', - description: 'ID for the integrator source. ', - name: 'threatintel.anomalithreatstream.source_feed_id', - type: 'keyword', - }, - 'threatintel.anomalithreatstream.state': { - category: 'threatintel', - description: 'State for this indicator. ', - example: 'active', - name: 'threatintel.anomalithreatstream.state', - type: 'keyword', - }, - 'threatintel.anomalithreatstream.trusted_circle_ids': { - category: 'threatintel', - description: 'ID of the trusted circle that imported the indicator. ', - name: 'threatintel.anomalithreatstream.trusted_circle_ids', - type: 'keyword', - }, - 'threatintel.anomalithreatstream.update_id': { - category: 'threatintel', - description: 'Update ID. ', - name: 'threatintel.anomalithreatstream.update_id', - type: 'keyword', - }, - 'threatintel.anomalithreatstream.url': { - category: 'threatintel', - description: 'URL for the indicator. ', - name: 'threatintel.anomalithreatstream.url', - type: 'keyword', - }, - 'threatintel.anomalithreatstream.value_type': { - category: 'threatintel', - description: 'Data type of the indicator. Possible values: ip, domain, url, email, md5. ', - name: 'threatintel.anomalithreatstream.value_type', - type: 'keyword', - }, - 'threatintel.malwarebazaar.file_type': { - category: 'threatintel', - description: 'File type guessed by Malware Bazaar. ', - name: 'threatintel.malwarebazaar.file_type', - type: 'keyword', - }, - 'threatintel.malwarebazaar.signature': { - category: 'threatintel', - description: 'Malware familiy. ', - name: 'threatintel.malwarebazaar.signature', - type: 'keyword', - }, - 'threatintel.malwarebazaar.tags': { - category: 'threatintel', - description: 'A list of tags associated with the queried malware sample. ', - name: 'threatintel.malwarebazaar.tags', - type: 'keyword', - }, - 'threatintel.malwarebazaar.intelligence.downloads': { - category: 'threatintel', - description: 'Number of downloads from MalwareBazaar. ', - name: 'threatintel.malwarebazaar.intelligence.downloads', - type: 'long', - }, - 'threatintel.malwarebazaar.intelligence.uploads': { - category: 'threatintel', - description: 'Number of uploads from MalwareBazaar. ', - name: 'threatintel.malwarebazaar.intelligence.uploads', - type: 'long', - }, - 'threatintel.malwarebazaar.intelligence.mail.Generic': { - category: 'threatintel', - description: 'Malware seen in generic spam traffic. ', - name: 'threatintel.malwarebazaar.intelligence.mail.Generic', - type: 'keyword', - }, - 'threatintel.malwarebazaar.intelligence.mail.IT': { - category: 'threatintel', - description: 'Malware seen in IT spam traffic. ', - name: 'threatintel.malwarebazaar.intelligence.mail.IT', - type: 'keyword', - }, - 'threatintel.malwarebazaar.anonymous': { - category: 'threatintel', - description: 'Identifies if the sample was submitted anonymously. ', - name: 'threatintel.malwarebazaar.anonymous', - type: 'long', - }, - 'threatintel.malwarebazaar.code_sign': { - category: 'threatintel', - description: 'Code signing information for the sample. ', - name: 'threatintel.malwarebazaar.code_sign', - type: 'keyword', - }, - 'threatintel.misp.id': { - category: 'threatintel', - description: 'Attribute ID. ', - name: 'threatintel.misp.id', - type: 'keyword', - }, - 'threatintel.misp.orgc_id': { - category: 'threatintel', - description: 'Organization Community ID of the event. ', - name: 'threatintel.misp.orgc_id', - type: 'keyword', - }, - 'threatintel.misp.org_id': { - category: 'threatintel', - description: 'Organization ID of the event. ', - name: 'threatintel.misp.org_id', - type: 'keyword', - }, - 'threatintel.misp.threat_level_id': { - category: 'threatintel', - description: 'Threat level from 5 to 1, where 1 is the most critical. ', - name: 'threatintel.misp.threat_level_id', - type: 'long', - }, - 'threatintel.misp.info': { - category: 'threatintel', - description: 'Additional text or information related to the event. ', - name: 'threatintel.misp.info', - type: 'keyword', - }, - 'threatintel.misp.published': { - category: 'threatintel', - description: 'When the event was published. ', - name: 'threatintel.misp.published', - type: 'boolean', - }, - 'threatintel.misp.uuid': { - category: 'threatintel', - description: 'The UUID of the event object. ', - name: 'threatintel.misp.uuid', - type: 'keyword', - }, - 'threatintel.misp.date': { - category: 'threatintel', - description: 'The date of when the event object was created. ', - name: 'threatintel.misp.date', - type: 'date', - }, - 'threatintel.misp.attribute_count': { - category: 'threatintel', - description: 'How many attributes are included in a single event object. ', - name: 'threatintel.misp.attribute_count', - type: 'long', - }, - 'threatintel.misp.timestamp': { - category: 'threatintel', - description: 'The timestamp of when the event object was created. ', - name: 'threatintel.misp.timestamp', - type: 'date', - }, - 'threatintel.misp.distribution': { - category: 'threatintel', - description: 'Distribution type related to MISP. ', - name: 'threatintel.misp.distribution', - type: 'keyword', - }, - 'threatintel.misp.proposal_email_lock': { - category: 'threatintel', - description: 'Settings configured on MISP for email lock on this event object. ', - name: 'threatintel.misp.proposal_email_lock', - type: 'boolean', - }, - 'threatintel.misp.locked': { - category: 'threatintel', - description: 'If the current MISP event object is locked or not. ', - name: 'threatintel.misp.locked', - type: 'boolean', - }, - 'threatintel.misp.publish_timestamp': { - category: 'threatintel', - description: 'At what time the event object was published ', - name: 'threatintel.misp.publish_timestamp', - type: 'date', - }, - 'threatintel.misp.sharing_group_id': { - category: 'threatintel', - description: 'The ID of the grouped events or sources of the event. ', - name: 'threatintel.misp.sharing_group_id', - type: 'keyword', - }, - 'threatintel.misp.disable_correlation': { - category: 'threatintel', - description: 'If correlation is disabled on the MISP event object. ', - name: 'threatintel.misp.disable_correlation', - type: 'boolean', - }, - 'threatintel.misp.extends_uuid': { - category: 'threatintel', - description: 'The UUID of the event object it might extend. ', - name: 'threatintel.misp.extends_uuid', - type: 'keyword', - }, - 'threatintel.misp.org.id': { - category: 'threatintel', - description: 'The organization ID related to the event object. ', - name: 'threatintel.misp.org.id', - type: 'keyword', - }, - 'threatintel.misp.org.name': { - category: 'threatintel', - description: 'The organization name related to the event object. ', - name: 'threatintel.misp.org.name', - type: 'keyword', - }, - 'threatintel.misp.org.uuid': { - category: 'threatintel', - description: 'The UUID of the organization related to the event object. ', - name: 'threatintel.misp.org.uuid', - type: 'keyword', - }, - 'threatintel.misp.org.local': { - category: 'threatintel', - description: 'If the event object is local or from a remote source. ', - name: 'threatintel.misp.org.local', - type: 'boolean', - }, - 'threatintel.misp.orgc.id': { - category: 'threatintel', - description: 'The Organization Community ID in which the event object was reported from. ', - name: 'threatintel.misp.orgc.id', - type: 'keyword', - }, - 'threatintel.misp.orgc.name': { - category: 'threatintel', - description: 'The Organization Community name in which the event object was reported from. ', - name: 'threatintel.misp.orgc.name', - type: 'keyword', - }, - 'threatintel.misp.orgc.uuid': { - category: 'threatintel', - description: 'The Organization Community UUID in which the event object was reported from. ', - name: 'threatintel.misp.orgc.uuid', - type: 'keyword', - }, - 'threatintel.misp.orgc.local': { - category: 'threatintel', - description: 'If the Organization Community was local or synced from a remote source. ', - name: 'threatintel.misp.orgc.local', - type: 'boolean', - }, - 'threatintel.misp.attribute.id': { - category: 'threatintel', - description: 'The ID of the attribute related to the event object. ', - name: 'threatintel.misp.attribute.id', - type: 'keyword', - }, - 'threatintel.misp.attribute.type': { - category: 'threatintel', - description: - 'The type of the attribute related to the event object. For example email, ipv4, sha1 and such. ', - name: 'threatintel.misp.attribute.type', - type: 'keyword', - }, - 'threatintel.misp.attribute.category': { - category: 'threatintel', - description: - 'The category of the attribute related to the event object. For example "Network Activity". ', - name: 'threatintel.misp.attribute.category', - type: 'keyword', - }, - 'threatintel.misp.attribute.to_ids': { - category: 'threatintel', - description: 'If the attribute should be automatically synced with an IDS. ', - name: 'threatintel.misp.attribute.to_ids', - type: 'boolean', - }, - 'threatintel.misp.attribute.uuid': { - category: 'threatintel', - description: 'The UUID of the attribute related to the event. ', - name: 'threatintel.misp.attribute.uuid', - type: 'keyword', - }, - 'threatintel.misp.attribute.event_id': { - category: 'threatintel', - description: 'The local event ID of the attribute related to the event. ', - name: 'threatintel.misp.attribute.event_id', - type: 'keyword', - }, - 'threatintel.misp.attribute.distribution': { - category: 'threatintel', - description: 'How the attribute has been distributed, represented by integer numbers. ', - name: 'threatintel.misp.attribute.distribution', - type: 'long', - }, - 'threatintel.misp.attribute.timestamp': { - category: 'threatintel', - description: 'The timestamp in which the attribute was attached to the event object. ', - name: 'threatintel.misp.attribute.timestamp', - type: 'date', - }, - 'threatintel.misp.attribute.comment': { - category: 'threatintel', - description: 'Comments made to the attribute itself. ', - name: 'threatintel.misp.attribute.comment', - type: 'keyword', - }, - 'threatintel.misp.attribute.sharing_group_id': { - category: 'threatintel', - description: 'The group ID of the sharing group related to the specific attribute. ', - name: 'threatintel.misp.attribute.sharing_group_id', - type: 'keyword', - }, - 'threatintel.misp.attribute.deleted': { - category: 'threatintel', - description: 'If the attribute has been removed from the event object. ', - name: 'threatintel.misp.attribute.deleted', - type: 'boolean', - }, - 'threatintel.misp.attribute.disable_correlation': { - category: 'threatintel', - description: 'If correlation has been enabled on the attribute related to the event object. ', - name: 'threatintel.misp.attribute.disable_correlation', - type: 'boolean', - }, - 'threatintel.misp.attribute.object_id': { - category: 'threatintel', - description: 'The ID of the Object in which the attribute is attached. ', - name: 'threatintel.misp.attribute.object_id', - type: 'keyword', - }, - 'threatintel.misp.attribute.object_relation': { - category: 'threatintel', - description: 'The type of relation the attribute has with the event object itself. ', - name: 'threatintel.misp.attribute.object_relation', - type: 'keyword', - }, - 'threatintel.misp.attribute.value': { - category: 'threatintel', - description: 'The value of the attribute, depending on the type like "url, sha1, email-src". ', - name: 'threatintel.misp.attribute.value', - type: 'keyword', - }, - 'threatintel.otx.id': { - category: 'threatintel', - description: 'The ID of the indicator. ', - name: 'threatintel.otx.id', - type: 'keyword', - }, - 'threatintel.otx.indicator': { - category: 'threatintel', - description: - 'The value of the indicator, for example if the type is domain, this would be the value. ', - name: 'threatintel.otx.indicator', - type: 'keyword', - }, - 'threatintel.otx.description': { - category: 'threatintel', - description: 'A description of the indicator. ', - name: 'threatintel.otx.description', - type: 'keyword', - }, - 'threatintel.otx.title': { - category: 'threatintel', - description: 'Title describing the indicator. ', - name: 'threatintel.otx.title', - type: 'keyword', - }, - 'threatintel.otx.content': { - category: 'threatintel', - description: 'Extra text or descriptive content related to the indicator. ', - name: 'threatintel.otx.content', - type: 'keyword', - }, - 'threatintel.otx.type': { - category: 'threatintel', - description: 'The indicator type, can for example be "domain, email, FileHash-SHA256". ', - name: 'threatintel.otx.type', - type: 'keyword', - }, - 'threatintel.recordedfuture.entity.id': { - category: 'threatintel', - description: 'Entity ID. ', - example: 'ip:192.0.2.13', - name: 'threatintel.recordedfuture.entity.id', - type: 'keyword', - }, - 'threatintel.recordedfuture.entity.name': { - category: 'threatintel', - description: 'Entity name. Value for the entity. ', - example: '192.0.2.13', - name: 'threatintel.recordedfuture.entity.name', - type: 'keyword', - }, - 'threatintel.recordedfuture.entity.type': { - category: 'threatintel', - description: 'Entity type. ', - example: 'IpAddress', - name: 'threatintel.recordedfuture.entity.type', - type: 'keyword', - }, - 'threatintel.recordedfuture.intelCard': { - category: 'threatintel', - description: 'Link to the Recorded Future Intelligence Card for to this indicator. ', - name: 'threatintel.recordedfuture.intelCard', - type: 'keyword', - }, - 'threatintel.recordedfuture.ip_range': { - category: 'threatintel', - description: 'Range of IPs for this indicator. ', - example: '192.0.2.0/16', - name: 'threatintel.recordedfuture.ip_range', - type: 'ip_range', - }, - 'threatintel.recordedfuture.risk.criticality': { - category: 'threatintel', - description: 'Risk criticality (0-4). ', - name: 'threatintel.recordedfuture.risk.criticality', - type: 'byte', - }, - 'threatintel.recordedfuture.risk.criticalityLabel': { - category: 'threatintel', - description: - 'Risk criticality label. One of None, Unusual, Suspicious, Malicious, Very Malicious. ', - name: 'threatintel.recordedfuture.risk.criticalityLabel', - type: 'keyword', - }, - 'threatintel.recordedfuture.risk.evidenceDetails': { - category: 'threatintel', - description: "Risk's evidence details. ", - name: 'threatintel.recordedfuture.risk.evidenceDetails', - type: 'flattened', - }, - 'threatintel.recordedfuture.risk.score': { - category: 'threatintel', - description: 'Risk score (0-99). ', - name: 'threatintel.recordedfuture.risk.score', - type: 'short', - }, - 'threatintel.recordedfuture.risk.riskString': { - category: 'threatintel', - description: 'Number of Risk Rules observed as a factor of total number of rules. ', - example: '1/54', - name: 'threatintel.recordedfuture.risk.riskString', - type: 'keyword', - }, - 'threatintel.recordedfuture.risk.riskSummary': { - category: 'threatintel', - description: 'Risk summary. ', - example: '1 of 54 Risk Rules currently observed.', - name: 'threatintel.recordedfuture.risk.riskSummary', - type: 'keyword', - }, - 'threatintel.recordedfuture.risk.rules': { - category: 'threatintel', - description: 'Number of rules observed. ', - name: 'threatintel.recordedfuture.risk.rules', - type: 'long', - }, - 'zeek.session_id': { - category: 'zeek', - description: 'A unique identifier of the session ', - name: 'zeek.session_id', - type: 'keyword', - }, - 'zeek.capture_loss.ts_delta': { - category: 'zeek', - description: 'The time delay between this measurement and the last. ', - name: 'zeek.capture_loss.ts_delta', - type: 'integer', - }, - 'zeek.capture_loss.peer': { - category: 'zeek', - description: - 'In the event that there are multiple Bro instances logging to the same host, this distinguishes each peer with its individual name. ', - name: 'zeek.capture_loss.peer', - type: 'keyword', - }, - 'zeek.capture_loss.gaps': { - category: 'zeek', - description: 'Number of missed ACKs from the previous measurement interval. ', - name: 'zeek.capture_loss.gaps', - type: 'integer', - }, - 'zeek.capture_loss.acks': { - category: 'zeek', - description: 'Total number of ACKs seen in the previous measurement interval. ', - name: 'zeek.capture_loss.acks', - type: 'integer', - }, - 'zeek.capture_loss.percent_lost': { - category: 'zeek', - description: "Percentage of ACKs seen where the data being ACKed wasn't seen. ", - name: 'zeek.capture_loss.percent_lost', - type: 'double', - }, - 'zeek.connection.local_orig': { - category: 'zeek', - description: 'Indicates whether the session is originated locally. ', - name: 'zeek.connection.local_orig', - type: 'boolean', - }, - 'zeek.connection.local_resp': { - category: 'zeek', - description: 'Indicates whether the session is responded locally. ', - name: 'zeek.connection.local_resp', - type: 'boolean', - }, - 'zeek.connection.missed_bytes': { - category: 'zeek', - description: 'Missed bytes for the session. ', - name: 'zeek.connection.missed_bytes', - type: 'long', - }, - 'zeek.connection.state': { - category: 'zeek', - description: 'Code indicating the state of the session. ', - name: 'zeek.connection.state', - type: 'keyword', - }, - 'zeek.connection.state_message': { - category: 'zeek', - description: 'The state of the session. ', - name: 'zeek.connection.state_message', - type: 'keyword', - }, - 'zeek.connection.icmp.type': { - category: 'zeek', - description: 'ICMP message type. ', - name: 'zeek.connection.icmp.type', - type: 'integer', - }, - 'zeek.connection.icmp.code': { - category: 'zeek', - description: 'ICMP message code. ', - name: 'zeek.connection.icmp.code', - type: 'integer', - }, - 'zeek.connection.history': { - category: 'zeek', - description: 'Flags indicating the history of the session. ', - name: 'zeek.connection.history', - type: 'keyword', - }, - 'zeek.connection.vlan': { - category: 'zeek', - description: 'VLAN identifier. ', - name: 'zeek.connection.vlan', - type: 'integer', - }, - 'zeek.connection.inner_vlan': { - category: 'zeek', - description: 'VLAN identifier. ', - name: 'zeek.connection.inner_vlan', - type: 'integer', - }, - 'zeek.dce_rpc.rtt': { - category: 'zeek', - description: - "Round trip time from the request to the response. If either the request or response wasn't seen, this will be null. ", - name: 'zeek.dce_rpc.rtt', - type: 'integer', - }, - 'zeek.dce_rpc.named_pipe': { - category: 'zeek', - description: 'Remote pipe name. ', - name: 'zeek.dce_rpc.named_pipe', - type: 'keyword', - }, - 'zeek.dce_rpc.endpoint': { - category: 'zeek', - description: 'Endpoint name looked up from the uuid. ', - name: 'zeek.dce_rpc.endpoint', - type: 'keyword', - }, - 'zeek.dce_rpc.operation': { - category: 'zeek', - description: 'Operation seen in the call. ', - name: 'zeek.dce_rpc.operation', - type: 'keyword', - }, - 'zeek.dhcp.domain': { - category: 'zeek', - description: 'Domain given by the server in option 15. ', - name: 'zeek.dhcp.domain', - type: 'keyword', - }, - 'zeek.dhcp.duration': { - category: 'zeek', - description: - 'Duration of the DHCP session representing the time from the first message to the last, in seconds. ', - name: 'zeek.dhcp.duration', - type: 'double', - }, - 'zeek.dhcp.hostname': { - category: 'zeek', - description: 'Name given by client in Hostname option 12. ', - name: 'zeek.dhcp.hostname', - type: 'keyword', - }, - 'zeek.dhcp.client_fqdn': { - category: 'zeek', - description: 'FQDN given by client in Client FQDN option 81. ', - name: 'zeek.dhcp.client_fqdn', - type: 'keyword', - }, - 'zeek.dhcp.lease_time': { - category: 'zeek', - description: 'IP address lease interval in seconds. ', - name: 'zeek.dhcp.lease_time', - type: 'integer', - }, - 'zeek.dhcp.address.assigned': { - category: 'zeek', - description: 'IP address assigned by the server. ', - name: 'zeek.dhcp.address.assigned', - type: 'ip', - }, - 'zeek.dhcp.address.client': { - category: 'zeek', - description: - 'IP address of the client. If a transaction is only a client sending INFORM messages then there is no lease information exchanged so this is helpful to know who sent the messages. Getting an address in this field does require that the client sources at least one DHCP message using a non-broadcast address. ', - name: 'zeek.dhcp.address.client', - type: 'ip', - }, - 'zeek.dhcp.address.mac': { - category: 'zeek', - description: "Client's hardware address. ", - name: 'zeek.dhcp.address.mac', - type: 'keyword', - }, - 'zeek.dhcp.address.requested': { - category: 'zeek', - description: 'IP address requested by the client. ', - name: 'zeek.dhcp.address.requested', - type: 'ip', - }, - 'zeek.dhcp.address.server': { - category: 'zeek', - description: 'IP address of the DHCP server. ', - name: 'zeek.dhcp.address.server', - type: 'ip', - }, - 'zeek.dhcp.msg.types': { - category: 'zeek', - description: 'List of DHCP message types seen in this exchange. ', - name: 'zeek.dhcp.msg.types', - type: 'keyword', - }, - 'zeek.dhcp.msg.origin': { - category: 'zeek', - description: - '(present if policy/protocols/dhcp/msg-orig.bro is loaded) The address that originated each message from the msg.types field. ', - name: 'zeek.dhcp.msg.origin', - type: 'ip', - }, - 'zeek.dhcp.msg.client': { - category: 'zeek', - description: - 'Message typically accompanied with a DHCP_DECLINE so the client can tell the server why it rejected an address. ', - name: 'zeek.dhcp.msg.client', - type: 'keyword', - }, - 'zeek.dhcp.msg.server': { - category: 'zeek', - description: - 'Message typically accompanied with a DHCP_NAK to let the client know why it rejected the request. ', - name: 'zeek.dhcp.msg.server', - type: 'keyword', - }, - 'zeek.dhcp.software.client': { - category: 'zeek', - description: - '(present if policy/protocols/dhcp/software.bro is loaded) Software reported by the client in the vendor_class option. ', - name: 'zeek.dhcp.software.client', - type: 'keyword', - }, - 'zeek.dhcp.software.server': { - category: 'zeek', - description: - '(present if policy/protocols/dhcp/software.bro is loaded) Software reported by the client in the vendor_class option. ', - name: 'zeek.dhcp.software.server', - type: 'keyword', - }, - 'zeek.dhcp.id.circuit': { - category: 'zeek', - description: - '(present if policy/protocols/dhcp/sub-opts.bro is loaded) Added by DHCP relay agents which terminate switched or permanent circuits. It encodes an agent-local identifier of the circuit from which a DHCP client-to-server packet was received. Typically it should represent a router or switch interface number. ', - name: 'zeek.dhcp.id.circuit', - type: 'keyword', - }, - 'zeek.dhcp.id.remote_agent': { - category: 'zeek', - description: - '(present if policy/protocols/dhcp/sub-opts.bro is loaded) A globally unique identifier added by relay agents to identify the remote host end of the circuit. ', - name: 'zeek.dhcp.id.remote_agent', - type: 'keyword', - }, - 'zeek.dhcp.id.subscriber': { - category: 'zeek', - description: - "(present if policy/protocols/dhcp/sub-opts.bro is loaded) The subscriber ID is a value independent of the physical network configuration so that a customer's DHCP configuration can be given to them correctly no matter where they are physically connected. ", - name: 'zeek.dhcp.id.subscriber', - type: 'keyword', - }, - 'zeek.dnp3.function.request': { - category: 'zeek', - description: 'The name of the function message in the request. ', - name: 'zeek.dnp3.function.request', - type: 'keyword', - }, - 'zeek.dnp3.function.reply': { - category: 'zeek', - description: 'The name of the function message in the reply. ', - name: 'zeek.dnp3.function.reply', - type: 'keyword', - }, - 'zeek.dnp3.id': { - category: 'zeek', - description: "The response's internal indication number. ", - name: 'zeek.dnp3.id', - type: 'integer', - }, - 'zeek.dns.trans_id': { - category: 'zeek', - description: 'DNS transaction identifier. ', - name: 'zeek.dns.trans_id', - type: 'keyword', - }, - 'zeek.dns.rtt': { - category: 'zeek', - description: 'Round trip time for the query and response. ', - name: 'zeek.dns.rtt', - type: 'double', - }, - 'zeek.dns.query': { - category: 'zeek', - description: 'The domain name that is the subject of the DNS query. ', - name: 'zeek.dns.query', - type: 'keyword', - }, - 'zeek.dns.qclass': { - category: 'zeek', - description: 'The QCLASS value specifying the class of the query. ', - name: 'zeek.dns.qclass', - type: 'long', - }, - 'zeek.dns.qclass_name': { - category: 'zeek', - description: 'A descriptive name for the class of the query. ', - name: 'zeek.dns.qclass_name', - type: 'keyword', - }, - 'zeek.dns.qtype': { - category: 'zeek', - description: 'A QTYPE value specifying the type of the query. ', - name: 'zeek.dns.qtype', - type: 'long', - }, - 'zeek.dns.qtype_name': { - category: 'zeek', - description: 'A descriptive name for the type of the query. ', - name: 'zeek.dns.qtype_name', - type: 'keyword', - }, - 'zeek.dns.rcode': { - category: 'zeek', - description: 'The response code value in DNS response messages. ', - name: 'zeek.dns.rcode', - type: 'long', - }, - 'zeek.dns.rcode_name': { - category: 'zeek', - description: 'A descriptive name for the response code value. ', - name: 'zeek.dns.rcode_name', - type: 'keyword', - }, - 'zeek.dns.AA': { - category: 'zeek', - description: - 'The Authoritative Answer bit for response messages specifies that the responding name server is an authority for the domain name in the question section. ', - name: 'zeek.dns.AA', - type: 'boolean', - }, - 'zeek.dns.TC': { - category: 'zeek', - description: 'The Truncation bit specifies that the message was truncated. ', - name: 'zeek.dns.TC', - type: 'boolean', - }, - 'zeek.dns.RD': { - category: 'zeek', - description: - 'The Recursion Desired bit in a request message indicates that the client wants recursive service for this query. ', - name: 'zeek.dns.RD', - type: 'boolean', - }, - 'zeek.dns.RA': { - category: 'zeek', - description: - 'The Recursion Available bit in a response message indicates that the name server supports recursive queries. ', - name: 'zeek.dns.RA', - type: 'boolean', - }, - 'zeek.dns.answers': { - category: 'zeek', - description: 'The set of resource descriptions in the query answer. ', - name: 'zeek.dns.answers', - type: 'keyword', - }, - 'zeek.dns.TTLs': { - category: 'zeek', - description: 'The caching intervals of the associated RRs described by the answers field. ', - name: 'zeek.dns.TTLs', - type: 'double', - }, - 'zeek.dns.rejected': { - category: 'zeek', - description: 'Indicates whether the DNS query was rejected by the server. ', - name: 'zeek.dns.rejected', - type: 'boolean', - }, - 'zeek.dns.total_answers': { - category: 'zeek', - description: 'The total number of resource records in the reply. ', - name: 'zeek.dns.total_answers', - type: 'integer', - }, - 'zeek.dns.total_replies': { - category: 'zeek', - description: 'The total number of resource records in the reply message. ', - name: 'zeek.dns.total_replies', - type: 'integer', - }, - 'zeek.dns.saw_query': { - category: 'zeek', - description: 'Whether the full DNS query has been seen. ', - name: 'zeek.dns.saw_query', - type: 'boolean', - }, - 'zeek.dns.saw_reply': { - category: 'zeek', - description: 'Whether the full DNS reply has been seen. ', - name: 'zeek.dns.saw_reply', - type: 'boolean', - }, - 'zeek.dpd.analyzer': { - category: 'zeek', - description: 'The analyzer that generated the violation. ', - name: 'zeek.dpd.analyzer', - type: 'keyword', - }, - 'zeek.dpd.failure_reason': { - category: 'zeek', - description: 'The textual reason for the analysis failure. ', - name: 'zeek.dpd.failure_reason', - type: 'keyword', - }, - 'zeek.dpd.packet_segment': { - category: 'zeek', - description: - '(present if policy/frameworks/dpd/packet-segment-logging.bro is loaded) A chunk of the payload that most likely resulted in the protocol violation. ', - name: 'zeek.dpd.packet_segment', - type: 'keyword', - }, - 'zeek.files.fuid': { - category: 'zeek', - description: 'A file unique identifier. ', - name: 'zeek.files.fuid', - type: 'keyword', - }, - 'zeek.files.tx_host': { - category: 'zeek', - description: 'The host that transferred the file. ', - name: 'zeek.files.tx_host', - type: 'ip', - }, - 'zeek.files.rx_host': { - category: 'zeek', - description: 'The host that received the file. ', - name: 'zeek.files.rx_host', - type: 'ip', - }, - 'zeek.files.session_ids': { - category: 'zeek', - description: 'The sessions that have this file. ', - name: 'zeek.files.session_ids', - type: 'keyword', - }, - 'zeek.files.source': { - category: 'zeek', - description: - 'An identification of the source of the file data. E.g. it may be a network protocol over which it was transferred, or a local file path which was read, or some other input source. ', - name: 'zeek.files.source', - type: 'keyword', - }, - 'zeek.files.depth': { - category: 'zeek', - description: - 'A value to represent the depth of this file in relation to its source. In SMTP, it is the depth of the MIME attachment on the message. In HTTP, it is the depth of the request within the TCP connection. ', - name: 'zeek.files.depth', - type: 'long', - }, - 'zeek.files.analyzers': { - category: 'zeek', - description: 'A set of analysis types done during the file analysis. ', - name: 'zeek.files.analyzers', - type: 'keyword', - }, - 'zeek.files.mime_type': { - category: 'zeek', - description: 'Mime type of the file. ', - name: 'zeek.files.mime_type', - type: 'keyword', - }, - 'zeek.files.filename': { - category: 'zeek', - description: 'Name of the file if available. ', - name: 'zeek.files.filename', - type: 'keyword', - }, - 'zeek.files.local_orig': { - category: 'zeek', - description: - 'If the source of this file is a network connection, this field indicates if the data originated from the local network or not. ', - name: 'zeek.files.local_orig', - type: 'boolean', - }, - 'zeek.files.is_orig': { - category: 'zeek', - description: - 'If the source of this file is a network connection, this field indicates if the file is being sent by the originator of the connection or the responder. ', - name: 'zeek.files.is_orig', - type: 'boolean', - }, - 'zeek.files.duration': { - category: 'zeek', - description: 'The duration the file was analyzed for. Not the duration of the session. ', - name: 'zeek.files.duration', - type: 'double', - }, - 'zeek.files.seen_bytes': { - category: 'zeek', - description: 'Number of bytes provided to the file analysis engine for the file. ', - name: 'zeek.files.seen_bytes', - type: 'long', - }, - 'zeek.files.total_bytes': { - category: 'zeek', - description: 'Total number of bytes that are supposed to comprise the full file. ', - name: 'zeek.files.total_bytes', - type: 'long', - }, - 'zeek.files.missing_bytes': { - category: 'zeek', - description: - 'The number of bytes in the file stream that were completely missed during the process of analysis. ', - name: 'zeek.files.missing_bytes', - type: 'long', - }, - 'zeek.files.overflow_bytes': { - category: 'zeek', - description: - "The number of bytes in the file stream that were not delivered to stream file analyzers. This could be overlapping bytes or bytes that couldn't be reassembled. ", - name: 'zeek.files.overflow_bytes', - type: 'long', - }, - 'zeek.files.timedout': { - category: 'zeek', - description: 'Whether the file analysis timed out at least once for the file. ', - name: 'zeek.files.timedout', - type: 'boolean', - }, - 'zeek.files.parent_fuid': { - category: 'zeek', - description: - 'Identifier associated with a container file from which this one was extracted as part of the file analysis. ', - name: 'zeek.files.parent_fuid', - type: 'keyword', - }, - 'zeek.files.md5': { - category: 'zeek', - description: 'An MD5 digest of the file contents. ', - name: 'zeek.files.md5', - type: 'keyword', - }, - 'zeek.files.sha1': { - category: 'zeek', - description: 'A SHA1 digest of the file contents. ', - name: 'zeek.files.sha1', - type: 'keyword', - }, - 'zeek.files.sha256': { - category: 'zeek', - description: 'A SHA256 digest of the file contents. ', - name: 'zeek.files.sha256', - type: 'keyword', - }, - 'zeek.files.extracted': { - category: 'zeek', - description: 'Local filename of extracted file. ', - name: 'zeek.files.extracted', - type: 'keyword', - }, - 'zeek.files.extracted_cutoff': { - category: 'zeek', - description: - 'Indicate whether the file being extracted was cut off hence not extracted completely. ', - name: 'zeek.files.extracted_cutoff', - type: 'boolean', - }, - 'zeek.files.extracted_size': { - category: 'zeek', - description: 'The number of bytes extracted to disk. ', - name: 'zeek.files.extracted_size', - type: 'long', - }, - 'zeek.files.entropy': { - category: 'zeek', - description: 'The information density of the contents of the file. ', - name: 'zeek.files.entropy', - type: 'double', - }, - 'zeek.ftp.user': { - category: 'zeek', - description: 'User name for the current FTP session. ', - name: 'zeek.ftp.user', - type: 'keyword', - }, - 'zeek.ftp.password': { - category: 'zeek', - description: 'Password for the current FTP session if captured. ', - name: 'zeek.ftp.password', - type: 'keyword', - }, - 'zeek.ftp.command': { - category: 'zeek', - description: 'Command given by the client. ', - name: 'zeek.ftp.command', - type: 'keyword', - }, - 'zeek.ftp.arg': { - category: 'zeek', - description: 'Argument for the command if one is given. ', - name: 'zeek.ftp.arg', - type: 'keyword', - }, - 'zeek.ftp.file.size': { - category: 'zeek', - description: 'Size of the file if the command indicates a file transfer. ', - name: 'zeek.ftp.file.size', - type: 'long', - }, - 'zeek.ftp.file.mime_type': { - category: 'zeek', - description: 'Sniffed mime type of file. ', - name: 'zeek.ftp.file.mime_type', - type: 'keyword', - }, - 'zeek.ftp.file.fuid': { - category: 'zeek', - description: '(present if base/protocols/ftp/files.bro is loaded) File unique ID. ', - name: 'zeek.ftp.file.fuid', - type: 'keyword', - }, - 'zeek.ftp.reply.code': { - category: 'zeek', - description: 'Reply code from the server in response to the command. ', - name: 'zeek.ftp.reply.code', - type: 'integer', - }, - 'zeek.ftp.reply.msg': { - category: 'zeek', - description: 'Reply message from the server in response to the command. ', - name: 'zeek.ftp.reply.msg', - type: 'keyword', - }, - 'zeek.ftp.data_channel.passive': { - category: 'zeek', - description: 'Whether PASV mode is toggled for control channel. ', - name: 'zeek.ftp.data_channel.passive', - type: 'boolean', - }, - 'zeek.ftp.data_channel.originating_host': { - category: 'zeek', - description: 'The host that will be initiating the data connection. ', - name: 'zeek.ftp.data_channel.originating_host', - type: 'ip', - }, - 'zeek.ftp.data_channel.response_host': { - category: 'zeek', - description: 'The host that will be accepting the data connection. ', - name: 'zeek.ftp.data_channel.response_host', - type: 'ip', - }, - 'zeek.ftp.data_channel.response_port': { - category: 'zeek', - description: 'The port at which the acceptor is listening for the data connection. ', - name: 'zeek.ftp.data_channel.response_port', - type: 'integer', - }, - 'zeek.ftp.cwd': { - category: 'zeek', - description: - "Current working directory that this session is in. By making the default value '.', we can indicate that unless something more concrete is discovered that the existing but unknown directory is ok to use. ", - name: 'zeek.ftp.cwd', - type: 'keyword', - }, - 'zeek.ftp.cmdarg.cmd': { - category: 'zeek', - description: 'Command. ', - name: 'zeek.ftp.cmdarg.cmd', - type: 'keyword', - }, - 'zeek.ftp.cmdarg.arg': { - category: 'zeek', - description: 'Argument for the command if one was given. ', - name: 'zeek.ftp.cmdarg.arg', - type: 'keyword', - }, - 'zeek.ftp.cmdarg.seq': { - category: 'zeek', - description: 'Counter to track how many commands have been executed. ', - name: 'zeek.ftp.cmdarg.seq', - type: 'integer', - }, - 'zeek.ftp.pending_commands': { - category: 'zeek', - description: - 'Queue for commands that have been sent but not yet responded to are tracked here. ', - name: 'zeek.ftp.pending_commands', - type: 'integer', - }, - 'zeek.ftp.passive': { - category: 'zeek', - description: 'Indicates if the session is in active or passive mode. ', - name: 'zeek.ftp.passive', - type: 'boolean', - }, - 'zeek.ftp.capture_password': { - category: 'zeek', - description: 'Determines if the password will be captured for this request. ', - name: 'zeek.ftp.capture_password', - type: 'boolean', - }, - 'zeek.ftp.last_auth_requested': { - category: 'zeek', - description: - 'present if base/protocols/ftp/gridftp.bro is loaded. Last authentication/security mechanism that was used. ', - name: 'zeek.ftp.last_auth_requested', - type: 'keyword', - }, - 'zeek.http.trans_depth': { - category: 'zeek', - description: - 'Represents the pipelined depth into the connection of this request/response transaction. ', - name: 'zeek.http.trans_depth', - type: 'integer', - }, - 'zeek.http.status_msg': { - category: 'zeek', - description: 'Status message returned by the server. ', - name: 'zeek.http.status_msg', - type: 'keyword', - }, - 'zeek.http.info_code': { - category: 'zeek', - description: 'Last seen 1xx informational reply code returned by the server. ', - name: 'zeek.http.info_code', - type: 'integer', - }, - 'zeek.http.info_msg': { - category: 'zeek', - description: 'Last seen 1xx informational reply message returned by the server. ', - name: 'zeek.http.info_msg', - type: 'keyword', - }, - 'zeek.http.tags': { - category: 'zeek', - description: - 'A set of indicators of various attributes discovered and related to a particular request/response pair. ', - name: 'zeek.http.tags', - type: 'keyword', - }, - 'zeek.http.password': { - category: 'zeek', - description: 'Password if basic-auth is performed for the request. ', - name: 'zeek.http.password', - type: 'keyword', - }, - 'zeek.http.captured_password': { - category: 'zeek', - description: 'Determines if the password will be captured for this request. ', - name: 'zeek.http.captured_password', - type: 'boolean', - }, - 'zeek.http.proxied': { - category: 'zeek', - description: 'All of the headers that may indicate if the HTTP request was proxied. ', - name: 'zeek.http.proxied', - type: 'keyword', - }, - 'zeek.http.range_request': { - category: 'zeek', - description: 'Indicates if this request can assume 206 partial content in response. ', - name: 'zeek.http.range_request', - type: 'boolean', - }, - 'zeek.http.client_header_names': { - category: 'zeek', - description: - 'The vector of HTTP header names sent by the client. No header values are included here, just the header names. ', - name: 'zeek.http.client_header_names', - type: 'keyword', - }, - 'zeek.http.server_header_names': { - category: 'zeek', - description: - 'The vector of HTTP header names sent by the server. No header values are included here, just the header names. ', - name: 'zeek.http.server_header_names', - type: 'keyword', - }, - 'zeek.http.orig_fuids': { - category: 'zeek', - description: 'An ordered vector of file unique IDs from the originator. ', - name: 'zeek.http.orig_fuids', - type: 'keyword', - }, - 'zeek.http.orig_mime_types': { - category: 'zeek', - description: 'An ordered vector of mime types from the originator. ', - name: 'zeek.http.orig_mime_types', - type: 'keyword', - }, - 'zeek.http.orig_filenames': { - category: 'zeek', - description: 'An ordered vector of filenames from the originator. ', - name: 'zeek.http.orig_filenames', - type: 'keyword', - }, - 'zeek.http.resp_fuids': { - category: 'zeek', - description: 'An ordered vector of file unique IDs from the responder. ', - name: 'zeek.http.resp_fuids', - type: 'keyword', - }, - 'zeek.http.resp_mime_types': { - category: 'zeek', - description: 'An ordered vector of mime types from the responder. ', - name: 'zeek.http.resp_mime_types', - type: 'keyword', - }, - 'zeek.http.resp_filenames': { - category: 'zeek', - description: 'An ordered vector of filenames from the responder. ', - name: 'zeek.http.resp_filenames', - type: 'keyword', - }, - 'zeek.http.orig_mime_depth': { - category: 'zeek', - description: 'Current number of MIME entities in the HTTP request message body. ', - name: 'zeek.http.orig_mime_depth', - type: 'integer', - }, - 'zeek.http.resp_mime_depth': { - category: 'zeek', - description: 'Current number of MIME entities in the HTTP response message body. ', - name: 'zeek.http.resp_mime_depth', - type: 'integer', - }, - 'zeek.intel.seen.indicator': { - category: 'zeek', - description: 'The intelligence indicator. ', - name: 'zeek.intel.seen.indicator', - type: 'keyword', - }, - 'zeek.intel.seen.indicator_type': { - category: 'zeek', - description: 'The type of data the indicator represents. ', - name: 'zeek.intel.seen.indicator_type', - type: 'keyword', - }, - 'zeek.intel.seen.host': { - category: 'zeek', - description: 'If the indicator type was Intel::ADDR, then this field will be present. ', - name: 'zeek.intel.seen.host', - type: 'keyword', - }, - 'zeek.intel.seen.conn': { - category: 'zeek', - description: - 'If the data was discovered within a connection, the connection record should go here to give context to the data. ', - name: 'zeek.intel.seen.conn', - type: 'keyword', - }, - 'zeek.intel.seen.where': { - category: 'zeek', - description: 'Where the data was discovered. ', - name: 'zeek.intel.seen.where', - type: 'keyword', - }, - 'zeek.intel.seen.node': { - category: 'zeek', - description: 'The name of the node where the match was discovered. ', - name: 'zeek.intel.seen.node', - type: 'keyword', - }, - 'zeek.intel.seen.uid': { - category: 'zeek', - description: - 'If the data was discovered within a connection, the connection uid should go here to give context to the data. If the conn field is provided, this will be automatically filled out. ', - name: 'zeek.intel.seen.uid', - type: 'keyword', - }, - 'zeek.intel.seen.f': { - category: 'zeek', - description: - 'If the data was discovered within a file, the file record should go here to provide context to the data. ', - name: 'zeek.intel.seen.f', - type: 'object', - }, - 'zeek.intel.seen.fuid': { - category: 'zeek', - description: - 'If the data was discovered within a file, the file uid should go here to provide context to the data. If the file record f is provided, this will be automatically filled out. ', - name: 'zeek.intel.seen.fuid', - type: 'keyword', - }, - 'zeek.intel.matched': { - category: 'zeek', - description: 'Event to represent a match in the intelligence data from data that was seen. ', - name: 'zeek.intel.matched', - type: 'keyword', - }, - 'zeek.intel.sources': { - category: 'zeek', - description: 'Sources which supplied data for this match. ', - name: 'zeek.intel.sources', - type: 'keyword', - }, - 'zeek.intel.fuid': { - category: 'zeek', - description: - 'If a file was associated with this intelligence hit, this is the uid for the file. ', - name: 'zeek.intel.fuid', - type: 'keyword', - }, - 'zeek.intel.file_mime_type': { - category: 'zeek', - description: - 'A mime type if the intelligence hit is related to a file. If the $f field is provided this will be automatically filled out. ', - name: 'zeek.intel.file_mime_type', - type: 'keyword', - }, - 'zeek.intel.file_desc': { - category: 'zeek', - description: - 'Frequently files can be described to give a bit more context. If the $f field is provided this field will be automatically filled out. ', - name: 'zeek.intel.file_desc', - type: 'keyword', - }, - 'zeek.irc.nick': { - category: 'zeek', - description: 'Nickname given for the connection. ', - name: 'zeek.irc.nick', - type: 'keyword', - }, - 'zeek.irc.user': { - category: 'zeek', - description: 'Username given for the connection. ', - name: 'zeek.irc.user', - type: 'keyword', - }, - 'zeek.irc.command': { - category: 'zeek', - description: 'Command given by the client. ', - name: 'zeek.irc.command', - type: 'keyword', - }, - 'zeek.irc.value': { - category: 'zeek', - description: 'Value for the command given by the client. ', - name: 'zeek.irc.value', - type: 'keyword', - }, - 'zeek.irc.addl': { - category: 'zeek', - description: 'Any additional data for the command. ', - name: 'zeek.irc.addl', - type: 'keyword', - }, - 'zeek.irc.dcc.file.name': { - category: 'zeek', - description: 'Present if base/protocols/irc/dcc-send.bro is loaded. DCC filename requested. ', - name: 'zeek.irc.dcc.file.name', - type: 'keyword', - }, - 'zeek.irc.dcc.file.size': { - category: 'zeek', - description: - 'Present if base/protocols/irc/dcc-send.bro is loaded. Size of the DCC transfer as indicated by the sender. ', - name: 'zeek.irc.dcc.file.size', - type: 'long', - }, - 'zeek.irc.dcc.mime_type': { - category: 'zeek', - description: - 'present if base/protocols/irc/dcc-send.bro is loaded. Sniffed mime type of the file. ', - name: 'zeek.irc.dcc.mime_type', - type: 'keyword', - }, - 'zeek.irc.fuid': { - category: 'zeek', - description: 'present if base/protocols/irc/files.bro is loaded. File unique ID. ', - name: 'zeek.irc.fuid', - type: 'keyword', - }, - 'zeek.kerberos.request_type': { - category: 'zeek', - description: 'Request type - Authentication Service (AS) or Ticket Granting Service (TGS). ', - name: 'zeek.kerberos.request_type', - type: 'keyword', - }, - 'zeek.kerberos.client': { - category: 'zeek', - description: 'Client name. ', - name: 'zeek.kerberos.client', - type: 'keyword', - }, - 'zeek.kerberos.service': { - category: 'zeek', - description: 'Service name. ', - name: 'zeek.kerberos.service', - type: 'keyword', - }, - 'zeek.kerberos.success': { - category: 'zeek', - description: 'Request result. ', - name: 'zeek.kerberos.success', - type: 'boolean', - }, - 'zeek.kerberos.error.code': { - category: 'zeek', - description: 'Error code. ', - name: 'zeek.kerberos.error.code', - type: 'integer', - }, - 'zeek.kerberos.error.msg': { - category: 'zeek', - description: 'Error message. ', - name: 'zeek.kerberos.error.msg', - type: 'keyword', - }, - 'zeek.kerberos.valid.from': { - category: 'zeek', - description: 'Ticket valid from. ', - name: 'zeek.kerberos.valid.from', - type: 'date', - }, - 'zeek.kerberos.valid.until': { - category: 'zeek', - description: 'Ticket valid until. ', - name: 'zeek.kerberos.valid.until', - type: 'date', - }, - 'zeek.kerberos.valid.days': { - category: 'zeek', - description: 'Number of days the ticket is valid for. ', - name: 'zeek.kerberos.valid.days', - type: 'integer', - }, - 'zeek.kerberos.cipher': { - category: 'zeek', - description: 'Ticket encryption type. ', - name: 'zeek.kerberos.cipher', - type: 'keyword', - }, - 'zeek.kerberos.forwardable': { - category: 'zeek', - description: 'Forwardable ticket requested. ', - name: 'zeek.kerberos.forwardable', - type: 'boolean', - }, - 'zeek.kerberos.renewable': { - category: 'zeek', - description: 'Renewable ticket requested. ', - name: 'zeek.kerberos.renewable', - type: 'boolean', - }, - 'zeek.kerberos.ticket.auth': { - category: 'zeek', - description: 'Hash of ticket used to authorize request/transaction. ', - name: 'zeek.kerberos.ticket.auth', - type: 'keyword', - }, - 'zeek.kerberos.ticket.new': { - category: 'zeek', - description: 'Hash of ticket returned by the KDC. ', - name: 'zeek.kerberos.ticket.new', - type: 'keyword', - }, - 'zeek.kerberos.cert.client.value': { - category: 'zeek', - description: 'Client certificate. ', - name: 'zeek.kerberos.cert.client.value', - type: 'keyword', - }, - 'zeek.kerberos.cert.client.fuid': { - category: 'zeek', - description: 'File unique ID of client cert. ', - name: 'zeek.kerberos.cert.client.fuid', - type: 'keyword', - }, - 'zeek.kerberos.cert.client.subject': { - category: 'zeek', - description: 'Subject of client certificate. ', - name: 'zeek.kerberos.cert.client.subject', - type: 'keyword', - }, - 'zeek.kerberos.cert.server.value': { - category: 'zeek', - description: 'Server certificate. ', - name: 'zeek.kerberos.cert.server.value', - type: 'keyword', - }, - 'zeek.kerberos.cert.server.fuid': { - category: 'zeek', - description: 'File unique ID of server certificate. ', - name: 'zeek.kerberos.cert.server.fuid', - type: 'keyword', - }, - 'zeek.kerberos.cert.server.subject': { - category: 'zeek', - description: 'Subject of server certificate. ', - name: 'zeek.kerberos.cert.server.subject', - type: 'keyword', - }, - 'zeek.modbus.function': { - category: 'zeek', - description: 'The name of the function message that was sent. ', - name: 'zeek.modbus.function', - type: 'keyword', - }, - 'zeek.modbus.exception': { - category: 'zeek', - description: 'The exception if the response was a failure. ', - name: 'zeek.modbus.exception', - type: 'keyword', - }, - 'zeek.modbus.track_address': { - category: 'zeek', - description: - 'Present if policy/protocols/modbus/track-memmap.bro is loaded. Modbus track address. ', - name: 'zeek.modbus.track_address', - type: 'integer', - }, - 'zeek.mysql.cmd': { - category: 'zeek', - description: 'The command that was issued. ', - name: 'zeek.mysql.cmd', - type: 'keyword', - }, - 'zeek.mysql.arg': { - category: 'zeek', - description: 'The argument issued to the command. ', - name: 'zeek.mysql.arg', - type: 'keyword', - }, - 'zeek.mysql.success': { - category: 'zeek', - description: 'Whether the command succeeded. ', - name: 'zeek.mysql.success', - type: 'boolean', - }, - 'zeek.mysql.rows': { - category: 'zeek', - description: 'The number of affected rows, if any. ', - name: 'zeek.mysql.rows', - type: 'integer', - }, - 'zeek.mysql.response': { - category: 'zeek', - description: 'Server message, if any. ', - name: 'zeek.mysql.response', - type: 'keyword', - }, - 'zeek.notice.connection_id': { - category: 'zeek', - description: 'Identifier of the related connection session. ', - name: 'zeek.notice.connection_id', - type: 'keyword', - }, - 'zeek.notice.icmp_id': { - category: 'zeek', - description: 'Identifier of the related ICMP session. ', - name: 'zeek.notice.icmp_id', - type: 'keyword', - }, - 'zeek.notice.file.id': { - category: 'zeek', - description: 'An identifier associated with a single file that is related to this notice. ', - name: 'zeek.notice.file.id', - type: 'keyword', - }, - 'zeek.notice.file.parent_id': { - category: 'zeek', - description: 'Identifier associated with a container file from which this one was extracted. ', - name: 'zeek.notice.file.parent_id', - type: 'keyword', - }, - 'zeek.notice.file.source': { - category: 'zeek', - description: - 'An identification of the source of the file data. E.g. it may be a network protocol over which it was transferred, or a local file path which was read, or some other input source. ', - name: 'zeek.notice.file.source', - type: 'keyword', - }, - 'zeek.notice.file.mime_type': { - category: 'zeek', - description: 'A mime type if the notice is related to a file. ', - name: 'zeek.notice.file.mime_type', - type: 'keyword', - }, - 'zeek.notice.file.is_orig': { - category: 'zeek', - description: - 'If the source of this file is a network connection, this field indicates if the file is being sent by the originator of the connection or the responder. ', - name: 'zeek.notice.file.is_orig', - type: 'boolean', - }, - 'zeek.notice.file.seen_bytes': { - category: 'zeek', - description: 'Number of bytes provided to the file analysis engine for the file. ', - name: 'zeek.notice.file.seen_bytes', - type: 'long', - }, - 'zeek.notice.ffile.total_bytes': { - category: 'zeek', - description: 'Total number of bytes that are supposed to comprise the full file. ', - name: 'zeek.notice.ffile.total_bytes', - type: 'long', - }, - 'zeek.notice.file.missing_bytes': { - category: 'zeek', - description: - 'The number of bytes in the file stream that were completely missed during the process of analysis. ', - name: 'zeek.notice.file.missing_bytes', - type: 'long', - }, - 'zeek.notice.file.overflow_bytes': { - category: 'zeek', - description: - "The number of bytes in the file stream that were not delivered to stream file analyzers. This could be overlapping bytes or bytes that couldn't be reassembled. ", - name: 'zeek.notice.file.overflow_bytes', - type: 'long', - }, - 'zeek.notice.fuid': { - category: 'zeek', - description: 'A file unique ID if this notice is related to a file. ', - name: 'zeek.notice.fuid', - type: 'keyword', - }, - 'zeek.notice.note': { - category: 'zeek', - description: 'The type of the notice. ', - name: 'zeek.notice.note', - type: 'keyword', - }, - 'zeek.notice.msg': { - category: 'zeek', - description: 'The human readable message for the notice. ', - name: 'zeek.notice.msg', - type: 'keyword', - }, - 'zeek.notice.sub': { - category: 'zeek', - description: 'The human readable sub-message. ', - name: 'zeek.notice.sub', - type: 'keyword', - }, - 'zeek.notice.n': { - category: 'zeek', - description: 'Associated count, or a status code. ', - name: 'zeek.notice.n', - type: 'long', - }, - 'zeek.notice.peer_name': { - category: 'zeek', - description: 'Name of remote peer that raised this notice. ', - name: 'zeek.notice.peer_name', - type: 'keyword', - }, - 'zeek.notice.peer_descr': { - category: 'zeek', - description: 'Textual description for the peer that raised this notice. ', - name: 'zeek.notice.peer_descr', - type: 'text', - }, - 'zeek.notice.actions': { - category: 'zeek', - description: 'The actions which have been applied to this notice. ', - name: 'zeek.notice.actions', - type: 'keyword', - }, - 'zeek.notice.email_body_sections': { - category: 'zeek', - description: - 'By adding chunks of text into this element, other scripts can expand on notices that are being emailed. ', - name: 'zeek.notice.email_body_sections', - type: 'text', - }, - 'zeek.notice.email_delay_tokens': { - category: 'zeek', - description: - 'Adding a string token to this set will cause the built-in emailing functionality to delay sending the email either the token has been removed or the email has been delayed for the specified time duration. ', - name: 'zeek.notice.email_delay_tokens', - type: 'keyword', - }, - 'zeek.notice.identifier': { - category: 'zeek', - description: - 'This field is provided when a notice is generated for the purpose of deduplicating notices. ', - name: 'zeek.notice.identifier', - type: 'keyword', - }, - 'zeek.notice.suppress_for': { - category: 'zeek', - description: - 'This field indicates the length of time that this unique notice should be suppressed. ', - name: 'zeek.notice.suppress_for', - type: 'double', - }, - 'zeek.notice.dropped': { - category: 'zeek', - description: 'Indicate if the source IP address was dropped and denied network access. ', - name: 'zeek.notice.dropped', - type: 'boolean', - }, - 'zeek.ntlm.domain': { - category: 'zeek', - description: 'Domain name given by the client. ', - name: 'zeek.ntlm.domain', - type: 'keyword', - }, - 'zeek.ntlm.hostname': { - category: 'zeek', - description: 'Hostname given by the client. ', - name: 'zeek.ntlm.hostname', - type: 'keyword', - }, - 'zeek.ntlm.success': { - category: 'zeek', - description: 'Indicate whether or not the authentication was successful. ', - name: 'zeek.ntlm.success', - type: 'boolean', - }, - 'zeek.ntlm.username': { - category: 'zeek', - description: 'Username given by the client. ', - name: 'zeek.ntlm.username', - type: 'keyword', - }, - 'zeek.ntlm.server.name.dns': { - category: 'zeek', - description: 'DNS name given by the server in a CHALLENGE. ', - name: 'zeek.ntlm.server.name.dns', - type: 'keyword', - }, - 'zeek.ntlm.server.name.netbios': { - category: 'zeek', - description: 'NetBIOS name given by the server in a CHALLENGE. ', - name: 'zeek.ntlm.server.name.netbios', - type: 'keyword', - }, - 'zeek.ntlm.server.name.tree': { - category: 'zeek', - description: 'Tree name given by the server in a CHALLENGE. ', - name: 'zeek.ntlm.server.name.tree', - type: 'keyword', - }, - 'zeek.ntp.version': { - category: 'zeek', - description: 'The NTP version number (1, 2, 3, 4). ', - name: 'zeek.ntp.version', - type: 'integer', - }, - 'zeek.ntp.mode': { - category: 'zeek', - description: 'The NTP mode being used. ', - name: 'zeek.ntp.mode', - type: 'integer', - }, - 'zeek.ntp.stratum': { - category: 'zeek', - description: 'The stratum (primary server, secondary server, etc.). ', - name: 'zeek.ntp.stratum', - type: 'integer', - }, - 'zeek.ntp.poll': { - category: 'zeek', - description: 'The maximum interval between successive messages in seconds. ', - name: 'zeek.ntp.poll', - type: 'double', - }, - 'zeek.ntp.precision': { - category: 'zeek', - description: 'The precision of the system clock in seconds. ', - name: 'zeek.ntp.precision', - type: 'double', - }, - 'zeek.ntp.root_delay': { - category: 'zeek', - description: 'Total round-trip delay to the reference clock in seconds. ', - name: 'zeek.ntp.root_delay', - type: 'double', - }, - 'zeek.ntp.root_disp': { - category: 'zeek', - description: 'Total dispersion to the reference clock in seconds. ', - name: 'zeek.ntp.root_disp', - type: 'double', - }, - 'zeek.ntp.ref_id': { - category: 'zeek', - description: - 'For stratum 0, 4 character string used for debugging. For stratum 1, ID assigned to the reference clock by IANA. Above stratum 1, when using IPv4, the IP address of the reference clock. Note that the NTP protocol did not originally specify a large enough field to represent IPv6 addresses, so they use the first four bytes of the MD5 hash of the reference clock’s IPv6 address (i.e. an IPv4 address here is not necessarily IPv4). ', - name: 'zeek.ntp.ref_id', - type: 'keyword', - }, - 'zeek.ntp.ref_time': { - category: 'zeek', - description: 'Time when the system clock was last set or correct. ', - name: 'zeek.ntp.ref_time', - type: 'date', - }, - 'zeek.ntp.org_time': { - category: 'zeek', - description: 'Time at the client when the request departed for the NTP server. ', - name: 'zeek.ntp.org_time', - type: 'date', - }, - 'zeek.ntp.rec_time': { - category: 'zeek', - description: 'Time at the server when the request arrived from the NTP client. ', - name: 'zeek.ntp.rec_time', - type: 'date', - }, - 'zeek.ntp.xmt_time': { - category: 'zeek', - description: 'Time at the server when the response departed for the NTP client. ', - name: 'zeek.ntp.xmt_time', - type: 'date', - }, - 'zeek.ntp.num_exts': { - category: 'zeek', - description: 'Number of extension fields (which are not currently parsed). ', - name: 'zeek.ntp.num_exts', - type: 'integer', - }, - 'zeek.ocsp.file_id': { - category: 'zeek', - description: 'File id of the OCSP reply. ', - name: 'zeek.ocsp.file_id', - type: 'keyword', - }, - 'zeek.ocsp.hash.algorithm': { - category: 'zeek', - description: 'Hash algorithm used to generate issuerNameHash and issuerKeyHash. ', - name: 'zeek.ocsp.hash.algorithm', - type: 'keyword', - }, - 'zeek.ocsp.hash.issuer.name': { - category: 'zeek', - description: "Hash of the issuer's distingueshed name. ", - name: 'zeek.ocsp.hash.issuer.name', - type: 'keyword', - }, - 'zeek.ocsp.hash.issuer.key': { - category: 'zeek', - description: "Hash of the issuer's public key. ", - name: 'zeek.ocsp.hash.issuer.key', - type: 'keyword', - }, - 'zeek.ocsp.serial_number': { - category: 'zeek', - description: 'Serial number of the affected certificate. ', - name: 'zeek.ocsp.serial_number', - type: 'keyword', - }, - 'zeek.ocsp.status': { - category: 'zeek', - description: 'Status of the affected certificate. ', - name: 'zeek.ocsp.status', - type: 'keyword', - }, - 'zeek.ocsp.revoke.time': { - category: 'zeek', - description: 'Time at which the certificate was revoked. ', - name: 'zeek.ocsp.revoke.time', - type: 'date', - }, - 'zeek.ocsp.revoke.reason': { - category: 'zeek', - description: 'Reason for which the certificate was revoked. ', - name: 'zeek.ocsp.revoke.reason', - type: 'keyword', - }, - 'zeek.ocsp.update.this': { - category: 'zeek', - description: 'The time at which the status being shows is known to have been correct. ', - name: 'zeek.ocsp.update.this', - type: 'date', - }, - 'zeek.ocsp.update.next': { - category: 'zeek', - description: - 'The latest time at which new information about the status of the certificate will be available. ', - name: 'zeek.ocsp.update.next', - type: 'date', - }, - 'zeek.pe.client': { - category: 'zeek', - description: "The client's version string. ", - name: 'zeek.pe.client', - type: 'keyword', - }, - 'zeek.pe.id': { - category: 'zeek', - description: 'File id of this portable executable file. ', - name: 'zeek.pe.id', - type: 'keyword', - }, - 'zeek.pe.machine': { - category: 'zeek', - description: 'The target machine that the file was compiled for. ', - name: 'zeek.pe.machine', - type: 'keyword', - }, - 'zeek.pe.compile_time': { - category: 'zeek', - description: 'The time that the file was created at. ', - name: 'zeek.pe.compile_time', - type: 'date', - }, - 'zeek.pe.os': { - category: 'zeek', - description: 'The required operating system. ', - name: 'zeek.pe.os', - type: 'keyword', - }, - 'zeek.pe.subsystem': { - category: 'zeek', - description: 'The subsystem that is required to run this file. ', - name: 'zeek.pe.subsystem', - type: 'keyword', - }, - 'zeek.pe.is_exe': { - category: 'zeek', - description: 'Is the file an executable, or just an object file? ', - name: 'zeek.pe.is_exe', - type: 'boolean', - }, - 'zeek.pe.is_64bit': { - category: 'zeek', - description: 'Is the file a 64-bit executable? ', - name: 'zeek.pe.is_64bit', - type: 'boolean', - }, - 'zeek.pe.uses_aslr': { - category: 'zeek', - description: 'Does the file support Address Space Layout Randomization? ', - name: 'zeek.pe.uses_aslr', - type: 'boolean', - }, - 'zeek.pe.uses_dep': { - category: 'zeek', - description: 'Does the file support Data Execution Prevention? ', - name: 'zeek.pe.uses_dep', - type: 'boolean', - }, - 'zeek.pe.uses_code_integrity': { - category: 'zeek', - description: 'Does the file enforce code integrity checks? ', - name: 'zeek.pe.uses_code_integrity', - type: 'boolean', - }, - 'zeek.pe.uses_seh': { - category: 'zeek', - description: 'Does the file use structured exception handing? ', - name: 'zeek.pe.uses_seh', - type: 'boolean', - }, - 'zeek.pe.has_import_table': { - category: 'zeek', - description: 'Does the file have an import table? ', - name: 'zeek.pe.has_import_table', - type: 'boolean', - }, - 'zeek.pe.has_export_table': { - category: 'zeek', - description: 'Does the file have an export table? ', - name: 'zeek.pe.has_export_table', - type: 'boolean', - }, - 'zeek.pe.has_cert_table': { - category: 'zeek', - description: 'Does the file have an attribute certificate table? ', - name: 'zeek.pe.has_cert_table', - type: 'boolean', - }, - 'zeek.pe.has_debug_data': { - category: 'zeek', - description: 'Does the file have a debug table? ', - name: 'zeek.pe.has_debug_data', - type: 'boolean', - }, - 'zeek.pe.section_names': { - category: 'zeek', - description: 'The names of the sections, in order. ', - name: 'zeek.pe.section_names', - type: 'keyword', - }, - 'zeek.radius.username': { - category: 'zeek', - description: 'The username, if present. ', - name: 'zeek.radius.username', - type: 'keyword', - }, - 'zeek.radius.mac': { - category: 'zeek', - description: 'MAC address, if present. ', - name: 'zeek.radius.mac', - type: 'keyword', - }, - 'zeek.radius.framed_addr': { - category: 'zeek', - description: - 'The address given to the network access server, if present. This is only a hint from the RADIUS server and the network access server is not required to honor the address. ', - name: 'zeek.radius.framed_addr', - type: 'ip', - }, - 'zeek.radius.remote_ip': { - category: 'zeek', - description: - 'Remote IP address, if present. This is collected from the Tunnel-Client-Endpoint attribute. ', - name: 'zeek.radius.remote_ip', - type: 'ip', - }, - 'zeek.radius.connect_info': { - category: 'zeek', - description: 'Connect info, if present. ', - name: 'zeek.radius.connect_info', - type: 'keyword', - }, - 'zeek.radius.reply_msg': { - category: 'zeek', - description: - 'Reply message from the server challenge. This is frequently shown to the user authenticating. ', - name: 'zeek.radius.reply_msg', - type: 'keyword', - }, - 'zeek.radius.result': { - category: 'zeek', - description: 'Successful or failed authentication. ', - name: 'zeek.radius.result', - type: 'keyword', - }, - 'zeek.radius.ttl': { - category: 'zeek', - description: - 'The duration between the first request and either the "Access-Accept" message or an error. If the field is empty, it means that either the request or response was not seen. ', - name: 'zeek.radius.ttl', - type: 'integer', - }, - 'zeek.radius.logged': { - category: 'zeek', - description: 'Whether this has already been logged and can be ignored. ', - name: 'zeek.radius.logged', - type: 'boolean', - }, - 'zeek.rdp.cookie': { - category: 'zeek', - description: 'Cookie value used by the client machine. This is typically a username. ', - name: 'zeek.rdp.cookie', - type: 'keyword', - }, - 'zeek.rdp.result': { - category: 'zeek', - description: - "Status result for the connection. It's a mix between RDP negotation failure messages and GCC server create response messages. ", - name: 'zeek.rdp.result', - type: 'keyword', - }, - 'zeek.rdp.security_protocol': { - category: 'zeek', - description: 'Security protocol chosen by the server. ', - name: 'zeek.rdp.security_protocol', - type: 'keyword', - }, - 'zeek.rdp.keyboard_layout': { - category: 'zeek', - description: 'Keyboard layout (language) of the client machine. ', - name: 'zeek.rdp.keyboard_layout', - type: 'keyword', - }, - 'zeek.rdp.client.build': { - category: 'zeek', - description: 'RDP client version used by the client machine. ', - name: 'zeek.rdp.client.build', - type: 'keyword', - }, - 'zeek.rdp.client.client_name': { - category: 'zeek', - description: 'Name of the client machine. ', - name: 'zeek.rdp.client.client_name', - type: 'keyword', - }, - 'zeek.rdp.client.product_id': { - category: 'zeek', - description: 'Product ID of the client machine. ', - name: 'zeek.rdp.client.product_id', - type: 'keyword', - }, - 'zeek.rdp.desktop.width': { - category: 'zeek', - description: 'Desktop width of the client machine. ', - name: 'zeek.rdp.desktop.width', - type: 'integer', - }, - 'zeek.rdp.desktop.height': { - category: 'zeek', - description: 'Desktop height of the client machine. ', - name: 'zeek.rdp.desktop.height', - type: 'integer', - }, - 'zeek.rdp.desktop.color_depth': { - category: 'zeek', - description: 'The color depth requested by the client in the high_color_depth field. ', - name: 'zeek.rdp.desktop.color_depth', - type: 'keyword', - }, - 'zeek.rdp.cert.type': { - category: 'zeek', - description: - 'If the connection is being encrypted with native RDP encryption, this is the type of cert being used. ', - name: 'zeek.rdp.cert.type', - type: 'keyword', - }, - 'zeek.rdp.cert.count': { - category: 'zeek', - description: 'The number of certs seen. X.509 can transfer an entire certificate chain. ', - name: 'zeek.rdp.cert.count', - type: 'integer', - }, - 'zeek.rdp.cert.permanent': { - category: 'zeek', - description: - 'Indicates if the provided certificate or certificate chain is permanent or temporary. ', - name: 'zeek.rdp.cert.permanent', - type: 'boolean', - }, - 'zeek.rdp.encryption.level': { - category: 'zeek', - description: 'Encryption level of the connection. ', - name: 'zeek.rdp.encryption.level', - type: 'keyword', - }, - 'zeek.rdp.encryption.method': { - category: 'zeek', - description: 'Encryption method of the connection. ', - name: 'zeek.rdp.encryption.method', - type: 'keyword', - }, - 'zeek.rdp.done': { - category: 'zeek', - description: 'Track status of logging RDP connections. ', - name: 'zeek.rdp.done', - type: 'boolean', - }, - 'zeek.rdp.ssl': { - category: 'zeek', - description: - '(present if policy/protocols/rdp/indicate_ssl.bro is loaded) Flag the connection if it was seen over SSL. ', - name: 'zeek.rdp.ssl', - type: 'boolean', - }, - 'zeek.rfb.version.client.major': { - category: 'zeek', - description: 'Major version of the client. ', - name: 'zeek.rfb.version.client.major', - type: 'keyword', - }, - 'zeek.rfb.version.client.minor': { - category: 'zeek', - description: 'Minor version of the client. ', - name: 'zeek.rfb.version.client.minor', - type: 'keyword', - }, - 'zeek.rfb.version.server.major': { - category: 'zeek', - description: 'Major version of the server. ', - name: 'zeek.rfb.version.server.major', - type: 'keyword', - }, - 'zeek.rfb.version.server.minor': { - category: 'zeek', - description: 'Minor version of the server. ', - name: 'zeek.rfb.version.server.minor', - type: 'keyword', - }, - 'zeek.rfb.auth.success': { - category: 'zeek', - description: 'Whether or not authentication was successful. ', - name: 'zeek.rfb.auth.success', - type: 'boolean', - }, - 'zeek.rfb.auth.method': { - category: 'zeek', - description: 'Identifier of authentication method used. ', - name: 'zeek.rfb.auth.method', - type: 'keyword', - }, - 'zeek.rfb.share_flag': { - category: 'zeek', - description: 'Whether the client has an exclusive or a shared session. ', - name: 'zeek.rfb.share_flag', - type: 'boolean', - }, - 'zeek.rfb.desktop_name': { - category: 'zeek', - description: 'Name of the screen that is being shared. ', - name: 'zeek.rfb.desktop_name', - type: 'keyword', - }, - 'zeek.rfb.width': { - category: 'zeek', - description: 'Width of the screen that is being shared. ', - name: 'zeek.rfb.width', - type: 'integer', - }, - 'zeek.rfb.height': { - category: 'zeek', - description: 'Height of the screen that is being shared. ', - name: 'zeek.rfb.height', - type: 'integer', - }, - 'zeek.signature.note': { - category: 'zeek', - description: 'Notice associated with signature event. ', - name: 'zeek.signature.note', - type: 'keyword', - }, - 'zeek.signature.sig_id': { - category: 'zeek', - description: 'The name of the signature that matched. ', - name: 'zeek.signature.sig_id', - type: 'keyword', - }, - 'zeek.signature.event_msg': { - category: 'zeek', - description: 'A more descriptive message of the signature-matching event. ', - name: 'zeek.signature.event_msg', - type: 'keyword', - }, - 'zeek.signature.sub_msg': { - category: 'zeek', - description: 'Extracted payload data or extra message. ', - name: 'zeek.signature.sub_msg', - type: 'keyword', - }, - 'zeek.signature.sig_count': { - category: 'zeek', - description: 'Number of sigs, usually from summary count. ', - name: 'zeek.signature.sig_count', - type: 'integer', - }, - 'zeek.signature.host_count': { - category: 'zeek', - description: 'Number of hosts, from a summary count. ', - name: 'zeek.signature.host_count', - type: 'integer', - }, - 'zeek.sip.transaction_depth': { - category: 'zeek', - description: - 'Represents the pipelined depth into the connection of this request/response transaction. ', - name: 'zeek.sip.transaction_depth', - type: 'integer', - }, - 'zeek.sip.sequence.method': { - category: 'zeek', - description: 'Verb used in the SIP request (INVITE, REGISTER etc.). ', - name: 'zeek.sip.sequence.method', - type: 'keyword', - }, - 'zeek.sip.sequence.number': { - category: 'zeek', - description: 'Contents of the CSeq: header from the client. ', - name: 'zeek.sip.sequence.number', - type: 'keyword', - }, - 'zeek.sip.uri': { - category: 'zeek', - description: 'URI used in the request. ', - name: 'zeek.sip.uri', - type: 'keyword', - }, - 'zeek.sip.date': { - category: 'zeek', - description: 'Contents of the Date: header from the client. ', - name: 'zeek.sip.date', - type: 'keyword', - }, - 'zeek.sip.request.from': { - category: 'zeek', - description: - "Contents of the request From: header Note: The tag= value that's usually appended to the sender is stripped off and not logged. ", - name: 'zeek.sip.request.from', - type: 'keyword', - }, - 'zeek.sip.request.to': { - category: 'zeek', - description: 'Contents of the To: header. ', - name: 'zeek.sip.request.to', - type: 'keyword', - }, - 'zeek.sip.request.path': { - category: 'zeek', - description: 'The client message transmission path, as extracted from the headers. ', - name: 'zeek.sip.request.path', - type: 'keyword', - }, - 'zeek.sip.request.body_length': { - category: 'zeek', - description: 'Contents of the Content-Length: header from the client. ', - name: 'zeek.sip.request.body_length', - type: 'long', - }, - 'zeek.sip.response.from': { - category: 'zeek', - description: - "Contents of the response From: header Note: The tag= value that's usually appended to the sender is stripped off and not logged. ", - name: 'zeek.sip.response.from', - type: 'keyword', - }, - 'zeek.sip.response.to': { - category: 'zeek', - description: 'Contents of the response To: header. ', - name: 'zeek.sip.response.to', - type: 'keyword', - }, - 'zeek.sip.response.path': { - category: 'zeek', - description: 'The server message transmission path, as extracted from the headers. ', - name: 'zeek.sip.response.path', - type: 'keyword', - }, - 'zeek.sip.response.body_length': { - category: 'zeek', - description: 'Contents of the Content-Length: header from the server. ', - name: 'zeek.sip.response.body_length', - type: 'long', - }, - 'zeek.sip.reply_to': { - category: 'zeek', - description: 'Contents of the Reply-To: header. ', - name: 'zeek.sip.reply_to', - type: 'keyword', - }, - 'zeek.sip.call_id': { - category: 'zeek', - description: 'Contents of the Call-ID: header from the client. ', - name: 'zeek.sip.call_id', - type: 'keyword', - }, - 'zeek.sip.subject': { - category: 'zeek', - description: 'Contents of the Subject: header from the client. ', - name: 'zeek.sip.subject', - type: 'keyword', - }, - 'zeek.sip.user_agent': { - category: 'zeek', - description: 'Contents of the User-Agent: header from the client. ', - name: 'zeek.sip.user_agent', - type: 'keyword', - }, - 'zeek.sip.status.code': { - category: 'zeek', - description: 'Status code returned by the server. ', - name: 'zeek.sip.status.code', - type: 'integer', - }, - 'zeek.sip.status.msg': { - category: 'zeek', - description: 'Status message returned by the server. ', - name: 'zeek.sip.status.msg', - type: 'keyword', - }, - 'zeek.sip.warning': { - category: 'zeek', - description: 'Contents of the Warning: header. ', - name: 'zeek.sip.warning', - type: 'keyword', - }, - 'zeek.sip.content_type': { - category: 'zeek', - description: 'Contents of the Content-Type: header from the server. ', - name: 'zeek.sip.content_type', - type: 'keyword', - }, - 'zeek.smb_cmd.command': { - category: 'zeek', - description: 'The command sent by the client. ', - name: 'zeek.smb_cmd.command', - type: 'keyword', - }, - 'zeek.smb_cmd.sub_command': { - category: 'zeek', - description: 'The subcommand sent by the client, if present. ', - name: 'zeek.smb_cmd.sub_command', - type: 'keyword', - }, - 'zeek.smb_cmd.argument': { - category: 'zeek', - description: 'Command argument sent by the client, if any. ', - name: 'zeek.smb_cmd.argument', - type: 'keyword', - }, - 'zeek.smb_cmd.status': { - category: 'zeek', - description: "Server reply to the client's command. ", - name: 'zeek.smb_cmd.status', - type: 'keyword', - }, - 'zeek.smb_cmd.rtt': { - category: 'zeek', - description: 'Round trip time from the request to the response. ', - name: 'zeek.smb_cmd.rtt', - type: 'double', - }, - 'zeek.smb_cmd.version': { - category: 'zeek', - description: 'Version of SMB for the command. ', - name: 'zeek.smb_cmd.version', - type: 'keyword', - }, - 'zeek.smb_cmd.username': { - category: 'zeek', - description: 'Authenticated username, if available. ', - name: 'zeek.smb_cmd.username', - type: 'keyword', - }, - 'zeek.smb_cmd.tree': { - category: 'zeek', - description: - 'If this is related to a tree, this is the tree that was used for the current command. ', - name: 'zeek.smb_cmd.tree', - type: 'keyword', - }, - 'zeek.smb_cmd.tree_service': { - category: 'zeek', - description: 'The type of tree (disk share, printer share, named pipe, etc.). ', - name: 'zeek.smb_cmd.tree_service', - type: 'keyword', - }, - 'zeek.smb_cmd.file.name': { - category: 'zeek', - description: 'Filename if one was seen. ', - name: 'zeek.smb_cmd.file.name', - type: 'keyword', - }, - 'zeek.smb_cmd.file.action': { - category: 'zeek', - description: 'Action this log record represents. ', - name: 'zeek.smb_cmd.file.action', - type: 'keyword', - }, - 'zeek.smb_cmd.file.uid': { - category: 'zeek', - description: 'UID of the referenced file. ', - name: 'zeek.smb_cmd.file.uid', - type: 'keyword', - }, - 'zeek.smb_cmd.file.host.tx': { - category: 'zeek', - description: 'Address of the transmitting host. ', - name: 'zeek.smb_cmd.file.host.tx', - type: 'ip', - }, - 'zeek.smb_cmd.file.host.rx': { - category: 'zeek', - description: 'Address of the receiving host. ', - name: 'zeek.smb_cmd.file.host.rx', - type: 'ip', - }, - 'zeek.smb_cmd.smb1_offered_dialects': { - category: 'zeek', - description: - 'Present if base/protocols/smb/smb1-main.bro is loaded. Dialects offered by the client. ', - name: 'zeek.smb_cmd.smb1_offered_dialects', - type: 'keyword', - }, - 'zeek.smb_cmd.smb2_offered_dialects': { - category: 'zeek', - description: - 'Present if base/protocols/smb/smb2-main.bro is loaded. Dialects offered by the client. ', - name: 'zeek.smb_cmd.smb2_offered_dialects', - type: 'integer', - }, - 'zeek.smb_files.action': { - category: 'zeek', - description: 'Action this log record represents. ', - name: 'zeek.smb_files.action', - type: 'keyword', - }, - 'zeek.smb_files.fid': { - category: 'zeek', - description: 'ID referencing this file. ', - name: 'zeek.smb_files.fid', - type: 'integer', - }, - 'zeek.smb_files.name': { - category: 'zeek', - description: 'Filename if one was seen. ', - name: 'zeek.smb_files.name', - type: 'keyword', - }, - 'zeek.smb_files.path': { - category: 'zeek', - description: 'Path pulled from the tree this file was transferred to or from. ', - name: 'zeek.smb_files.path', - type: 'keyword', - }, - 'zeek.smb_files.previous_name': { - category: 'zeek', - description: "If the rename action was seen, this will be the file's previous name. ", - name: 'zeek.smb_files.previous_name', - type: 'keyword', - }, - 'zeek.smb_files.size': { - category: 'zeek', - description: 'Byte size of the file. ', - name: 'zeek.smb_files.size', - type: 'long', - }, - 'zeek.smb_files.times.accessed': { - category: 'zeek', - description: "The file's access time. ", - name: 'zeek.smb_files.times.accessed', - type: 'date', - }, - 'zeek.smb_files.times.changed': { - category: 'zeek', - description: "The file's change time. ", - name: 'zeek.smb_files.times.changed', - type: 'date', - }, - 'zeek.smb_files.times.created': { - category: 'zeek', - description: "The file's create time. ", - name: 'zeek.smb_files.times.created', - type: 'date', - }, - 'zeek.smb_files.times.modified': { - category: 'zeek', - description: "The file's modify time. ", - name: 'zeek.smb_files.times.modified', - type: 'date', - }, - 'zeek.smb_files.uuid': { - category: 'zeek', - description: 'UUID referencing this file if DCE/RPC. ', - name: 'zeek.smb_files.uuid', - type: 'keyword', - }, - 'zeek.smb_mapping.path': { - category: 'zeek', - description: 'Name of the tree path. ', - name: 'zeek.smb_mapping.path', - type: 'keyword', - }, - 'zeek.smb_mapping.service': { - category: 'zeek', - description: 'The type of resource of the tree (disk share, printer share, named pipe, etc.). ', - name: 'zeek.smb_mapping.service', - type: 'keyword', - }, - 'zeek.smb_mapping.native_file_system': { - category: 'zeek', - description: 'File system of the tree. ', - name: 'zeek.smb_mapping.native_file_system', - type: 'keyword', - }, - 'zeek.smb_mapping.share_type': { - category: 'zeek', - description: - 'If this is SMB2, a share type will be included. For SMB1, the type of share will be deduced and included as well. ', - name: 'zeek.smb_mapping.share_type', - type: 'keyword', - }, - 'zeek.smtp.transaction_depth': { - category: 'zeek', - description: - 'A count to represent the depth of this message transaction in a single connection where multiple messages were transferred. ', - name: 'zeek.smtp.transaction_depth', - type: 'integer', - }, - 'zeek.smtp.helo': { - category: 'zeek', - description: 'Contents of the Helo header. ', - name: 'zeek.smtp.helo', - type: 'keyword', - }, - 'zeek.smtp.mail_from': { - category: 'zeek', - description: 'Email addresses found in the MAIL FROM header. ', - name: 'zeek.smtp.mail_from', - type: 'keyword', - }, - 'zeek.smtp.rcpt_to': { - category: 'zeek', - description: 'Email addresses found in the RCPT TO header. ', - name: 'zeek.smtp.rcpt_to', - type: 'keyword', - }, - 'zeek.smtp.date': { - category: 'zeek', - description: 'Contents of the Date header. ', - name: 'zeek.smtp.date', - type: 'date', - }, - 'zeek.smtp.from': { - category: 'zeek', - description: 'Contents of the From header. ', - name: 'zeek.smtp.from', - type: 'keyword', - }, - 'zeek.smtp.to': { - category: 'zeek', - description: 'Contents of the To header. ', - name: 'zeek.smtp.to', - type: 'keyword', - }, - 'zeek.smtp.cc': { - category: 'zeek', - description: 'Contents of the CC header. ', - name: 'zeek.smtp.cc', - type: 'keyword', - }, - 'zeek.smtp.reply_to': { - category: 'zeek', - description: 'Contents of the ReplyTo header. ', - name: 'zeek.smtp.reply_to', - type: 'keyword', - }, - 'zeek.smtp.msg_id': { - category: 'zeek', - description: 'Contents of the MsgID header. ', - name: 'zeek.smtp.msg_id', - type: 'keyword', - }, - 'zeek.smtp.in_reply_to': { - category: 'zeek', - description: 'Contents of the In-Reply-To header. ', - name: 'zeek.smtp.in_reply_to', - type: 'keyword', - }, - 'zeek.smtp.subject': { - category: 'zeek', - description: 'Contents of the Subject header. ', - name: 'zeek.smtp.subject', - type: 'keyword', - }, - 'zeek.smtp.x_originating_ip': { - category: 'zeek', - description: 'Contents of the X-Originating-IP header. ', - name: 'zeek.smtp.x_originating_ip', - type: 'keyword', - }, - 'zeek.smtp.first_received': { - category: 'zeek', - description: 'Contents of the first Received header. ', - name: 'zeek.smtp.first_received', - type: 'keyword', - }, - 'zeek.smtp.second_received': { - category: 'zeek', - description: 'Contents of the second Received header. ', - name: 'zeek.smtp.second_received', - type: 'keyword', - }, - 'zeek.smtp.last_reply': { - category: 'zeek', - description: 'The last message that the server sent to the client. ', - name: 'zeek.smtp.last_reply', - type: 'keyword', - }, - 'zeek.smtp.path': { - category: 'zeek', - description: 'The message transmission path, as extracted from the headers. ', - name: 'zeek.smtp.path', - type: 'ip', - }, - 'zeek.smtp.user_agent': { - category: 'zeek', - description: 'Value of the User-Agent header from the client. ', - name: 'zeek.smtp.user_agent', - type: 'keyword', - }, - 'zeek.smtp.tls': { - category: 'zeek', - description: 'Indicates that the connection has switched to using TLS. ', - name: 'zeek.smtp.tls', - type: 'boolean', - }, - 'zeek.smtp.process_received_from': { - category: 'zeek', - description: 'Indicates if the "Received: from" headers should still be processed. ', - name: 'zeek.smtp.process_received_from', - type: 'boolean', - }, - 'zeek.smtp.has_client_activity': { - category: 'zeek', - description: 'Indicates if client activity has been seen, but not yet logged. ', - name: 'zeek.smtp.has_client_activity', - type: 'boolean', - }, - 'zeek.smtp.fuids': { - category: 'zeek', - description: - '(present if base/protocols/smtp/files.bro is loaded) An ordered vector of file unique IDs seen attached to the message. ', - name: 'zeek.smtp.fuids', - type: 'keyword', - }, - 'zeek.smtp.is_webmail': { - category: 'zeek', - description: 'Indicates if the message was sent through a webmail interface. ', - name: 'zeek.smtp.is_webmail', - type: 'boolean', - }, - 'zeek.snmp.duration': { - category: 'zeek', - description: - 'The amount of time between the first packet beloning to the SNMP session and the latest one seen. ', - name: 'zeek.snmp.duration', - type: 'double', - }, - 'zeek.snmp.version': { - category: 'zeek', - description: 'The version of SNMP being used. ', - name: 'zeek.snmp.version', - type: 'keyword', - }, - 'zeek.snmp.community': { - category: 'zeek', - description: - "The community string of the first SNMP packet associated with the session. This is used as part of SNMP's (v1 and v2c) administrative/security framework. See RFC 1157 or RFC 1901. ", - name: 'zeek.snmp.community', - type: 'keyword', - }, - 'zeek.snmp.get.requests': { - category: 'zeek', - description: - 'The number of variable bindings in GetRequest/GetNextRequest PDUs seen for the session. ', - name: 'zeek.snmp.get.requests', - type: 'integer', - }, - 'zeek.snmp.get.bulk_requests': { - category: 'zeek', - description: 'The number of variable bindings in GetBulkRequest PDUs seen for the session. ', - name: 'zeek.snmp.get.bulk_requests', - type: 'integer', - }, - 'zeek.snmp.get.responses': { - category: 'zeek', - description: - 'The number of variable bindings in GetResponse/Response PDUs seen for the session. ', - name: 'zeek.snmp.get.responses', - type: 'integer', - }, - 'zeek.snmp.set.requests': { - category: 'zeek', - description: 'The number of variable bindings in SetRequest PDUs seen for the session. ', - name: 'zeek.snmp.set.requests', - type: 'integer', - }, - 'zeek.snmp.display_string': { - category: 'zeek', - description: 'A system description of the SNMP responder endpoint. ', - name: 'zeek.snmp.display_string', - type: 'keyword', - }, - 'zeek.snmp.up_since': { - category: 'zeek', - description: "The time at which the SNMP responder endpoint claims it's been up since. ", - name: 'zeek.snmp.up_since', - type: 'date', - }, - 'zeek.socks.version': { - category: 'zeek', - description: 'Protocol version of SOCKS. ', - name: 'zeek.socks.version', - type: 'integer', - }, - 'zeek.socks.user': { - category: 'zeek', - description: 'Username used to request a login to the proxy. ', - name: 'zeek.socks.user', - type: 'keyword', - }, - 'zeek.socks.password': { - category: 'zeek', - description: 'Password used to request a login to the proxy. ', - name: 'zeek.socks.password', - type: 'keyword', - }, - 'zeek.socks.status': { - category: 'zeek', - description: 'Server status for the attempt at using the proxy. ', - name: 'zeek.socks.status', - type: 'keyword', - }, - 'zeek.socks.request.host': { - category: 'zeek', - description: 'Client requested SOCKS address. Could be an address, a name or both. ', - name: 'zeek.socks.request.host', - type: 'keyword', - }, - 'zeek.socks.request.port': { - category: 'zeek', - description: 'Client requested port. ', - name: 'zeek.socks.request.port', - type: 'integer', - }, - 'zeek.socks.bound.host': { - category: 'zeek', - description: 'Server bound address. Could be an address, a name or both. ', - name: 'zeek.socks.bound.host', - type: 'keyword', - }, - 'zeek.socks.bound.port': { - category: 'zeek', - description: 'Server bound port. ', - name: 'zeek.socks.bound.port', - type: 'integer', - }, - 'zeek.socks.capture_password': { - category: 'zeek', - description: 'Determines if the password will be captured for this request. ', - name: 'zeek.socks.capture_password', - type: 'boolean', - }, - 'zeek.ssh.client': { - category: 'zeek', - description: "The client's version string. ", - name: 'zeek.ssh.client', - type: 'keyword', - }, - 'zeek.ssh.direction': { - category: 'zeek', - description: - 'Direction of the connection. If the client was a local host logging into an external host, this would be OUTBOUND. INBOUND would be set for the opposite situation. ', - name: 'zeek.ssh.direction', - type: 'keyword', - }, - 'zeek.ssh.host_key': { - category: 'zeek', - description: "The server's key thumbprint. ", - name: 'zeek.ssh.host_key', - type: 'keyword', - }, - 'zeek.ssh.server': { - category: 'zeek', - description: "The server's version string. ", - name: 'zeek.ssh.server', - type: 'keyword', - }, - 'zeek.ssh.version': { - category: 'zeek', - description: 'SSH major version (1 or 2). ', - name: 'zeek.ssh.version', - type: 'integer', - }, - 'zeek.ssh.algorithm.cipher': { - category: 'zeek', - description: 'The encryption algorithm in use. ', - name: 'zeek.ssh.algorithm.cipher', - type: 'keyword', - }, - 'zeek.ssh.algorithm.compression': { - category: 'zeek', - description: 'The compression algorithm in use. ', - name: 'zeek.ssh.algorithm.compression', - type: 'keyword', - }, - 'zeek.ssh.algorithm.host_key': { - category: 'zeek', - description: "The server host key's algorithm. ", - name: 'zeek.ssh.algorithm.host_key', - type: 'keyword', - }, - 'zeek.ssh.algorithm.key_exchange': { - category: 'zeek', - description: 'The key exchange algorithm in use. ', - name: 'zeek.ssh.algorithm.key_exchange', - type: 'keyword', - }, - 'zeek.ssh.algorithm.mac': { - category: 'zeek', - description: 'The signing (MAC) algorithm in use. ', - name: 'zeek.ssh.algorithm.mac', - type: 'keyword', - }, - 'zeek.ssh.auth.attempts': { - category: 'zeek', - description: - "The number of authentication attemps we observed. There's always at least one, since some servers might support no authentication at all. It's important to note that not all of these are failures, since some servers require two-factor auth (e.g. password AND pubkey). ", - name: 'zeek.ssh.auth.attempts', - type: 'integer', - }, - 'zeek.ssh.auth.success': { - category: 'zeek', - description: 'Authentication result. ', - name: 'zeek.ssh.auth.success', - type: 'boolean', - }, - 'zeek.ssl.version': { - category: 'zeek', - description: 'SSL/TLS version that was logged. ', - name: 'zeek.ssl.version', - type: 'keyword', - }, - 'zeek.ssl.cipher': { - category: 'zeek', - description: 'SSL/TLS cipher suite that was logged. ', - name: 'zeek.ssl.cipher', - type: 'keyword', - }, - 'zeek.ssl.curve': { - category: 'zeek', - description: 'Elliptic curve that was logged when using ECDH/ECDHE. ', - name: 'zeek.ssl.curve', - type: 'keyword', - }, - 'zeek.ssl.resumed': { - category: 'zeek', - description: - 'Flag to indicate if the session was resumed reusing the key material exchanged in an earlier connection. ', - name: 'zeek.ssl.resumed', - type: 'boolean', - }, - 'zeek.ssl.next_protocol': { - category: 'zeek', - description: - 'Next protocol the server chose using the application layer next protocol extension. ', - name: 'zeek.ssl.next_protocol', - type: 'keyword', - }, - 'zeek.ssl.established': { - category: 'zeek', - description: 'Flag to indicate if this ssl session has been established successfully. ', - name: 'zeek.ssl.established', - type: 'boolean', - }, - 'zeek.ssl.validation.status': { - category: 'zeek', - description: 'Result of certificate validation for this connection. ', - name: 'zeek.ssl.validation.status', - type: 'keyword', - }, - 'zeek.ssl.validation.code': { - category: 'zeek', - description: - 'Result of certificate validation for this connection, given as OpenSSL validation code. ', - name: 'zeek.ssl.validation.code', - type: 'keyword', - }, - 'zeek.ssl.last_alert': { - category: 'zeek', - description: 'Last alert that was seen during the connection. ', - name: 'zeek.ssl.last_alert', - type: 'keyword', - }, - 'zeek.ssl.server.name': { - category: 'zeek', - description: - 'Value of the Server Name Indicator SSL/TLS extension. It indicates the server name that the client was requesting. ', - name: 'zeek.ssl.server.name', - type: 'keyword', - }, - 'zeek.ssl.server.cert_chain': { - category: 'zeek', - description: - 'Chain of certificates offered by the server to validate its complete signing chain. ', - name: 'zeek.ssl.server.cert_chain', - type: 'keyword', - }, - 'zeek.ssl.server.cert_chain_fuids': { - category: 'zeek', - description: - 'An ordered vector of certificate file identifiers for the certificates offered by the server. ', - name: 'zeek.ssl.server.cert_chain_fuids', - type: 'keyword', - }, - 'zeek.ssl.server.issuer.common_name': { - category: 'zeek', - description: 'Common name of the signer of the X.509 certificate offered by the server. ', - name: 'zeek.ssl.server.issuer.common_name', - type: 'keyword', - }, - 'zeek.ssl.server.issuer.country': { - category: 'zeek', - description: 'Country code of the signer of the X.509 certificate offered by the server. ', - name: 'zeek.ssl.server.issuer.country', - type: 'keyword', - }, - 'zeek.ssl.server.issuer.locality': { - category: 'zeek', - description: 'Locality of the signer of the X.509 certificate offered by the server. ', - name: 'zeek.ssl.server.issuer.locality', - type: 'keyword', - }, - 'zeek.ssl.server.issuer.organization': { - category: 'zeek', - description: 'Organization of the signer of the X.509 certificate offered by the server. ', - name: 'zeek.ssl.server.issuer.organization', - type: 'keyword', - }, - 'zeek.ssl.server.issuer.organizational_unit': { - category: 'zeek', - description: - 'Organizational unit of the signer of the X.509 certificate offered by the server. ', - name: 'zeek.ssl.server.issuer.organizational_unit', - type: 'keyword', - }, - 'zeek.ssl.server.issuer.state': { - category: 'zeek', - description: - 'State or province name of the signer of the X.509 certificate offered by the server. ', - name: 'zeek.ssl.server.issuer.state', - type: 'keyword', - }, - 'zeek.ssl.server.subject.common_name': { - category: 'zeek', - description: 'Common name of the X.509 certificate offered by the server. ', - name: 'zeek.ssl.server.subject.common_name', - type: 'keyword', - }, - 'zeek.ssl.server.subject.country': { - category: 'zeek', - description: 'Country code of the X.509 certificate offered by the server. ', - name: 'zeek.ssl.server.subject.country', - type: 'keyword', - }, - 'zeek.ssl.server.subject.locality': { - category: 'zeek', - description: 'Locality of the X.509 certificate offered by the server. ', - name: 'zeek.ssl.server.subject.locality', - type: 'keyword', - }, - 'zeek.ssl.server.subject.organization': { - category: 'zeek', - description: 'Organization of the X.509 certificate offered by the server. ', - name: 'zeek.ssl.server.subject.organization', - type: 'keyword', - }, - 'zeek.ssl.server.subject.organizational_unit': { - category: 'zeek', - description: 'Organizational unit of the X.509 certificate offered by the server. ', - name: 'zeek.ssl.server.subject.organizational_unit', - type: 'keyword', - }, - 'zeek.ssl.server.subject.state': { - category: 'zeek', - description: 'State or province name of the X.509 certificate offered by the server. ', - name: 'zeek.ssl.server.subject.state', - type: 'keyword', - }, - 'zeek.ssl.client.cert_chain': { - category: 'zeek', - description: - 'Chain of certificates offered by the client to validate its complete signing chain. ', - name: 'zeek.ssl.client.cert_chain', - type: 'keyword', - }, - 'zeek.ssl.client.cert_chain_fuids': { - category: 'zeek', - description: - 'An ordered vector of certificate file identifiers for the certificates offered by the client. ', - name: 'zeek.ssl.client.cert_chain_fuids', - type: 'keyword', - }, - 'zeek.ssl.client.issuer.common_name': { - category: 'zeek', - description: 'Common name of the signer of the X.509 certificate offered by the client. ', - name: 'zeek.ssl.client.issuer.common_name', - type: 'keyword', - }, - 'zeek.ssl.client.issuer.country': { - category: 'zeek', - description: 'Country code of the signer of the X.509 certificate offered by the client. ', - name: 'zeek.ssl.client.issuer.country', - type: 'keyword', - }, - 'zeek.ssl.client.issuer.locality': { - category: 'zeek', - description: 'Locality of the signer of the X.509 certificate offered by the client. ', - name: 'zeek.ssl.client.issuer.locality', - type: 'keyword', - }, - 'zeek.ssl.client.issuer.organization': { - category: 'zeek', - description: 'Organization of the signer of the X.509 certificate offered by the client. ', - name: 'zeek.ssl.client.issuer.organization', - type: 'keyword', - }, - 'zeek.ssl.client.issuer.organizational_unit': { - category: 'zeek', - description: - 'Organizational unit of the signer of the X.509 certificate offered by the client. ', - name: 'zeek.ssl.client.issuer.organizational_unit', - type: 'keyword', - }, - 'zeek.ssl.client.issuer.state': { - category: 'zeek', - description: - 'State or province name of the signer of the X.509 certificate offered by the client. ', - name: 'zeek.ssl.client.issuer.state', - type: 'keyword', - }, - 'zeek.ssl.client.subject.common_name': { - category: 'zeek', - description: 'Common name of the X.509 certificate offered by the client. ', - name: 'zeek.ssl.client.subject.common_name', - type: 'keyword', - }, - 'zeek.ssl.client.subject.country': { - category: 'zeek', - description: 'Country code of the X.509 certificate offered by the client. ', - name: 'zeek.ssl.client.subject.country', - type: 'keyword', - }, - 'zeek.ssl.client.subject.locality': { - category: 'zeek', - description: 'Locality of the X.509 certificate offered by the client. ', - name: 'zeek.ssl.client.subject.locality', - type: 'keyword', - }, - 'zeek.ssl.client.subject.organization': { - category: 'zeek', - description: 'Organization of the X.509 certificate offered by the client. ', - name: 'zeek.ssl.client.subject.organization', - type: 'keyword', - }, - 'zeek.ssl.client.subject.organizational_unit': { - category: 'zeek', - description: 'Organizational unit of the X.509 certificate offered by the client. ', - name: 'zeek.ssl.client.subject.organizational_unit', - type: 'keyword', - }, - 'zeek.ssl.client.subject.state': { - category: 'zeek', - description: 'State or province name of the X.509 certificate offered by the client. ', - name: 'zeek.ssl.client.subject.state', - type: 'keyword', - }, - 'zeek.stats.peer': { - category: 'zeek', - description: 'Peer that generated this log. Mostly for clusters. ', - name: 'zeek.stats.peer', - type: 'keyword', - }, - 'zeek.stats.memory': { - category: 'zeek', - description: 'Amount of memory currently in use in MB. ', - name: 'zeek.stats.memory', - type: 'integer', - }, - 'zeek.stats.packets.processed': { - category: 'zeek', - description: 'Number of packets processed since the last stats interval. ', - name: 'zeek.stats.packets.processed', - type: 'long', - }, - 'zeek.stats.packets.dropped': { - category: 'zeek', - description: - 'Number of packets dropped since the last stats interval if reading live traffic. ', - name: 'zeek.stats.packets.dropped', - type: 'long', - }, - 'zeek.stats.packets.received': { - category: 'zeek', - description: - 'Number of packets seen on the link since the last stats interval if reading live traffic. ', - name: 'zeek.stats.packets.received', - type: 'long', - }, - 'zeek.stats.bytes.received': { - category: 'zeek', - description: 'Number of bytes received since the last stats interval if reading live traffic. ', - name: 'zeek.stats.bytes.received', - type: 'long', - }, - 'zeek.stats.connections.tcp.active': { - category: 'zeek', - description: 'TCP connections currently in memory. ', - name: 'zeek.stats.connections.tcp.active', - type: 'integer', - }, - 'zeek.stats.connections.tcp.count': { - category: 'zeek', - description: 'TCP connections seen since last stats interval. ', - name: 'zeek.stats.connections.tcp.count', - type: 'integer', - }, - 'zeek.stats.connections.udp.active': { - category: 'zeek', - description: 'UDP connections currently in memory. ', - name: 'zeek.stats.connections.udp.active', - type: 'integer', - }, - 'zeek.stats.connections.udp.count': { - category: 'zeek', - description: 'UDP connections seen since last stats interval. ', - name: 'zeek.stats.connections.udp.count', - type: 'integer', - }, - 'zeek.stats.connections.icmp.active': { - category: 'zeek', - description: 'ICMP connections currently in memory. ', - name: 'zeek.stats.connections.icmp.active', - type: 'integer', - }, - 'zeek.stats.connections.icmp.count': { - category: 'zeek', - description: 'ICMP connections seen since last stats interval. ', - name: 'zeek.stats.connections.icmp.count', - type: 'integer', - }, - 'zeek.stats.events.processed': { - category: 'zeek', - description: 'Number of events processed since the last stats interval. ', - name: 'zeek.stats.events.processed', - type: 'integer', - }, - 'zeek.stats.events.queued': { - category: 'zeek', - description: 'Number of events that have been queued since the last stats interval. ', - name: 'zeek.stats.events.queued', - type: 'integer', - }, - 'zeek.stats.timers.count': { - category: 'zeek', - description: 'Number of timers scheduled since last stats interval. ', - name: 'zeek.stats.timers.count', - type: 'integer', - }, - 'zeek.stats.timers.active': { - category: 'zeek', - description: 'Current number of scheduled timers. ', - name: 'zeek.stats.timers.active', - type: 'integer', - }, - 'zeek.stats.files.count': { - category: 'zeek', - description: 'Number of files seen since last stats interval. ', - name: 'zeek.stats.files.count', - type: 'integer', - }, - 'zeek.stats.files.active': { - category: 'zeek', - description: 'Current number of files actively being seen. ', - name: 'zeek.stats.files.active', - type: 'integer', - }, - 'zeek.stats.dns_requests.count': { - category: 'zeek', - description: 'Number of DNS requests seen since last stats interval. ', - name: 'zeek.stats.dns_requests.count', - type: 'integer', - }, - 'zeek.stats.dns_requests.active': { - category: 'zeek', - description: 'Current number of DNS requests awaiting a reply. ', - name: 'zeek.stats.dns_requests.active', - type: 'integer', - }, - 'zeek.stats.reassembly_size.tcp': { - category: 'zeek', - description: 'Current size of TCP data in reassembly. ', - name: 'zeek.stats.reassembly_size.tcp', - type: 'integer', - }, - 'zeek.stats.reassembly_size.file': { - category: 'zeek', - description: 'Current size of File data in reassembly. ', - name: 'zeek.stats.reassembly_size.file', - type: 'integer', - }, - 'zeek.stats.reassembly_size.frag': { - category: 'zeek', - description: 'Current size of packet fragment data in reassembly. ', - name: 'zeek.stats.reassembly_size.frag', - type: 'integer', - }, - 'zeek.stats.reassembly_size.unknown': { - category: 'zeek', - description: 'Current size of unknown data in reassembly (this is only PIA buffer right now). ', - name: 'zeek.stats.reassembly_size.unknown', - type: 'integer', - }, - 'zeek.stats.timestamp_lag': { - category: 'zeek', - description: 'Lag between the wall clock and packet timestamps if reading live traffic. ', - name: 'zeek.stats.timestamp_lag', - type: 'integer', - }, - 'zeek.syslog.facility': { - category: 'zeek', - description: 'Syslog facility for the message. ', - name: 'zeek.syslog.facility', - type: 'keyword', - }, - 'zeek.syslog.severity': { - category: 'zeek', - description: 'Syslog severity for the message. ', - name: 'zeek.syslog.severity', - type: 'keyword', - }, - 'zeek.syslog.message': { - category: 'zeek', - description: 'The plain text message. ', - name: 'zeek.syslog.message', - type: 'keyword', - }, - 'zeek.tunnel.type': { - category: 'zeek', - description: 'The type of tunnel. ', - name: 'zeek.tunnel.type', - type: 'keyword', - }, - 'zeek.tunnel.action': { - category: 'zeek', - description: 'The type of activity that occurred. ', - name: 'zeek.tunnel.action', - type: 'keyword', - }, - 'zeek.weird.name': { - category: 'zeek', - description: 'The name of the weird that occurred. ', - name: 'zeek.weird.name', - type: 'keyword', - }, - 'zeek.weird.additional_info': { - category: 'zeek', - description: 'Additional information accompanying the weird if any. ', - name: 'zeek.weird.additional_info', - type: 'keyword', - }, - 'zeek.weird.notice': { - category: 'zeek', - description: 'Indicate if this weird was also turned into a notice. ', - name: 'zeek.weird.notice', - type: 'boolean', - }, - 'zeek.weird.peer': { - category: 'zeek', - description: - 'The peer that originated this weird. This is helpful in cluster deployments if a particular cluster node is having trouble to help identify which node is having trouble. ', - name: 'zeek.weird.peer', - type: 'keyword', - }, - 'zeek.weird.identifier': { - category: 'zeek', - description: - 'This field is to be provided when a weird is generated for the purpose of deduplicating weirds. The identifier string should be unique for a single instance of the weird. This field is used to define when a weird is conceptually a duplicate of a previous weird. ', - name: 'zeek.weird.identifier', - type: 'keyword', - }, - 'zeek.x509.id': { - category: 'zeek', - description: 'File id of this certificate. ', - name: 'zeek.x509.id', - type: 'keyword', - }, - 'zeek.x509.certificate.version': { - category: 'zeek', - description: 'Version number. ', - name: 'zeek.x509.certificate.version', - type: 'integer', - }, - 'zeek.x509.certificate.serial': { - category: 'zeek', - description: 'Serial number. ', - name: 'zeek.x509.certificate.serial', - type: 'keyword', - }, - 'zeek.x509.certificate.subject.country': { - category: 'zeek', - description: 'Country provided in the certificate subject. ', - name: 'zeek.x509.certificate.subject.country', - type: 'keyword', - }, - 'zeek.x509.certificate.subject.common_name': { - category: 'zeek', - description: 'Common name provided in the certificate subject. ', - name: 'zeek.x509.certificate.subject.common_name', - type: 'keyword', - }, - 'zeek.x509.certificate.subject.locality': { - category: 'zeek', - description: 'Locality provided in the certificate subject. ', - name: 'zeek.x509.certificate.subject.locality', - type: 'keyword', - }, - 'zeek.x509.certificate.subject.organization': { - category: 'zeek', - description: 'Organization provided in the certificate subject. ', - name: 'zeek.x509.certificate.subject.organization', - type: 'keyword', - }, - 'zeek.x509.certificate.subject.organizational_unit': { - category: 'zeek', - description: 'Organizational unit provided in the certificate subject. ', - name: 'zeek.x509.certificate.subject.organizational_unit', - type: 'keyword', - }, - 'zeek.x509.certificate.subject.state': { - category: 'zeek', - description: 'State or province provided in the certificate subject. ', - name: 'zeek.x509.certificate.subject.state', - type: 'keyword', - }, - 'zeek.x509.certificate.issuer.country': { - category: 'zeek', - description: 'Country provided in the certificate issuer field. ', - name: 'zeek.x509.certificate.issuer.country', - type: 'keyword', - }, - 'zeek.x509.certificate.issuer.common_name': { - category: 'zeek', - description: 'Common name provided in the certificate issuer field. ', - name: 'zeek.x509.certificate.issuer.common_name', - type: 'keyword', - }, - 'zeek.x509.certificate.issuer.locality': { - category: 'zeek', - description: 'Locality provided in the certificate issuer field. ', - name: 'zeek.x509.certificate.issuer.locality', - type: 'keyword', - }, - 'zeek.x509.certificate.issuer.organization': { - category: 'zeek', - description: 'Organization provided in the certificate issuer field. ', - name: 'zeek.x509.certificate.issuer.organization', - type: 'keyword', - }, - 'zeek.x509.certificate.issuer.organizational_unit': { - category: 'zeek', - description: 'Organizational unit provided in the certificate issuer field. ', - name: 'zeek.x509.certificate.issuer.organizational_unit', - type: 'keyword', - }, - 'zeek.x509.certificate.issuer.state': { - category: 'zeek', - description: 'State or province provided in the certificate issuer field. ', - name: 'zeek.x509.certificate.issuer.state', - type: 'keyword', - }, - 'zeek.x509.certificate.common_name': { - category: 'zeek', - description: 'Last (most specific) common name. ', - name: 'zeek.x509.certificate.common_name', - type: 'keyword', - }, - 'zeek.x509.certificate.valid.from': { - category: 'zeek', - description: 'Timestamp before when certificate is not valid. ', - name: 'zeek.x509.certificate.valid.from', - type: 'date', - }, - 'zeek.x509.certificate.valid.until': { - category: 'zeek', - description: 'Timestamp after when certificate is not valid. ', - name: 'zeek.x509.certificate.valid.until', - type: 'date', - }, - 'zeek.x509.certificate.key.algorithm': { - category: 'zeek', - description: 'Name of the key algorithm. ', - name: 'zeek.x509.certificate.key.algorithm', - type: 'keyword', - }, - 'zeek.x509.certificate.key.type': { - category: 'zeek', - description: 'Key type, if key parseable by openssl (either rsa, dsa or ec). ', - name: 'zeek.x509.certificate.key.type', - type: 'keyword', - }, - 'zeek.x509.certificate.key.length': { - category: 'zeek', - description: 'Key length in bits. ', - name: 'zeek.x509.certificate.key.length', - type: 'integer', - }, - 'zeek.x509.certificate.signature_algorithm': { - category: 'zeek', - description: 'Name of the signature algorithm. ', - name: 'zeek.x509.certificate.signature_algorithm', - type: 'keyword', - }, - 'zeek.x509.certificate.exponent': { - category: 'zeek', - description: 'Exponent, if RSA-certificate. ', - name: 'zeek.x509.certificate.exponent', - type: 'keyword', - }, - 'zeek.x509.certificate.curve': { - category: 'zeek', - description: 'Curve, if EC-certificate. ', - name: 'zeek.x509.certificate.curve', - type: 'keyword', - }, - 'zeek.x509.san.dns': { - category: 'zeek', - description: 'List of DNS entries in SAN. ', - name: 'zeek.x509.san.dns', - type: 'keyword', - }, - 'zeek.x509.san.uri': { - category: 'zeek', - description: 'List of URI entries in SAN. ', - name: 'zeek.x509.san.uri', - type: 'keyword', - }, - 'zeek.x509.san.email': { - category: 'zeek', - description: 'List of email entries in SAN. ', - name: 'zeek.x509.san.email', - type: 'keyword', - }, - 'zeek.x509.san.ip': { - category: 'zeek', - description: 'List of IP entries in SAN. ', - name: 'zeek.x509.san.ip', - type: 'ip', - }, - 'zeek.x509.san.other_fields': { - category: 'zeek', - description: 'True if the certificate contained other, not recognized or parsed name fields. ', - name: 'zeek.x509.san.other_fields', - type: 'boolean', - }, - 'zeek.x509.basic_constraints.certificate_authority': { - category: 'zeek', - description: 'CA flag set or not. ', - name: 'zeek.x509.basic_constraints.certificate_authority', - type: 'boolean', - }, - 'zeek.x509.basic_constraints.path_length': { - category: 'zeek', - description: 'Maximum path length. ', - name: 'zeek.x509.basic_constraints.path_length', - type: 'integer', - }, - 'zeek.x509.log_cert': { - category: 'zeek', - description: - 'Present if policy/protocols/ssl/log-hostcerts-only.bro is loaded Logging of certificate is suppressed if set to F. ', - name: 'zeek.x509.log_cert', - type: 'boolean', - }, - 'zookeeper.audit.session': { - category: 'zookeeper', - description: 'Client session id ', - name: 'zookeeper.audit.session', - type: 'keyword', - }, - 'zookeeper.audit.znode': { - category: 'zookeeper', - description: 'Path of the znode ', - name: 'zookeeper.audit.znode', - type: 'keyword', - }, - 'zookeeper.audit.znode_type': { - category: 'zookeeper', - description: 'Type of znode in case of creation operation ', - name: 'zookeeper.audit.znode_type', - type: 'keyword', - }, - 'zookeeper.audit.acl': { - category: 'zookeeper', - description: - 'String representation of znode ACL like cdrwa(create, delete,read, write, admin). This is logged only for setAcl operation ', - name: 'zookeeper.audit.acl', - type: 'keyword', - }, - 'zookeeper.audit.result': { - category: 'zookeeper', - description: - 'Result of the operation. Possible values are (success/failure/invoked). Result "invoked" is used for serverStop operation because stop is logged before ensuring that server actually stopped. ', - name: 'zookeeper.audit.result', - type: 'keyword', - }, - 'zookeeper.audit.user': { - category: 'zookeeper', - description: 'Comma separated list of users who are associate with a client session ', - name: 'zookeeper.audit.user', - type: 'keyword', - }, - 'zookeeper.log': { - category: 'zookeeper', - description: 'ZooKeeper logs. ', - name: 'zookeeper.log', - type: 'group', - }, - 'zoom.master_account_id': { - category: 'zoom', - description: 'Master Account related to a specific Sub Account ', - name: 'zoom.master_account_id', - type: 'keyword', - }, - 'zoom.sub_account_id': { - category: 'zoom', - description: 'Related Sub Account ', - name: 'zoom.sub_account_id', - type: 'keyword', - }, - 'zoom.operator_id': { - category: 'zoom', - description: 'UserID that triggered the event ', - name: 'zoom.operator_id', - type: 'keyword', - }, - 'zoom.operator': { - category: 'zoom', - description: 'Username/Email related to the user that triggered the event ', - name: 'zoom.operator', - type: 'keyword', - }, - 'zoom.account_id': { - category: 'zoom', - description: 'Related accountID to the event ', - name: 'zoom.account_id', - type: 'keyword', - }, - 'zoom.timestamp': { - category: 'zoom', - description: 'Timestamp related to the event ', - name: 'zoom.timestamp', - type: 'date', - }, - 'zoom.creation_type': { - category: 'zoom', - description: 'Creation type ', - name: 'zoom.creation_type', - type: 'keyword', - }, - 'zoom.account.owner_id': { - category: 'zoom', - description: 'UserID of the user whose sub account was created/disassociated ', - name: 'zoom.account.owner_id', - type: 'keyword', - }, - 'zoom.account.email': { - category: 'zoom', - description: 'Email related to the user the action was performed on ', - name: 'zoom.account.email', - type: 'keyword', - }, - 'zoom.account.owner_email': { - category: 'zoom', - description: 'Email of the user whose sub account was created/disassociated ', - name: 'zoom.account.owner_email', - type: 'keyword', - }, - 'zoom.account.account_name': { - category: 'zoom', - description: 'When an account name is updated, this is the new value set ', - name: 'zoom.account.account_name', - type: 'keyword', - }, - 'zoom.account.account_alias': { - category: 'zoom', - description: 'When an account alias is updated, this is the new value set ', - name: 'zoom.account.account_alias', - type: 'keyword', - }, - 'zoom.account.account_support_name': { - category: 'zoom', - description: 'When an account support_name is updated, this is the new value set ', - name: 'zoom.account.account_support_name', - type: 'keyword', - }, - 'zoom.account.account_support_email': { - category: 'zoom', - description: 'When an account support_email is updated, this is the new value set ', - name: 'zoom.account.account_support_email', - type: 'keyword', - }, - 'zoom.chat_channel.name': { - category: 'zoom', - description: 'The name of the channel that has been added/modified/deleted ', - name: 'zoom.chat_channel.name', - type: 'keyword', - }, - 'zoom.chat_channel.id': { - category: 'zoom', - description: 'The ID of the channel that has been added/modified/deleted ', - name: 'zoom.chat_channel.id', - type: 'keyword', - }, - 'zoom.chat_channel.type': { - category: 'zoom', - description: - 'Type of channel related to the event. Can be 1(Invite-Only), 2(Private) or 3(Public) ', - name: 'zoom.chat_channel.type', - type: 'keyword', - }, - 'zoom.chat_message.id': { - category: 'zoom', - description: 'Unique ID of the related chat message ', - name: 'zoom.chat_message.id', - type: 'keyword', - }, - 'zoom.chat_message.type': { - category: 'zoom', - description: 'Type of message, can be either "to_contact" or "to_channel" ', - name: 'zoom.chat_message.type', - type: 'keyword', - }, - 'zoom.chat_message.session_id': { - category: 'zoom', - description: 'SessionID for the channel related to the message ', - name: 'zoom.chat_message.session_id', - type: 'keyword', - }, - 'zoom.chat_message.contact_email': { - category: 'zoom', - description: 'Email address related to the user sending the message ', - name: 'zoom.chat_message.contact_email', - type: 'keyword', - }, - 'zoom.chat_message.contact_id': { - category: 'zoom', - description: 'UserID belonging to the user receiving a message ', - name: 'zoom.chat_message.contact_id', - type: 'keyword', - }, - 'zoom.chat_message.channel_id': { - category: 'zoom', - description: 'ChannelID related to the message ', - name: 'zoom.chat_message.channel_id', - type: 'keyword', - }, - 'zoom.chat_message.channel_name': { - category: 'zoom', - description: 'Channel name related to the message ', - name: 'zoom.chat_message.channel_name', - type: 'keyword', - }, - 'zoom.chat_message.message': { - category: 'zoom', - description: 'A string containing the full message that was sent ', - name: 'zoom.chat_message.message', - type: 'keyword', - }, - 'zoom.meeting.id': { - category: 'zoom', - description: 'Unique ID of the related meeting ', - name: 'zoom.meeting.id', - type: 'keyword', - }, - 'zoom.meeting.uuid': { - category: 'zoom', - description: 'The UUID of the related meeting ', - name: 'zoom.meeting.uuid', - type: 'keyword', - }, - 'zoom.meeting.host_id': { - category: 'zoom', - description: 'The UserID of the configured meeting host ', - name: 'zoom.meeting.host_id', - type: 'keyword', - }, - 'zoom.meeting.topic': { - category: 'zoom', - description: 'Topic of the related meeting ', - name: 'zoom.meeting.topic', - type: 'keyword', - }, - 'zoom.meeting.type': { - category: 'zoom', - description: 'Type of meeting created ', - name: 'zoom.meeting.type', - type: 'keyword', - }, - 'zoom.meeting.start_time': { - category: 'zoom', - description: 'Date and time the meeting started ', - name: 'zoom.meeting.start_time', - type: 'date', - }, - 'zoom.meeting.timezone': { - category: 'zoom', - description: 'Which timezone is used for the meeting timestamps ', - name: 'zoom.meeting.timezone', - type: 'keyword', - }, - 'zoom.meeting.duration': { - category: 'zoom', - description: 'The duration of a meeting in minutes ', - name: 'zoom.meeting.duration', - type: 'long', - }, - 'zoom.meeting.issues': { - category: 'zoom', - description: - 'When a user reports an issue with the meeting, for example: "Unstable audio quality" ', - name: 'zoom.meeting.issues', - type: 'keyword', - }, - 'zoom.meeting.password': { - category: 'zoom', - description: 'Password related to the meeting ', - name: 'zoom.meeting.password', - type: 'keyword', - }, - 'zoom.phone.id': { - category: 'zoom', - description: 'Unique ID for the phone or conversation ', - name: 'zoom.phone.id', - type: 'keyword', - }, - 'zoom.phone.user_id': { - category: 'zoom', - description: 'UserID for the phone owner related to a Call Log being completed ', - name: 'zoom.phone.user_id', - type: 'keyword', - }, - 'zoom.phone.download_url': { - category: 'zoom', - description: 'Download URL for the voicemail ', - name: 'zoom.phone.download_url', - type: 'keyword', - }, - 'zoom.phone.ringing_start_time': { - category: 'zoom', - description: 'The timestamp when a ringtone was established to the callee ', - name: 'zoom.phone.ringing_start_time', - type: 'date', - }, - 'zoom.phone.connected_start_time': { - category: 'zoom', - description: 'The date and time when a ringtone was established to the callee ', - name: 'zoom.phone.connected_start_time', - type: 'date', - }, - 'zoom.phone.answer_start_time': { - category: 'zoom', - description: 'The date and time when the call was answered ', - name: 'zoom.phone.answer_start_time', - type: 'date', - }, - 'zoom.phone.call_end_time': { - category: 'zoom', - description: 'The date and time when the call ended ', - name: 'zoom.phone.call_end_time', - type: 'date', - }, - 'zoom.phone.call_id': { - category: 'zoom', - description: 'Unique ID of the related call ', - name: 'zoom.phone.call_id', - type: 'keyword', - }, - 'zoom.phone.duration': { - category: 'zoom', - description: 'Duration of a voicemail in minutes ', - name: 'zoom.phone.duration', - type: 'long', - }, - 'zoom.phone.caller.id': { - category: 'zoom', - description: 'UserID of the caller related to the voicemail/call ', - name: 'zoom.phone.caller.id', - type: 'keyword', - }, - 'zoom.phone.caller.user_id': { - category: 'zoom', - description: 'UserID of the person which initiated the call ', - name: 'zoom.phone.caller.user_id', - type: 'keyword', - }, - 'zoom.phone.caller.number_type': { - category: 'zoom', - description: 'The type of number, can be 1(Internal) or 2(External) ', - name: 'zoom.phone.caller.number_type', - type: 'keyword', - }, - 'zoom.phone.caller.name': { - category: 'zoom', - description: 'The name of the related callee ', - name: 'zoom.phone.caller.name', - type: 'keyword', - }, - 'zoom.phone.caller.phone_number': { - category: 'zoom', - description: 'Phone Number of the caller related to the call ', - name: 'zoom.phone.caller.phone_number', - type: 'keyword', - }, - 'zoom.phone.caller.extension_type': { - category: 'zoom', - description: - 'Extension type of the caller number, can be user, callQueue, autoReceptionist or shareLineGroup ', - name: 'zoom.phone.caller.extension_type', - type: 'keyword', - }, - 'zoom.phone.caller.extension_number': { - category: 'zoom', - description: 'Extension number of the caller ', - name: 'zoom.phone.caller.extension_number', - type: 'keyword', - }, - 'zoom.phone.caller.timezone': { - category: 'zoom', - description: 'Timezone of the caller ', - name: 'zoom.phone.caller.timezone', - type: 'keyword', - }, - 'zoom.phone.caller.device_type': { - category: 'zoom', - description: 'Device type used by the caller ', - name: 'zoom.phone.caller.device_type', - type: 'keyword', - }, - 'zoom.phone.callee.id': { - category: 'zoom', - description: 'UserID of the callee related to the voicemail/call ', - name: 'zoom.phone.callee.id', - type: 'keyword', - }, - 'zoom.phone.callee.user_id': { - category: 'zoom', - description: 'UserID of the related callee of a voicemail/call ', - name: 'zoom.phone.callee.user_id', - type: 'keyword', - }, - 'zoom.phone.callee.name': { - category: 'zoom', - description: 'The name of the related callee ', - name: 'zoom.phone.callee.name', - type: 'keyword', - }, - 'zoom.phone.callee.number_type': { - category: 'zoom', - description: 'The type of number, can be 1(Internal) or 2(External) ', - name: 'zoom.phone.callee.number_type', - type: 'keyword', - }, - 'zoom.phone.callee.phone_number': { - category: 'zoom', - description: 'Phone Number of the callee related to the call ', - name: 'zoom.phone.callee.phone_number', - type: 'keyword', - }, - 'zoom.phone.callee.extension_type': { - category: 'zoom', - description: - 'Extension type of the callee number, can be user, callQueue, autoReceptionist or shareLineGroup ', - name: 'zoom.phone.callee.extension_type', - type: 'keyword', - }, - 'zoom.phone.callee.extension_number': { - category: 'zoom', - description: 'Extension number of the callee related to the call ', - name: 'zoom.phone.callee.extension_number', - type: 'keyword', - }, - 'zoom.phone.callee.timezone': { - category: 'zoom', - description: 'Timezone of the callee related to the call ', - name: 'zoom.phone.callee.timezone', - type: 'keyword', - }, - 'zoom.phone.callee.device_type': { - category: 'zoom', - description: 'Device type used by the callee related to the call ', - name: 'zoom.phone.callee.device_type', - type: 'keyword', - }, - 'zoom.phone.date_time': { - category: 'zoom', - description: 'Date and time of the related phone event ', - name: 'zoom.phone.date_time', - type: 'date', - }, - 'zoom.recording.id': { - category: 'zoom', - description: 'Unique ID of the related recording ', - name: 'zoom.recording.id', - type: 'keyword', - }, - 'zoom.recording.uuid': { - category: 'zoom', - description: 'UUID of the related recording ', - name: 'zoom.recording.uuid', - type: 'keyword', - }, - 'zoom.recording.host_id': { - category: 'zoom', - description: 'UserID of the host of the meeting that was recorded ', - name: 'zoom.recording.host_id', - type: 'keyword', - }, - 'zoom.recording.topic': { - category: 'zoom', - description: 'Topic of the meeting related to the recording ', - name: 'zoom.recording.topic', - type: 'keyword', - }, - 'zoom.recording.type': { - category: 'zoom', - description: - 'Type of recording, can be multiple type of values, please check Zoom documentation ', - name: 'zoom.recording.type', - type: 'keyword', - }, - 'zoom.recording.start_time': { - category: 'zoom', - description: 'The date and time when the recording started ', - name: 'zoom.recording.start_time', - type: 'date', - }, - 'zoom.recording.timezone': { - category: 'zoom', - description: 'The timezone used for the recording date ', - name: 'zoom.recording.timezone', - type: 'keyword', - }, - 'zoom.recording.duration': { - category: 'zoom', - description: 'Duration of the recording in minutes ', - name: 'zoom.recording.duration', - type: 'long', - }, - 'zoom.recording.share_url': { - category: 'zoom', - description: 'The URL to access the recording ', - name: 'zoom.recording.share_url', - type: 'keyword', - }, - 'zoom.recording.total_size': { - category: 'zoom', - description: 'Total size of the recording in bytes ', - name: 'zoom.recording.total_size', - type: 'long', - }, - 'zoom.recording.recording_count': { - category: 'zoom', - description: 'Number of recording files related to the recording ', - name: 'zoom.recording.recording_count', - type: 'long', - }, - 'zoom.recording.recording_file.recording_start': { - category: 'zoom', - description: 'The date and time the recording started ', - name: 'zoom.recording.recording_file.recording_start', - type: 'date', - }, - 'zoom.recording.recording_file.recording_end': { - category: 'zoom', - description: 'The date and time the recording finished ', - name: 'zoom.recording.recording_file.recording_end', - type: 'date', - }, - 'zoom.recording.host_email': { - category: 'zoom', - description: 'Email address of the host related to the meeting that was recorded ', - name: 'zoom.recording.host_email', - type: 'keyword', - }, - 'zoom.user.id': { - category: 'zoom', - description: 'UserID related to the user event ', - name: 'zoom.user.id', - type: 'keyword', - }, - 'zoom.user.first_name': { - category: 'zoom', - description: 'User first name related to the user event ', - name: 'zoom.user.first_name', - type: 'keyword', - }, - 'zoom.user.last_name': { - category: 'zoom', - description: 'User last name related to the user event ', - name: 'zoom.user.last_name', - type: 'keyword', - }, - 'zoom.user.email': { - category: 'zoom', - description: 'User email related to the user event ', - name: 'zoom.user.email', - type: 'keyword', - }, - 'zoom.user.type': { - category: 'zoom', - description: 'User type related to the user event ', - name: 'zoom.user.type', - type: 'keyword', - }, - 'zoom.user.phone_number': { - category: 'zoom', - description: 'User phone number related to the user event ', - name: 'zoom.user.phone_number', - type: 'keyword', - }, - 'zoom.user.phone_country': { - category: 'zoom', - description: 'User country code related to the user event ', - name: 'zoom.user.phone_country', - type: 'keyword', - }, - 'zoom.user.company': { - category: 'zoom', - description: 'User company related to the user event ', - name: 'zoom.user.company', - type: 'keyword', - }, - 'zoom.user.pmi': { - category: 'zoom', - description: 'User personal meeting ID related to the user event ', - name: 'zoom.user.pmi', - type: 'keyword', - }, - 'zoom.user.use_pmi': { - category: 'zoom', - description: 'If a user has PMI enabled ', - name: 'zoom.user.use_pmi', - type: 'boolean', - }, - 'zoom.user.pic_url': { - category: 'zoom', - description: 'Full URL to the profile picture used by the user ', - name: 'zoom.user.pic_url', - type: 'keyword', - }, - 'zoom.user.vanity_name': { - category: 'zoom', - description: 'Name of the personal meeting room related to the user event ', - name: 'zoom.user.vanity_name', - type: 'keyword', - }, - 'zoom.user.timezone': { - category: 'zoom', - description: 'Timezone configured for the user ', - name: 'zoom.user.timezone', - type: 'keyword', - }, - 'zoom.user.language': { - category: 'zoom', - description: 'Language configured for the user ', - name: 'zoom.user.language', - type: 'keyword', - }, - 'zoom.user.host_key': { - category: 'zoom', - description: 'Host key set for the user ', - name: 'zoom.user.host_key', - type: 'keyword', - }, - 'zoom.user.role': { - category: 'zoom', - description: 'The configured role for the user ', - name: 'zoom.user.role', - type: 'keyword', - }, - 'zoom.user.dept': { - category: 'zoom', - description: 'The configured departement for the user ', - name: 'zoom.user.dept', - type: 'keyword', - }, - 'zoom.user.presence_status': { - category: 'zoom', - description: 'Current presence status of user ', - name: 'zoom.user.presence_status', - type: 'keyword', - }, - 'zoom.user.personal_notes': { - category: 'zoom', - description: 'Personal notes for the User ', - name: 'zoom.user.personal_notes', - type: 'keyword', - }, - 'zoom.user.client_type': { - category: 'zoom', - description: 'Type of client used by the user. Can be browser, mac, win, iphone or android ', - name: 'zoom.user.client_type', - type: 'keyword', - }, - 'zoom.user.version': { - category: 'zoom', - description: 'Version of the client used by the user ', - name: 'zoom.user.version', - type: 'keyword', - }, - 'zoom.webinar.id': { - category: 'zoom', - description: 'Unique ID for the related webinar ', - name: 'zoom.webinar.id', - type: 'keyword', - }, - 'zoom.webinar.join_url': { - category: 'zoom', - description: 'The URL configured to join the webinar ', - name: 'zoom.webinar.join_url', - type: 'keyword', - }, - 'zoom.webinar.uuid': { - category: 'zoom', - description: 'UUID for the related webinar ', - name: 'zoom.webinar.uuid', - type: 'keyword', - }, - 'zoom.webinar.host_id': { - category: 'zoom', - description: 'UserID for the configured host of the webinar ', - name: 'zoom.webinar.host_id', - type: 'keyword', - }, - 'zoom.webinar.topic': { - category: 'zoom', - description: 'Meeting topic of the related webinar ', - name: 'zoom.webinar.topic', - type: 'keyword', - }, - 'zoom.webinar.type': { - category: 'zoom', - description: - 'Type of webinar created. Can be either 5(Webinar), 6(Recurring webinar without fixed time) or 9(Recurring webinar with fixed time) ', - name: 'zoom.webinar.type', - type: 'keyword', - }, - 'zoom.webinar.start_time': { - category: 'zoom', - description: 'The date and time when the webinar started ', - name: 'zoom.webinar.start_time', - type: 'date', - }, - 'zoom.webinar.timezone': { - category: 'zoom', - description: 'Timezone used for the dates related to the webinar ', - name: 'zoom.webinar.timezone', - type: 'keyword', - }, - 'zoom.webinar.duration': { - category: 'zoom', - description: 'Duration of the webinar in minutes ', - name: 'zoom.webinar.duration', - type: 'long', - }, - 'zoom.webinar.agenda': { - category: 'zoom', - description: 'The configured agenda of the webinar ', - name: 'zoom.webinar.agenda', - type: 'keyword', - }, - 'zoom.webinar.password': { - category: 'zoom', - description: 'Password configured to access the webinar ', - name: 'zoom.webinar.password', - type: 'keyword', - }, - 'zoom.webinar.issues': { - category: 'zoom', - description: 'Any reported issues about a webinar is reported in this field ', - name: 'zoom.webinar.issues', - type: 'keyword', - }, - 'zoom.zoomroom.id': { - category: 'zoom', - description: 'Unique ID of the Zoom room ', - name: 'zoom.zoomroom.id', - type: 'keyword', - }, - 'zoom.zoomroom.room_name': { - category: 'zoom', - description: 'The configured name of the Zoom room ', - name: 'zoom.zoomroom.room_name', - type: 'keyword', - }, - 'zoom.zoomroom.calendar_name': { - category: 'zoom', - description: 'Calendar name of the Zoom room ', - name: 'zoom.zoomroom.calendar_name', - type: 'keyword', - }, - 'zoom.zoomroom.calendar_id': { - category: 'zoom', - description: 'Unique ID of the calendar used by the Zoom room ', - name: 'zoom.zoomroom.calendar_id', - type: 'keyword', - }, - 'zoom.zoomroom.event_id': { - category: 'zoom', - description: 'Unique ID of the calendar event associated with the Zoom Room ', - name: 'zoom.zoomroom.event_id', - type: 'keyword', - }, - 'zoom.zoomroom.change_key': { - category: 'zoom', - description: - 'Key used by Microsoft products integration that represents a specific version of a calendar ', - name: 'zoom.zoomroom.change_key', - type: 'keyword', - }, - 'zoom.zoomroom.resource_email': { - category: 'zoom', - description: 'Email address associated with the calendar in use by the Zoom room ', - name: 'zoom.zoomroom.resource_email', - type: 'keyword', - }, - 'zoom.zoomroom.email': { - category: 'zoom', - description: 'Email address associated with the Zoom room itself ', - name: 'zoom.zoomroom.email', - type: 'keyword', - }, - 'zoom.zoomroom.issue': { - category: 'zoom', - description: 'Any reported alerts or issues related to the Zoom room or its equipment ', - name: 'zoom.zoomroom.issue', - type: 'keyword', - }, - 'zoom.zoomroom.alert_type': { - category: 'zoom', - description: - 'An integer value representing the type of alert. The list of alert types can be found in the Zoom documentation ', - name: 'zoom.zoomroom.alert_type', - type: 'keyword', - }, - 'zoom.zoomroom.component': { - category: 'zoom', - description: - 'An integer value representing the type of equipment or component, The list of component types can be found in the Zoom documentation ', - name: 'zoom.zoomroom.component', - type: 'keyword', - }, - 'zoom.zoomroom.alert_kind': { - category: 'zoom', - description: - 'An integer value showing if the Zoom room alert has been either 1(Triggered) or 2(Cleared) ', - name: 'zoom.zoomroom.alert_kind', - type: 'keyword', - }, - 'zoom.registrant.id': { - category: 'zoom', - description: 'Unique ID of the user registering to a meeting or webinar ', - name: 'zoom.registrant.id', - type: 'keyword', - }, - 'zoom.registrant.status': { - category: 'zoom', - description: 'Status of the specific user registration ', - name: 'zoom.registrant.status', - type: 'keyword', - }, - 'zoom.registrant.email': { - category: 'zoom', - description: 'Email of the user registering to a meeting or webinar ', - name: 'zoom.registrant.email', - type: 'keyword', - }, - 'zoom.registrant.first_name': { - category: 'zoom', - description: 'First name of the user registering to a meeting or webinar ', - name: 'zoom.registrant.first_name', - type: 'keyword', - }, - 'zoom.registrant.last_name': { - category: 'zoom', - description: 'Last name of the user registering to a meeting or webinar ', - name: 'zoom.registrant.last_name', - type: 'keyword', - }, - 'zoom.registrant.address': { - category: 'zoom', - description: 'Address of the user registering to a meeting or webinar ', - name: 'zoom.registrant.address', - type: 'keyword', - }, - 'zoom.registrant.city': { - category: 'zoom', - description: 'City of the user registering to a meeting or webinar ', - name: 'zoom.registrant.city', - type: 'keyword', - }, - 'zoom.registrant.country': { - category: 'zoom', - description: 'Country of the user registering to a meeting or webinar ', - name: 'zoom.registrant.country', - type: 'keyword', - }, - 'zoom.registrant.zip': { - category: 'zoom', - description: 'Zip code of the user registering to a meeting or webinar ', - name: 'zoom.registrant.zip', - type: 'keyword', - }, - 'zoom.registrant.state': { - category: 'zoom', - description: 'State of the user registering to a meeting or webinar ', - name: 'zoom.registrant.state', - type: 'keyword', - }, - 'zoom.registrant.phone': { - category: 'zoom', - description: 'Phone number of the user registering to a meeting or webinar ', - name: 'zoom.registrant.phone', - type: 'keyword', - }, - 'zoom.registrant.industry': { - category: 'zoom', - description: 'Related industry of the user registering to a meeting or webinar ', - name: 'zoom.registrant.industry', - type: 'keyword', - }, - 'zoom.registrant.org': { - category: 'zoom', - description: 'Organization related to the user registering to a meeting or webinar ', - name: 'zoom.registrant.org', - type: 'keyword', - }, - 'zoom.registrant.job_title': { - category: 'zoom', - description: 'Job title of the user registering to a meeting or webinar ', - name: 'zoom.registrant.job_title', - type: 'keyword', - }, - 'zoom.registrant.purchasing_time_frame': { - category: 'zoom', - description: 'Choosen purchase timeframe of the user registering to a meeting or webinar ', - name: 'zoom.registrant.purchasing_time_frame', - type: 'keyword', - }, - 'zoom.registrant.role_in_purchase_process': { - category: 'zoom', - description: - 'Choosen role in a purchase process related to the user registering to a meeting or webinar ', - name: 'zoom.registrant.role_in_purchase_process', - type: 'keyword', - }, - 'zoom.registrant.no_of_employees': { - category: 'zoom', - description: 'Number of employees choosen by the user registering to a meeting or webinar ', - name: 'zoom.registrant.no_of_employees', - type: 'keyword', - }, - 'zoom.registrant.comments': { - category: 'zoom', - description: 'Comments left by the user registering to a meeting or webinar ', - name: 'zoom.registrant.comments', - type: 'keyword', - }, - 'zoom.registrant.join_url': { - category: 'zoom', - description: 'The URL that the registrant can use to join the webinar ', - name: 'zoom.registrant.join_url', - type: 'keyword', - }, - 'zoom.participant.id': { - category: 'zoom', - description: 'Unique ID of the participant related to a meeting ', - name: 'zoom.participant.id', - type: 'keyword', - }, - 'zoom.participant.user_id': { - category: 'zoom', - description: 'UserID of the participant related to a meeting ', - name: 'zoom.participant.user_id', - type: 'keyword', - }, - 'zoom.participant.user_name': { - category: 'zoom', - description: 'Username of the participant related to a meeting ', - name: 'zoom.participant.user_name', - type: 'keyword', - }, - 'zoom.participant.join_time': { - category: 'zoom', - description: 'The date and time a participant joined a meeting ', - name: 'zoom.participant.join_time', - type: 'date', - }, - 'zoom.participant.leave_time': { - category: 'zoom', - description: 'The date and time a participant left a meeting ', - name: 'zoom.participant.leave_time', - type: 'date', - }, - 'zoom.participant.sharing_details.link_source': { - category: 'zoom', - description: 'Method of sharing with dropbox integration ', - name: 'zoom.participant.sharing_details.link_source', - type: 'keyword', - }, - 'zoom.participant.sharing_details.content': { - category: 'zoom', - description: 'Type of content that was shared ', - name: 'zoom.participant.sharing_details.content', - type: 'keyword', - }, - 'zoom.participant.sharing_details.file_link': { - category: 'zoom', - description: 'The file link that was shared ', - name: 'zoom.participant.sharing_details.file_link', - type: 'keyword', - }, - 'zoom.participant.sharing_details.date_time': { - category: 'zoom', - description: 'Timestamp the sharing started ', - name: 'zoom.participant.sharing_details.date_time', - type: 'keyword', - }, - 'zoom.participant.sharing_details.source': { - category: 'zoom', - description: 'The file source that was share ', - name: 'zoom.participant.sharing_details.source', - type: 'keyword', - }, - 'zoom.old_values': { - category: 'zoom', - description: - 'Includes the old values when updating a object like user, meeting, account or webinar ', - name: 'zoom.old_values', - type: 'flattened', - }, - 'zoom.settings': { - category: 'zoom', - description: - 'The current active settings related to a object like user, meeting, account or webinar ', - name: 'zoom.settings', - type: 'flattened', - }, - 'aws-cloudwatch.log_group': { - category: 'aws-cloudwatch', - description: 'The name of the log group to which this event belongs.', - name: 'aws-cloudwatch.log_group', - type: 'keyword', - }, - 'aws-cloudwatch.log_stream': { - category: 'aws-cloudwatch', - description: 'The name of the log stream to which this event belongs.', - name: 'aws-cloudwatch.log_stream', - type: 'keyword', - }, - 'aws-cloudwatch.ingestion_time': { - category: 'aws-cloudwatch', - description: 'The time the event was ingested in AWS CloudWatch.', - name: 'aws-cloudwatch.ingestion_time', - type: 'keyword', - }, - 'bucket.name': { - category: 'bucket', - description: 'Name of the S3 bucket that this log retrieved from. ', - name: 'bucket.name', - type: 'keyword', - }, - 'bucket.arn': { - category: 'bucket', - description: 'ARN of the S3 bucket that this log retrieved from. ', - name: 'bucket.arn', - type: 'keyword', - }, - 'object.key': { - category: 'object', - description: 'Name of the S3 object that this log retrieved from. ', - name: 'object.key', - type: 'keyword', - }, - metadata: { - category: 'base', - description: 'AWS S3 object metadata values.', - name: 'metadata', - type: 'flattened', - }, - 'netflow.type': { - category: 'netflow', - description: 'The type of NetFlow record described by this event. ', - name: 'netflow.type', - type: 'keyword', - }, - 'netflow.exporter.address': { - category: 'netflow', - description: "Exporter's network address in IP:port format. ", - name: 'netflow.exporter.address', - type: 'keyword', - }, - 'netflow.exporter.source_id': { - category: 'netflow', - description: 'Observation domain ID to which this record belongs. ', - name: 'netflow.exporter.source_id', - type: 'long', - }, - 'netflow.exporter.timestamp': { - category: 'netflow', - description: 'Time and date of export. ', - name: 'netflow.exporter.timestamp', - type: 'date', - }, - 'netflow.exporter.uptime_millis': { - category: 'netflow', - description: 'How long the exporter process has been running, in milliseconds. ', - name: 'netflow.exporter.uptime_millis', - type: 'long', - }, - 'netflow.exporter.version': { - category: 'netflow', - description: 'NetFlow version used. ', - name: 'netflow.exporter.version', - type: 'integer', - }, - 'netflow.octet_delta_count': { - category: 'netflow', - name: 'netflow.octet_delta_count', - type: 'long', - }, - 'netflow.packet_delta_count': { - category: 'netflow', - name: 'netflow.packet_delta_count', - type: 'long', - }, - 'netflow.delta_flow_count': { - category: 'netflow', - name: 'netflow.delta_flow_count', - type: 'long', - }, - 'netflow.protocol_identifier': { - category: 'netflow', - name: 'netflow.protocol_identifier', - type: 'short', - }, - 'netflow.ip_class_of_service': { - category: 'netflow', - name: 'netflow.ip_class_of_service', - type: 'short', - }, - 'netflow.tcp_control_bits': { - category: 'netflow', - name: 'netflow.tcp_control_bits', - type: 'integer', - }, - 'netflow.source_transport_port': { - category: 'netflow', - name: 'netflow.source_transport_port', - type: 'integer', - }, - 'netflow.source_ipv4_address': { - category: 'netflow', - name: 'netflow.source_ipv4_address', - type: 'ip', - }, - 'netflow.source_ipv4_prefix_length': { - category: 'netflow', - name: 'netflow.source_ipv4_prefix_length', - type: 'short', - }, - 'netflow.ingress_interface': { - category: 'netflow', - name: 'netflow.ingress_interface', - type: 'long', - }, - 'netflow.destination_transport_port': { - category: 'netflow', - name: 'netflow.destination_transport_port', - type: 'integer', - }, - 'netflow.destination_ipv4_address': { - category: 'netflow', - name: 'netflow.destination_ipv4_address', - type: 'ip', - }, - 'netflow.destination_ipv4_prefix_length': { - category: 'netflow', - name: 'netflow.destination_ipv4_prefix_length', - type: 'short', - }, - 'netflow.egress_interface': { - category: 'netflow', - name: 'netflow.egress_interface', - type: 'long', - }, - 'netflow.ip_next_hop_ipv4_address': { - category: 'netflow', - name: 'netflow.ip_next_hop_ipv4_address', - type: 'ip', - }, - 'netflow.bgp_source_as_number': { - category: 'netflow', - name: 'netflow.bgp_source_as_number', - type: 'long', - }, - 'netflow.bgp_destination_as_number': { - category: 'netflow', - name: 'netflow.bgp_destination_as_number', - type: 'long', - }, - 'netflow.bgp_next_hop_ipv4_address': { - category: 'netflow', - name: 'netflow.bgp_next_hop_ipv4_address', - type: 'ip', - }, - 'netflow.post_mcast_packet_delta_count': { - category: 'netflow', - name: 'netflow.post_mcast_packet_delta_count', - type: 'long', - }, - 'netflow.post_mcast_octet_delta_count': { - category: 'netflow', - name: 'netflow.post_mcast_octet_delta_count', - type: 'long', - }, - 'netflow.flow_end_sys_up_time': { - category: 'netflow', - name: 'netflow.flow_end_sys_up_time', - type: 'long', - }, - 'netflow.flow_start_sys_up_time': { - category: 'netflow', - name: 'netflow.flow_start_sys_up_time', - type: 'long', - }, - 'netflow.post_octet_delta_count': { - category: 'netflow', - name: 'netflow.post_octet_delta_count', - type: 'long', - }, - 'netflow.post_packet_delta_count': { - category: 'netflow', - name: 'netflow.post_packet_delta_count', - type: 'long', - }, - 'netflow.minimum_ip_total_length': { - category: 'netflow', - name: 'netflow.minimum_ip_total_length', - type: 'long', - }, - 'netflow.maximum_ip_total_length': { - category: 'netflow', - name: 'netflow.maximum_ip_total_length', - type: 'long', - }, - 'netflow.source_ipv6_address': { - category: 'netflow', - name: 'netflow.source_ipv6_address', - type: 'ip', - }, - 'netflow.destination_ipv6_address': { - category: 'netflow', - name: 'netflow.destination_ipv6_address', - type: 'ip', - }, - 'netflow.source_ipv6_prefix_length': { - category: 'netflow', - name: 'netflow.source_ipv6_prefix_length', - type: 'short', - }, - 'netflow.destination_ipv6_prefix_length': { - category: 'netflow', - name: 'netflow.destination_ipv6_prefix_length', - type: 'short', - }, - 'netflow.flow_label_ipv6': { - category: 'netflow', - name: 'netflow.flow_label_ipv6', - type: 'long', - }, - 'netflow.icmp_type_code_ipv4': { - category: 'netflow', - name: 'netflow.icmp_type_code_ipv4', - type: 'integer', - }, - 'netflow.igmp_type': { - category: 'netflow', - name: 'netflow.igmp_type', - type: 'short', - }, - 'netflow.sampling_interval': { - category: 'netflow', - name: 'netflow.sampling_interval', - type: 'long', - }, - 'netflow.sampling_algorithm': { - category: 'netflow', - name: 'netflow.sampling_algorithm', - type: 'short', - }, - 'netflow.flow_active_timeout': { - category: 'netflow', - name: 'netflow.flow_active_timeout', - type: 'integer', - }, - 'netflow.flow_idle_timeout': { - category: 'netflow', - name: 'netflow.flow_idle_timeout', - type: 'integer', - }, - 'netflow.engine_type': { - category: 'netflow', - name: 'netflow.engine_type', - type: 'short', - }, - 'netflow.engine_id': { - category: 'netflow', - name: 'netflow.engine_id', - type: 'short', - }, - 'netflow.exported_octet_total_count': { - category: 'netflow', - name: 'netflow.exported_octet_total_count', - type: 'long', - }, - 'netflow.exported_message_total_count': { - category: 'netflow', - name: 'netflow.exported_message_total_count', - type: 'long', - }, - 'netflow.exported_flow_record_total_count': { - category: 'netflow', - name: 'netflow.exported_flow_record_total_count', - type: 'long', - }, - 'netflow.ipv4_router_sc': { - category: 'netflow', - name: 'netflow.ipv4_router_sc', - type: 'ip', - }, - 'netflow.source_ipv4_prefix': { - category: 'netflow', - name: 'netflow.source_ipv4_prefix', - type: 'ip', - }, - 'netflow.destination_ipv4_prefix': { - category: 'netflow', - name: 'netflow.destination_ipv4_prefix', - type: 'ip', - }, - 'netflow.mpls_top_label_type': { - category: 'netflow', - name: 'netflow.mpls_top_label_type', - type: 'short', - }, - 'netflow.mpls_top_label_ipv4_address': { - category: 'netflow', - name: 'netflow.mpls_top_label_ipv4_address', - type: 'ip', - }, - 'netflow.sampler_id': { - category: 'netflow', - name: 'netflow.sampler_id', - type: 'short', - }, - 'netflow.sampler_mode': { - category: 'netflow', - name: 'netflow.sampler_mode', - type: 'short', - }, - 'netflow.sampler_random_interval': { - category: 'netflow', - name: 'netflow.sampler_random_interval', - type: 'long', - }, - 'netflow.class_id': { - category: 'netflow', - name: 'netflow.class_id', - type: 'long', - }, - 'netflow.minimum_ttl': { - category: 'netflow', - name: 'netflow.minimum_ttl', - type: 'short', - }, - 'netflow.maximum_ttl': { - category: 'netflow', - name: 'netflow.maximum_ttl', - type: 'short', - }, - 'netflow.fragment_identification': { - category: 'netflow', - name: 'netflow.fragment_identification', - type: 'long', - }, - 'netflow.post_ip_class_of_service': { - category: 'netflow', - name: 'netflow.post_ip_class_of_service', - type: 'short', - }, - 'netflow.source_mac_address': { - category: 'netflow', - name: 'netflow.source_mac_address', - type: 'keyword', - }, - 'netflow.post_destination_mac_address': { - category: 'netflow', - name: 'netflow.post_destination_mac_address', - type: 'keyword', - }, - 'netflow.vlan_id': { - category: 'netflow', - name: 'netflow.vlan_id', - type: 'integer', - }, - 'netflow.post_vlan_id': { - category: 'netflow', - name: 'netflow.post_vlan_id', - type: 'integer', - }, - 'netflow.ip_version': { - category: 'netflow', - name: 'netflow.ip_version', - type: 'short', - }, - 'netflow.flow_direction': { - category: 'netflow', - name: 'netflow.flow_direction', - type: 'short', - }, - 'netflow.ip_next_hop_ipv6_address': { - category: 'netflow', - name: 'netflow.ip_next_hop_ipv6_address', - type: 'ip', - }, - 'netflow.bgp_next_hop_ipv6_address': { - category: 'netflow', - name: 'netflow.bgp_next_hop_ipv6_address', - type: 'ip', - }, - 'netflow.ipv6_extension_headers': { - category: 'netflow', - name: 'netflow.ipv6_extension_headers', - type: 'long', - }, - 'netflow.mpls_top_label_stack_section': { - category: 'netflow', - name: 'netflow.mpls_top_label_stack_section', - type: 'short', - }, - 'netflow.mpls_label_stack_section2': { - category: 'netflow', - name: 'netflow.mpls_label_stack_section2', - type: 'short', - }, - 'netflow.mpls_label_stack_section3': { - category: 'netflow', - name: 'netflow.mpls_label_stack_section3', - type: 'short', - }, - 'netflow.mpls_label_stack_section4': { - category: 'netflow', - name: 'netflow.mpls_label_stack_section4', - type: 'short', - }, - 'netflow.mpls_label_stack_section5': { - category: 'netflow', - name: 'netflow.mpls_label_stack_section5', - type: 'short', - }, - 'netflow.mpls_label_stack_section6': { - category: 'netflow', - name: 'netflow.mpls_label_stack_section6', - type: 'short', - }, - 'netflow.mpls_label_stack_section7': { - category: 'netflow', - name: 'netflow.mpls_label_stack_section7', - type: 'short', - }, - 'netflow.mpls_label_stack_section8': { - category: 'netflow', - name: 'netflow.mpls_label_stack_section8', - type: 'short', - }, - 'netflow.mpls_label_stack_section9': { - category: 'netflow', - name: 'netflow.mpls_label_stack_section9', - type: 'short', - }, - 'netflow.mpls_label_stack_section10': { - category: 'netflow', - name: 'netflow.mpls_label_stack_section10', - type: 'short', - }, - 'netflow.destination_mac_address': { - category: 'netflow', - name: 'netflow.destination_mac_address', - type: 'keyword', - }, - 'netflow.post_source_mac_address': { - category: 'netflow', - name: 'netflow.post_source_mac_address', - type: 'keyword', - }, - 'netflow.interface_name': { - category: 'netflow', - name: 'netflow.interface_name', - type: 'keyword', - }, - 'netflow.interface_description': { - category: 'netflow', - name: 'netflow.interface_description', - type: 'keyword', - }, - 'netflow.sampler_name': { - category: 'netflow', - name: 'netflow.sampler_name', - type: 'keyword', - }, - 'netflow.octet_total_count': { - category: 'netflow', - name: 'netflow.octet_total_count', - type: 'long', - }, - 'netflow.packet_total_count': { - category: 'netflow', - name: 'netflow.packet_total_count', - type: 'long', - }, - 'netflow.flags_and_sampler_id': { - category: 'netflow', - name: 'netflow.flags_and_sampler_id', - type: 'long', - }, - 'netflow.fragment_offset': { - category: 'netflow', - name: 'netflow.fragment_offset', - type: 'integer', - }, - 'netflow.forwarding_status': { - category: 'netflow', - name: 'netflow.forwarding_status', - type: 'short', - }, - 'netflow.mpls_vpn_route_distinguisher': { - category: 'netflow', - name: 'netflow.mpls_vpn_route_distinguisher', - type: 'short', - }, - 'netflow.mpls_top_label_prefix_length': { - category: 'netflow', - name: 'netflow.mpls_top_label_prefix_length', - type: 'short', - }, - 'netflow.src_traffic_index': { - category: 'netflow', - name: 'netflow.src_traffic_index', - type: 'long', - }, - 'netflow.dst_traffic_index': { - category: 'netflow', - name: 'netflow.dst_traffic_index', - type: 'long', - }, - 'netflow.application_description': { - category: 'netflow', - name: 'netflow.application_description', - type: 'keyword', - }, - 'netflow.application_id': { - category: 'netflow', - name: 'netflow.application_id', - type: 'short', - }, - 'netflow.application_name': { - category: 'netflow', - name: 'netflow.application_name', - type: 'keyword', - }, - 'netflow.post_ip_diff_serv_code_point': { - category: 'netflow', - name: 'netflow.post_ip_diff_serv_code_point', - type: 'short', - }, - 'netflow.multicast_replication_factor': { - category: 'netflow', - name: 'netflow.multicast_replication_factor', - type: 'long', - }, - 'netflow.class_name': { - category: 'netflow', - name: 'netflow.class_name', - type: 'keyword', - }, - 'netflow.classification_engine_id': { - category: 'netflow', - name: 'netflow.classification_engine_id', - type: 'short', - }, - 'netflow.layer2packet_section_offset': { - category: 'netflow', - name: 'netflow.layer2packet_section_offset', - type: 'integer', - }, - 'netflow.layer2packet_section_size': { - category: 'netflow', - name: 'netflow.layer2packet_section_size', - type: 'integer', - }, - 'netflow.layer2packet_section_data': { - category: 'netflow', - name: 'netflow.layer2packet_section_data', - type: 'short', - }, - 'netflow.bgp_next_adjacent_as_number': { - category: 'netflow', - name: 'netflow.bgp_next_adjacent_as_number', - type: 'long', - }, - 'netflow.bgp_prev_adjacent_as_number': { - category: 'netflow', - name: 'netflow.bgp_prev_adjacent_as_number', - type: 'long', - }, - 'netflow.exporter_ipv4_address': { - category: 'netflow', - name: 'netflow.exporter_ipv4_address', - type: 'ip', - }, - 'netflow.exporter_ipv6_address': { - category: 'netflow', - name: 'netflow.exporter_ipv6_address', - type: 'ip', - }, - 'netflow.dropped_octet_delta_count': { - category: 'netflow', - name: 'netflow.dropped_octet_delta_count', - type: 'long', - }, - 'netflow.dropped_packet_delta_count': { - category: 'netflow', - name: 'netflow.dropped_packet_delta_count', - type: 'long', - }, - 'netflow.dropped_octet_total_count': { - category: 'netflow', - name: 'netflow.dropped_octet_total_count', - type: 'long', - }, - 'netflow.dropped_packet_total_count': { - category: 'netflow', - name: 'netflow.dropped_packet_total_count', - type: 'long', - }, - 'netflow.flow_end_reason': { - category: 'netflow', - name: 'netflow.flow_end_reason', - type: 'short', - }, - 'netflow.common_properties_id': { - category: 'netflow', - name: 'netflow.common_properties_id', - type: 'long', - }, - 'netflow.observation_point_id': { - category: 'netflow', - name: 'netflow.observation_point_id', - type: 'long', - }, - 'netflow.icmp_type_code_ipv6': { - category: 'netflow', - name: 'netflow.icmp_type_code_ipv6', - type: 'integer', - }, - 'netflow.mpls_top_label_ipv6_address': { - category: 'netflow', - name: 'netflow.mpls_top_label_ipv6_address', - type: 'ip', - }, - 'netflow.line_card_id': { - category: 'netflow', - name: 'netflow.line_card_id', - type: 'long', - }, - 'netflow.port_id': { - category: 'netflow', - name: 'netflow.port_id', - type: 'long', - }, - 'netflow.metering_process_id': { - category: 'netflow', - name: 'netflow.metering_process_id', - type: 'long', - }, - 'netflow.exporting_process_id': { - category: 'netflow', - name: 'netflow.exporting_process_id', - type: 'long', - }, - 'netflow.template_id': { - category: 'netflow', - name: 'netflow.template_id', - type: 'integer', - }, - 'netflow.wlan_channel_id': { - category: 'netflow', - name: 'netflow.wlan_channel_id', - type: 'short', - }, - 'netflow.wlan_ssid': { - category: 'netflow', - name: 'netflow.wlan_ssid', - type: 'keyword', - }, - 'netflow.flow_id': { - category: 'netflow', - name: 'netflow.flow_id', - type: 'long', - }, - 'netflow.observation_domain_id': { - category: 'netflow', - name: 'netflow.observation_domain_id', - type: 'long', - }, - 'netflow.flow_start_seconds': { - category: 'netflow', - name: 'netflow.flow_start_seconds', - type: 'date', - }, - 'netflow.flow_end_seconds': { - category: 'netflow', - name: 'netflow.flow_end_seconds', - type: 'date', - }, - 'netflow.flow_start_milliseconds': { - category: 'netflow', - name: 'netflow.flow_start_milliseconds', - type: 'date', - }, - 'netflow.flow_end_milliseconds': { - category: 'netflow', - name: 'netflow.flow_end_milliseconds', - type: 'date', - }, - 'netflow.flow_start_microseconds': { - category: 'netflow', - name: 'netflow.flow_start_microseconds', - type: 'date', - }, - 'netflow.flow_end_microseconds': { - category: 'netflow', - name: 'netflow.flow_end_microseconds', - type: 'date', - }, - 'netflow.flow_start_nanoseconds': { - category: 'netflow', - name: 'netflow.flow_start_nanoseconds', - type: 'date', - }, - 'netflow.flow_end_nanoseconds': { - category: 'netflow', - name: 'netflow.flow_end_nanoseconds', - type: 'date', - }, - 'netflow.flow_start_delta_microseconds': { - category: 'netflow', - name: 'netflow.flow_start_delta_microseconds', - type: 'long', - }, - 'netflow.flow_end_delta_microseconds': { - category: 'netflow', - name: 'netflow.flow_end_delta_microseconds', - type: 'long', - }, - 'netflow.system_init_time_milliseconds': { - category: 'netflow', - name: 'netflow.system_init_time_milliseconds', - type: 'date', - }, - 'netflow.flow_duration_milliseconds': { - category: 'netflow', - name: 'netflow.flow_duration_milliseconds', - type: 'long', - }, - 'netflow.flow_duration_microseconds': { - category: 'netflow', - name: 'netflow.flow_duration_microseconds', - type: 'long', - }, - 'netflow.observed_flow_total_count': { - category: 'netflow', - name: 'netflow.observed_flow_total_count', - type: 'long', - }, - 'netflow.ignored_packet_total_count': { - category: 'netflow', - name: 'netflow.ignored_packet_total_count', - type: 'long', - }, - 'netflow.ignored_octet_total_count': { - category: 'netflow', - name: 'netflow.ignored_octet_total_count', - type: 'long', - }, - 'netflow.not_sent_flow_total_count': { - category: 'netflow', - name: 'netflow.not_sent_flow_total_count', - type: 'long', - }, - 'netflow.not_sent_packet_total_count': { - category: 'netflow', - name: 'netflow.not_sent_packet_total_count', - type: 'long', - }, - 'netflow.not_sent_octet_total_count': { - category: 'netflow', - name: 'netflow.not_sent_octet_total_count', - type: 'long', - }, - 'netflow.destination_ipv6_prefix': { - category: 'netflow', - name: 'netflow.destination_ipv6_prefix', - type: 'ip', - }, - 'netflow.source_ipv6_prefix': { - category: 'netflow', - name: 'netflow.source_ipv6_prefix', - type: 'ip', - }, - 'netflow.post_octet_total_count': { - category: 'netflow', - name: 'netflow.post_octet_total_count', - type: 'long', - }, - 'netflow.post_packet_total_count': { - category: 'netflow', - name: 'netflow.post_packet_total_count', - type: 'long', - }, - 'netflow.flow_key_indicator': { - category: 'netflow', - name: 'netflow.flow_key_indicator', - type: 'long', - }, - 'netflow.post_mcast_packet_total_count': { - category: 'netflow', - name: 'netflow.post_mcast_packet_total_count', - type: 'long', - }, - 'netflow.post_mcast_octet_total_count': { - category: 'netflow', - name: 'netflow.post_mcast_octet_total_count', - type: 'long', - }, - 'netflow.icmp_type_ipv4': { - category: 'netflow', - name: 'netflow.icmp_type_ipv4', - type: 'short', - }, - 'netflow.icmp_code_ipv4': { - category: 'netflow', - name: 'netflow.icmp_code_ipv4', - type: 'short', - }, - 'netflow.icmp_type_ipv6': { - category: 'netflow', - name: 'netflow.icmp_type_ipv6', - type: 'short', - }, - 'netflow.icmp_code_ipv6': { - category: 'netflow', - name: 'netflow.icmp_code_ipv6', - type: 'short', - }, - 'netflow.udp_source_port': { - category: 'netflow', - name: 'netflow.udp_source_port', - type: 'integer', - }, - 'netflow.udp_destination_port': { - category: 'netflow', - name: 'netflow.udp_destination_port', - type: 'integer', - }, - 'netflow.tcp_source_port': { - category: 'netflow', - name: 'netflow.tcp_source_port', - type: 'integer', - }, - 'netflow.tcp_destination_port': { - category: 'netflow', - name: 'netflow.tcp_destination_port', - type: 'integer', - }, - 'netflow.tcp_sequence_number': { - category: 'netflow', - name: 'netflow.tcp_sequence_number', - type: 'long', - }, - 'netflow.tcp_acknowledgement_number': { - category: 'netflow', - name: 'netflow.tcp_acknowledgement_number', - type: 'long', - }, - 'netflow.tcp_window_size': { - category: 'netflow', - name: 'netflow.tcp_window_size', - type: 'integer', - }, - 'netflow.tcp_urgent_pointer': { - category: 'netflow', - name: 'netflow.tcp_urgent_pointer', - type: 'integer', - }, - 'netflow.tcp_header_length': { - category: 'netflow', - name: 'netflow.tcp_header_length', - type: 'short', - }, - 'netflow.ip_header_length': { - category: 'netflow', - name: 'netflow.ip_header_length', - type: 'short', - }, - 'netflow.total_length_ipv4': { - category: 'netflow', - name: 'netflow.total_length_ipv4', - type: 'integer', - }, - 'netflow.payload_length_ipv6': { - category: 'netflow', - name: 'netflow.payload_length_ipv6', - type: 'integer', - }, - 'netflow.ip_ttl': { - category: 'netflow', - name: 'netflow.ip_ttl', - type: 'short', - }, - 'netflow.next_header_ipv6': { - category: 'netflow', - name: 'netflow.next_header_ipv6', - type: 'short', - }, - 'netflow.mpls_payload_length': { - category: 'netflow', - name: 'netflow.mpls_payload_length', - type: 'long', - }, - 'netflow.ip_diff_serv_code_point': { - category: 'netflow', - name: 'netflow.ip_diff_serv_code_point', - type: 'short', - }, - 'netflow.ip_precedence': { - category: 'netflow', - name: 'netflow.ip_precedence', - type: 'short', - }, - 'netflow.fragment_flags': { - category: 'netflow', - name: 'netflow.fragment_flags', - type: 'short', - }, - 'netflow.octet_delta_sum_of_squares': { - category: 'netflow', - name: 'netflow.octet_delta_sum_of_squares', - type: 'long', - }, - 'netflow.octet_total_sum_of_squares': { - category: 'netflow', - name: 'netflow.octet_total_sum_of_squares', - type: 'long', - }, - 'netflow.mpls_top_label_ttl': { - category: 'netflow', - name: 'netflow.mpls_top_label_ttl', - type: 'short', - }, - 'netflow.mpls_label_stack_length': { - category: 'netflow', - name: 'netflow.mpls_label_stack_length', - type: 'long', - }, - 'netflow.mpls_label_stack_depth': { - category: 'netflow', - name: 'netflow.mpls_label_stack_depth', - type: 'long', - }, - 'netflow.mpls_top_label_exp': { - category: 'netflow', - name: 'netflow.mpls_top_label_exp', - type: 'short', - }, - 'netflow.ip_payload_length': { - category: 'netflow', - name: 'netflow.ip_payload_length', - type: 'long', - }, - 'netflow.udp_message_length': { - category: 'netflow', - name: 'netflow.udp_message_length', - type: 'integer', - }, - 'netflow.is_multicast': { - category: 'netflow', - name: 'netflow.is_multicast', - type: 'short', - }, - 'netflow.ipv4_ihl': { - category: 'netflow', - name: 'netflow.ipv4_ihl', - type: 'short', - }, - 'netflow.ipv4_options': { - category: 'netflow', - name: 'netflow.ipv4_options', - type: 'long', - }, - 'netflow.tcp_options': { - category: 'netflow', - name: 'netflow.tcp_options', - type: 'long', - }, - 'netflow.padding_octets': { - category: 'netflow', - name: 'netflow.padding_octets', - type: 'short', - }, - 'netflow.collector_ipv4_address': { - category: 'netflow', - name: 'netflow.collector_ipv4_address', - type: 'ip', - }, - 'netflow.collector_ipv6_address': { - category: 'netflow', - name: 'netflow.collector_ipv6_address', - type: 'ip', - }, - 'netflow.export_interface': { - category: 'netflow', - name: 'netflow.export_interface', - type: 'long', - }, - 'netflow.export_protocol_version': { - category: 'netflow', - name: 'netflow.export_protocol_version', - type: 'short', - }, - 'netflow.export_transport_protocol': { - category: 'netflow', - name: 'netflow.export_transport_protocol', - type: 'short', - }, - 'netflow.collector_transport_port': { - category: 'netflow', - name: 'netflow.collector_transport_port', - type: 'integer', - }, - 'netflow.exporter_transport_port': { - category: 'netflow', - name: 'netflow.exporter_transport_port', - type: 'integer', - }, - 'netflow.tcp_syn_total_count': { - category: 'netflow', - name: 'netflow.tcp_syn_total_count', - type: 'long', - }, - 'netflow.tcp_fin_total_count': { - category: 'netflow', - name: 'netflow.tcp_fin_total_count', - type: 'long', - }, - 'netflow.tcp_rst_total_count': { - category: 'netflow', - name: 'netflow.tcp_rst_total_count', - type: 'long', - }, - 'netflow.tcp_psh_total_count': { - category: 'netflow', - name: 'netflow.tcp_psh_total_count', - type: 'long', - }, - 'netflow.tcp_ack_total_count': { - category: 'netflow', - name: 'netflow.tcp_ack_total_count', - type: 'long', - }, - 'netflow.tcp_urg_total_count': { - category: 'netflow', - name: 'netflow.tcp_urg_total_count', - type: 'long', - }, - 'netflow.ip_total_length': { - category: 'netflow', - name: 'netflow.ip_total_length', - type: 'long', - }, - 'netflow.post_nat_source_ipv4_address': { - category: 'netflow', - name: 'netflow.post_nat_source_ipv4_address', - type: 'ip', - }, - 'netflow.post_nat_destination_ipv4_address': { - category: 'netflow', - name: 'netflow.post_nat_destination_ipv4_address', - type: 'ip', - }, - 'netflow.post_napt_source_transport_port': { - category: 'netflow', - name: 'netflow.post_napt_source_transport_port', - type: 'integer', - }, - 'netflow.post_napt_destination_transport_port': { - category: 'netflow', - name: 'netflow.post_napt_destination_transport_port', - type: 'integer', - }, - 'netflow.nat_originating_address_realm': { - category: 'netflow', - name: 'netflow.nat_originating_address_realm', - type: 'short', - }, - 'netflow.nat_event': { - category: 'netflow', - name: 'netflow.nat_event', - type: 'short', - }, - 'netflow.initiator_octets': { - category: 'netflow', - name: 'netflow.initiator_octets', - type: 'long', - }, - 'netflow.responder_octets': { - category: 'netflow', - name: 'netflow.responder_octets', - type: 'long', - }, - 'netflow.firewall_event': { - category: 'netflow', - name: 'netflow.firewall_event', - type: 'short', - }, - 'netflow.ingress_vrfid': { - category: 'netflow', - name: 'netflow.ingress_vrfid', - type: 'long', - }, - 'netflow.egress_vrfid': { - category: 'netflow', - name: 'netflow.egress_vrfid', - type: 'long', - }, - 'netflow.vr_fname': { - category: 'netflow', - name: 'netflow.vr_fname', - type: 'keyword', - }, - 'netflow.post_mpls_top_label_exp': { - category: 'netflow', - name: 'netflow.post_mpls_top_label_exp', - type: 'short', - }, - 'netflow.tcp_window_scale': { - category: 'netflow', - name: 'netflow.tcp_window_scale', - type: 'integer', - }, - 'netflow.biflow_direction': { - category: 'netflow', - name: 'netflow.biflow_direction', - type: 'short', - }, - 'netflow.ethernet_header_length': { - category: 'netflow', - name: 'netflow.ethernet_header_length', - type: 'short', - }, - 'netflow.ethernet_payload_length': { - category: 'netflow', - name: 'netflow.ethernet_payload_length', - type: 'integer', - }, - 'netflow.ethernet_total_length': { - category: 'netflow', - name: 'netflow.ethernet_total_length', - type: 'integer', - }, - 'netflow.dot1q_vlan_id': { - category: 'netflow', - name: 'netflow.dot1q_vlan_id', - type: 'integer', - }, - 'netflow.dot1q_priority': { - category: 'netflow', - name: 'netflow.dot1q_priority', - type: 'short', - }, - 'netflow.dot1q_customer_vlan_id': { - category: 'netflow', - name: 'netflow.dot1q_customer_vlan_id', - type: 'integer', - }, - 'netflow.dot1q_customer_priority': { - category: 'netflow', - name: 'netflow.dot1q_customer_priority', - type: 'short', - }, - 'netflow.metro_evc_id': { - category: 'netflow', - name: 'netflow.metro_evc_id', - type: 'keyword', - }, - 'netflow.metro_evc_type': { - category: 'netflow', - name: 'netflow.metro_evc_type', - type: 'short', - }, - 'netflow.pseudo_wire_id': { - category: 'netflow', - name: 'netflow.pseudo_wire_id', - type: 'long', - }, - 'netflow.pseudo_wire_type': { - category: 'netflow', - name: 'netflow.pseudo_wire_type', - type: 'integer', - }, - 'netflow.pseudo_wire_control_word': { - category: 'netflow', - name: 'netflow.pseudo_wire_control_word', - type: 'long', - }, - 'netflow.ingress_physical_interface': { - category: 'netflow', - name: 'netflow.ingress_physical_interface', - type: 'long', - }, - 'netflow.egress_physical_interface': { - category: 'netflow', - name: 'netflow.egress_physical_interface', - type: 'long', - }, - 'netflow.post_dot1q_vlan_id': { - category: 'netflow', - name: 'netflow.post_dot1q_vlan_id', - type: 'integer', - }, - 'netflow.post_dot1q_customer_vlan_id': { - category: 'netflow', - name: 'netflow.post_dot1q_customer_vlan_id', - type: 'integer', - }, - 'netflow.ethernet_type': { - category: 'netflow', - name: 'netflow.ethernet_type', - type: 'integer', - }, - 'netflow.post_ip_precedence': { - category: 'netflow', - name: 'netflow.post_ip_precedence', - type: 'short', - }, - 'netflow.collection_time_milliseconds': { - category: 'netflow', - name: 'netflow.collection_time_milliseconds', - type: 'date', - }, - 'netflow.export_sctp_stream_id': { - category: 'netflow', - name: 'netflow.export_sctp_stream_id', - type: 'integer', - }, - 'netflow.max_export_seconds': { - category: 'netflow', - name: 'netflow.max_export_seconds', - type: 'date', - }, - 'netflow.max_flow_end_seconds': { - category: 'netflow', - name: 'netflow.max_flow_end_seconds', - type: 'date', - }, - 'netflow.message_md5_checksum': { - category: 'netflow', - name: 'netflow.message_md5_checksum', - type: 'short', - }, - 'netflow.message_scope': { - category: 'netflow', - name: 'netflow.message_scope', - type: 'short', - }, - 'netflow.min_export_seconds': { - category: 'netflow', - name: 'netflow.min_export_seconds', - type: 'date', - }, - 'netflow.min_flow_start_seconds': { - category: 'netflow', - name: 'netflow.min_flow_start_seconds', - type: 'date', - }, - 'netflow.opaque_octets': { - category: 'netflow', - name: 'netflow.opaque_octets', - type: 'short', - }, - 'netflow.session_scope': { - category: 'netflow', - name: 'netflow.session_scope', - type: 'short', - }, - 'netflow.max_flow_end_microseconds': { - category: 'netflow', - name: 'netflow.max_flow_end_microseconds', - type: 'date', - }, - 'netflow.max_flow_end_milliseconds': { - category: 'netflow', - name: 'netflow.max_flow_end_milliseconds', - type: 'date', - }, - 'netflow.max_flow_end_nanoseconds': { - category: 'netflow', - name: 'netflow.max_flow_end_nanoseconds', - type: 'date', - }, - 'netflow.min_flow_start_microseconds': { - category: 'netflow', - name: 'netflow.min_flow_start_microseconds', - type: 'date', - }, - 'netflow.min_flow_start_milliseconds': { - category: 'netflow', - name: 'netflow.min_flow_start_milliseconds', - type: 'date', - }, - 'netflow.min_flow_start_nanoseconds': { - category: 'netflow', - name: 'netflow.min_flow_start_nanoseconds', - type: 'date', - }, - 'netflow.collector_certificate': { - category: 'netflow', - name: 'netflow.collector_certificate', - type: 'short', - }, - 'netflow.exporter_certificate': { - category: 'netflow', - name: 'netflow.exporter_certificate', - type: 'short', - }, - 'netflow.data_records_reliability': { - category: 'netflow', - name: 'netflow.data_records_reliability', - type: 'boolean', - }, - 'netflow.observation_point_type': { - category: 'netflow', - name: 'netflow.observation_point_type', - type: 'short', - }, - 'netflow.new_connection_delta_count': { - category: 'netflow', - name: 'netflow.new_connection_delta_count', - type: 'long', - }, - 'netflow.connection_sum_duration_seconds': { - category: 'netflow', - name: 'netflow.connection_sum_duration_seconds', - type: 'long', - }, - 'netflow.connection_transaction_id': { - category: 'netflow', - name: 'netflow.connection_transaction_id', - type: 'long', - }, - 'netflow.post_nat_source_ipv6_address': { - category: 'netflow', - name: 'netflow.post_nat_source_ipv6_address', - type: 'ip', - }, - 'netflow.post_nat_destination_ipv6_address': { - category: 'netflow', - name: 'netflow.post_nat_destination_ipv6_address', - type: 'ip', - }, - 'netflow.nat_pool_id': { - category: 'netflow', - name: 'netflow.nat_pool_id', - type: 'long', - }, - 'netflow.nat_pool_name': { - category: 'netflow', - name: 'netflow.nat_pool_name', - type: 'keyword', - }, - 'netflow.anonymization_flags': { - category: 'netflow', - name: 'netflow.anonymization_flags', - type: 'integer', - }, - 'netflow.anonymization_technique': { - category: 'netflow', - name: 'netflow.anonymization_technique', - type: 'integer', - }, - 'netflow.information_element_index': { - category: 'netflow', - name: 'netflow.information_element_index', - type: 'integer', - }, - 'netflow.p2p_technology': { - category: 'netflow', - name: 'netflow.p2p_technology', - type: 'keyword', - }, - 'netflow.tunnel_technology': { - category: 'netflow', - name: 'netflow.tunnel_technology', - type: 'keyword', - }, - 'netflow.encrypted_technology': { - category: 'netflow', - name: 'netflow.encrypted_technology', - type: 'keyword', - }, - 'netflow.bgp_validity_state': { - category: 'netflow', - name: 'netflow.bgp_validity_state', - type: 'short', - }, - 'netflow.ip_sec_spi': { - category: 'netflow', - name: 'netflow.ip_sec_spi', - type: 'long', - }, - 'netflow.gre_key': { - category: 'netflow', - name: 'netflow.gre_key', - type: 'long', - }, - 'netflow.nat_type': { - category: 'netflow', - name: 'netflow.nat_type', - type: 'short', - }, - 'netflow.initiator_packets': { - category: 'netflow', - name: 'netflow.initiator_packets', - type: 'long', - }, - 'netflow.responder_packets': { - category: 'netflow', - name: 'netflow.responder_packets', - type: 'long', - }, - 'netflow.observation_domain_name': { - category: 'netflow', - name: 'netflow.observation_domain_name', - type: 'keyword', - }, - 'netflow.selection_sequence_id': { - category: 'netflow', - name: 'netflow.selection_sequence_id', - type: 'long', - }, - 'netflow.selector_id': { - category: 'netflow', - name: 'netflow.selector_id', - type: 'long', - }, - 'netflow.information_element_id': { - category: 'netflow', - name: 'netflow.information_element_id', - type: 'integer', - }, - 'netflow.selector_algorithm': { - category: 'netflow', - name: 'netflow.selector_algorithm', - type: 'integer', - }, - 'netflow.sampling_packet_interval': { - category: 'netflow', - name: 'netflow.sampling_packet_interval', - type: 'long', - }, - 'netflow.sampling_packet_space': { - category: 'netflow', - name: 'netflow.sampling_packet_space', - type: 'long', - }, - 'netflow.sampling_time_interval': { - category: 'netflow', - name: 'netflow.sampling_time_interval', - type: 'long', - }, - 'netflow.sampling_time_space': { - category: 'netflow', - name: 'netflow.sampling_time_space', - type: 'long', - }, - 'netflow.sampling_size': { - category: 'netflow', - name: 'netflow.sampling_size', - type: 'long', - }, - 'netflow.sampling_population': { - category: 'netflow', - name: 'netflow.sampling_population', - type: 'long', - }, - 'netflow.sampling_probability': { - category: 'netflow', - name: 'netflow.sampling_probability', - type: 'double', - }, - 'netflow.data_link_frame_size': { - category: 'netflow', - name: 'netflow.data_link_frame_size', - type: 'integer', - }, - 'netflow.ip_header_packet_section': { - category: 'netflow', - name: 'netflow.ip_header_packet_section', - type: 'short', - }, - 'netflow.ip_payload_packet_section': { - category: 'netflow', - name: 'netflow.ip_payload_packet_section', - type: 'short', - }, - 'netflow.data_link_frame_section': { - category: 'netflow', - name: 'netflow.data_link_frame_section', - type: 'short', - }, - 'netflow.mpls_label_stack_section': { - category: 'netflow', - name: 'netflow.mpls_label_stack_section', - type: 'short', - }, - 'netflow.mpls_payload_packet_section': { - category: 'netflow', - name: 'netflow.mpls_payload_packet_section', - type: 'short', - }, - 'netflow.selector_id_total_pkts_observed': { - category: 'netflow', - name: 'netflow.selector_id_total_pkts_observed', - type: 'long', - }, - 'netflow.selector_id_total_pkts_selected': { - category: 'netflow', - name: 'netflow.selector_id_total_pkts_selected', - type: 'long', - }, - 'netflow.absolute_error': { - category: 'netflow', - name: 'netflow.absolute_error', - type: 'double', - }, - 'netflow.relative_error': { - category: 'netflow', - name: 'netflow.relative_error', - type: 'double', - }, - 'netflow.observation_time_seconds': { - category: 'netflow', - name: 'netflow.observation_time_seconds', - type: 'date', - }, - 'netflow.observation_time_milliseconds': { - category: 'netflow', - name: 'netflow.observation_time_milliseconds', - type: 'date', - }, - 'netflow.observation_time_microseconds': { - category: 'netflow', - name: 'netflow.observation_time_microseconds', - type: 'date', - }, - 'netflow.observation_time_nanoseconds': { - category: 'netflow', - name: 'netflow.observation_time_nanoseconds', - type: 'date', - }, - 'netflow.digest_hash_value': { - category: 'netflow', - name: 'netflow.digest_hash_value', - type: 'long', - }, - 'netflow.hash_ip_payload_offset': { - category: 'netflow', - name: 'netflow.hash_ip_payload_offset', - type: 'long', - }, - 'netflow.hash_ip_payload_size': { - category: 'netflow', - name: 'netflow.hash_ip_payload_size', - type: 'long', - }, - 'netflow.hash_output_range_min': { - category: 'netflow', - name: 'netflow.hash_output_range_min', - type: 'long', - }, - 'netflow.hash_output_range_max': { - category: 'netflow', - name: 'netflow.hash_output_range_max', - type: 'long', - }, - 'netflow.hash_selected_range_min': { - category: 'netflow', - name: 'netflow.hash_selected_range_min', - type: 'long', - }, - 'netflow.hash_selected_range_max': { - category: 'netflow', - name: 'netflow.hash_selected_range_max', - type: 'long', - }, - 'netflow.hash_digest_output': { - category: 'netflow', - name: 'netflow.hash_digest_output', - type: 'boolean', - }, - 'netflow.hash_initialiser_value': { - category: 'netflow', - name: 'netflow.hash_initialiser_value', - type: 'long', - }, - 'netflow.selector_name': { - category: 'netflow', - name: 'netflow.selector_name', - type: 'keyword', - }, - 'netflow.upper_ci_limit': { - category: 'netflow', - name: 'netflow.upper_ci_limit', - type: 'double', - }, - 'netflow.lower_ci_limit': { - category: 'netflow', - name: 'netflow.lower_ci_limit', - type: 'double', - }, - 'netflow.confidence_level': { - category: 'netflow', - name: 'netflow.confidence_level', - type: 'double', - }, - 'netflow.information_element_data_type': { - category: 'netflow', - name: 'netflow.information_element_data_type', - type: 'short', - }, - 'netflow.information_element_description': { - category: 'netflow', - name: 'netflow.information_element_description', - type: 'keyword', - }, - 'netflow.information_element_name': { - category: 'netflow', - name: 'netflow.information_element_name', - type: 'keyword', - }, - 'netflow.information_element_range_begin': { - category: 'netflow', - name: 'netflow.information_element_range_begin', - type: 'long', - }, - 'netflow.information_element_range_end': { - category: 'netflow', - name: 'netflow.information_element_range_end', - type: 'long', - }, - 'netflow.information_element_semantics': { - category: 'netflow', - name: 'netflow.information_element_semantics', - type: 'short', - }, - 'netflow.information_element_units': { - category: 'netflow', - name: 'netflow.information_element_units', - type: 'integer', - }, - 'netflow.private_enterprise_number': { - category: 'netflow', - name: 'netflow.private_enterprise_number', - type: 'long', - }, - 'netflow.virtual_station_interface_id': { - category: 'netflow', - name: 'netflow.virtual_station_interface_id', - type: 'short', - }, - 'netflow.virtual_station_interface_name': { - category: 'netflow', - name: 'netflow.virtual_station_interface_name', - type: 'keyword', - }, - 'netflow.virtual_station_uuid': { - category: 'netflow', - name: 'netflow.virtual_station_uuid', - type: 'short', - }, - 'netflow.virtual_station_name': { - category: 'netflow', - name: 'netflow.virtual_station_name', - type: 'keyword', - }, - 'netflow.layer2_segment_id': { - category: 'netflow', - name: 'netflow.layer2_segment_id', - type: 'long', - }, - 'netflow.layer2_octet_delta_count': { - category: 'netflow', - name: 'netflow.layer2_octet_delta_count', - type: 'long', - }, - 'netflow.layer2_octet_total_count': { - category: 'netflow', - name: 'netflow.layer2_octet_total_count', - type: 'long', - }, - 'netflow.ingress_unicast_packet_total_count': { - category: 'netflow', - name: 'netflow.ingress_unicast_packet_total_count', - type: 'long', - }, - 'netflow.ingress_multicast_packet_total_count': { - category: 'netflow', - name: 'netflow.ingress_multicast_packet_total_count', - type: 'long', - }, - 'netflow.ingress_broadcast_packet_total_count': { - category: 'netflow', - name: 'netflow.ingress_broadcast_packet_total_count', - type: 'long', - }, - 'netflow.egress_unicast_packet_total_count': { - category: 'netflow', - name: 'netflow.egress_unicast_packet_total_count', - type: 'long', - }, - 'netflow.egress_broadcast_packet_total_count': { - category: 'netflow', - name: 'netflow.egress_broadcast_packet_total_count', - type: 'long', - }, - 'netflow.monitoring_interval_start_milli_seconds': { - category: 'netflow', - name: 'netflow.monitoring_interval_start_milli_seconds', - type: 'date', - }, - 'netflow.monitoring_interval_end_milli_seconds': { - category: 'netflow', - name: 'netflow.monitoring_interval_end_milli_seconds', - type: 'date', - }, - 'netflow.port_range_start': { - category: 'netflow', - name: 'netflow.port_range_start', - type: 'integer', - }, - 'netflow.port_range_end': { - category: 'netflow', - name: 'netflow.port_range_end', - type: 'integer', - }, - 'netflow.port_range_step_size': { - category: 'netflow', - name: 'netflow.port_range_step_size', - type: 'integer', - }, - 'netflow.port_range_num_ports': { - category: 'netflow', - name: 'netflow.port_range_num_ports', - type: 'integer', - }, - 'netflow.sta_mac_address': { - category: 'netflow', - name: 'netflow.sta_mac_address', - type: 'keyword', - }, - 'netflow.sta_ipv4_address': { - category: 'netflow', - name: 'netflow.sta_ipv4_address', - type: 'ip', - }, - 'netflow.wtp_mac_address': { - category: 'netflow', - name: 'netflow.wtp_mac_address', - type: 'keyword', - }, - 'netflow.ingress_interface_type': { - category: 'netflow', - name: 'netflow.ingress_interface_type', - type: 'long', - }, - 'netflow.egress_interface_type': { - category: 'netflow', - name: 'netflow.egress_interface_type', - type: 'long', - }, - 'netflow.rtp_sequence_number': { - category: 'netflow', - name: 'netflow.rtp_sequence_number', - type: 'integer', - }, - 'netflow.user_name': { - category: 'netflow', - name: 'netflow.user_name', - type: 'keyword', - }, - 'netflow.application_category_name': { - category: 'netflow', - name: 'netflow.application_category_name', - type: 'keyword', - }, - 'netflow.application_sub_category_name': { - category: 'netflow', - name: 'netflow.application_sub_category_name', - type: 'keyword', - }, - 'netflow.application_group_name': { - category: 'netflow', - name: 'netflow.application_group_name', - type: 'keyword', - }, - 'netflow.original_flows_present': { - category: 'netflow', - name: 'netflow.original_flows_present', - type: 'long', - }, - 'netflow.original_flows_initiated': { - category: 'netflow', - name: 'netflow.original_flows_initiated', - type: 'long', - }, - 'netflow.original_flows_completed': { - category: 'netflow', - name: 'netflow.original_flows_completed', - type: 'long', - }, - 'netflow.distinct_count_of_source_ip_address': { - category: 'netflow', - name: 'netflow.distinct_count_of_source_ip_address', - type: 'long', - }, - 'netflow.distinct_count_of_destination_ip_address': { - category: 'netflow', - name: 'netflow.distinct_count_of_destination_ip_address', - type: 'long', - }, - 'netflow.distinct_count_of_source_ipv4_address': { - category: 'netflow', - name: 'netflow.distinct_count_of_source_ipv4_address', - type: 'long', - }, - 'netflow.distinct_count_of_destination_ipv4_address': { - category: 'netflow', - name: 'netflow.distinct_count_of_destination_ipv4_address', - type: 'long', - }, - 'netflow.distinct_count_of_source_ipv6_address': { - category: 'netflow', - name: 'netflow.distinct_count_of_source_ipv6_address', - type: 'long', - }, - 'netflow.distinct_count_of_destination_ipv6_address': { - category: 'netflow', - name: 'netflow.distinct_count_of_destination_ipv6_address', - type: 'long', - }, - 'netflow.value_distribution_method': { - category: 'netflow', - name: 'netflow.value_distribution_method', - type: 'short', - }, - 'netflow.rfc3550_jitter_milliseconds': { - category: 'netflow', - name: 'netflow.rfc3550_jitter_milliseconds', - type: 'long', - }, - 'netflow.rfc3550_jitter_microseconds': { - category: 'netflow', - name: 'netflow.rfc3550_jitter_microseconds', - type: 'long', - }, - 'netflow.rfc3550_jitter_nanoseconds': { - category: 'netflow', - name: 'netflow.rfc3550_jitter_nanoseconds', - type: 'long', - }, - 'netflow.dot1q_dei': { - category: 'netflow', - name: 'netflow.dot1q_dei', - type: 'boolean', - }, - 'netflow.dot1q_customer_dei': { - category: 'netflow', - name: 'netflow.dot1q_customer_dei', - type: 'boolean', - }, - 'netflow.flow_selector_algorithm': { - category: 'netflow', - name: 'netflow.flow_selector_algorithm', - type: 'integer', - }, - 'netflow.flow_selected_octet_delta_count': { - category: 'netflow', - name: 'netflow.flow_selected_octet_delta_count', - type: 'long', - }, - 'netflow.flow_selected_packet_delta_count': { - category: 'netflow', - name: 'netflow.flow_selected_packet_delta_count', - type: 'long', - }, - 'netflow.flow_selected_flow_delta_count': { - category: 'netflow', - name: 'netflow.flow_selected_flow_delta_count', - type: 'long', - }, - 'netflow.selector_id_total_flows_observed': { - category: 'netflow', - name: 'netflow.selector_id_total_flows_observed', - type: 'long', - }, - 'netflow.selector_id_total_flows_selected': { - category: 'netflow', - name: 'netflow.selector_id_total_flows_selected', - type: 'long', - }, - 'netflow.sampling_flow_interval': { - category: 'netflow', - name: 'netflow.sampling_flow_interval', - type: 'long', - }, - 'netflow.sampling_flow_spacing': { - category: 'netflow', - name: 'netflow.sampling_flow_spacing', - type: 'long', - }, - 'netflow.flow_sampling_time_interval': { - category: 'netflow', - name: 'netflow.flow_sampling_time_interval', - type: 'long', - }, - 'netflow.flow_sampling_time_spacing': { - category: 'netflow', - name: 'netflow.flow_sampling_time_spacing', - type: 'long', - }, - 'netflow.hash_flow_domain': { - category: 'netflow', - name: 'netflow.hash_flow_domain', - type: 'integer', - }, - 'netflow.transport_octet_delta_count': { - category: 'netflow', - name: 'netflow.transport_octet_delta_count', - type: 'long', - }, - 'netflow.transport_packet_delta_count': { - category: 'netflow', - name: 'netflow.transport_packet_delta_count', - type: 'long', - }, - 'netflow.original_exporter_ipv4_address': { - category: 'netflow', - name: 'netflow.original_exporter_ipv4_address', - type: 'ip', - }, - 'netflow.original_exporter_ipv6_address': { - category: 'netflow', - name: 'netflow.original_exporter_ipv6_address', - type: 'ip', - }, - 'netflow.original_observation_domain_id': { - category: 'netflow', - name: 'netflow.original_observation_domain_id', - type: 'long', - }, - 'netflow.intermediate_process_id': { - category: 'netflow', - name: 'netflow.intermediate_process_id', - type: 'long', - }, - 'netflow.ignored_data_record_total_count': { - category: 'netflow', - name: 'netflow.ignored_data_record_total_count', - type: 'long', - }, - 'netflow.data_link_frame_type': { - category: 'netflow', - name: 'netflow.data_link_frame_type', - type: 'integer', - }, - 'netflow.section_offset': { - category: 'netflow', - name: 'netflow.section_offset', - type: 'integer', - }, - 'netflow.section_exported_octets': { - category: 'netflow', - name: 'netflow.section_exported_octets', - type: 'integer', - }, - 'netflow.dot1q_service_instance_tag': { - category: 'netflow', - name: 'netflow.dot1q_service_instance_tag', - type: 'short', - }, - 'netflow.dot1q_service_instance_id': { - category: 'netflow', - name: 'netflow.dot1q_service_instance_id', - type: 'long', - }, - 'netflow.dot1q_service_instance_priority': { - category: 'netflow', - name: 'netflow.dot1q_service_instance_priority', - type: 'short', - }, - 'netflow.dot1q_customer_source_mac_address': { - category: 'netflow', - name: 'netflow.dot1q_customer_source_mac_address', - type: 'keyword', - }, - 'netflow.dot1q_customer_destination_mac_address': { - category: 'netflow', - name: 'netflow.dot1q_customer_destination_mac_address', - type: 'keyword', - }, - 'netflow.post_layer2_octet_delta_count': { - category: 'netflow', - name: 'netflow.post_layer2_octet_delta_count', - type: 'long', - }, - 'netflow.post_mcast_layer2_octet_delta_count': { - category: 'netflow', - name: 'netflow.post_mcast_layer2_octet_delta_count', - type: 'long', - }, - 'netflow.post_layer2_octet_total_count': { - category: 'netflow', - name: 'netflow.post_layer2_octet_total_count', - type: 'long', - }, - 'netflow.post_mcast_layer2_octet_total_count': { - category: 'netflow', - name: 'netflow.post_mcast_layer2_octet_total_count', - type: 'long', - }, - 'netflow.minimum_layer2_total_length': { - category: 'netflow', - name: 'netflow.minimum_layer2_total_length', - type: 'long', - }, - 'netflow.maximum_layer2_total_length': { - category: 'netflow', - name: 'netflow.maximum_layer2_total_length', - type: 'long', - }, - 'netflow.dropped_layer2_octet_delta_count': { - category: 'netflow', - name: 'netflow.dropped_layer2_octet_delta_count', - type: 'long', - }, - 'netflow.dropped_layer2_octet_total_count': { - category: 'netflow', - name: 'netflow.dropped_layer2_octet_total_count', - type: 'long', - }, - 'netflow.ignored_layer2_octet_total_count': { - category: 'netflow', - name: 'netflow.ignored_layer2_octet_total_count', - type: 'long', - }, - 'netflow.not_sent_layer2_octet_total_count': { - category: 'netflow', - name: 'netflow.not_sent_layer2_octet_total_count', - type: 'long', - }, - 'netflow.layer2_octet_delta_sum_of_squares': { - category: 'netflow', - name: 'netflow.layer2_octet_delta_sum_of_squares', - type: 'long', - }, - 'netflow.layer2_octet_total_sum_of_squares': { - category: 'netflow', - name: 'netflow.layer2_octet_total_sum_of_squares', - type: 'long', - }, - 'netflow.layer2_frame_delta_count': { - category: 'netflow', - name: 'netflow.layer2_frame_delta_count', - type: 'long', - }, - 'netflow.layer2_frame_total_count': { - category: 'netflow', - name: 'netflow.layer2_frame_total_count', - type: 'long', - }, - 'netflow.pseudo_wire_destination_ipv4_address': { - category: 'netflow', - name: 'netflow.pseudo_wire_destination_ipv4_address', - type: 'ip', - }, - 'netflow.ignored_layer2_frame_total_count': { - category: 'netflow', - name: 'netflow.ignored_layer2_frame_total_count', - type: 'long', - }, - 'netflow.mib_object_value_integer': { - category: 'netflow', - name: 'netflow.mib_object_value_integer', - type: 'integer', - }, - 'netflow.mib_object_value_octet_string': { - category: 'netflow', - name: 'netflow.mib_object_value_octet_string', - type: 'short', - }, - 'netflow.mib_object_value_oid': { - category: 'netflow', - name: 'netflow.mib_object_value_oid', - type: 'short', - }, - 'netflow.mib_object_value_bits': { - category: 'netflow', - name: 'netflow.mib_object_value_bits', - type: 'short', - }, - 'netflow.mib_object_value_ip_address': { - category: 'netflow', - name: 'netflow.mib_object_value_ip_address', - type: 'ip', - }, - 'netflow.mib_object_value_counter': { - category: 'netflow', - name: 'netflow.mib_object_value_counter', - type: 'long', - }, - 'netflow.mib_object_value_gauge': { - category: 'netflow', - name: 'netflow.mib_object_value_gauge', - type: 'long', - }, - 'netflow.mib_object_value_time_ticks': { - category: 'netflow', - name: 'netflow.mib_object_value_time_ticks', - type: 'long', - }, - 'netflow.mib_object_value_unsigned': { - category: 'netflow', - name: 'netflow.mib_object_value_unsigned', - type: 'long', - }, - 'netflow.mib_object_identifier': { - category: 'netflow', - name: 'netflow.mib_object_identifier', - type: 'short', - }, - 'netflow.mib_sub_identifier': { - category: 'netflow', - name: 'netflow.mib_sub_identifier', - type: 'long', - }, - 'netflow.mib_index_indicator': { - category: 'netflow', - name: 'netflow.mib_index_indicator', - type: 'long', - }, - 'netflow.mib_capture_time_semantics': { - category: 'netflow', - name: 'netflow.mib_capture_time_semantics', - type: 'short', - }, - 'netflow.mib_context_engine_id': { - category: 'netflow', - name: 'netflow.mib_context_engine_id', - type: 'short', - }, - 'netflow.mib_context_name': { - category: 'netflow', - name: 'netflow.mib_context_name', - type: 'keyword', - }, - 'netflow.mib_object_name': { - category: 'netflow', - name: 'netflow.mib_object_name', - type: 'keyword', - }, - 'netflow.mib_object_description': { - category: 'netflow', - name: 'netflow.mib_object_description', - type: 'keyword', - }, - 'netflow.mib_object_syntax': { - category: 'netflow', - name: 'netflow.mib_object_syntax', - type: 'keyword', - }, - 'netflow.mib_module_name': { - category: 'netflow', - name: 'netflow.mib_module_name', - type: 'keyword', - }, - 'netflow.mobile_imsi': { - category: 'netflow', - name: 'netflow.mobile_imsi', - type: 'keyword', - }, - 'netflow.mobile_msisdn': { - category: 'netflow', - name: 'netflow.mobile_msisdn', - type: 'keyword', - }, - 'netflow.http_status_code': { - category: 'netflow', - name: 'netflow.http_status_code', - type: 'integer', - }, - 'netflow.source_transport_ports_limit': { - category: 'netflow', - name: 'netflow.source_transport_ports_limit', - type: 'integer', - }, - 'netflow.http_request_method': { - category: 'netflow', - name: 'netflow.http_request_method', - type: 'keyword', - }, - 'netflow.http_request_host': { - category: 'netflow', - name: 'netflow.http_request_host', - type: 'keyword', - }, - 'netflow.http_request_target': { - category: 'netflow', - name: 'netflow.http_request_target', - type: 'keyword', - }, - 'netflow.http_message_version': { - category: 'netflow', - name: 'netflow.http_message_version', - type: 'keyword', - }, - 'netflow.nat_instance_id': { - category: 'netflow', - name: 'netflow.nat_instance_id', - type: 'long', - }, - 'netflow.internal_address_realm': { - category: 'netflow', - name: 'netflow.internal_address_realm', - type: 'short', - }, - 'netflow.external_address_realm': { - category: 'netflow', - name: 'netflow.external_address_realm', - type: 'short', - }, - 'netflow.nat_quota_exceeded_event': { - category: 'netflow', - name: 'netflow.nat_quota_exceeded_event', - type: 'long', - }, - 'netflow.nat_threshold_event': { - category: 'netflow', - name: 'netflow.nat_threshold_event', - type: 'long', - }, - 'netflow.http_user_agent': { - category: 'netflow', - name: 'netflow.http_user_agent', - type: 'keyword', - }, - 'netflow.http_content_type': { - category: 'netflow', - name: 'netflow.http_content_type', - type: 'keyword', - }, - 'netflow.http_reason_phrase': { - category: 'netflow', - name: 'netflow.http_reason_phrase', - type: 'keyword', - }, - 'netflow.max_session_entries': { - category: 'netflow', - name: 'netflow.max_session_entries', - type: 'long', - }, - 'netflow.max_bib_entries': { - category: 'netflow', - name: 'netflow.max_bib_entries', - type: 'long', - }, - 'netflow.max_entries_per_user': { - category: 'netflow', - name: 'netflow.max_entries_per_user', - type: 'long', - }, - 'netflow.max_subscribers': { - category: 'netflow', - name: 'netflow.max_subscribers', - type: 'long', - }, - 'netflow.max_fragments_pending_reassembly': { - category: 'netflow', - name: 'netflow.max_fragments_pending_reassembly', - type: 'long', - }, - 'netflow.address_pool_high_threshold': { - category: 'netflow', - name: 'netflow.address_pool_high_threshold', - type: 'long', - }, - 'netflow.address_pool_low_threshold': { - category: 'netflow', - name: 'netflow.address_pool_low_threshold', - type: 'long', - }, - 'netflow.address_port_mapping_high_threshold': { - category: 'netflow', - name: 'netflow.address_port_mapping_high_threshold', - type: 'long', - }, - 'netflow.address_port_mapping_low_threshold': { - category: 'netflow', - name: 'netflow.address_port_mapping_low_threshold', - type: 'long', - }, - 'netflow.address_port_mapping_per_user_high_threshold': { - category: 'netflow', - name: 'netflow.address_port_mapping_per_user_high_threshold', - type: 'long', - }, - 'netflow.global_address_mapping_high_threshold': { - category: 'netflow', - name: 'netflow.global_address_mapping_high_threshold', - type: 'long', - }, - 'netflow.vpn_identifier': { - category: 'netflow', - name: 'netflow.vpn_identifier', - type: 'short', - }, - 'cef.version': { - category: 'cef', - description: 'Version of the CEF specification used by the message. ', - name: 'cef.version', - type: 'keyword', - }, - 'cef.device.vendor': { - category: 'cef', - description: 'Vendor of the device that produced the message. ', - name: 'cef.device.vendor', - type: 'keyword', - }, - 'cef.device.product': { - category: 'cef', - description: 'Product of the device that produced the message. ', - name: 'cef.device.product', - type: 'keyword', - }, - 'cef.device.version': { - category: 'cef', - description: 'Version of the product that produced the message. ', - name: 'cef.device.version', - type: 'keyword', - }, - 'cef.device.event_class_id': { - category: 'cef', - description: 'Unique identifier of the event type. ', - name: 'cef.device.event_class_id', - type: 'keyword', - }, - 'cef.severity': { - category: 'cef', - description: - 'Importance of the event. The valid string values are Unknown, Low, Medium, High, and Very-High. The valid integer values are 0-3=Low, 4-6=Medium, 7- 8=High, and 9-10=Very-High. ', - example: 'Very-High', - name: 'cef.severity', - type: 'keyword', - }, - 'cef.name': { - category: 'cef', - description: 'Short description of the event. ', - name: 'cef.name', - type: 'keyword', - }, - 'cef.extensions.agentAddress': { - category: 'cef', - description: 'The IP address of the ArcSight connector that processed the event.', - name: 'cef.extensions.agentAddress', - type: 'ip', - }, - 'cef.extensions.agentDnsDomain': { - category: 'cef', - description: 'The DNS domain name of the ArcSight connector that processed the event.', - name: 'cef.extensions.agentDnsDomain', - type: 'keyword', - }, - 'cef.extensions.agentHostName': { - category: 'cef', - description: 'The hostname of the ArcSight connector that processed the event.', - name: 'cef.extensions.agentHostName', - type: 'keyword', - }, - 'cef.extensions.agentId': { - category: 'cef', - description: 'The agent ID of the ArcSight connector that processed the event.', - name: 'cef.extensions.agentId', - type: 'keyword', - }, - 'cef.extensions.agentMacAddress': { - category: 'cef', - description: 'The MAC address of the ArcSight connector that processed the event.', - name: 'cef.extensions.agentMacAddress', - type: 'keyword', - }, - 'cef.extensions.agentNtDomain': { - category: 'cef', - description: 'null', - name: 'cef.extensions.agentNtDomain', - type: 'keyword', - }, - 'cef.extensions.agentReceiptTime': { - category: 'cef', - description: - 'The time at which information about the event was received by the ArcSight connector.', - name: 'cef.extensions.agentReceiptTime', - type: 'date', - }, - 'cef.extensions.agentTimeZone': { - category: 'cef', - description: 'The agent time zone of the ArcSight connector that processed the event.', - name: 'cef.extensions.agentTimeZone', - type: 'keyword', - }, - 'cef.extensions.agentTranslatedAddress': { - category: 'cef', - description: 'null', - name: 'cef.extensions.agentTranslatedAddress', - type: 'ip', - }, - 'cef.extensions.agentTranslatedZoneExternalID': { - category: 'cef', - description: 'null', - name: 'cef.extensions.agentTranslatedZoneExternalID', - type: 'keyword', - }, - 'cef.extensions.agentTranslatedZoneURI': { - category: 'cef', - description: 'null', - name: 'cef.extensions.agentTranslatedZoneURI', - type: 'keyword', - }, - 'cef.extensions.agentType': { - category: 'cef', - description: 'The agent type of the ArcSight connector that processed the event', - name: 'cef.extensions.agentType', - type: 'keyword', - }, - 'cef.extensions.agentVersion': { - category: 'cef', - description: 'The version of the ArcSight connector that processed the event.', - name: 'cef.extensions.agentVersion', - type: 'keyword', - }, - 'cef.extensions.agentZoneExternalID': { - category: 'cef', - description: 'null', - name: 'cef.extensions.agentZoneExternalID', - type: 'keyword', - }, - 'cef.extensions.agentZoneURI': { - category: 'cef', - description: 'null', - name: 'cef.extensions.agentZoneURI', - type: 'keyword', - }, - 'cef.extensions.applicationProtocol': { - category: 'cef', - description: - 'Application level protocol, example values are HTTP, HTTPS, SSHv2, Telnet, POP, IMPA, IMAPS, and so on.', - name: 'cef.extensions.applicationProtocol', - type: 'keyword', - }, - 'cef.extensions.baseEventCount': { - category: 'cef', - description: - 'A count associated with this event. How many times was this same event observed? Count can be omitted if it is 1.', - name: 'cef.extensions.baseEventCount', - type: 'long', - }, - 'cef.extensions.bytesIn': { - category: 'cef', - description: - 'Number of bytes transferred inbound, relative to the source to destination relationship, meaning that data was flowing from source to destination.', - name: 'cef.extensions.bytesIn', - type: 'long', - }, - 'cef.extensions.bytesOut': { - category: 'cef', - description: - 'Number of bytes transferred outbound relative to the source to destination relationship. For example, the byte number of data flowing from the destination to the source.', - name: 'cef.extensions.bytesOut', - type: 'long', - }, - 'cef.extensions.customerExternalID': { - category: 'cef', - description: 'null', - name: 'cef.extensions.customerExternalID', - type: 'keyword', - }, - 'cef.extensions.customerURI': { - category: 'cef', - description: 'null', - name: 'cef.extensions.customerURI', - type: 'keyword', - }, - 'cef.extensions.destinationAddress': { - category: 'cef', - description: - 'Identifies the destination address that the event refers to in an IP network. The format is an IPv4 address.', - name: 'cef.extensions.destinationAddress', - type: 'ip', - }, - 'cef.extensions.destinationDnsDomain': { - category: 'cef', - description: 'The DNS domain part of the complete fully qualified domain name (FQDN).', - name: 'cef.extensions.destinationDnsDomain', - type: 'keyword', - }, - 'cef.extensions.destinationGeoLatitude': { - category: 'cef', - description: "The latitudinal value from which the destination's IP address belongs.", - name: 'cef.extensions.destinationGeoLatitude', - type: 'double', - }, - 'cef.extensions.destinationGeoLongitude': { - category: 'cef', - description: "The longitudinal value from which the destination's IP address belongs.", - name: 'cef.extensions.destinationGeoLongitude', - type: 'double', - }, - 'cef.extensions.destinationHostName': { - category: 'cef', - description: - 'Identifies the destination that an event refers to in an IP network. The format should be a fully qualified domain name (FQDN) associated with the destination node, when a node is available.', - name: 'cef.extensions.destinationHostName', - type: 'keyword', - }, - 'cef.extensions.destinationMacAddress': { - category: 'cef', - description: 'Six colon-seperated hexadecimal numbers.', - name: 'cef.extensions.destinationMacAddress', - type: 'keyword', - }, - 'cef.extensions.destinationNtDomain': { - category: 'cef', - description: 'The Windows domain name of the destination address.', - name: 'cef.extensions.destinationNtDomain', - type: 'keyword', - }, - 'cef.extensions.destinationPort': { - category: 'cef', - description: 'The valid port numbers are between 0 and 65535.', - name: 'cef.extensions.destinationPort', - type: 'long', - }, - 'cef.extensions.destinationProcessId': { - category: 'cef', - description: - 'Provides the ID of the destination process associated with the event. For example, if an event contains process ID 105, "105" is the process ID.', - name: 'cef.extensions.destinationProcessId', - type: 'long', - }, - 'cef.extensions.destinationProcessName': { - category: 'cef', - description: "The name of the event's destination process.", - name: 'cef.extensions.destinationProcessName', - type: 'keyword', - }, - 'cef.extensions.destinationServiceName': { - category: 'cef', - description: 'The service targeted by this event.', - name: 'cef.extensions.destinationServiceName', - type: 'keyword', - }, - 'cef.extensions.destinationTranslatedAddress': { - category: 'cef', - description: 'Identifies the translated destination that the event refers to in an IP network.', - name: 'cef.extensions.destinationTranslatedAddress', - type: 'ip', - }, - 'cef.extensions.destinationTranslatedPort': { - category: 'cef', - description: - 'Port after it was translated; for example, a firewall. Valid port numbers are 0 to 65535.', - name: 'cef.extensions.destinationTranslatedPort', - type: 'long', - }, - 'cef.extensions.destinationTranslatedZoneExternalID': { - category: 'cef', - description: 'null', - name: 'cef.extensions.destinationTranslatedZoneExternalID', - type: 'keyword', - }, - 'cef.extensions.destinationTranslatedZoneURI': { - category: 'cef', - description: - 'The URI for the Translated Zone that the destination asset has been assigned to in ArcSight.', - name: 'cef.extensions.destinationTranslatedZoneURI', - type: 'keyword', - }, - 'cef.extensions.destinationUserId': { - category: 'cef', - description: - 'Identifies the destination user by ID. For example, in UNIX, the root user is generally associated with user ID 0.', - name: 'cef.extensions.destinationUserId', - type: 'keyword', - }, - 'cef.extensions.destinationUserName': { - category: 'cef', - description: - "Identifies the destination user by name. This is the user associated with the event's destination. Email addresses are often mapped into the UserName fields. The recipient is a candidate to put into this field.", - name: 'cef.extensions.destinationUserName', - type: 'keyword', - }, - 'cef.extensions.destinationUserPrivileges': { - category: 'cef', - description: - 'The typical values are "Administrator", "User", and "Guest". This identifies the destination user\'s privileges. In UNIX, for example, activity executed on the root user would be identified with destinationUser Privileges of "Administrator".', - name: 'cef.extensions.destinationUserPrivileges', - type: 'keyword', - }, - 'cef.extensions.destinationZoneExternalID': { - category: 'cef', - description: 'null', - name: 'cef.extensions.destinationZoneExternalID', - type: 'keyword', - }, - 'cef.extensions.destinationZoneURI': { - category: 'cef', - description: - 'The URI for the Zone that the destination asset has been assigned to in ArcSight.', - name: 'cef.extensions.destinationZoneURI', - type: 'keyword', - }, - 'cef.extensions.deviceAction': { - category: 'cef', - description: 'Action taken by the device.', - name: 'cef.extensions.deviceAction', - type: 'keyword', - }, - 'cef.extensions.deviceAddress': { - category: 'cef', - description: 'Identifies the device address that an event refers to in an IP network.', - name: 'cef.extensions.deviceAddress', - type: 'ip', - }, - 'cef.extensions.deviceCustomFloatingPoint1Label': { - category: 'cef', - description: - 'All custom fields have a corresponding label field. Each of these fields is a string and describes the purpose of the custom field.', - name: 'cef.extensions.deviceCustomFloatingPoint1Label', - type: 'keyword', - }, - 'cef.extensions.deviceCustomFloatingPoint3Label': { - category: 'cef', - description: - 'All custom fields have a corresponding label field. Each of these fields is a string and describes the purpose of the custom field.', - name: 'cef.extensions.deviceCustomFloatingPoint3Label', - type: 'keyword', - }, - 'cef.extensions.deviceCustomFloatingPoint4Label': { - category: 'cef', - description: - 'All custom fields have a corresponding label field. Each of these fields is a string and describes the purpose of the custom field.', - name: 'cef.extensions.deviceCustomFloatingPoint4Label', - type: 'keyword', - }, - 'cef.extensions.deviceCustomDate1': { - category: 'cef', - description: - 'One of two timestamp fields available to map fields that do not apply to any other in this dictionary.', - name: 'cef.extensions.deviceCustomDate1', - type: 'date', - }, - 'cef.extensions.deviceCustomDate1Label': { - category: 'cef', - description: - 'All custom fields have a corresponding label field. Each of these fields is a string and describes the purpose of the custom field.', - name: 'cef.extensions.deviceCustomDate1Label', - type: 'keyword', - }, - 'cef.extensions.deviceCustomDate2': { - category: 'cef', - description: - 'One of two timestamp fields available to map fields that do not apply to any other in this dictionary.', - name: 'cef.extensions.deviceCustomDate2', - type: 'date', - }, - 'cef.extensions.deviceCustomDate2Label': { - category: 'cef', - description: - 'All custom fields have a corresponding label field. Each of these fields is a string and describes the purpose of the custom field.', - name: 'cef.extensions.deviceCustomDate2Label', - type: 'keyword', - }, - 'cef.extensions.deviceCustomFloatingPoint1': { - category: 'cef', - description: - 'One of four floating point fields available to map fields that do not apply to any other in this dictionary.', - name: 'cef.extensions.deviceCustomFloatingPoint1', - type: 'double', - }, - 'cef.extensions.deviceCustomFloatingPoint2': { - category: 'cef', - description: - 'One of four floating point fields available to map fields that do not apply to any other in this dictionary.', - name: 'cef.extensions.deviceCustomFloatingPoint2', - type: 'double', - }, - 'cef.extensions.deviceCustomFloatingPoint2Label': { - category: 'cef', - description: - 'All custom fields have a corresponding label field. Each of these fields is a string and describes the purpose of the custom field.', - name: 'cef.extensions.deviceCustomFloatingPoint2Label', - type: 'keyword', - }, - 'cef.extensions.deviceCustomFloatingPoint3': { - category: 'cef', - description: - 'One of four floating point fields available to map fields that do not apply to any other in this dictionary.', - name: 'cef.extensions.deviceCustomFloatingPoint3', - type: 'double', - }, - 'cef.extensions.deviceCustomFloatingPoint4': { - category: 'cef', - description: - 'One of four floating point fields available to map fields that do not apply to any other in this dictionary.', - name: 'cef.extensions.deviceCustomFloatingPoint4', - type: 'double', - }, - 'cef.extensions.deviceCustomIPv6Address1': { - category: 'cef', - description: - 'One of four IPv6 address fields available to map fields that do not apply to any other in this dictionary.', - name: 'cef.extensions.deviceCustomIPv6Address1', - type: 'ip', - }, - 'cef.extensions.deviceCustomIPv6Address1Label': { - category: 'cef', - description: - 'All custom fields have a corresponding label field. Each of these fields is a string and describes the purpose of the custom field.', - name: 'cef.extensions.deviceCustomIPv6Address1Label', - type: 'keyword', - }, - 'cef.extensions.deviceCustomIPv6Address2': { - category: 'cef', - description: - 'One of four IPv6 address fields available to map fields that do not apply to any other in this dictionary.', - name: 'cef.extensions.deviceCustomIPv6Address2', - type: 'ip', - }, - 'cef.extensions.deviceCustomIPv6Address2Label': { - category: 'cef', - description: - 'All custom fields have a corresponding label field. Each of these fields is a string and describes the purpose of the custom field.', - name: 'cef.extensions.deviceCustomIPv6Address2Label', - type: 'keyword', - }, - 'cef.extensions.deviceCustomIPv6Address3': { - category: 'cef', - description: - 'One of four IPv6 address fields available to map fields that do not apply to any other in this dictionary.', - name: 'cef.extensions.deviceCustomIPv6Address3', - type: 'ip', - }, - 'cef.extensions.deviceCustomIPv6Address3Label': { - category: 'cef', - description: - 'All custom fields have a corresponding label field. Each of these fields is a string and describes the purpose of the custom field.', - name: 'cef.extensions.deviceCustomIPv6Address3Label', - type: 'keyword', - }, - 'cef.extensions.deviceCustomIPv6Address4': { - category: 'cef', - description: - 'One of four IPv6 address fields available to map fields that do not apply to any other in this dictionary.', - name: 'cef.extensions.deviceCustomIPv6Address4', - type: 'ip', - }, - 'cef.extensions.deviceCustomIPv6Address4Label': { - category: 'cef', - description: - 'All custom fields have a corresponding label field. Each of these fields is a string and describes the purpose of the custom field.', - name: 'cef.extensions.deviceCustomIPv6Address4Label', - type: 'keyword', - }, - 'cef.extensions.deviceCustomNumber1': { - category: 'cef', - description: - 'One of three number fields available to map fields that do not apply to any other in this dictionary. Use sparingly and seek a more specific, dictionary supplied field when possible.', - name: 'cef.extensions.deviceCustomNumber1', - type: 'long', - }, - 'cef.extensions.deviceCustomNumber1Label': { - category: 'cef', - description: - 'All custom fields have a corresponding label field. Each of these fields is a string and describes the purpose of the custom field.', - name: 'cef.extensions.deviceCustomNumber1Label', - type: 'keyword', - }, - 'cef.extensions.deviceCustomNumber2': { - category: 'cef', - description: - 'One of three number fields available to map fields that do not apply to any other in this dictionary. Use sparingly and seek a more specific, dictionary supplied field when possible.', - name: 'cef.extensions.deviceCustomNumber2', - type: 'long', - }, - 'cef.extensions.deviceCustomNumber2Label': { - category: 'cef', - description: - 'All custom fields have a corresponding label field. Each of these fields is a string and describes the purpose of the custom field.', - name: 'cef.extensions.deviceCustomNumber2Label', - type: 'keyword', - }, - 'cef.extensions.deviceCustomNumber3': { - category: 'cef', - description: - 'One of three number fields available to map fields that do not apply to any other in this dictionary. Use sparingly and seek a more specific, dictionary supplied field when possible.', - name: 'cef.extensions.deviceCustomNumber3', - type: 'long', - }, - 'cef.extensions.deviceCustomNumber3Label': { - category: 'cef', - description: - 'All custom fields have a corresponding label field. Each of these fields is a string and describes the purpose of the custom field.', - name: 'cef.extensions.deviceCustomNumber3Label', - type: 'keyword', - }, - 'cef.extensions.deviceCustomString1': { - category: 'cef', - description: - 'One of six strings available to map fields that do not apply to any other in this dictionary. Use sparingly and seek a more specific, dictionary supplied field when possible.', - name: 'cef.extensions.deviceCustomString1', - type: 'keyword', - }, - 'cef.extensions.deviceCustomString1Label': { - category: 'cef', - description: - 'All custom fields have a corresponding label field. Each of these fields is a string and describes the purpose of the custom field.', - name: 'cef.extensions.deviceCustomString1Label', - type: 'keyword', - }, - 'cef.extensions.deviceCustomString2': { - category: 'cef', - description: - 'One of six strings available to map fields that do not apply to any other in this dictionary. Use sparingly and seek a more specific, dictionary supplied field when possible.', - name: 'cef.extensions.deviceCustomString2', - type: 'keyword', - }, - 'cef.extensions.deviceCustomString2Label': { - category: 'cef', - description: - 'All custom fields have a corresponding label field. Each of these fields is a string and describes the purpose of the custom field.', - name: 'cef.extensions.deviceCustomString2Label', - type: 'keyword', - }, - 'cef.extensions.deviceCustomString3': { - category: 'cef', - description: - 'One of six strings available to map fields that do not apply to any other in this dictionary. Use sparingly and seek a more specific, dictionary supplied field when possible.', - name: 'cef.extensions.deviceCustomString3', - type: 'keyword', - }, - 'cef.extensions.deviceCustomString3Label': { - category: 'cef', - description: - 'All custom fields have a corresponding label field. Each of these fields is a string and describes the purpose of the custom field.', - name: 'cef.extensions.deviceCustomString3Label', - type: 'keyword', - }, - 'cef.extensions.deviceCustomString4': { - category: 'cef', - description: - 'One of six strings available to map fields that do not apply to any other in this dictionary. Use sparingly and seek a more specific, dictionary supplied field when possible.', - name: 'cef.extensions.deviceCustomString4', - type: 'keyword', - }, - 'cef.extensions.deviceCustomString4Label': { - category: 'cef', - description: - 'All custom fields have a corresponding label field. Each of these fields is a string and describes the purpose of the custom field.', - name: 'cef.extensions.deviceCustomString4Label', - type: 'keyword', - }, - 'cef.extensions.deviceCustomString5': { - category: 'cef', - description: - 'One of six strings available to map fields that do not apply to any other in this dictionary. Use sparingly and seek a more specific, dictionary supplied field when possible.', - name: 'cef.extensions.deviceCustomString5', - type: 'keyword', - }, - 'cef.extensions.deviceCustomString5Label': { - category: 'cef', - description: - 'All custom fields have a corresponding label field. Each of these fields is a string and describes the purpose of the custom field.', - name: 'cef.extensions.deviceCustomString5Label', - type: 'keyword', - }, - 'cef.extensions.deviceCustomString6': { - category: 'cef', - description: - 'One of six strings available to map fields that do not apply to any other in this dictionary. Use sparingly and seek a more specific, dictionary supplied field when possible.', - name: 'cef.extensions.deviceCustomString6', - type: 'keyword', - }, - 'cef.extensions.deviceCustomString6Label': { - category: 'cef', - description: - 'All custom fields have a corresponding label field. Each of these fields is a string and describes the purpose of the custom field.', - name: 'cef.extensions.deviceCustomString6Label', - type: 'keyword', - }, - 'cef.extensions.deviceDirection': { - category: 'cef', - description: - 'Any information about what direction the observed communication has taken. The following values are supported - "0" for inbound or "1" for outbound.', - name: 'cef.extensions.deviceDirection', - type: 'long', - }, - 'cef.extensions.deviceDnsDomain': { - category: 'cef', - description: 'The DNS domain part of the complete fully qualified domain name (FQDN).', - name: 'cef.extensions.deviceDnsDomain', - type: 'keyword', - }, - 'cef.extensions.deviceEventCategory': { - category: 'cef', - description: - 'Represents the category assigned by the originating device. Devices often use their own categorization schema to classify event. Example "/Monitor/Disk/Read".', - name: 'cef.extensions.deviceEventCategory', - type: 'keyword', - }, - 'cef.extensions.deviceExternalId': { - category: 'cef', - description: 'A name that uniquely identifies the device generating this event.', - name: 'cef.extensions.deviceExternalId', - type: 'keyword', - }, - 'cef.extensions.deviceFacility': { - category: 'cef', - description: - 'The facility generating this event. For example, Syslog has an explicit facility associated with every event.', - name: 'cef.extensions.deviceFacility', - type: 'keyword', - }, - 'cef.extensions.deviceFlexNumber1': { - category: 'cef', - description: - 'One of two alternative number fields available to map fields that do not apply to any other in this dictionary. Use sparingly and seek a more specific, dictionary supplied field when possible.', - name: 'cef.extensions.deviceFlexNumber1', - type: 'long', - }, - 'cef.extensions.deviceFlexNumber1Label': { - category: 'cef', - description: - 'All custom fields have a corresponding label field. Each of these fields is a string and describes the purpose of the custom field.', - name: 'cef.extensions.deviceFlexNumber1Label', - type: 'keyword', - }, - 'cef.extensions.deviceFlexNumber2': { - category: 'cef', - description: - 'One of two alternative number fields available to map fields that do not apply to any other in this dictionary. Use sparingly and seek a more specific, dictionary supplied field when possible.', - name: 'cef.extensions.deviceFlexNumber2', - type: 'long', - }, - 'cef.extensions.deviceFlexNumber2Label': { - category: 'cef', - description: - 'All custom fields have a corresponding label field. Each of these fields is a string and describes the purpose of the custom field.', - name: 'cef.extensions.deviceFlexNumber2Label', - type: 'keyword', - }, - 'cef.extensions.deviceHostName': { - category: 'cef', - description: - 'The format should be a fully qualified domain name (FQDN) associated with the device node, when a node is available.', - name: 'cef.extensions.deviceHostName', - type: 'keyword', - }, - 'cef.extensions.deviceInboundInterface': { - category: 'cef', - description: 'Interface on which the packet or data entered the device.', - name: 'cef.extensions.deviceInboundInterface', - type: 'keyword', - }, - 'cef.extensions.deviceMacAddress': { - category: 'cef', - description: 'Six colon-separated hexadecimal numbers.', - name: 'cef.extensions.deviceMacAddress', - type: 'keyword', - }, - 'cef.extensions.deviceNtDomain': { - category: 'cef', - description: 'The Windows domain name of the device address.', - name: 'cef.extensions.deviceNtDomain', - type: 'keyword', - }, - 'cef.extensions.deviceOutboundInterface': { - category: 'cef', - description: 'Interface on which the packet or data left the device.', - name: 'cef.extensions.deviceOutboundInterface', - type: 'keyword', - }, - 'cef.extensions.devicePayloadId': { - category: 'cef', - description: 'Unique identifier for the payload associated with the event.', - name: 'cef.extensions.devicePayloadId', - type: 'keyword', - }, - 'cef.extensions.deviceProcessId': { - category: 'cef', - description: 'Provides the ID of the process on the device generating the event.', - name: 'cef.extensions.deviceProcessId', - type: 'long', - }, - 'cef.extensions.deviceProcessName': { - category: 'cef', - description: - 'Process name associated with the event. An example might be the process generating the syslog entry in UNIX.', - name: 'cef.extensions.deviceProcessName', - type: 'keyword', - }, - 'cef.extensions.deviceReceiptTime': { - category: 'cef', - description: - 'The time at which the event related to the activity was received. The format is MMM dd yyyy HH:mm:ss or milliseconds since epoch (Jan 1st 1970)', - name: 'cef.extensions.deviceReceiptTime', - type: 'date', - }, - 'cef.extensions.deviceTimeZone': { - category: 'cef', - description: 'The time zone for the device generating the event.', - name: 'cef.extensions.deviceTimeZone', - type: 'keyword', - }, - 'cef.extensions.deviceTranslatedAddress': { - category: 'cef', - description: - 'Identifies the translated device address that the event refers to in an IP network.', - name: 'cef.extensions.deviceTranslatedAddress', - type: 'ip', - }, - 'cef.extensions.deviceTranslatedZoneExternalID': { - category: 'cef', - description: 'null', - name: 'cef.extensions.deviceTranslatedZoneExternalID', - type: 'keyword', - }, - 'cef.extensions.deviceTranslatedZoneURI': { - category: 'cef', - description: - 'The URI for the Translated Zone that the device asset has been assigned to in ArcSight.', - name: 'cef.extensions.deviceTranslatedZoneURI', - type: 'keyword', - }, - 'cef.extensions.deviceZoneExternalID': { - category: 'cef', - description: 'null', - name: 'cef.extensions.deviceZoneExternalID', - type: 'keyword', - }, - 'cef.extensions.deviceZoneURI': { - category: 'cef', - description: 'Thee URI for the Zone that the device asset has been assigned to in ArcSight.', - name: 'cef.extensions.deviceZoneURI', - type: 'keyword', - }, - 'cef.extensions.endTime': { - category: 'cef', - description: - 'The time at which the activity related to the event ended. The format is MMM dd yyyy HH:mm:ss or milliseconds since epoch (Jan 1st1970). An example would be reporting the end of a session.', - name: 'cef.extensions.endTime', - type: 'date', - }, - 'cef.extensions.eventId': { - category: 'cef', - description: 'This is a unique ID that ArcSight assigns to each event.', - name: 'cef.extensions.eventId', - type: 'long', - }, - 'cef.extensions.eventOutcome': { - category: 'cef', - description: "Displays the outcome, usually as 'success' or 'failure'.", - name: 'cef.extensions.eventOutcome', - type: 'keyword', - }, - 'cef.extensions.externalId': { - category: 'cef', - description: - 'The ID used by an originating device. They are usually increasing numbers, associated with events.', - name: 'cef.extensions.externalId', - type: 'keyword', - }, - 'cef.extensions.fileCreateTime': { - category: 'cef', - description: 'Time when the file was created.', - name: 'cef.extensions.fileCreateTime', - type: 'date', - }, - 'cef.extensions.fileHash': { - category: 'cef', - description: 'Hash of a file.', - name: 'cef.extensions.fileHash', - type: 'keyword', - }, - 'cef.extensions.fileId': { - category: 'cef', - description: 'An ID associated with a file could be the inode.', - name: 'cef.extensions.fileId', - type: 'keyword', - }, - 'cef.extensions.fileModificationTime': { - category: 'cef', - description: 'Time when the file was last modified.', - name: 'cef.extensions.fileModificationTime', - type: 'date', - }, - 'cef.extensions.filename': { - category: 'cef', - description: 'Name of the file only (without its path).', - name: 'cef.extensions.filename', - type: 'keyword', - }, - 'cef.extensions.filePath': { - category: 'cef', - description: 'Full path to the file, including file name itself.', - name: 'cef.extensions.filePath', - type: 'keyword', - }, - 'cef.extensions.filePermission': { - category: 'cef', - description: 'Permissions of the file.', - name: 'cef.extensions.filePermission', - type: 'keyword', - }, - 'cef.extensions.fileSize': { - category: 'cef', - description: 'Size of the file.', - name: 'cef.extensions.fileSize', - type: 'long', - }, - 'cef.extensions.fileType': { - category: 'cef', - description: 'Type of file (pipe, socket, etc.)', - name: 'cef.extensions.fileType', - type: 'keyword', - }, - 'cef.extensions.flexDate1': { - category: 'cef', - description: - 'A timestamp field available to map a timestamp that does not apply to any other defined timestamp field in this dictionary. Use all flex fields sparingly and seek a more specific, dictionary supplied field when possible. These fields are typically reserved for customer use and should not be set by vendors unless necessary.', - name: 'cef.extensions.flexDate1', - type: 'date', - }, - 'cef.extensions.flexDate1Label': { - category: 'cef', - description: 'The label field is a string and describes the purpose of the flex field.', - name: 'cef.extensions.flexDate1Label', - type: 'keyword', - }, - 'cef.extensions.flexString1': { - category: 'cef', - description: - 'One of four floating point fields available to map fields that do not apply to any other in this dictionary. Use sparingly and seek a more specific, dictionary supplied field when possible. These fields are typically reserved for customer use and should not be set by vendors unless necessary.', - name: 'cef.extensions.flexString1', - type: 'keyword', - }, - 'cef.extensions.flexString2': { - category: 'cef', - description: - 'One of four floating point fields available to map fields that do not apply to any other in this dictionary. Use sparingly and seek a more specific, dictionary supplied field when possible. These fields are typically reserved for customer use and should not be set by vendors unless necessary.', - name: 'cef.extensions.flexString2', - type: 'keyword', - }, - 'cef.extensions.flexString1Label': { - category: 'cef', - description: 'The label field is a string and describes the purpose of the flex field.', - name: 'cef.extensions.flexString1Label', - type: 'keyword', - }, - 'cef.extensions.flexString2Label': { - category: 'cef', - description: 'The label field is a string and describes the purpose of the flex field.', - name: 'cef.extensions.flexString2Label', - type: 'keyword', - }, - 'cef.extensions.message': { - category: 'cef', - description: - 'An arbitrary message giving more details about the event. Multi-line entries can be produced by using \\n as the new line separator.', - name: 'cef.extensions.message', - type: 'keyword', - }, - 'cef.extensions.oldFileCreateTime': { - category: 'cef', - description: 'Time when old file was created.', - name: 'cef.extensions.oldFileCreateTime', - type: 'date', - }, - 'cef.extensions.oldFileHash': { - category: 'cef', - description: 'Hash of the old file.', - name: 'cef.extensions.oldFileHash', - type: 'keyword', - }, - 'cef.extensions.oldFileId': { - category: 'cef', - description: 'An ID associated with the old file could be the inode.', - name: 'cef.extensions.oldFileId', - type: 'keyword', - }, - 'cef.extensions.oldFileModificationTime': { - category: 'cef', - description: 'Time when old file was last modified.', - name: 'cef.extensions.oldFileModificationTime', - type: 'date', - }, - 'cef.extensions.oldFileName': { - category: 'cef', - description: 'Name of the old file.', - name: 'cef.extensions.oldFileName', - type: 'keyword', - }, - 'cef.extensions.oldFilePath': { - category: 'cef', - description: 'Full path to the old file, including the file name itself.', - name: 'cef.extensions.oldFilePath', - type: 'keyword', - }, - 'cef.extensions.oldFilePermission': { - category: 'cef', - description: 'Permissions of the old file.', - name: 'cef.extensions.oldFilePermission', - type: 'keyword', - }, - 'cef.extensions.oldFileSize': { - category: 'cef', - description: 'Size of the old file.', - name: 'cef.extensions.oldFileSize', - type: 'long', - }, - 'cef.extensions.oldFileType': { - category: 'cef', - description: 'Type of the old file (pipe, socket, etc.)', - name: 'cef.extensions.oldFileType', - type: 'keyword', - }, - 'cef.extensions.rawEvent': { - category: 'cef', - description: 'null', - name: 'cef.extensions.rawEvent', - type: 'keyword', - }, - 'cef.extensions.Reason': { - category: 'cef', - description: - 'The reason an audit event was generated. For example "bad password" or "unknown user". This could also be an error or return code. Example "0x1234".', - name: 'cef.extensions.Reason', - type: 'keyword', - }, - 'cef.extensions.requestClientApplication': { - category: 'cef', - description: 'The User-Agent associated with the request.', - name: 'cef.extensions.requestClientApplication', - type: 'keyword', - }, - 'cef.extensions.requestContext': { - category: 'cef', - description: - 'Description of the content from which the request originated (for example, HTTP Referrer)', - name: 'cef.extensions.requestContext', - type: 'keyword', - }, - 'cef.extensions.requestCookies': { - category: 'cef', - description: 'Cookies associated with the request.', - name: 'cef.extensions.requestCookies', - type: 'keyword', - }, - 'cef.extensions.requestMethod': { - category: 'cef', - description: 'The HTTP method used to access a URL.', - name: 'cef.extensions.requestMethod', - type: 'keyword', - }, - 'cef.extensions.requestUrl': { - category: 'cef', - description: - 'In the case of an HTTP request, this field contains the URL accessed. The URL should contain the protocol as well.', - name: 'cef.extensions.requestUrl', - type: 'keyword', - }, - 'cef.extensions.sourceAddress': { - category: 'cef', - description: 'Identifies the source that an event refers to in an IP network.', - name: 'cef.extensions.sourceAddress', - type: 'ip', - }, - 'cef.extensions.sourceDnsDomain': { - category: 'cef', - description: 'The DNS domain part of the complete fully qualified domain name (FQDN).', - name: 'cef.extensions.sourceDnsDomain', - type: 'keyword', - }, - 'cef.extensions.sourceGeoLatitude': { - category: 'cef', - description: 'null', - name: 'cef.extensions.sourceGeoLatitude', - type: 'double', - }, - 'cef.extensions.sourceGeoLongitude': { - category: 'cef', - description: 'null', - name: 'cef.extensions.sourceGeoLongitude', - type: 'double', - }, - 'cef.extensions.sourceHostName': { - category: 'cef', - description: - "Identifies the source that an event refers to in an IP network. The format should be a fully qualified domain name (FQDN) associated with the source node, when a mode is available. Examples: 'host' or 'host.domain.com'. ", - name: 'cef.extensions.sourceHostName', - type: 'keyword', - }, - 'cef.extensions.sourceMacAddress': { - category: 'cef', - description: 'Six colon-separated hexadecimal numbers.', - example: '00:0d:60:af:1b:61', - name: 'cef.extensions.sourceMacAddress', - type: 'keyword', - }, - 'cef.extensions.sourceNtDomain': { - category: 'cef', - description: 'The Windows domain name for the source address.', - name: 'cef.extensions.sourceNtDomain', - type: 'keyword', - }, - 'cef.extensions.sourcePort': { - category: 'cef', - description: 'The valid port numbers are 0 to 65535.', - name: 'cef.extensions.sourcePort', - type: 'long', - }, - 'cef.extensions.sourceProcessId': { - category: 'cef', - description: 'The ID of the source process associated with the event.', - name: 'cef.extensions.sourceProcessId', - type: 'long', - }, - 'cef.extensions.sourceProcessName': { - category: 'cef', - description: "The name of the event's source process.", - name: 'cef.extensions.sourceProcessName', - type: 'keyword', - }, - 'cef.extensions.sourceServiceName': { - category: 'cef', - description: 'The service that is responsible for generating this event.', - name: 'cef.extensions.sourceServiceName', - type: 'keyword', - }, - 'cef.extensions.sourceTranslatedAddress': { - category: 'cef', - description: 'Identifies the translated source that the event refers to in an IP network.', - name: 'cef.extensions.sourceTranslatedAddress', - type: 'ip', - }, - 'cef.extensions.sourceTranslatedPort': { - category: 'cef', - description: - 'A port number after being translated by, for example, a firewall. Valid port numbers are 0 to 65535.', - name: 'cef.extensions.sourceTranslatedPort', - type: 'long', - }, - 'cef.extensions.sourceTranslatedZoneExternalID': { - category: 'cef', - description: 'null', - name: 'cef.extensions.sourceTranslatedZoneExternalID', - type: 'keyword', - }, - 'cef.extensions.sourceTranslatedZoneURI': { - category: 'cef', - description: - 'The URI for the Translated Zone that the destination asset has been assigned to in ArcSight.', - name: 'cef.extensions.sourceTranslatedZoneURI', - type: 'keyword', - }, - 'cef.extensions.sourceUserId': { - category: 'cef', - description: - 'Identifies the source user by ID. This is the user associated with the source of the event. For example, in UNIX, the root user is generally associated with user ID 0.', - name: 'cef.extensions.sourceUserId', - type: 'keyword', - }, - 'cef.extensions.sourceUserName': { - category: 'cef', - description: - 'Identifies the source user by name. Email addresses are also mapped into the UserName fields. The sender is a candidate to put into this field.', - name: 'cef.extensions.sourceUserName', - type: 'keyword', - }, - 'cef.extensions.sourceUserPrivileges': { - category: 'cef', - description: - 'The typical values are "Administrator", "User", and "Guest". It identifies the source user\'s privileges. In UNIX, for example, activity executed by the root user would be identified with "Administrator".', - name: 'cef.extensions.sourceUserPrivileges', - type: 'keyword', - }, - 'cef.extensions.sourceZoneExternalID': { - category: 'cef', - description: 'null', - name: 'cef.extensions.sourceZoneExternalID', - type: 'keyword', - }, - 'cef.extensions.sourceZoneURI': { - category: 'cef', - description: 'The URI for the Zone that the source asset has been assigned to in ArcSight.', - name: 'cef.extensions.sourceZoneURI', - type: 'keyword', - }, - 'cef.extensions.startTime': { - category: 'cef', - description: - 'The time when the activity the event referred to started. The format is MMM dd yyyy HH:mm:ss or milliseconds since epoch (Jan 1st 1970)', - name: 'cef.extensions.startTime', - type: 'date', - }, - 'cef.extensions.transportProtocol': { - category: 'cef', - description: - 'Identifies the Layer-4 protocol used. The possible values are protocols such as TCP or UDP.', - name: 'cef.extensions.transportProtocol', - type: 'keyword', - }, - 'cef.extensions.type': { - category: 'cef', - description: - '0 means base event, 1 means aggregated, 2 means correlation, and 3 means action. This field can be omitted for base events (type 0).', - name: 'cef.extensions.type', - type: 'long', - }, - 'cef.extensions.categoryDeviceType': { - category: 'cef', - description: 'Device type. Examples - Proxy, IDS, Web Server', - name: 'cef.extensions.categoryDeviceType', - type: 'keyword', - }, - 'cef.extensions.categoryObject': { - category: 'cef', - description: - 'Object that the event is about. For example it can be an operating sytem, database, file, etc.', - name: 'cef.extensions.categoryObject', - type: 'keyword', - }, - 'cef.extensions.categoryBehavior': { - category: 'cef', - description: - "Action or a behavior associated with an event. It's what is being done to the object.", - name: 'cef.extensions.categoryBehavior', - type: 'keyword', - }, - 'cef.extensions.categoryTechnique': { - category: 'cef', - description: 'Technique being used (e.g. /DoS).', - name: 'cef.extensions.categoryTechnique', - type: 'keyword', - }, - 'cef.extensions.categoryDeviceGroup': { - category: 'cef', - description: 'General device group like Firewall.', - name: 'cef.extensions.categoryDeviceGroup', - type: 'keyword', - }, - 'cef.extensions.categorySignificance': { - category: 'cef', - description: 'Characterization of the importance of the event.', - name: 'cef.extensions.categorySignificance', - type: 'keyword', - }, - 'cef.extensions.categoryOutcome': { - category: 'cef', - description: 'Outcome of the event (e.g. sucess, failure, or attempt).', - name: 'cef.extensions.categoryOutcome', - type: 'keyword', - }, - 'cef.extensions.managerReceiptTime': { - category: 'cef', - description: 'When the Arcsight ESM received the event.', - name: 'cef.extensions.managerReceiptTime', - type: 'date', - }, - 'source.service.name': { - category: 'source', - description: 'Service that is the source of the event.', - name: 'source.service.name', - type: 'keyword', - }, - 'destination.service.name': { - category: 'destination', - description: 'Service that is the target of the event.', - name: 'destination.service.name', - type: 'keyword', - }, - type: { - category: 'base', - description: - 'The type of the transaction (for example, HTTP, MySQL, Redis, or RUM) or "flow" in case of flows. ', - name: 'type', - }, - 'server.process.name': { - category: 'server', - description: 'The name of the process that served the transaction. ', - name: 'server.process.name', - }, - 'server.process.args': { - category: 'server', - description: 'The command-line of the process that served the transaction. ', - name: 'server.process.args', - }, - 'server.process.executable': { - category: 'server', - description: 'Absolute path to the server process executable. ', - name: 'server.process.executable', - }, - 'server.process.working_directory': { - category: 'server', - description: 'The working directory of the server process. ', - name: 'server.process.working_directory', - }, - 'server.process.start': { - category: 'server', - description: 'The time the server process started. ', - name: 'server.process.start', - }, - 'client.process.name': { - category: 'client', - description: 'The name of the process that initiated the transaction. ', - name: 'client.process.name', - }, - 'client.process.args': { - category: 'client', - description: 'The command-line of the process that initiated the transaction. ', - name: 'client.process.args', - }, - 'client.process.executable': { - category: 'client', - description: 'Absolute path to the client process executable. ', - name: 'client.process.executable', - }, - 'client.process.working_directory': { - category: 'client', - description: 'The working directory of the client process. ', - name: 'client.process.working_directory', - }, - 'client.process.start': { - category: 'client', - description: 'The time the client process started. ', - name: 'client.process.start', - }, - real_ip: { - category: 'base', - description: - 'If the server initiating the transaction is a proxy, this field contains the original client IP address. For HTTP, for example, the IP address extracted from a configurable HTTP header, by default `X-Forwarded-For`. Unless this field is disabled, it always has a value, and it matches the `client_ip` for non proxy clients. ', - name: 'real_ip', - type: 'alias', - }, - transport: { - category: 'base', - description: - 'The transport protocol used for the transaction. If not specified, then tcp is assumed. ', - name: 'transport', - type: 'alias', - }, - 'flow.final': { - category: 'flow', - description: - 'Indicates if event is last event in flow. If final is false, the event reports an intermediate flow state only. ', - name: 'flow.final', - type: 'boolean', - }, - 'flow.id': { - category: 'flow', - description: 'Internal flow ID based on connection meta data and address. ', - name: 'flow.id', - }, - 'flow.vlan': { - category: 'flow', - description: - "VLAN identifier from the 802.1q frame. In case of a multi-tagged frame this field will be an array with the outer tag's VLAN identifier listed first. ", - name: 'flow.vlan', - type: 'long', - }, - flow_id: { - category: 'base', - name: 'flow_id', - type: 'alias', - }, - final: { - category: 'base', - name: 'final', - type: 'alias', - }, - vlan: { - category: 'base', - name: 'vlan', - type: 'alias', - }, - 'source.stats.net_bytes_total': { - category: 'source', - name: 'source.stats.net_bytes_total', - type: 'alias', - }, - 'source.stats.net_packets_total': { - category: 'source', - name: 'source.stats.net_packets_total', - type: 'alias', - }, - 'dest.stats.net_bytes_total': { - category: 'dest', - name: 'dest.stats.net_bytes_total', - type: 'alias', - }, - 'dest.stats.net_packets_total': { - category: 'dest', - name: 'dest.stats.net_packets_total', - type: 'alias', - }, - status: { - category: 'base', - description: - 'The high level status of the transaction. The way to compute this value depends on the protocol, but the result has a meaning independent of the protocol. ', - name: 'status', - }, - method: { - category: 'base', - description: - 'The command/verb/method of the transaction. For HTTP, this is the method name (GET, POST, PUT, and so on), for SQL this is the verb (SELECT, UPDATE, DELETE, and so on). ', - name: 'method', - }, - resource: { - category: 'base', - description: - 'The logical resource that this transaction refers to. For HTTP, this is the URL path up to the last slash (/). For example, if the URL is `/users/1`, the resource is `/users`. For databases, the resource is typically the table name. The field is not filled for all transaction types. ', - name: 'resource', - }, - path: { - category: 'base', - description: - 'The path the transaction refers to. For HTTP, this is the URL. For SQL databases, this is the table name. For key-value stores, this is the key. ', - name: 'path', - }, - query: { - category: 'base', - description: - 'The query in a human readable format. For HTTP, it will typically be something like `GET /users/_search?name=test`. For MySQL, it is something like `SELECT id from users where name=test`. ', - name: 'query', - type: 'keyword', - }, - params: { - category: 'base', - description: - 'The request parameters. For HTTP, these are the POST or GET parameters. For Thrift-RPC, these are the parameters from the request. ', - name: 'params', - type: 'text', - }, - notes: { - category: 'base', - description: - 'Messages from Packetbeat itself. This field usually contains error messages for interpreting the raw data. This information can be helpful for troubleshooting. ', - name: 'notes', - type: 'alias', - }, - request: { - category: 'base', - description: - 'For text protocols, this is the request as seen on the wire (application layer only). For binary protocols this is our representation of the request. ', - name: 'request', - type: 'text', - }, - response: { - category: 'base', - description: - 'For text protocols, this is the response as seen on the wire (application layer only). For binary protocols this is our representation of the request. ', - name: 'response', - type: 'text', - }, - bytes_in: { - category: 'base', - description: - 'The number of bytes of the request. Note that this size is the application layer message length, without the length of the IP or TCP headers. ', - name: 'bytes_in', - type: 'alias', - }, - bytes_out: { - category: 'base', - description: - 'The number of bytes of the response. Note that this size is the application layer message length, without the length of the IP or TCP headers. ', - name: 'bytes_out', - type: 'alias', - }, - 'amqp.reply-code': { - category: 'amqp', - description: 'AMQP reply code to an error, similar to http reply-code ', - example: 404, - name: 'amqp.reply-code', - type: 'long', - }, - 'amqp.reply-text': { - category: 'amqp', - description: 'Text explaining the error. ', - name: 'amqp.reply-text', - type: 'keyword', - }, - 'amqp.class-id': { - category: 'amqp', - description: 'Failing method class. ', - name: 'amqp.class-id', - type: 'long', - }, - 'amqp.method-id': { - category: 'amqp', - description: 'Failing method ID. ', - name: 'amqp.method-id', - type: 'long', - }, - 'amqp.exchange': { - category: 'amqp', - description: 'Name of the exchange. ', - name: 'amqp.exchange', - type: 'keyword', - }, - 'amqp.exchange-type': { - category: 'amqp', - description: 'Exchange type. ', - example: 'fanout', - name: 'amqp.exchange-type', - type: 'keyword', - }, - 'amqp.passive': { - category: 'amqp', - description: 'If set, do not create exchange/queue. ', - name: 'amqp.passive', - type: 'boolean', - }, - 'amqp.durable': { - category: 'amqp', - description: 'If set, request a durable exchange/queue. ', - name: 'amqp.durable', - type: 'boolean', - }, - 'amqp.exclusive': { - category: 'amqp', - description: 'If set, request an exclusive queue. ', - name: 'amqp.exclusive', - type: 'boolean', - }, - 'amqp.auto-delete': { - category: 'amqp', - description: 'If set, auto-delete queue when unused. ', - name: 'amqp.auto-delete', - type: 'boolean', - }, - 'amqp.no-wait': { - category: 'amqp', - description: 'If set, the server will not respond to the method. ', - name: 'amqp.no-wait', - type: 'boolean', - }, - 'amqp.consumer-tag': { - category: 'amqp', - description: 'Identifier for the consumer, valid within the current channel. ', - name: 'amqp.consumer-tag', - }, - 'amqp.delivery-tag': { - category: 'amqp', - description: 'The server-assigned and channel-specific delivery tag. ', - name: 'amqp.delivery-tag', - type: 'long', - }, - 'amqp.message-count': { - category: 'amqp', - description: - 'The number of messages in the queue, which will be zero for newly-declared queues. ', - name: 'amqp.message-count', - type: 'long', - }, - 'amqp.consumer-count': { - category: 'amqp', - description: 'The number of consumers of a queue. ', - name: 'amqp.consumer-count', - type: 'long', - }, - 'amqp.routing-key': { - category: 'amqp', - description: 'Message routing key. ', - name: 'amqp.routing-key', - type: 'keyword', - }, - 'amqp.no-ack': { - category: 'amqp', - description: 'If set, the server does not expect acknowledgements for messages. ', - name: 'amqp.no-ack', - type: 'boolean', - }, - 'amqp.no-local': { - category: 'amqp', - description: - 'If set, the server will not send messages to the connection that published them. ', - name: 'amqp.no-local', - type: 'boolean', - }, - 'amqp.if-unused': { - category: 'amqp', - description: 'Delete only if unused. ', - name: 'amqp.if-unused', - type: 'boolean', - }, - 'amqp.if-empty': { - category: 'amqp', - description: 'Delete only if empty. ', - name: 'amqp.if-empty', - type: 'boolean', - }, - 'amqp.queue': { - category: 'amqp', - description: 'The queue name identifies the queue within the vhost. ', - name: 'amqp.queue', - type: 'keyword', - }, - 'amqp.redelivered': { - category: 'amqp', - description: - 'Indicates that the message has been previously delivered to this or another client. ', - name: 'amqp.redelivered', - type: 'boolean', - }, - 'amqp.multiple': { - category: 'amqp', - description: 'Acknowledge multiple messages. ', - name: 'amqp.multiple', - type: 'boolean', - }, - 'amqp.arguments': { - category: 'amqp', - description: 'Optional additional arguments passed to some methods. Can be of various types. ', - name: 'amqp.arguments', - type: 'object', - }, - 'amqp.mandatory': { - category: 'amqp', - description: 'Indicates mandatory routing. ', - name: 'amqp.mandatory', - type: 'boolean', - }, - 'amqp.immediate': { - category: 'amqp', - description: 'Request immediate delivery. ', - name: 'amqp.immediate', - type: 'boolean', - }, - 'amqp.content-type': { - category: 'amqp', - description: 'MIME content type. ', - example: 'text/plain', - name: 'amqp.content-type', - type: 'keyword', - }, - 'amqp.content-encoding': { - category: 'amqp', - description: 'MIME content encoding. ', - name: 'amqp.content-encoding', - type: 'keyword', - }, - 'amqp.headers': { - category: 'amqp', - description: 'Message header field table. ', - name: 'amqp.headers', - type: 'object', - }, - 'amqp.delivery-mode': { - category: 'amqp', - description: 'Non-persistent (1) or persistent (2). ', - name: 'amqp.delivery-mode', - type: 'keyword', - }, - 'amqp.priority': { - category: 'amqp', - description: 'Message priority, 0 to 9. ', - name: 'amqp.priority', - type: 'long', - }, - 'amqp.correlation-id': { - category: 'amqp', - description: 'Application correlation identifier. ', - name: 'amqp.correlation-id', - type: 'keyword', - }, - 'amqp.reply-to': { - category: 'amqp', - description: 'Address to reply to. ', - name: 'amqp.reply-to', - type: 'keyword', - }, - 'amqp.expiration': { - category: 'amqp', - description: 'Message expiration specification. ', - name: 'amqp.expiration', - type: 'keyword', - }, - 'amqp.message-id': { - category: 'amqp', - description: 'Application message identifier. ', - name: 'amqp.message-id', - type: 'keyword', - }, - 'amqp.timestamp': { - category: 'amqp', - description: 'Message timestamp. ', - name: 'amqp.timestamp', - type: 'keyword', - }, - 'amqp.type': { - category: 'amqp', - description: 'Message type name. ', - name: 'amqp.type', - type: 'keyword', - }, - 'amqp.user-id': { - category: 'amqp', - description: 'Creating user id. ', - name: 'amqp.user-id', - type: 'keyword', - }, - 'amqp.app-id': { - category: 'amqp', - description: 'Creating application id. ', - name: 'amqp.app-id', - type: 'keyword', - }, - no_request: { - category: 'base', - name: 'no_request', - type: 'alias', - }, - 'cassandra.no_request': { - category: 'cassandra', - description: 'Indicates that there is no request because this is a PUSH message. ', - name: 'cassandra.no_request', - type: 'boolean', - }, - 'cassandra.request.headers.version': { - category: 'cassandra', - description: 'The version of the protocol.', - name: 'cassandra.request.headers.version', - type: 'long', - }, - 'cassandra.request.headers.flags': { - category: 'cassandra', - description: 'Flags applying to this frame.', - name: 'cassandra.request.headers.flags', - type: 'keyword', - }, - 'cassandra.request.headers.stream': { - category: 'cassandra', - description: - 'A frame has a stream id. If a client sends a request message with the stream id X, it is guaranteed that the stream id of the response to that message will be X.', - name: 'cassandra.request.headers.stream', - type: 'keyword', - }, - 'cassandra.request.headers.op': { - category: 'cassandra', - description: 'An operation type that distinguishes the actual message.', - name: 'cassandra.request.headers.op', - type: 'keyword', - }, - 'cassandra.request.headers.length': { - category: 'cassandra', - description: - 'A integer representing the length of the body of the frame (a frame is limited to 256MB in length).', - name: 'cassandra.request.headers.length', - type: 'long', - }, - 'cassandra.request.query': { - category: 'cassandra', - description: 'The CQL query which client send to cassandra.', - name: 'cassandra.request.query', - type: 'keyword', - }, - 'cassandra.response.headers.version': { - category: 'cassandra', - description: 'The version of the protocol.', - name: 'cassandra.response.headers.version', - type: 'long', - }, - 'cassandra.response.headers.flags': { - category: 'cassandra', - description: 'Flags applying to this frame.', - name: 'cassandra.response.headers.flags', - type: 'keyword', - }, - 'cassandra.response.headers.stream': { - category: 'cassandra', - description: - 'A frame has a stream id. If a client sends a request message with the stream id X, it is guaranteed that the stream id of the response to that message will be X.', - name: 'cassandra.response.headers.stream', - type: 'keyword', - }, - 'cassandra.response.headers.op': { - category: 'cassandra', - description: 'An operation type that distinguishes the actual message.', - name: 'cassandra.response.headers.op', - type: 'keyword', - }, - 'cassandra.response.headers.length': { - category: 'cassandra', - description: - 'A integer representing the length of the body of the frame (a frame is limited to 256MB in length).', - name: 'cassandra.response.headers.length', - type: 'long', - }, - 'cassandra.response.result.type': { - category: 'cassandra', - description: 'Cassandra result type.', - name: 'cassandra.response.result.type', - type: 'keyword', - }, - 'cassandra.response.result.rows.num_rows': { - category: 'cassandra', - description: 'Representing the number of rows present in this result.', - name: 'cassandra.response.result.rows.num_rows', - type: 'long', - }, - 'cassandra.response.result.rows.meta.keyspace': { - category: 'cassandra', - description: 'Only present after set Global_tables_spec, the keyspace name.', - name: 'cassandra.response.result.rows.meta.keyspace', - type: 'keyword', - }, - 'cassandra.response.result.rows.meta.table': { - category: 'cassandra', - description: 'Only present after set Global_tables_spec, the table name.', - name: 'cassandra.response.result.rows.meta.table', - type: 'keyword', - }, - 'cassandra.response.result.rows.meta.flags': { - category: 'cassandra', - description: 'Provides information on the formatting of the remaining information.', - name: 'cassandra.response.result.rows.meta.flags', - type: 'keyword', - }, - 'cassandra.response.result.rows.meta.col_count': { - category: 'cassandra', - description: - 'Representing the number of columns selected by the query that produced this result.', - name: 'cassandra.response.result.rows.meta.col_count', - type: 'long', - }, - 'cassandra.response.result.rows.meta.pkey_columns': { - category: 'cassandra', - description: 'Representing the PK columns index and counts.', - name: 'cassandra.response.result.rows.meta.pkey_columns', - type: 'long', - }, - 'cassandra.response.result.rows.meta.paging_state': { - category: 'cassandra', - description: - 'The paging_state is a bytes value that should be used in QUERY/EXECUTE to continue paging and retrieve the remainder of the result for this query.', - name: 'cassandra.response.result.rows.meta.paging_state', - type: 'keyword', - }, - 'cassandra.response.result.keyspace': { - category: 'cassandra', - description: 'Indicating the name of the keyspace that has been set.', - name: 'cassandra.response.result.keyspace', - type: 'keyword', - }, - 'cassandra.response.result.schema_change.change': { - category: 'cassandra', - description: 'Representing the type of changed involved.', - name: 'cassandra.response.result.schema_change.change', - type: 'keyword', - }, - 'cassandra.response.result.schema_change.keyspace': { - category: 'cassandra', - description: 'This describes which keyspace has changed.', - name: 'cassandra.response.result.schema_change.keyspace', - type: 'keyword', - }, - 'cassandra.response.result.schema_change.table': { - category: 'cassandra', - description: 'This describes which table has changed.', - name: 'cassandra.response.result.schema_change.table', - type: 'keyword', - }, - 'cassandra.response.result.schema_change.object': { - category: 'cassandra', - description: - 'This describes the name of said affected object (either the table, user type, function, or aggregate name).', - name: 'cassandra.response.result.schema_change.object', - type: 'keyword', - }, - 'cassandra.response.result.schema_change.target': { - category: 'cassandra', - description: 'Target could be "FUNCTION" or "AGGREGATE", multiple arguments.', - name: 'cassandra.response.result.schema_change.target', - type: 'keyword', - }, - 'cassandra.response.result.schema_change.name': { - category: 'cassandra', - description: 'The function/aggregate name.', - name: 'cassandra.response.result.schema_change.name', - type: 'keyword', - }, - 'cassandra.response.result.schema_change.args': { - category: 'cassandra', - description: 'One string for each argument type (as CQL type).', - name: 'cassandra.response.result.schema_change.args', - type: 'keyword', - }, - 'cassandra.response.result.prepared.prepared_id': { - category: 'cassandra', - description: 'Representing the prepared query ID.', - name: 'cassandra.response.result.prepared.prepared_id', - type: 'keyword', - }, - 'cassandra.response.result.prepared.req_meta.keyspace': { - category: 'cassandra', - description: 'Only present after set Global_tables_spec, the keyspace name.', - name: 'cassandra.response.result.prepared.req_meta.keyspace', - type: 'keyword', - }, - 'cassandra.response.result.prepared.req_meta.table': { - category: 'cassandra', - description: 'Only present after set Global_tables_spec, the table name.', - name: 'cassandra.response.result.prepared.req_meta.table', - type: 'keyword', - }, - 'cassandra.response.result.prepared.req_meta.flags': { - category: 'cassandra', - description: 'Provides information on the formatting of the remaining information.', - name: 'cassandra.response.result.prepared.req_meta.flags', - type: 'keyword', - }, - 'cassandra.response.result.prepared.req_meta.col_count': { - category: 'cassandra', - description: - 'Representing the number of columns selected by the query that produced this result.', - name: 'cassandra.response.result.prepared.req_meta.col_count', - type: 'long', - }, - 'cassandra.response.result.prepared.req_meta.pkey_columns': { - category: 'cassandra', - description: 'Representing the PK columns index and counts.', - name: 'cassandra.response.result.prepared.req_meta.pkey_columns', - type: 'long', - }, - 'cassandra.response.result.prepared.req_meta.paging_state': { - category: 'cassandra', - description: - 'The paging_state is a bytes value that should be used in QUERY/EXECUTE to continue paging and retrieve the remainder of the result for this query.', - name: 'cassandra.response.result.prepared.req_meta.paging_state', - type: 'keyword', - }, - 'cassandra.response.result.prepared.resp_meta.keyspace': { - category: 'cassandra', - description: 'Only present after set Global_tables_spec, the keyspace name.', - name: 'cassandra.response.result.prepared.resp_meta.keyspace', - type: 'keyword', - }, - 'cassandra.response.result.prepared.resp_meta.table': { - category: 'cassandra', - description: 'Only present after set Global_tables_spec, the table name.', - name: 'cassandra.response.result.prepared.resp_meta.table', - type: 'keyword', - }, - 'cassandra.response.result.prepared.resp_meta.flags': { - category: 'cassandra', - description: 'Provides information on the formatting of the remaining information.', - name: 'cassandra.response.result.prepared.resp_meta.flags', - type: 'keyword', - }, - 'cassandra.response.result.prepared.resp_meta.col_count': { - category: 'cassandra', - description: - 'Representing the number of columns selected by the query that produced this result.', - name: 'cassandra.response.result.prepared.resp_meta.col_count', - type: 'long', - }, - 'cassandra.response.result.prepared.resp_meta.pkey_columns': { - category: 'cassandra', - description: 'Representing the PK columns index and counts.', - name: 'cassandra.response.result.prepared.resp_meta.pkey_columns', - type: 'long', - }, - 'cassandra.response.result.prepared.resp_meta.paging_state': { - category: 'cassandra', - description: - 'The paging_state is a bytes value that should be used in QUERY/EXECUTE to continue paging and retrieve the remainder of the result for this query.', - name: 'cassandra.response.result.prepared.resp_meta.paging_state', - type: 'keyword', - }, - 'cassandra.response.supported': { - category: 'cassandra', - description: - 'Indicates which startup options are supported by the server. This message comes as a response to an OPTIONS message.', - name: 'cassandra.response.supported', - type: 'object', - }, - 'cassandra.response.authentication.class': { - category: 'cassandra', - description: 'Indicates the full class name of the IAuthenticator in use', - name: 'cassandra.response.authentication.class', - type: 'keyword', - }, - 'cassandra.response.warnings': { - category: 'cassandra', - description: 'The text of the warnings, only occur when Warning flag was set.', - name: 'cassandra.response.warnings', - type: 'keyword', - }, - 'cassandra.response.event.type': { - category: 'cassandra', - description: 'Representing the event type.', - name: 'cassandra.response.event.type', - type: 'keyword', - }, - 'cassandra.response.event.change': { - category: 'cassandra', - description: - 'The message corresponding respectively to the type of change followed by the address of the new/removed node.', - name: 'cassandra.response.event.change', - type: 'keyword', - }, - 'cassandra.response.event.host': { - category: 'cassandra', - description: 'Representing the node ip.', - name: 'cassandra.response.event.host', - type: 'keyword', - }, - 'cassandra.response.event.port': { - category: 'cassandra', - description: 'Representing the node port.', - name: 'cassandra.response.event.port', - type: 'long', - }, - 'cassandra.response.event.schema_change.change': { - category: 'cassandra', - description: 'Representing the type of changed involved.', - name: 'cassandra.response.event.schema_change.change', - type: 'keyword', - }, - 'cassandra.response.event.schema_change.keyspace': { - category: 'cassandra', - description: 'This describes which keyspace has changed.', - name: 'cassandra.response.event.schema_change.keyspace', - type: 'keyword', - }, - 'cassandra.response.event.schema_change.table': { - category: 'cassandra', - description: 'This describes which table has changed.', - name: 'cassandra.response.event.schema_change.table', - type: 'keyword', - }, - 'cassandra.response.event.schema_change.object': { - category: 'cassandra', - description: - 'This describes the name of said affected object (either the table, user type, function, or aggregate name).', - name: 'cassandra.response.event.schema_change.object', - type: 'keyword', - }, - 'cassandra.response.event.schema_change.target': { - category: 'cassandra', - description: 'Target could be "FUNCTION" or "AGGREGATE", multiple arguments.', - name: 'cassandra.response.event.schema_change.target', - type: 'keyword', - }, - 'cassandra.response.event.schema_change.name': { - category: 'cassandra', - description: 'The function/aggregate name.', - name: 'cassandra.response.event.schema_change.name', - type: 'keyword', - }, - 'cassandra.response.event.schema_change.args': { - category: 'cassandra', - description: 'One string for each argument type (as CQL type).', - name: 'cassandra.response.event.schema_change.args', - type: 'keyword', - }, - 'cassandra.response.error.code': { - category: 'cassandra', - description: 'The error code of the Cassandra response.', - name: 'cassandra.response.error.code', - type: 'long', - }, - 'cassandra.response.error.msg': { - category: 'cassandra', - description: 'The error message of the Cassandra response.', - name: 'cassandra.response.error.msg', - type: 'keyword', - }, - 'cassandra.response.error.type': { - category: 'cassandra', - description: 'The error type of the Cassandra response.', - name: 'cassandra.response.error.type', - type: 'keyword', - }, - 'cassandra.response.error.details.read_consistency': { - category: 'cassandra', - description: 'Representing the consistency level of the query that triggered the exception.', - name: 'cassandra.response.error.details.read_consistency', - type: 'keyword', - }, - 'cassandra.response.error.details.required': { - category: 'cassandra', - description: - 'Representing the number of nodes that should be alive to respect consistency level.', - name: 'cassandra.response.error.details.required', - type: 'long', - }, - 'cassandra.response.error.details.alive': { - category: 'cassandra', - description: - 'Representing the number of replicas that were known to be alive when the request had been processed (since an unavailable exception has been triggered).', - name: 'cassandra.response.error.details.alive', - type: 'long', - }, - 'cassandra.response.error.details.received': { - category: 'cassandra', - description: 'Representing the number of nodes having acknowledged the request.', - name: 'cassandra.response.error.details.received', - type: 'long', - }, - 'cassandra.response.error.details.blockfor': { - category: 'cassandra', - description: - 'Representing the number of replicas whose acknowledgement is required to achieve consistency level.', - name: 'cassandra.response.error.details.blockfor', - type: 'long', - }, - 'cassandra.response.error.details.write_type': { - category: 'cassandra', - description: 'Describe the type of the write that timed out.', - name: 'cassandra.response.error.details.write_type', - type: 'keyword', - }, - 'cassandra.response.error.details.data_present': { - category: 'cassandra', - description: 'It means the replica that was asked for data had responded.', - name: 'cassandra.response.error.details.data_present', - type: 'boolean', - }, - 'cassandra.response.error.details.keyspace': { - category: 'cassandra', - description: 'The keyspace of the failed function.', - name: 'cassandra.response.error.details.keyspace', - type: 'keyword', - }, - 'cassandra.response.error.details.table': { - category: 'cassandra', - description: 'The keyspace of the failed function.', - name: 'cassandra.response.error.details.table', - type: 'keyword', - }, - 'cassandra.response.error.details.stmt_id': { - category: 'cassandra', - description: 'Representing the unknown ID.', - name: 'cassandra.response.error.details.stmt_id', - type: 'keyword', - }, - 'cassandra.response.error.details.num_failures': { - category: 'cassandra', - description: - 'Representing the number of nodes that experience a failure while executing the request.', - name: 'cassandra.response.error.details.num_failures', - type: 'keyword', - }, - 'cassandra.response.error.details.function': { - category: 'cassandra', - description: 'The name of the failed function.', - name: 'cassandra.response.error.details.function', - type: 'keyword', - }, - 'cassandra.response.error.details.arg_types': { - category: 'cassandra', - description: 'One string for each argument type (as CQL type) of the failed function.', - name: 'cassandra.response.error.details.arg_types', - type: 'keyword', - }, - 'dhcpv4.transaction_id': { - category: 'dhcpv4', - description: - 'Transaction ID, a random number chosen by the client, used by the client and server to associate messages and responses between a client and a server. ', - name: 'dhcpv4.transaction_id', - type: 'keyword', - }, - 'dhcpv4.seconds': { - category: 'dhcpv4', - description: - 'Number of seconds elapsed since client began address acquisition or renewal process. ', - name: 'dhcpv4.seconds', - type: 'long', - }, - 'dhcpv4.flags': { - category: 'dhcpv4', - description: - 'Flags are set by the client to indicate how the DHCP server should its reply -- either unicast or broadcast. ', - name: 'dhcpv4.flags', - type: 'keyword', - }, - 'dhcpv4.client_ip': { - category: 'dhcpv4', - description: 'The current IP address of the client.', - name: 'dhcpv4.client_ip', - type: 'ip', - }, - 'dhcpv4.assigned_ip': { - category: 'dhcpv4', - description: - 'The IP address that the DHCP server is assigning to the client. This field is also known as "your" IP address. ', - name: 'dhcpv4.assigned_ip', - type: 'ip', - }, - 'dhcpv4.server_ip': { - category: 'dhcpv4', - description: - 'The IP address of the DHCP server that the client should use for the next step in the bootstrap process. ', - name: 'dhcpv4.server_ip', - type: 'ip', - }, - 'dhcpv4.relay_ip': { - category: 'dhcpv4', - description: - 'The relay IP address used by the client to contact the server (i.e. a DHCP relay server). ', - name: 'dhcpv4.relay_ip', - type: 'ip', - }, - 'dhcpv4.client_mac': { - category: 'dhcpv4', - description: "The client's MAC address (layer two).", - name: 'dhcpv4.client_mac', - type: 'keyword', - }, - 'dhcpv4.server_name': { - category: 'dhcpv4', - description: - 'The name of the server sending the message. Optional. Used in DHCPOFFER or DHCPACK messages. ', - name: 'dhcpv4.server_name', - type: 'keyword', - }, - 'dhcpv4.op_code': { - category: 'dhcpv4', - description: 'The message op code (bootrequest or bootreply). ', - example: 'bootreply', - name: 'dhcpv4.op_code', - type: 'keyword', - }, - 'dhcpv4.hops': { - category: 'dhcpv4', - description: 'The number of hops the DHCP message went through.', - name: 'dhcpv4.hops', - type: 'long', - }, - 'dhcpv4.hardware_type': { - category: 'dhcpv4', - description: 'The type of hardware used for the local network (Ethernet, LocalTalk, etc). ', - name: 'dhcpv4.hardware_type', - type: 'keyword', - }, - 'dhcpv4.option.message_type': { - category: 'dhcpv4', - description: - 'The specific type of DHCP message being sent (e.g. discover, offer, request, decline, ack, nak, release, inform). ', - example: 'ack', - name: 'dhcpv4.option.message_type', - type: 'keyword', - }, - 'dhcpv4.option.parameter_request_list': { - category: 'dhcpv4', - description: - 'This option is used by a DHCP client to request values for specified configuration parameters. ', - name: 'dhcpv4.option.parameter_request_list', - type: 'keyword', - }, - 'dhcpv4.option.requested_ip_address': { - category: 'dhcpv4', - description: - 'This option is used in a client request (DHCPDISCOVER) to allow the client to request that a particular IP address be assigned. ', - name: 'dhcpv4.option.requested_ip_address', - type: 'ip', - }, - 'dhcpv4.option.server_identifier': { - category: 'dhcpv4', - description: 'IP address of the individual DHCP server which handled this message. ', - name: 'dhcpv4.option.server_identifier', - type: 'ip', - }, - 'dhcpv4.option.broadcast_address': { - category: 'dhcpv4', - description: "This option specifies the broadcast address in use on the client's subnet. ", - name: 'dhcpv4.option.broadcast_address', - type: 'ip', - }, - 'dhcpv4.option.max_dhcp_message_size': { - category: 'dhcpv4', - description: - 'This option specifies the maximum length DHCP message that the client is willing to accept. ', - name: 'dhcpv4.option.max_dhcp_message_size', - type: 'long', - }, - 'dhcpv4.option.class_identifier': { - category: 'dhcpv4', - description: - "This option is used by DHCP clients to optionally identify the vendor type and configuration of a DHCP client. Vendors may choose to define specific vendor class identifiers to convey particular configuration or other identification information about a client. For example, the identifier may encode the client's hardware configuration. ", - name: 'dhcpv4.option.class_identifier', - type: 'keyword', - }, - 'dhcpv4.option.domain_name': { - category: 'dhcpv4', - description: - 'This option specifies the domain name that client should use when resolving hostnames via the Domain Name System. ', - name: 'dhcpv4.option.domain_name', - type: 'keyword', - }, - 'dhcpv4.option.dns_servers': { - category: 'dhcpv4', - description: - 'The domain name server option specifies a list of Domain Name System servers available to the client. ', - name: 'dhcpv4.option.dns_servers', - type: 'ip', - }, - 'dhcpv4.option.vendor_identifying_options': { - category: 'dhcpv4', - description: - 'A DHCP client may use this option to unambiguously identify the vendor that manufactured the hardware on which the client is running, the software in use, or an industry consortium to which the vendor belongs. This field is described in RFC 3925. ', - name: 'dhcpv4.option.vendor_identifying_options', - type: 'object', - }, - 'dhcpv4.option.subnet_mask': { - category: 'dhcpv4', - description: 'The subnet mask that the client should use on the currnet network. ', - name: 'dhcpv4.option.subnet_mask', - type: 'ip', - }, - 'dhcpv4.option.utc_time_offset_sec': { - category: 'dhcpv4', - description: - "The time offset field specifies the offset of the client's subnet in seconds from Coordinated Universal Time (UTC). ", - name: 'dhcpv4.option.utc_time_offset_sec', - type: 'long', - }, - 'dhcpv4.option.router': { - category: 'dhcpv4', - description: - "The router option specifies a list of IP addresses for routers on the client's subnet. ", - name: 'dhcpv4.option.router', - type: 'ip', - }, - 'dhcpv4.option.time_servers': { - category: 'dhcpv4', - description: - 'The time server option specifies a list of RFC 868 time servers available to the client. ', - name: 'dhcpv4.option.time_servers', - type: 'ip', - }, - 'dhcpv4.option.ntp_servers': { - category: 'dhcpv4', - description: - 'This option specifies a list of IP addresses indicating NTP servers available to the client. ', - name: 'dhcpv4.option.ntp_servers', - type: 'ip', - }, - 'dhcpv4.option.hostname': { - category: 'dhcpv4', - description: 'This option specifies the name of the client. ', - name: 'dhcpv4.option.hostname', - type: 'keyword', - }, - 'dhcpv4.option.ip_address_lease_time_sec': { - category: 'dhcpv4', - description: - 'This option is used in a client request (DHCPDISCOVER or DHCPREQUEST) to allow the client to request a lease time for the IP address. In a server reply (DHCPOFFER), a DHCP server uses this option to specify the lease time it is willing to offer. ', - name: 'dhcpv4.option.ip_address_lease_time_sec', - type: 'long', - }, - 'dhcpv4.option.message': { - category: 'dhcpv4', - description: - 'This option is used by a DHCP server to provide an error message to a DHCP client in a DHCPNAK message in the event of a failure. A client may use this option in a DHCPDECLINE message to indicate the why the client declined the offered parameters. ', - name: 'dhcpv4.option.message', - type: 'text', - }, - 'dhcpv4.option.renewal_time_sec': { - category: 'dhcpv4', - description: - 'This option specifies the time interval from address assignment until the client transitions to the RENEWING state. ', - name: 'dhcpv4.option.renewal_time_sec', - type: 'long', - }, - 'dhcpv4.option.rebinding_time_sec': { - category: 'dhcpv4', - description: - 'This option specifies the time interval from address assignment until the client transitions to the REBINDING state. ', - name: 'dhcpv4.option.rebinding_time_sec', - type: 'long', - }, - 'dhcpv4.option.boot_file_name': { - category: 'dhcpv4', - description: - "This option is used to identify a bootfile when the 'file' field in the DHCP header has been used for DHCP options. ", - name: 'dhcpv4.option.boot_file_name', - type: 'keyword', - }, - 'dns.flags.authoritative': { - category: 'dns', - description: - 'A DNS flag specifying that the responding server is an authority for the domain name used in the question. ', - name: 'dns.flags.authoritative', - type: 'boolean', - }, - 'dns.flags.recursion_available': { - category: 'dns', - description: - 'A DNS flag specifying whether recursive query support is available in the name server. ', - name: 'dns.flags.recursion_available', - type: 'boolean', - }, - 'dns.flags.recursion_desired': { - category: 'dns', - description: - 'A DNS flag specifying that the client directs the server to pursue a query recursively. Recursive query support is optional. ', - name: 'dns.flags.recursion_desired', - type: 'boolean', - }, - 'dns.flags.authentic_data': { - category: 'dns', - description: - 'A DNS flag specifying that the recursive server considers the response authentic. ', - name: 'dns.flags.authentic_data', - type: 'boolean', - }, - 'dns.flags.checking_disabled': { - category: 'dns', - description: - 'A DNS flag specifying that the client disables the server signature validation of the query. ', - name: 'dns.flags.checking_disabled', - type: 'boolean', - }, - 'dns.flags.truncated_response': { - category: 'dns', - description: 'A DNS flag specifying that only the first 512 bytes of the reply were returned. ', - name: 'dns.flags.truncated_response', - type: 'boolean', - }, - 'dns.question.etld_plus_one': { - category: 'dns', - description: - 'The effective top-level domain (eTLD) plus one more label. For example, the eTLD+1 for "foo.bar.golang.org." is "golang.org.". The data for determining the eTLD comes from an embedded copy of the data from http://publicsuffix.org.', - example: 'amazon.co.uk.', - name: 'dns.question.etld_plus_one', - }, - 'dns.answers_count': { - category: 'dns', - description: 'The number of resource records contained in the `dns.answers` field. ', - name: 'dns.answers_count', - type: 'long', - }, - 'dns.authorities': { - category: 'dns', - description: 'An array containing a dictionary for each authority section from the answer. ', - name: 'dns.authorities', - type: 'object', - }, - 'dns.authorities_count': { - category: 'dns', - description: - 'The number of resource records contained in the `dns.authorities` field. The `dns.authorities` field may or may not be included depending on the configuration of Packetbeat. ', - name: 'dns.authorities_count', - type: 'long', - }, - 'dns.authorities.name': { - category: 'dns', - description: 'The domain name to which this resource record pertains.', - example: 'example.com.', - name: 'dns.authorities.name', - }, - 'dns.authorities.type': { - category: 'dns', - description: 'The type of data contained in this resource record.', - example: 'NS', - name: 'dns.authorities.type', - }, - 'dns.authorities.class': { - category: 'dns', - description: 'The class of DNS data contained in this resource record.', - example: 'IN', - name: 'dns.authorities.class', - }, - 'dns.additionals': { - category: 'dns', - description: 'An array containing a dictionary for each additional section from the answer. ', - name: 'dns.additionals', - type: 'object', - }, - 'dns.additionals_count': { - category: 'dns', - description: - 'The number of resource records contained in the `dns.additionals` field. The `dns.additionals` field may or may not be included depending on the configuration of Packetbeat. ', - name: 'dns.additionals_count', - type: 'long', - }, - 'dns.additionals.name': { - category: 'dns', - description: 'The domain name to which this resource record pertains.', - example: 'example.com.', - name: 'dns.additionals.name', - }, - 'dns.additionals.type': { - category: 'dns', - description: 'The type of data contained in this resource record.', - example: 'NS', - name: 'dns.additionals.type', - }, - 'dns.additionals.class': { - category: 'dns', - description: 'The class of DNS data contained in this resource record.', - example: 'IN', - name: 'dns.additionals.class', - }, - 'dns.additionals.ttl': { - category: 'dns', - description: - 'The time interval in seconds that this resource record may be cached before it should be discarded. Zero values mean that the data should not be cached. ', - name: 'dns.additionals.ttl', - type: 'long', - }, - 'dns.additionals.data': { - category: 'dns', - description: - 'The data describing the resource. The meaning of this data depends on the type and class of the resource record. ', - name: 'dns.additionals.data', - }, - 'dns.opt.version': { - category: 'dns', - description: 'The EDNS version.', - example: '0', - name: 'dns.opt.version', - }, - 'dns.opt.do': { - category: 'dns', - description: 'If set, the transaction uses DNSSEC.', - name: 'dns.opt.do', - type: 'boolean', - }, - 'dns.opt.ext_rcode': { - category: 'dns', - description: 'Extended response code field.', - example: 'BADVERS', - name: 'dns.opt.ext_rcode', - }, - 'dns.opt.udp_size': { - category: 'dns', - description: "Requestor's UDP payload size (in bytes).", - name: 'dns.opt.udp_size', - type: 'long', - }, - 'http.request.headers': { - category: 'http', - description: - 'A map containing the captured header fields from the request. Which headers to capture is configurable. If headers with the same header name are present in the message, they will be separated by commas. ', - name: 'http.request.headers', - type: 'object', - }, - 'http.request.params': { - category: 'http', - name: 'http.request.params', - type: 'alias', - }, - 'http.response.status_phrase': { - category: 'http', - description: 'The HTTP status phrase.', - example: 'Not Found', - name: 'http.response.status_phrase', - }, - 'http.response.headers': { - category: 'http', - description: - 'A map containing the captured header fields from the response. Which headers to capture is configurable. If headers with the same header name are present in the message, they will be separated by commas. ', - name: 'http.response.headers', - type: 'object', - }, - 'http.response.code': { - category: 'http', - name: 'http.response.code', - type: 'alias', - }, - 'http.response.phrase': { - category: 'http', - name: 'http.response.phrase', - type: 'alias', - }, - 'icmp.version': { - category: 'icmp', - description: 'The version of the ICMP protocol.', - name: 'icmp.version', - }, - 'icmp.request.message': { - category: 'icmp', - description: 'A human readable form of the request.', - name: 'icmp.request.message', - type: 'keyword', - }, - 'icmp.request.type': { - category: 'icmp', - description: 'The request type.', - name: 'icmp.request.type', - type: 'long', - }, - 'icmp.request.code': { - category: 'icmp', - description: 'The request code.', - name: 'icmp.request.code', - type: 'long', - }, - 'icmp.response.message': { - category: 'icmp', - description: 'A human readable form of the response.', - name: 'icmp.response.message', - type: 'keyword', - }, - 'icmp.response.type': { - category: 'icmp', - description: 'The response type.', - name: 'icmp.response.type', - type: 'long', - }, - 'icmp.response.code': { - category: 'icmp', - description: 'The response code.', - name: 'icmp.response.code', - type: 'long', - }, - 'memcache.protocol_type': { - category: 'memcache', - description: - 'The memcache protocol implementation. The value can be "binary" for binary-based, "text" for text-based, or "unknown" for an unknown memcache protocol type. ', - name: 'memcache.protocol_type', - type: 'keyword', - }, - 'memcache.request.line': { - category: 'memcache', - description: 'The raw command line for unknown commands ONLY. ', - name: 'memcache.request.line', - type: 'keyword', - }, - 'memcache.request.command': { - category: 'memcache', - description: - 'The memcache command being requested in the memcache text protocol. For example "set" or "get". The binary protocol opcodes are translated into memcache text protocol commands. ', - name: 'memcache.request.command', - type: 'keyword', - }, - 'memcache.response.command': { - category: 'memcache', - description: - 'Either the text based protocol response message type or the name of the originating request if binary protocol is used. ', - name: 'memcache.response.command', - type: 'keyword', - }, - 'memcache.request.type': { - category: 'memcache', - description: - 'The memcache command classification. This value can be "UNKNOWN", "Load", "Store", "Delete", "Counter", "Info", "SlabCtrl", "LRUCrawler", "Stats", "Success", "Fail", or "Auth". ', - name: 'memcache.request.type', - type: 'keyword', - }, - 'memcache.response.type': { - category: 'memcache', - description: - 'The memcache command classification. This value can be "UNKNOWN", "Load", "Store", "Delete", "Counter", "Info", "SlabCtrl", "LRUCrawler", "Stats", "Success", "Fail", or "Auth". The text based protocol will employ any of these, whereas the binary based protocol will mirror the request commands only (see `memcache.response.status` for binary protocol). ', - name: 'memcache.response.type', - type: 'keyword', - }, - 'memcache.response.error_msg': { - category: 'memcache', - description: 'The optional error message in the memcache response (text based protocol only). ', - name: 'memcache.response.error_msg', - type: 'keyword', - }, - 'memcache.request.opcode': { - category: 'memcache', - description: 'The binary protocol message opcode name. ', - name: 'memcache.request.opcode', - type: 'keyword', - }, - 'memcache.response.opcode': { - category: 'memcache', - description: 'The binary protocol message opcode name. ', - name: 'memcache.response.opcode', - type: 'keyword', - }, - 'memcache.request.opcode_value': { - category: 'memcache', - description: 'The binary protocol message opcode value. ', - name: 'memcache.request.opcode_value', - type: 'long', - }, - 'memcache.response.opcode_value': { - category: 'memcache', - description: 'The binary protocol message opcode value. ', - name: 'memcache.response.opcode_value', - type: 'long', - }, - 'memcache.request.opaque': { - category: 'memcache', - description: - 'The binary protocol opaque header value used for correlating request with response messages. ', - name: 'memcache.request.opaque', - type: 'long', - }, - 'memcache.response.opaque': { - category: 'memcache', - description: - 'The binary protocol opaque header value used for correlating request with response messages. ', - name: 'memcache.response.opaque', - type: 'long', - }, - 'memcache.request.vbucket': { - category: 'memcache', - description: 'The vbucket index sent in the binary message. ', - name: 'memcache.request.vbucket', - type: 'long', - }, - 'memcache.response.status': { - category: 'memcache', - description: 'The textual representation of the response error code (binary protocol only). ', - name: 'memcache.response.status', - type: 'keyword', - }, - 'memcache.response.status_code': { - category: 'memcache', - description: 'The status code value returned in the response (binary protocol only). ', - name: 'memcache.response.status_code', - type: 'long', - }, - 'memcache.request.keys': { - category: 'memcache', - description: 'The list of keys sent in the store or load commands. ', - name: 'memcache.request.keys', - type: 'array', - }, - 'memcache.response.keys': { - category: 'memcache', - description: 'The list of keys returned for the load command (if present). ', - name: 'memcache.response.keys', - type: 'array', - }, - 'memcache.request.count_values': { - category: 'memcache', - description: - 'The number of values found in the memcache request message. If the command does not send any data, this field is missing. ', - name: 'memcache.request.count_values', - type: 'long', - }, - 'memcache.response.count_values': { - category: 'memcache', - description: - 'The number of values found in the memcache response message. If the command does not send any data, this field is missing. ', - name: 'memcache.response.count_values', - type: 'long', - }, - 'memcache.request.values': { - category: 'memcache', - description: 'The list of base64 encoded values sent with the request (if present). ', - name: 'memcache.request.values', - type: 'array', - }, - 'memcache.response.values': { - category: 'memcache', - description: 'The list of base64 encoded values sent with the response (if present). ', - name: 'memcache.response.values', - type: 'array', - }, - 'memcache.request.bytes': { - category: 'memcache', - description: 'The byte count of the values being transferred. ', - name: 'memcache.request.bytes', - type: 'long', - format: 'bytes', - }, - 'memcache.response.bytes': { - category: 'memcache', - description: 'The byte count of the values being transferred. ', - name: 'memcache.response.bytes', - type: 'long', - format: 'bytes', - }, - 'memcache.request.delta': { - category: 'memcache', - description: 'The counter increment/decrement delta value. ', - name: 'memcache.request.delta', - type: 'long', - }, - 'memcache.request.initial': { - category: 'memcache', - description: 'The counter increment/decrement initial value parameter (binary protocol only). ', - name: 'memcache.request.initial', - type: 'long', - }, - 'memcache.request.verbosity': { - category: 'memcache', - description: 'The value of the memcache "verbosity" command. ', - name: 'memcache.request.verbosity', - type: 'long', - }, - 'memcache.request.raw_args': { - category: 'memcache', - description: - 'The text protocol raw arguments for the "stats ..." and "lru crawl ..." commands. ', - name: 'memcache.request.raw_args', - type: 'keyword', - }, - 'memcache.request.source_class': { - category: 'memcache', - description: "The source class id in 'slab reassign' command. ", - name: 'memcache.request.source_class', - type: 'long', - }, - 'memcache.request.dest_class': { - category: 'memcache', - description: "The destination class id in 'slab reassign' command. ", - name: 'memcache.request.dest_class', - type: 'long', - }, - 'memcache.request.automove': { - category: 'memcache', - description: - 'The automove mode in the \'slab automove\' command expressed as a string. This value can be "standby"(=0), "slow"(=1), "aggressive"(=2), or the raw value if the value is unknown. ', - name: 'memcache.request.automove', - type: 'keyword', - }, - 'memcache.request.flags': { - category: 'memcache', - description: 'The memcache command flags sent in the request (if present). ', - name: 'memcache.request.flags', - type: 'long', - }, - 'memcache.response.flags': { - category: 'memcache', - description: 'The memcache message flags sent in the response (if present). ', - name: 'memcache.response.flags', - type: 'long', - }, - 'memcache.request.exptime': { - category: 'memcache', - description: - 'The data expiry time in seconds sent with the memcache command (if present). If the value is <30 days, the expiry time is relative to "now", or else it is an absolute Unix time in seconds (32-bit). ', - name: 'memcache.request.exptime', - type: 'long', - }, - 'memcache.request.sleep_us': { - category: 'memcache', - description: "The sleep setting in microseconds for the 'lru_crawler sleep' command. ", - name: 'memcache.request.sleep_us', - type: 'long', - }, - 'memcache.response.value': { - category: 'memcache', - description: 'The counter value returned by a counter operation. ', - name: 'memcache.response.value', - type: 'long', - }, - 'memcache.request.noreply': { - category: 'memcache', - description: - 'Set to true if noreply was set in the request. The `memcache.response` field will be missing. ', - name: 'memcache.request.noreply', - type: 'boolean', - }, - 'memcache.request.quiet': { - category: 'memcache', - description: 'Set to true if the binary protocol message is to be treated as a quiet message. ', - name: 'memcache.request.quiet', - type: 'boolean', - }, - 'memcache.request.cas_unique': { - category: 'memcache', - description: 'The CAS (compare-and-swap) identifier if present. ', - name: 'memcache.request.cas_unique', - type: 'long', - }, - 'memcache.response.cas_unique': { - category: 'memcache', - description: - 'The CAS (compare-and-swap) identifier to be used with CAS-based updates (if present). ', - name: 'memcache.response.cas_unique', - type: 'long', - }, - 'memcache.response.stats': { - category: 'memcache', - description: - 'The list of statistic values returned. Each entry is a dictionary with the fields "name" and "value". ', - name: 'memcache.response.stats', - type: 'array', - }, - 'memcache.response.version': { - category: 'memcache', - description: 'The returned memcache version string. ', - name: 'memcache.response.version', - type: 'keyword', - }, - 'mongodb.error': { - category: 'mongodb', - description: - 'If the MongoDB request has resulted in an error, this field contains the error message returned by the server. ', - name: 'mongodb.error', - }, - 'mongodb.fullCollectionName': { - category: 'mongodb', - description: - 'The full collection name. The full collection name is the concatenation of the database name with the collection name, using a dot (.) for the concatenation. For example, for the database foo and the collection bar, the full collection name is foo.bar. ', - name: 'mongodb.fullCollectionName', - }, - 'mongodb.numberToSkip': { - category: 'mongodb', - description: - 'Sets the number of documents to omit - starting from the first document in the resulting dataset - when returning the result of the query. ', - name: 'mongodb.numberToSkip', - type: 'long', - }, - 'mongodb.numberToReturn': { - category: 'mongodb', - description: 'The requested maximum number of documents to be returned. ', - name: 'mongodb.numberToReturn', - type: 'long', - }, - 'mongodb.numberReturned': { - category: 'mongodb', - description: 'The number of documents in the reply. ', - name: 'mongodb.numberReturned', - type: 'long', - }, - 'mongodb.startingFrom': { - category: 'mongodb', - description: 'Where in the cursor this reply is starting. ', - name: 'mongodb.startingFrom', - }, - 'mongodb.query': { - category: 'mongodb', - description: - 'A JSON document that represents the query. The query will contain one or more elements, all of which must match for a document to be included in the result set. Possible elements include $query, $orderby, $hint, $explain, and $snapshot. ', - name: 'mongodb.query', - }, - 'mongodb.returnFieldsSelector': { - category: 'mongodb', - description: - 'A JSON document that limits the fields in the returned documents. The returnFieldsSelector contains one or more elements, each of which is the name of a field that should be returned, and the integer value 1. ', - name: 'mongodb.returnFieldsSelector', - }, - 'mongodb.selector': { - category: 'mongodb', - description: - 'A BSON document that specifies the query for selecting the document to update or delete. ', - name: 'mongodb.selector', - }, - 'mongodb.update': { - category: 'mongodb', - description: - 'A BSON document that specifies the update to be performed. For information on specifying updates, see the Update Operations documentation from the MongoDB Manual. ', - name: 'mongodb.update', - }, - 'mongodb.cursorId': { - category: 'mongodb', - description: - 'The cursor identifier returned in the OP_REPLY. This must be the value that was returned from the database. ', - name: 'mongodb.cursorId', - }, - 'mysql.affected_rows': { - category: 'mysql', - description: - 'If the MySQL command is successful, this field contains the affected number of rows of the last statement. ', - name: 'mysql.affected_rows', - type: 'long', - }, - 'mysql.insert_id': { - category: 'mysql', - description: - 'If the INSERT query is successful, this field contains the id of the newly inserted row. ', - name: 'mysql.insert_id', - }, - 'mysql.num_fields': { - category: 'mysql', - description: - 'If the SELECT query is successful, this field is set to the number of fields returned. ', - name: 'mysql.num_fields', - }, - 'mysql.num_rows': { - category: 'mysql', - description: - 'If the SELECT query is successful, this field is set to the number of rows returned. ', - name: 'mysql.num_rows', - }, - 'mysql.query': { - category: 'mysql', - description: "The row mysql query as read from the transaction's request. ", - name: 'mysql.query', - }, - 'mysql.error_code': { - category: 'mysql', - description: 'The error code returned by MySQL. ', - name: 'mysql.error_code', - type: 'long', - }, - 'mysql.error_message': { - category: 'mysql', - description: 'The error info message returned by MySQL. ', - name: 'mysql.error_message', - }, - 'nfs.version': { - category: 'nfs', - description: 'NFS protocol version number.', - name: 'nfs.version', - type: 'long', - }, - 'nfs.minor_version': { - category: 'nfs', - description: 'NFS protocol minor version number.', - name: 'nfs.minor_version', - type: 'long', - }, - 'nfs.tag': { - category: 'nfs', - description: 'NFS v4 COMPOUND operation tag.', - name: 'nfs.tag', - }, - 'nfs.opcode': { - category: 'nfs', - description: 'NFS operation name, or main operation name, in case of COMPOUND calls. ', - name: 'nfs.opcode', - }, - 'nfs.status': { - category: 'nfs', - description: 'NFS operation reply status.', - name: 'nfs.status', - }, - 'rpc.xid': { - category: 'rpc', - description: 'RPC message transaction identifier.', - name: 'rpc.xid', - }, - 'rpc.status': { - category: 'rpc', - description: 'RPC message reply status.', - name: 'rpc.status', - }, - 'rpc.auth_flavor': { - category: 'rpc', - description: 'RPC authentication flavor.', - name: 'rpc.auth_flavor', - }, - 'rpc.cred.uid': { - category: 'rpc', - description: "RPC caller's user id, in case of auth-unix.", - name: 'rpc.cred.uid', - type: 'long', - }, - 'rpc.cred.gid': { - category: 'rpc', - description: "RPC caller's group id, in case of auth-unix.", - name: 'rpc.cred.gid', - type: 'long', - }, - 'rpc.cred.gids': { - category: 'rpc', - description: "RPC caller's secondary group ids, in case of auth-unix.", - name: 'rpc.cred.gids', - }, - 'rpc.cred.stamp': { - category: 'rpc', - description: 'Arbitrary ID which the caller machine may generate.', - name: 'rpc.cred.stamp', - type: 'long', - }, - 'rpc.cred.machinename': { - category: 'rpc', - description: "The name of the caller's machine.", - name: 'rpc.cred.machinename', - }, - 'rpc.call_size': { - category: 'rpc', - description: 'RPC call size with argument.', - name: 'rpc.call_size', - type: 'alias', - }, - 'rpc.reply_size': { - category: 'rpc', - description: 'RPC reply size with argument.', - name: 'rpc.reply_size', - type: 'alias', - }, - 'pgsql.error_code': { - category: 'pgsql', - description: 'The PostgreSQL error code.', - name: 'pgsql.error_code', - type: 'long', - }, - 'pgsql.error_message': { - category: 'pgsql', - description: 'The PostgreSQL error message.', - name: 'pgsql.error_message', - }, - 'pgsql.error_severity': { - category: 'pgsql', - description: 'The PostgreSQL error severity.', - name: 'pgsql.error_severity', - }, - 'pgsql.num_fields': { - category: 'pgsql', - description: - 'If the SELECT query if successful, this field is set to the number of fields returned. ', - name: 'pgsql.num_fields', - }, - 'pgsql.num_rows': { - category: 'pgsql', - description: - 'If the SELECT query if successful, this field is set to the number of rows returned. ', - name: 'pgsql.num_rows', - }, - 'redis.return_value': { - category: 'redis', - description: 'The return value of the Redis command in a human readable format. ', - name: 'redis.return_value', - }, - 'redis.error': { - category: 'redis', - description: - 'If the Redis command has resulted in an error, this field contains the error message returned by the Redis server. ', - name: 'redis.error', - }, - 'sip.code': { - category: 'sip', - description: 'Response status code.', - name: 'sip.code', - type: 'keyword', - }, - 'sip.method': { - category: 'sip', - description: 'Request method.', - name: 'sip.method', - type: 'keyword', - }, - 'sip.status': { - category: 'sip', - description: 'Response status phrase.', - name: 'sip.status', - type: 'keyword', - }, - 'sip.type': { - category: 'sip', - description: 'Either request or response.', - name: 'sip.type', - type: 'keyword', - }, - 'sip.version': { - category: 'sip', - description: 'SIP protocol version.', - name: 'sip.version', - type: 'keyword', - }, - 'sip.uri.original': { - category: 'sip', - description: 'The original URI.', - name: 'sip.uri.original', - type: 'keyword', - }, - 'sip.uri.scheme': { - category: 'sip', - description: 'The URI scheme.', - name: 'sip.uri.scheme', - type: 'keyword', - }, - 'sip.uri.username': { - category: 'sip', - description: 'The URI user name.', - name: 'sip.uri.username', - type: 'keyword', - }, - 'sip.uri.host': { - category: 'sip', - description: 'The URI host.', - name: 'sip.uri.host', - type: 'keyword', - }, - 'sip.uri.port': { - category: 'sip', - description: 'The URI port.', - name: 'sip.uri.port', - type: 'keyword', - }, - 'sip.accept': { - category: 'sip', - description: 'Accept header value.', - name: 'sip.accept', - type: 'keyword', - }, - 'sip.allow': { - category: 'sip', - description: 'Allowed methods.', - name: 'sip.allow', - type: 'keyword', - }, - 'sip.call_id': { - category: 'sip', - description: 'Call ID.', - name: 'sip.call_id', - type: 'keyword', - }, - 'sip.content_length': { - category: 'sip', - name: 'sip.content_length', - type: 'long', - }, - 'sip.content_type': { - category: 'sip', - name: 'sip.content_type', - type: 'keyword', - }, - 'sip.max_forwards': { - category: 'sip', - name: 'sip.max_forwards', - type: 'long', - }, - 'sip.supported': { - category: 'sip', - description: 'Supported methods.', - name: 'sip.supported', - type: 'keyword', - }, - 'sip.user_agent.original': { - category: 'sip', - name: 'sip.user_agent.original', - type: 'keyword', - }, - 'sip.private.uri.original': { - category: 'sip', - description: 'Private original URI.', - name: 'sip.private.uri.original', - type: 'keyword', - }, - 'sip.private.uri.scheme': { - category: 'sip', - description: 'Private URI scheme.', - name: 'sip.private.uri.scheme', - type: 'keyword', - }, - 'sip.private.uri.username': { - category: 'sip', - description: 'Private URI user name.', - name: 'sip.private.uri.username', - type: 'keyword', - }, - 'sip.private.uri.host': { - category: 'sip', - description: 'Private URI host.', - name: 'sip.private.uri.host', - type: 'keyword', - }, - 'sip.private.uri.port': { - category: 'sip', - description: 'Private URI port.', - name: 'sip.private.uri.port', - type: 'keyword', - }, - 'sip.cseq.code': { - category: 'sip', - description: 'Sequence code.', - name: 'sip.cseq.code', - type: 'keyword', - }, - 'sip.cseq.method': { - category: 'sip', - description: 'Sequence method.', - name: 'sip.cseq.method', - type: 'keyword', - }, - 'sip.via.original': { - category: 'sip', - description: 'The original Via value.', - name: 'sip.via.original', - type: 'keyword', - }, - 'sip.to.display_info': { - category: 'sip', - description: 'To display info', - name: 'sip.to.display_info', - type: 'keyword', - }, - 'sip.to.uri.original': { - category: 'sip', - description: 'To original URI', - name: 'sip.to.uri.original', - type: 'keyword', - }, - 'sip.to.uri.scheme': { - category: 'sip', - description: 'To URI scheme', - name: 'sip.to.uri.scheme', - type: 'keyword', - }, - 'sip.to.uri.username': { - category: 'sip', - description: 'To URI user name', - name: 'sip.to.uri.username', - type: 'keyword', - }, - 'sip.to.uri.host': { - category: 'sip', - description: 'To URI host', - name: 'sip.to.uri.host', - type: 'keyword', - }, - 'sip.to.uri.port': { - category: 'sip', - description: 'To URI port', - name: 'sip.to.uri.port', - type: 'keyword', - }, - 'sip.to.tag': { - category: 'sip', - description: 'To tag', - name: 'sip.to.tag', - type: 'keyword', - }, - 'sip.from.display_info': { - category: 'sip', - description: 'From display info', - name: 'sip.from.display_info', - type: 'keyword', - }, - 'sip.from.uri.original': { - category: 'sip', - description: 'From original URI', - name: 'sip.from.uri.original', - type: 'keyword', - }, - 'sip.from.uri.scheme': { - category: 'sip', - description: 'From URI scheme', - name: 'sip.from.uri.scheme', - type: 'keyword', - }, - 'sip.from.uri.username': { - category: 'sip', - description: 'From URI user name', - name: 'sip.from.uri.username', - type: 'keyword', - }, - 'sip.from.uri.host': { - category: 'sip', - description: 'From URI host', - name: 'sip.from.uri.host', - type: 'keyword', - }, - 'sip.from.uri.port': { - category: 'sip', - description: 'From URI port', - name: 'sip.from.uri.port', - type: 'keyword', - }, - 'sip.from.tag': { - category: 'sip', - description: 'From tag', - name: 'sip.from.tag', - type: 'keyword', - }, - 'sip.contact.display_info': { - category: 'sip', - description: 'Contact display info', - name: 'sip.contact.display_info', - type: 'keyword', - }, - 'sip.contact.uri.original': { - category: 'sip', - description: 'Contact original URI', - name: 'sip.contact.uri.original', - type: 'keyword', - }, - 'sip.contact.uri.scheme': { - category: 'sip', - description: 'Contat URI scheme', - name: 'sip.contact.uri.scheme', - type: 'keyword', - }, - 'sip.contact.uri.username': { - category: 'sip', - description: 'Contact URI user name', - name: 'sip.contact.uri.username', - type: 'keyword', - }, - 'sip.contact.uri.host': { - category: 'sip', - description: 'Contact URI host', - name: 'sip.contact.uri.host', - type: 'keyword', - }, - 'sip.contact.uri.port': { - category: 'sip', - description: 'Contact URI port', - name: 'sip.contact.uri.port', - type: 'keyword', - }, - 'sip.contact.transport': { - category: 'sip', - description: 'Contact transport', - name: 'sip.contact.transport', - type: 'keyword', - }, - 'sip.contact.line': { - category: 'sip', - description: 'Contact line', - name: 'sip.contact.line', - type: 'keyword', - }, - 'sip.contact.expires': { - category: 'sip', - description: 'Contact expires', - name: 'sip.contact.expires', - type: 'keyword', - }, - 'sip.contact.q': { - category: 'sip', - description: 'Contact Q', - name: 'sip.contact.q', - type: 'keyword', - }, - 'sip.auth.scheme': { - category: 'sip', - description: 'Auth scheme', - name: 'sip.auth.scheme', - type: 'keyword', - }, - 'sip.auth.realm': { - category: 'sip', - description: 'Auth realm', - name: 'sip.auth.realm', - type: 'keyword', - }, - 'sip.auth.uri.original': { - category: 'sip', - description: 'Auth original URI', - name: 'sip.auth.uri.original', - type: 'keyword', - }, - 'sip.auth.uri.scheme': { - category: 'sip', - description: 'Auth URI scheme', - name: 'sip.auth.uri.scheme', - type: 'keyword', - }, - 'sip.auth.uri.host': { - category: 'sip', - description: 'Auth URI host', - name: 'sip.auth.uri.host', - type: 'keyword', - }, - 'sip.auth.uri.port': { - category: 'sip', - description: 'Auth URI port', - name: 'sip.auth.uri.port', - type: 'keyword', - }, - 'sip.sdp.version': { - category: 'sip', - description: 'SDP version', - name: 'sip.sdp.version', - type: 'keyword', - }, - 'sip.sdp.owner.username': { - category: 'sip', - description: 'SDP owner user name', - name: 'sip.sdp.owner.username', - type: 'keyword', - }, - 'sip.sdp.owner.session_id': { - category: 'sip', - description: 'SDP owner session ID', - name: 'sip.sdp.owner.session_id', - type: 'keyword', - }, - 'sip.sdp.owner.version': { - category: 'sip', - description: 'SDP owner version', - name: 'sip.sdp.owner.version', - type: 'keyword', - }, - 'sip.sdp.owner.ip': { - category: 'sip', - description: 'SDP owner IP', - name: 'sip.sdp.owner.ip', - type: 'ip', - }, - 'sip.sdp.session.name': { - category: 'sip', - description: 'SDP session name', - name: 'sip.sdp.session.name', - type: 'keyword', - }, - 'sip.sdp.connection.info': { - category: 'sip', - description: 'SDP connection info', - name: 'sip.sdp.connection.info', - type: 'keyword', - }, - 'sip.sdp.connection.address': { - category: 'sip', - description: 'SDP connection address', - name: 'sip.sdp.connection.address', - type: 'keyword', - }, - 'sip.sdp.body.original': { - category: 'sip', - description: 'SDP original body', - name: 'sip.sdp.body.original', - type: 'keyword', - }, - 'thrift.params': { - category: 'thrift', - description: - 'The RPC method call parameters in a human readable format. If the IDL files are available, the parameters use names whenever possible. Otherwise, the IDs from the message are used. ', - name: 'thrift.params', - }, - 'thrift.service': { - category: 'thrift', - description: 'The name of the Thrift-RPC service as defined in the IDL files. ', - name: 'thrift.service', - }, - 'thrift.return_value': { - category: 'thrift', - description: - 'The value returned by the Thrift-RPC call. This is encoded in a human readable format. ', - name: 'thrift.return_value', - }, - 'thrift.exceptions': { - category: 'thrift', - description: - 'If the call resulted in exceptions, this field contains the exceptions in a human readable format. ', - name: 'thrift.exceptions', - }, - 'tls.client.x509.version': { - category: 'tls', - description: 'Version of x509 format.', - example: 3, - name: 'tls.client.x509.version', - type: 'keyword', - }, - 'tls.client.x509.issuer.province': { - category: 'tls', - description: 'Province or region within country.', - name: 'tls.client.x509.issuer.province', - type: 'keyword', - }, - 'tls.client.x509.subject.province': { - category: 'tls', - description: 'Province or region within country.', - name: 'tls.client.x509.subject.province', - type: 'keyword', - }, - 'tls.server.x509.version': { - category: 'tls', - description: 'Version of x509 format.', - example: 3, - name: 'tls.server.x509.version', - type: 'keyword', - }, - 'tls.server.x509.issuer.province': { - category: 'tls', - description: 'Province or region within country.', - name: 'tls.server.x509.issuer.province', - type: 'keyword', - }, - 'tls.server.x509.subject.province': { - category: 'tls', - description: 'Province or region within country.', - name: 'tls.server.x509.subject.province', - type: 'keyword', - }, - 'tls.detailed.version': { - category: 'tls', - description: 'The version of the TLS protocol used. ', - example: 'TLS 1.3', - name: 'tls.detailed.version', - type: 'keyword', - }, - 'tls.detailed.resumption_method': { - category: 'tls', - description: - 'If the session has been resumed, the underlying method used. One of "id" for TLS session ID or "ticket" for TLS ticket extension. ', - name: 'tls.detailed.resumption_method', - type: 'keyword', - }, - 'tls.detailed.client_certificate_requested': { - category: 'tls', - description: - 'Whether the server has requested the client to authenticate itself using a client certificate. ', - name: 'tls.detailed.client_certificate_requested', - type: 'boolean', - }, - 'tls.detailed.client_hello.version': { - category: 'tls', - description: - 'The version of the TLS protocol by which the client wishes to communicate during this session. ', - name: 'tls.detailed.client_hello.version', - type: 'keyword', - }, - 'tls.detailed.client_hello.session_id': { - category: 'tls', - description: - 'Unique number to identify the session for the corresponding connection with the client. ', - name: 'tls.detailed.client_hello.session_id', - type: 'keyword', - }, - 'tls.detailed.client_hello.supported_compression_methods': { - category: 'tls', - description: - 'The list of compression methods the client supports. See https://www.iana.org/assignments/comp-meth-ids/comp-meth-ids.xhtml ', - name: 'tls.detailed.client_hello.supported_compression_methods', - type: 'keyword', - }, - 'tls.detailed.client_hello.extensions.server_name_indication': { - category: 'tls', - description: 'List of hostnames', - name: 'tls.detailed.client_hello.extensions.server_name_indication', - type: 'keyword', - }, - 'tls.detailed.client_hello.extensions.application_layer_protocol_negotiation': { - category: 'tls', - description: 'List of application-layer protocols the client is willing to use. ', - name: 'tls.detailed.client_hello.extensions.application_layer_protocol_negotiation', - type: 'keyword', - }, - 'tls.detailed.client_hello.extensions.session_ticket': { - category: 'tls', - description: - 'Length of the session ticket, if provided, or an empty string to advertise support for tickets. ', - name: 'tls.detailed.client_hello.extensions.session_ticket', - type: 'keyword', - }, - 'tls.detailed.client_hello.extensions.supported_versions': { - category: 'tls', - description: 'List of TLS versions that the client is willing to use. ', - name: 'tls.detailed.client_hello.extensions.supported_versions', - type: 'keyword', - }, - 'tls.detailed.client_hello.extensions.supported_groups': { - category: 'tls', - description: 'List of Elliptic Curve Cryptography (ECC) curve groups supported by the client. ', - name: 'tls.detailed.client_hello.extensions.supported_groups', - type: 'keyword', - }, - 'tls.detailed.client_hello.extensions.signature_algorithms': { - category: 'tls', - description: 'List of signature algorithms that may be use in digital signatures. ', - name: 'tls.detailed.client_hello.extensions.signature_algorithms', - type: 'keyword', - }, - 'tls.detailed.client_hello.extensions.ec_points_formats': { - category: 'tls', - description: - 'List of Elliptic Curve (EC) point formats. Indicates the set of point formats that the client can parse. ', - name: 'tls.detailed.client_hello.extensions.ec_points_formats', - type: 'keyword', - }, - 'tls.detailed.client_hello.extensions._unparsed_': { - category: 'tls', - description: 'List of extensions that were left unparsed by Packetbeat. ', - name: 'tls.detailed.client_hello.extensions._unparsed_', - type: 'keyword', - }, - 'tls.detailed.server_hello.version': { - category: 'tls', - description: - 'The version of the TLS protocol that is used for this session. It is the highest version supported by the server not exceeding the version requested in the client hello. ', - name: 'tls.detailed.server_hello.version', - type: 'keyword', - }, - 'tls.detailed.server_hello.selected_compression_method': { - category: 'tls', - description: - 'The compression method selected by the server from the list provided in the client hello. ', - name: 'tls.detailed.server_hello.selected_compression_method', - type: 'keyword', - }, - 'tls.detailed.server_hello.session_id': { - category: 'tls', - description: - 'Unique number to identify the session for the corresponding connection with the client. ', - name: 'tls.detailed.server_hello.session_id', - type: 'keyword', - }, - 'tls.detailed.server_hello.extensions.application_layer_protocol_negotiation': { - category: 'tls', - description: 'Negotiated application layer protocol', - name: 'tls.detailed.server_hello.extensions.application_layer_protocol_negotiation', - type: 'keyword', - }, - 'tls.detailed.server_hello.extensions.session_ticket': { - category: 'tls', - description: - 'Used to announce that a session ticket will be provided by the server. Always an empty string. ', - name: 'tls.detailed.server_hello.extensions.session_ticket', - type: 'keyword', - }, - 'tls.detailed.server_hello.extensions.supported_versions': { - category: 'tls', - description: 'Negotiated TLS version to be used. ', - name: 'tls.detailed.server_hello.extensions.supported_versions', - type: 'keyword', - }, - 'tls.detailed.server_hello.extensions.ec_points_formats': { - category: 'tls', - description: - 'List of Elliptic Curve (EC) point formats. Indicates the set of point formats that the server can parse. ', - name: 'tls.detailed.server_hello.extensions.ec_points_formats', - type: 'keyword', - }, - 'tls.detailed.server_hello.extensions._unparsed_': { - category: 'tls', - description: 'List of extensions that were left unparsed by Packetbeat. ', - name: 'tls.detailed.server_hello.extensions._unparsed_', - type: 'keyword', - }, - 'tls.detailed.client_certificate.version': { - category: 'tls', - description: 'X509 format version.', - name: 'tls.detailed.client_certificate.version', - type: 'long', - }, - 'tls.detailed.client_certificate.version_number': { - category: 'tls', - description: 'Version of x509 format.', - example: 3, - name: 'tls.detailed.client_certificate.version_number', - type: 'keyword', - }, - 'tls.detailed.client_certificate.serial_number': { - category: 'tls', - description: "The certificate's serial number.", - name: 'tls.detailed.client_certificate.serial_number', - type: 'keyword', - }, - 'tls.detailed.client_certificate.not_before': { - category: 'tls', - description: 'Date before which the certificate is not valid.', - name: 'tls.detailed.client_certificate.not_before', - type: 'date', - }, - 'tls.detailed.client_certificate.not_after': { - category: 'tls', - description: 'Date after which the certificate expires.', - name: 'tls.detailed.client_certificate.not_after', - type: 'date', - }, - 'tls.detailed.client_certificate.public_key_algorithm': { - category: 'tls', - description: "The algorithm used for this certificate's public key. One of RSA, DSA or ECDSA. ", - name: 'tls.detailed.client_certificate.public_key_algorithm', - type: 'keyword', - }, - 'tls.detailed.client_certificate.public_key_size': { - category: 'tls', - description: 'Size of the public key.', - name: 'tls.detailed.client_certificate.public_key_size', - type: 'long', - }, - 'tls.detailed.client_certificate.signature_algorithm': { - category: 'tls', - description: "The algorithm used for the certificate's signature. ", - name: 'tls.detailed.client_certificate.signature_algorithm', - type: 'keyword', - }, - 'tls.detailed.client_certificate.alternative_names': { - category: 'tls', - description: 'Subject Alternative Names for this certificate.', - name: 'tls.detailed.client_certificate.alternative_names', - type: 'keyword', - }, - 'tls.detailed.client_certificate.subject.country': { - category: 'tls', - description: 'Country code.', - name: 'tls.detailed.client_certificate.subject.country', - type: 'keyword', - }, - 'tls.detailed.client_certificate.subject.organization': { - category: 'tls', - description: 'Organization name.', - name: 'tls.detailed.client_certificate.subject.organization', - type: 'keyword', - }, - 'tls.detailed.client_certificate.subject.organizational_unit': { - category: 'tls', - description: 'Unit within organization.', - name: 'tls.detailed.client_certificate.subject.organizational_unit', - type: 'keyword', - }, - 'tls.detailed.client_certificate.subject.province': { - category: 'tls', - description: 'Province or region within country.', - name: 'tls.detailed.client_certificate.subject.province', - type: 'keyword', - }, - 'tls.detailed.client_certificate.subject.common_name': { - category: 'tls', - description: 'Name or host name identified by the certificate.', - name: 'tls.detailed.client_certificate.subject.common_name', - type: 'keyword', - }, - 'tls.detailed.client_certificate.subject.locality': { - category: 'tls', - description: 'Locality.', - name: 'tls.detailed.client_certificate.subject.locality', - type: 'keyword', - }, - 'tls.detailed.client_certificate.subject.distinguished_name': { - category: 'tls', - description: 'Distinguished name (DN) of the certificate subject entity.', - example: 'C=US, ST=California, L=San Francisco, O=Fastly, Inc., CN=r2.shared.global.fastly.net', - name: 'tls.detailed.client_certificate.subject.distinguished_name', - type: 'keyword', - }, - 'tls.detailed.client_certificate.issuer.country': { - category: 'tls', - description: 'Country code.', - name: 'tls.detailed.client_certificate.issuer.country', - type: 'keyword', - }, - 'tls.detailed.client_certificate.issuer.organization': { - category: 'tls', - description: 'Organization name.', - name: 'tls.detailed.client_certificate.issuer.organization', - type: 'keyword', - }, - 'tls.detailed.client_certificate.issuer.organizational_unit': { - category: 'tls', - description: 'Unit within organization.', - name: 'tls.detailed.client_certificate.issuer.organizational_unit', - type: 'keyword', - }, - 'tls.detailed.client_certificate.issuer.province': { - category: 'tls', - description: 'Province or region within country.', - name: 'tls.detailed.client_certificate.issuer.province', - type: 'keyword', - }, - 'tls.detailed.client_certificate.issuer.common_name': { - category: 'tls', - description: 'Name or host name identified by the certificate.', - name: 'tls.detailed.client_certificate.issuer.common_name', - type: 'keyword', - }, - 'tls.detailed.client_certificate.issuer.locality': { - category: 'tls', - description: 'Locality.', - name: 'tls.detailed.client_certificate.issuer.locality', - type: 'keyword', - }, - 'tls.detailed.client_certificate.issuer.distinguished_name': { - category: 'tls', - description: 'Distinguished name (DN) of the certificate issuer entity.', - example: 'C=US, ST=California, L=San Francisco, O=Fastly, Inc., CN=r2.shared.global.fastly.net', - name: 'tls.detailed.client_certificate.issuer.distinguished_name', - type: 'keyword', - }, - 'tls.detailed.server_certificate.version': { - category: 'tls', - description: 'X509 format version.', - name: 'tls.detailed.server_certificate.version', - type: 'long', - }, - 'tls.detailed.server_certificate.version_number': { - category: 'tls', - description: 'Version of x509 format.', - example: 3, - name: 'tls.detailed.server_certificate.version_number', - type: 'keyword', - }, - 'tls.detailed.server_certificate.serial_number': { - category: 'tls', - description: "The certificate's serial number.", - name: 'tls.detailed.server_certificate.serial_number', - type: 'keyword', - }, - 'tls.detailed.server_certificate.not_before': { - category: 'tls', - description: 'Date before which the certificate is not valid.', - name: 'tls.detailed.server_certificate.not_before', - type: 'date', - }, - 'tls.detailed.server_certificate.not_after': { - category: 'tls', - description: 'Date after which the certificate expires.', - name: 'tls.detailed.server_certificate.not_after', - type: 'date', - }, - 'tls.detailed.server_certificate.public_key_algorithm': { - category: 'tls', - description: "The algorithm used for this certificate's public key. One of RSA, DSA or ECDSA. ", - name: 'tls.detailed.server_certificate.public_key_algorithm', - type: 'keyword', - }, - 'tls.detailed.server_certificate.public_key_size': { - category: 'tls', - description: 'Size of the public key.', - name: 'tls.detailed.server_certificate.public_key_size', - type: 'long', - }, - 'tls.detailed.server_certificate.signature_algorithm': { - category: 'tls', - description: "The algorithm used for the certificate's signature. ", - name: 'tls.detailed.server_certificate.signature_algorithm', - type: 'keyword', - }, - 'tls.detailed.server_certificate.alternative_names': { - category: 'tls', - description: 'Subject Alternative Names for this certificate.', - name: 'tls.detailed.server_certificate.alternative_names', - type: 'keyword', - }, - 'tls.detailed.server_certificate.subject.country': { - category: 'tls', - description: 'Country code.', - name: 'tls.detailed.server_certificate.subject.country', - type: 'keyword', - }, - 'tls.detailed.server_certificate.subject.organization': { - category: 'tls', - description: 'Organization name.', - name: 'tls.detailed.server_certificate.subject.organization', - type: 'keyword', - }, - 'tls.detailed.server_certificate.subject.organizational_unit': { - category: 'tls', - description: 'Unit within organization.', - name: 'tls.detailed.server_certificate.subject.organizational_unit', - type: 'keyword', - }, - 'tls.detailed.server_certificate.subject.province': { - category: 'tls', - description: 'Province or region within country.', - name: 'tls.detailed.server_certificate.subject.province', - type: 'keyword', - }, - 'tls.detailed.server_certificate.subject.state_or_province': { - category: 'tls', - description: 'Province or region within country.', - name: 'tls.detailed.server_certificate.subject.state_or_province', - type: 'keyword', - }, - 'tls.detailed.server_certificate.subject.common_name': { - category: 'tls', - description: 'Name or host name identified by the certificate.', - name: 'tls.detailed.server_certificate.subject.common_name', - type: 'keyword', - }, - 'tls.detailed.server_certificate.subject.locality': { - category: 'tls', - description: 'Locality.', - name: 'tls.detailed.server_certificate.subject.locality', - type: 'keyword', - }, - 'tls.detailed.server_certificate.subject.distinguished_name': { - category: 'tls', - description: 'Distinguished name (DN) of the certificate subject entity.', - example: 'C=US, ST=California, L=San Francisco, O=Fastly, Inc., CN=r2.shared.global.fastly.net', - name: 'tls.detailed.server_certificate.subject.distinguished_name', - type: 'keyword', - }, - 'tls.detailed.server_certificate.issuer.country': { - category: 'tls', - description: 'Country code.', - name: 'tls.detailed.server_certificate.issuer.country', - type: 'keyword', - }, - 'tls.detailed.server_certificate.issuer.organization': { - category: 'tls', - description: 'Organization name.', - name: 'tls.detailed.server_certificate.issuer.organization', - type: 'keyword', - }, - 'tls.detailed.server_certificate.issuer.organizational_unit': { - category: 'tls', - description: 'Unit within organization.', - name: 'tls.detailed.server_certificate.issuer.organizational_unit', - type: 'keyword', - }, - 'tls.detailed.server_certificate.issuer.province': { - category: 'tls', - description: 'Province or region within country.', - name: 'tls.detailed.server_certificate.issuer.province', - type: 'keyword', - }, - 'tls.detailed.server_certificate.issuer.state_or_province': { - category: 'tls', - description: 'Province or region within country.', - name: 'tls.detailed.server_certificate.issuer.state_or_province', - type: 'keyword', - }, - 'tls.detailed.server_certificate.issuer.common_name': { - category: 'tls', - description: 'Name or host name identified by the certificate.', - name: 'tls.detailed.server_certificate.issuer.common_name', - type: 'keyword', - }, - 'tls.detailed.server_certificate.issuer.locality': { - category: 'tls', - description: 'Locality.', - name: 'tls.detailed.server_certificate.issuer.locality', - type: 'keyword', - }, - 'tls.detailed.server_certificate.issuer.distinguished_name': { - category: 'tls', - description: 'Distinguished name (DN) of the certificate issuer entity.', - example: 'C=US, ST=California, L=San Francisco, O=Fastly, Inc., CN=r2.shared.global.fastly.net', - name: 'tls.detailed.server_certificate.issuer.distinguished_name', - type: 'keyword', - }, - 'tls.detailed.server_certificate_chain': { - category: 'tls', - description: 'Chain of trust for the server certificate.', - name: 'tls.detailed.server_certificate_chain', - type: 'array', - }, - 'tls.detailed.client_certificate_chain': { - category: 'tls', - description: 'Chain of trust for the client certificate.', - name: 'tls.detailed.client_certificate_chain', - type: 'array', - }, - 'tls.detailed.alert_types': { - category: 'tls', - description: 'An array containing the TLS alert type for every alert received. ', - name: 'tls.detailed.alert_types', - type: 'keyword', - }, - 'tls.handshake_completed': { - category: 'tls', - name: 'tls.handshake_completed', - type: 'alias', - }, - 'tls.client_hello.supported_ciphers': { - category: 'tls', - name: 'tls.client_hello.supported_ciphers', - type: 'alias', - }, - 'tls.server_hello.selected_cipher': { - category: 'tls', - name: 'tls.server_hello.selected_cipher', - type: 'alias', - }, - 'tls.fingerprints.ja3': { - category: 'tls', - name: 'tls.fingerprints.ja3', - type: 'alias', - }, - 'tls.resumption_method': { - category: 'tls', - name: 'tls.resumption_method', - type: 'alias', - }, - 'tls.client_certificate_requested': { - category: 'tls', - name: 'tls.client_certificate_requested', - type: 'alias', - }, - 'tls.client_hello.version': { - category: 'tls', - name: 'tls.client_hello.version', - type: 'alias', - }, - 'tls.client_hello.session_id': { - category: 'tls', - name: 'tls.client_hello.session_id', - type: 'alias', - }, - 'tls.client_hello.supported_compression_methods': { - category: 'tls', - name: 'tls.client_hello.supported_compression_methods', - type: 'alias', - }, - 'tls.client_hello.extensions.server_name_indication': { - category: 'tls', - name: 'tls.client_hello.extensions.server_name_indication', - type: 'alias', - }, - 'tls.client_hello.extensions.application_layer_protocol_negotiation': { - category: 'tls', - name: 'tls.client_hello.extensions.application_layer_protocol_negotiation', - type: 'alias', - }, - 'tls.client_hello.extensions.session_ticket': { - category: 'tls', - name: 'tls.client_hello.extensions.session_ticket', - type: 'alias', - }, - 'tls.client_hello.extensions.supported_versions': { - category: 'tls', - name: 'tls.client_hello.extensions.supported_versions', - type: 'alias', - }, - 'tls.client_hello.extensions.supported_groups': { - category: 'tls', - name: 'tls.client_hello.extensions.supported_groups', - type: 'alias', - }, - 'tls.client_hello.extensions.signature_algorithms': { - category: 'tls', - name: 'tls.client_hello.extensions.signature_algorithms', - type: 'alias', - }, - 'tls.client_hello.extensions.ec_points_formats': { - category: 'tls', - name: 'tls.client_hello.extensions.ec_points_formats', - type: 'alias', - }, - 'tls.client_hello.extensions._unparsed_': { - category: 'tls', - name: 'tls.client_hello.extensions._unparsed_', - type: 'alias', - }, - 'tls.server_hello.version': { - category: 'tls', - name: 'tls.server_hello.version', - type: 'alias', - }, - 'tls.server_hello.selected_compression_method': { - category: 'tls', - name: 'tls.server_hello.selected_compression_method', - type: 'alias', - }, - 'tls.server_hello.session_id': { - category: 'tls', - name: 'tls.server_hello.session_id', - type: 'alias', - }, - 'tls.server_hello.extensions.application_layer_protocol_negotiation': { - category: 'tls', - name: 'tls.server_hello.extensions.application_layer_protocol_negotiation', - type: 'alias', - }, - 'tls.server_hello.extensions.session_ticket': { - category: 'tls', - name: 'tls.server_hello.extensions.session_ticket', - type: 'alias', - }, - 'tls.server_hello.extensions.supported_versions': { - category: 'tls', - name: 'tls.server_hello.extensions.supported_versions', - type: 'alias', - }, - 'tls.server_hello.extensions.ec_points_formats': { - category: 'tls', - name: 'tls.server_hello.extensions.ec_points_formats', - type: 'alias', - }, - 'tls.server_hello.extensions._unparsed_': { - category: 'tls', - name: 'tls.server_hello.extensions._unparsed_', - type: 'alias', - }, - 'tls.client_certificate.version': { - category: 'tls', - name: 'tls.client_certificate.version', - type: 'alias', - }, - 'tls.client_certificate.serial_number': { - category: 'tls', - name: 'tls.client_certificate.serial_number', - type: 'alias', - }, - 'tls.client_certificate.not_before': { - category: 'tls', - name: 'tls.client_certificate.not_before', - type: 'alias', - }, - 'tls.client_certificate.not_after': { - category: 'tls', - name: 'tls.client_certificate.not_after', - type: 'alias', - }, - 'tls.client_certificate.public_key_algorithm': { - category: 'tls', - name: 'tls.client_certificate.public_key_algorithm', - type: 'alias', - }, - 'tls.client_certificate.public_key_size': { - category: 'tls', - name: 'tls.client_certificate.public_key_size', - type: 'alias', - }, - 'tls.client_certificate.signature_algorithm': { - category: 'tls', - name: 'tls.client_certificate.signature_algorithm', - type: 'alias', - }, - 'tls.client_certificate.alternative_names': { - category: 'tls', - name: 'tls.client_certificate.alternative_names', - type: 'alias', - }, - 'tls.client_certificate.subject.country': { - category: 'tls', - name: 'tls.client_certificate.subject.country', - type: 'alias', - }, - 'tls.client_certificate.subject.organization': { - category: 'tls', - name: 'tls.client_certificate.subject.organization', - type: 'alias', - }, - 'tls.client_certificate.subject.organizational_unit': { - category: 'tls', - name: 'tls.client_certificate.subject.organizational_unit', - type: 'alias', - }, - 'tls.client_certificate.subject.province': { - category: 'tls', - name: 'tls.client_certificate.subject.province', - type: 'alias', - }, - 'tls.client_certificate.subject.common_name': { - category: 'tls', - name: 'tls.client_certificate.subject.common_name', - type: 'alias', - }, - 'tls.client_certificate.subject.locality': { - category: 'tls', - name: 'tls.client_certificate.subject.locality', - type: 'alias', - }, - 'tls.client_certificate.issuer.country': { - category: 'tls', - name: 'tls.client_certificate.issuer.country', - type: 'alias', - }, - 'tls.client_certificate.issuer.organization': { - category: 'tls', - name: 'tls.client_certificate.issuer.organization', - type: 'alias', - }, - 'tls.client_certificate.issuer.organizational_unit': { - category: 'tls', - name: 'tls.client_certificate.issuer.organizational_unit', - type: 'alias', - }, - 'tls.client_certificate.issuer.province': { - category: 'tls', - name: 'tls.client_certificate.issuer.province', - type: 'alias', - }, - 'tls.client_certificate.issuer.common_name': { - category: 'tls', - name: 'tls.client_certificate.issuer.common_name', - type: 'alias', - }, - 'tls.client_certificate.issuer.locality': { - category: 'tls', - name: 'tls.client_certificate.issuer.locality', - type: 'alias', - }, - 'tls.server_certificate.version': { - category: 'tls', - name: 'tls.server_certificate.version', - type: 'alias', - }, - 'tls.server_certificate.serial_number': { - category: 'tls', - name: 'tls.server_certificate.serial_number', - type: 'alias', - }, - 'tls.server_certificate.not_before': { - category: 'tls', - name: 'tls.server_certificate.not_before', - type: 'alias', - }, - 'tls.server_certificate.not_after': { - category: 'tls', - name: 'tls.server_certificate.not_after', - type: 'alias', - }, - 'tls.server_certificate.public_key_algorithm': { - category: 'tls', - name: 'tls.server_certificate.public_key_algorithm', - type: 'alias', - }, - 'tls.server_certificate.public_key_size': { - category: 'tls', - name: 'tls.server_certificate.public_key_size', - type: 'alias', - }, - 'tls.server_certificate.signature_algorithm': { - category: 'tls', - name: 'tls.server_certificate.signature_algorithm', - type: 'alias', - }, - 'tls.server_certificate.alternative_names': { - category: 'tls', - name: 'tls.server_certificate.alternative_names', - type: 'alias', - }, - 'tls.server_certificate.subject.country': { - category: 'tls', - name: 'tls.server_certificate.subject.country', - type: 'alias', - }, - 'tls.server_certificate.subject.organization': { - category: 'tls', - name: 'tls.server_certificate.subject.organization', - type: 'alias', - }, - 'tls.server_certificate.subject.organizational_unit': { - category: 'tls', - name: 'tls.server_certificate.subject.organizational_unit', - type: 'alias', - }, - 'tls.server_certificate.subject.province': { - category: 'tls', - name: 'tls.server_certificate.subject.province', - type: 'alias', - }, - 'tls.server_certificate.subject.common_name': { - category: 'tls', - name: 'tls.server_certificate.subject.common_name', - type: 'alias', - }, - 'tls.server_certificate.subject.locality': { - category: 'tls', - name: 'tls.server_certificate.subject.locality', - type: 'alias', - }, - 'tls.server_certificate.issuer.country': { - category: 'tls', - name: 'tls.server_certificate.issuer.country', - type: 'alias', - }, - 'tls.server_certificate.issuer.organization': { - category: 'tls', - name: 'tls.server_certificate.issuer.organization', - type: 'alias', - }, - 'tls.server_certificate.issuer.organizational_unit': { - category: 'tls', - name: 'tls.server_certificate.issuer.organizational_unit', - type: 'alias', - }, - 'tls.server_certificate.issuer.province': { - category: 'tls', - name: 'tls.server_certificate.issuer.province', - type: 'alias', - }, - 'tls.server_certificate.issuer.common_name': { - category: 'tls', - name: 'tls.server_certificate.issuer.common_name', - type: 'alias', - }, - 'tls.server_certificate.issuer.locality': { - category: 'tls', - name: 'tls.server_certificate.issuer.locality', - type: 'alias', - }, - 'tls.alert_types': { - category: 'tls', - name: 'tls.alert_types', - type: 'alias', - }, - 'winlog.api': { - category: 'winlog', - description: - 'The event log API type used to read the record. The possible values are "wineventlog" for the Windows Event Log API or "wineventlog-experimental" for its experimental implementation. ', - name: 'winlog.api', - }, - 'winlog.activity_id': { - category: 'winlog', - description: - 'A globally unique identifier that identifies the current activity. The events that are published with this identifier are part of the same activity. ', - name: 'winlog.activity_id', - type: 'keyword', - }, - 'winlog.computer_name': { - category: 'winlog', - description: - 'The name of the computer that generated the record. When using Windows event forwarding, this name can differ from `agent.hostname`. ', - name: 'winlog.computer_name', - type: 'keyword', - }, - 'winlog.event_data': { - category: 'winlog', - description: - 'The event-specific data. This field is mutually exclusive with `user_data`. If you are capturing event data on versions prior to Windows Vista, the parameters in `event_data` are named `param1`, `param2`, and so on, because event log parameters are unnamed in earlier versions of Windows. ', - name: 'winlog.event_data', - type: 'object', - }, - 'winlog.event_data.AuthenticationPackageName': { - category: 'winlog', - name: 'winlog.event_data.AuthenticationPackageName', - type: 'keyword', - }, - 'winlog.event_data.Binary': { - category: 'winlog', - name: 'winlog.event_data.Binary', - type: 'keyword', - }, - 'winlog.event_data.BitlockerUserInputTime': { - category: 'winlog', - name: 'winlog.event_data.BitlockerUserInputTime', - type: 'keyword', - }, - 'winlog.event_data.BootMode': { - category: 'winlog', - name: 'winlog.event_data.BootMode', - type: 'keyword', - }, - 'winlog.event_data.BootType': { - category: 'winlog', - name: 'winlog.event_data.BootType', - type: 'keyword', - }, - 'winlog.event_data.BuildVersion': { - category: 'winlog', - name: 'winlog.event_data.BuildVersion', - type: 'keyword', - }, - 'winlog.event_data.Company': { - category: 'winlog', - name: 'winlog.event_data.Company', - type: 'keyword', - }, - 'winlog.event_data.CorruptionActionState': { - category: 'winlog', - name: 'winlog.event_data.CorruptionActionState', - type: 'keyword', - }, - 'winlog.event_data.CreationUtcTime': { - category: 'winlog', - name: 'winlog.event_data.CreationUtcTime', - type: 'keyword', - }, - 'winlog.event_data.Description': { - category: 'winlog', - name: 'winlog.event_data.Description', - type: 'keyword', - }, - 'winlog.event_data.Detail': { - category: 'winlog', - name: 'winlog.event_data.Detail', - type: 'keyword', - }, - 'winlog.event_data.DeviceName': { - category: 'winlog', - name: 'winlog.event_data.DeviceName', - type: 'keyword', - }, - 'winlog.event_data.DeviceNameLength': { - category: 'winlog', - name: 'winlog.event_data.DeviceNameLength', - type: 'keyword', - }, - 'winlog.event_data.DeviceTime': { - category: 'winlog', - name: 'winlog.event_data.DeviceTime', - type: 'keyword', - }, - 'winlog.event_data.DeviceVersionMajor': { - category: 'winlog', - name: 'winlog.event_data.DeviceVersionMajor', - type: 'keyword', - }, - 'winlog.event_data.DeviceVersionMinor': { - category: 'winlog', - name: 'winlog.event_data.DeviceVersionMinor', - type: 'keyword', - }, - 'winlog.event_data.DriveName': { - category: 'winlog', - name: 'winlog.event_data.DriveName', - type: 'keyword', - }, - 'winlog.event_data.DriverName': { - category: 'winlog', - name: 'winlog.event_data.DriverName', - type: 'keyword', - }, - 'winlog.event_data.DriverNameLength': { - category: 'winlog', - name: 'winlog.event_data.DriverNameLength', - type: 'keyword', - }, - 'winlog.event_data.DwordVal': { - category: 'winlog', - name: 'winlog.event_data.DwordVal', - type: 'keyword', - }, - 'winlog.event_data.EntryCount': { - category: 'winlog', - name: 'winlog.event_data.EntryCount', - type: 'keyword', - }, - 'winlog.event_data.ExtraInfo': { - category: 'winlog', - name: 'winlog.event_data.ExtraInfo', - type: 'keyword', - }, - 'winlog.event_data.FailureName': { - category: 'winlog', - name: 'winlog.event_data.FailureName', - type: 'keyword', - }, - 'winlog.event_data.FailureNameLength': { - category: 'winlog', - name: 'winlog.event_data.FailureNameLength', - type: 'keyword', - }, - 'winlog.event_data.FileVersion': { - category: 'winlog', - name: 'winlog.event_data.FileVersion', - type: 'keyword', - }, - 'winlog.event_data.FinalStatus': { - category: 'winlog', - name: 'winlog.event_data.FinalStatus', - type: 'keyword', - }, - 'winlog.event_data.Group': { - category: 'winlog', - name: 'winlog.event_data.Group', - type: 'keyword', - }, - 'winlog.event_data.IdleImplementation': { - category: 'winlog', - name: 'winlog.event_data.IdleImplementation', - type: 'keyword', - }, - 'winlog.event_data.IdleStateCount': { - category: 'winlog', - name: 'winlog.event_data.IdleStateCount', - type: 'keyword', - }, - 'winlog.event_data.ImpersonationLevel': { - category: 'winlog', - name: 'winlog.event_data.ImpersonationLevel', - type: 'keyword', - }, - 'winlog.event_data.IntegrityLevel': { - category: 'winlog', - name: 'winlog.event_data.IntegrityLevel', - type: 'keyword', - }, - 'winlog.event_data.IpAddress': { - category: 'winlog', - name: 'winlog.event_data.IpAddress', - type: 'keyword', - }, - 'winlog.event_data.IpPort': { - category: 'winlog', - name: 'winlog.event_data.IpPort', - type: 'keyword', - }, - 'winlog.event_data.KeyLength': { - category: 'winlog', - name: 'winlog.event_data.KeyLength', - type: 'keyword', - }, - 'winlog.event_data.LastBootGood': { - category: 'winlog', - name: 'winlog.event_data.LastBootGood', - type: 'keyword', - }, - 'winlog.event_data.LastShutdownGood': { - category: 'winlog', - name: 'winlog.event_data.LastShutdownGood', - type: 'keyword', - }, - 'winlog.event_data.LmPackageName': { - category: 'winlog', - name: 'winlog.event_data.LmPackageName', - type: 'keyword', - }, - 'winlog.event_data.LogonGuid': { - category: 'winlog', - name: 'winlog.event_data.LogonGuid', - type: 'keyword', - }, - 'winlog.event_data.LogonId': { - category: 'winlog', - name: 'winlog.event_data.LogonId', - type: 'keyword', - }, - 'winlog.event_data.LogonProcessName': { - category: 'winlog', - name: 'winlog.event_data.LogonProcessName', - type: 'keyword', - }, - 'winlog.event_data.LogonType': { - category: 'winlog', - name: 'winlog.event_data.LogonType', - type: 'keyword', - }, - 'winlog.event_data.MajorVersion': { - category: 'winlog', - name: 'winlog.event_data.MajorVersion', - type: 'keyword', - }, - 'winlog.event_data.MaximumPerformancePercent': { - category: 'winlog', - name: 'winlog.event_data.MaximumPerformancePercent', - type: 'keyword', - }, - 'winlog.event_data.MemberName': { - category: 'winlog', - name: 'winlog.event_data.MemberName', - type: 'keyword', - }, - 'winlog.event_data.MemberSid': { - category: 'winlog', - name: 'winlog.event_data.MemberSid', - type: 'keyword', - }, - 'winlog.event_data.MinimumPerformancePercent': { - category: 'winlog', - name: 'winlog.event_data.MinimumPerformancePercent', - type: 'keyword', - }, - 'winlog.event_data.MinimumThrottlePercent': { - category: 'winlog', - name: 'winlog.event_data.MinimumThrottlePercent', - type: 'keyword', - }, - 'winlog.event_data.MinorVersion': { - category: 'winlog', - name: 'winlog.event_data.MinorVersion', - type: 'keyword', - }, - 'winlog.event_data.NewProcessId': { - category: 'winlog', - name: 'winlog.event_data.NewProcessId', - type: 'keyword', - }, - 'winlog.event_data.NewProcessName': { - category: 'winlog', - name: 'winlog.event_data.NewProcessName', - type: 'keyword', - }, - 'winlog.event_data.NewSchemeGuid': { - category: 'winlog', - name: 'winlog.event_data.NewSchemeGuid', - type: 'keyword', - }, - 'winlog.event_data.NewTime': { - category: 'winlog', - name: 'winlog.event_data.NewTime', - type: 'keyword', - }, - 'winlog.event_data.NominalFrequency': { - category: 'winlog', - name: 'winlog.event_data.NominalFrequency', - type: 'keyword', - }, - 'winlog.event_data.Number': { - category: 'winlog', - name: 'winlog.event_data.Number', - type: 'keyword', - }, - 'winlog.event_data.OldSchemeGuid': { - category: 'winlog', - name: 'winlog.event_data.OldSchemeGuid', - type: 'keyword', - }, - 'winlog.event_data.OldTime': { - category: 'winlog', - name: 'winlog.event_data.OldTime', - type: 'keyword', - }, - 'winlog.event_data.OriginalFileName': { - category: 'winlog', - name: 'winlog.event_data.OriginalFileName', - type: 'keyword', - }, - 'winlog.event_data.Path': { - category: 'winlog', - name: 'winlog.event_data.Path', - type: 'keyword', - }, - 'winlog.event_data.PerformanceImplementation': { - category: 'winlog', - name: 'winlog.event_data.PerformanceImplementation', - type: 'keyword', - }, - 'winlog.event_data.PreviousCreationUtcTime': { - category: 'winlog', - name: 'winlog.event_data.PreviousCreationUtcTime', - type: 'keyword', - }, - 'winlog.event_data.PreviousTime': { - category: 'winlog', - name: 'winlog.event_data.PreviousTime', - type: 'keyword', - }, - 'winlog.event_data.PrivilegeList': { - category: 'winlog', - name: 'winlog.event_data.PrivilegeList', - type: 'keyword', - }, - 'winlog.event_data.ProcessId': { - category: 'winlog', - name: 'winlog.event_data.ProcessId', - type: 'keyword', - }, - 'winlog.event_data.ProcessName': { - category: 'winlog', - name: 'winlog.event_data.ProcessName', - type: 'keyword', - }, - 'winlog.event_data.ProcessPath': { - category: 'winlog', - name: 'winlog.event_data.ProcessPath', - type: 'keyword', - }, - 'winlog.event_data.ProcessPid': { - category: 'winlog', - name: 'winlog.event_data.ProcessPid', - type: 'keyword', - }, - 'winlog.event_data.Product': { - category: 'winlog', - name: 'winlog.event_data.Product', - type: 'keyword', - }, - 'winlog.event_data.PuaCount': { - category: 'winlog', - name: 'winlog.event_data.PuaCount', - type: 'keyword', - }, - 'winlog.event_data.PuaPolicyId': { - category: 'winlog', - name: 'winlog.event_data.PuaPolicyId', - type: 'keyword', - }, - 'winlog.event_data.QfeVersion': { - category: 'winlog', - name: 'winlog.event_data.QfeVersion', - type: 'keyword', - }, - 'winlog.event_data.Reason': { - category: 'winlog', - name: 'winlog.event_data.Reason', - type: 'keyword', - }, - 'winlog.event_data.SchemaVersion': { - category: 'winlog', - name: 'winlog.event_data.SchemaVersion', - type: 'keyword', - }, - 'winlog.event_data.ScriptBlockText': { - category: 'winlog', - name: 'winlog.event_data.ScriptBlockText', - type: 'keyword', - }, - 'winlog.event_data.ServiceName': { - category: 'winlog', - name: 'winlog.event_data.ServiceName', - type: 'keyword', - }, - 'winlog.event_data.ServiceVersion': { - category: 'winlog', - name: 'winlog.event_data.ServiceVersion', - type: 'keyword', - }, - 'winlog.event_data.ShutdownActionType': { - category: 'winlog', - name: 'winlog.event_data.ShutdownActionType', - type: 'keyword', - }, - 'winlog.event_data.ShutdownEventCode': { - category: 'winlog', - name: 'winlog.event_data.ShutdownEventCode', - type: 'keyword', - }, - 'winlog.event_data.ShutdownReason': { - category: 'winlog', - name: 'winlog.event_data.ShutdownReason', - type: 'keyword', - }, - 'winlog.event_data.Signature': { - category: 'winlog', - name: 'winlog.event_data.Signature', - type: 'keyword', - }, - 'winlog.event_data.SignatureStatus': { - category: 'winlog', - name: 'winlog.event_data.SignatureStatus', - type: 'keyword', - }, - 'winlog.event_data.Signed': { - category: 'winlog', - name: 'winlog.event_data.Signed', - type: 'keyword', - }, - 'winlog.event_data.StartTime': { - category: 'winlog', - name: 'winlog.event_data.StartTime', - type: 'keyword', - }, - 'winlog.event_data.State': { - category: 'winlog', - name: 'winlog.event_data.State', - type: 'keyword', - }, - 'winlog.event_data.Status': { - category: 'winlog', - name: 'winlog.event_data.Status', - type: 'keyword', - }, - 'winlog.event_data.StopTime': { - category: 'winlog', - name: 'winlog.event_data.StopTime', - type: 'keyword', - }, - 'winlog.event_data.SubjectDomainName': { - category: 'winlog', - name: 'winlog.event_data.SubjectDomainName', - type: 'keyword', - }, - 'winlog.event_data.SubjectLogonId': { - category: 'winlog', - name: 'winlog.event_data.SubjectLogonId', - type: 'keyword', - }, - 'winlog.event_data.SubjectUserName': { - category: 'winlog', - name: 'winlog.event_data.SubjectUserName', - type: 'keyword', - }, - 'winlog.event_data.SubjectUserSid': { - category: 'winlog', - name: 'winlog.event_data.SubjectUserSid', - type: 'keyword', - }, - 'winlog.event_data.TSId': { - category: 'winlog', - name: 'winlog.event_data.TSId', - type: 'keyword', - }, - 'winlog.event_data.TargetDomainName': { - category: 'winlog', - name: 'winlog.event_data.TargetDomainName', - type: 'keyword', - }, - 'winlog.event_data.TargetInfo': { - category: 'winlog', - name: 'winlog.event_data.TargetInfo', - type: 'keyword', - }, - 'winlog.event_data.TargetLogonGuid': { - category: 'winlog', - name: 'winlog.event_data.TargetLogonGuid', - type: 'keyword', - }, - 'winlog.event_data.TargetLogonId': { - category: 'winlog', - name: 'winlog.event_data.TargetLogonId', - type: 'keyword', - }, - 'winlog.event_data.TargetServerName': { - category: 'winlog', - name: 'winlog.event_data.TargetServerName', - type: 'keyword', - }, - 'winlog.event_data.TargetUserName': { - category: 'winlog', - name: 'winlog.event_data.TargetUserName', - type: 'keyword', - }, - 'winlog.event_data.TargetUserSid': { - category: 'winlog', - name: 'winlog.event_data.TargetUserSid', - type: 'keyword', - }, - 'winlog.event_data.TerminalSessionId': { - category: 'winlog', - name: 'winlog.event_data.TerminalSessionId', - type: 'keyword', - }, - 'winlog.event_data.TokenElevationType': { - category: 'winlog', - name: 'winlog.event_data.TokenElevationType', - type: 'keyword', - }, - 'winlog.event_data.TransmittedServices': { - category: 'winlog', - name: 'winlog.event_data.TransmittedServices', - type: 'keyword', - }, - 'winlog.event_data.UserSid': { - category: 'winlog', - name: 'winlog.event_data.UserSid', - type: 'keyword', - }, - 'winlog.event_data.Version': { - category: 'winlog', - name: 'winlog.event_data.Version', - type: 'keyword', - }, - 'winlog.event_data.Workstation': { - category: 'winlog', - name: 'winlog.event_data.Workstation', - type: 'keyword', - }, - 'winlog.event_data.param1': { - category: 'winlog', - name: 'winlog.event_data.param1', - type: 'keyword', - }, - 'winlog.event_data.param2': { - category: 'winlog', - name: 'winlog.event_data.param2', - type: 'keyword', - }, - 'winlog.event_data.param3': { - category: 'winlog', - name: 'winlog.event_data.param3', - type: 'keyword', - }, - 'winlog.event_data.param4': { - category: 'winlog', - name: 'winlog.event_data.param4', - type: 'keyword', - }, - 'winlog.event_data.param5': { - category: 'winlog', - name: 'winlog.event_data.param5', - type: 'keyword', - }, - 'winlog.event_data.param6': { - category: 'winlog', - name: 'winlog.event_data.param6', - type: 'keyword', - }, - 'winlog.event_data.param7': { - category: 'winlog', - name: 'winlog.event_data.param7', - type: 'keyword', - }, - 'winlog.event_data.param8': { - category: 'winlog', - name: 'winlog.event_data.param8', - type: 'keyword', - }, - 'winlog.event_id': { - category: 'winlog', - description: 'The event identifier. The value is specific to the source of the event. ', - name: 'winlog.event_id', - type: 'keyword', - }, - 'winlog.keywords': { - category: 'winlog', - description: 'The keywords are used to classify an event. ', - name: 'winlog.keywords', - type: 'keyword', - }, - 'winlog.channel': { - category: 'winlog', - description: - 'The name of the channel from which this record was read. This value is one of the names from the `event_logs` collection in the configuration. ', - name: 'winlog.channel', - type: 'keyword', - }, - 'winlog.record_id': { - category: 'winlog', - description: - 'The record ID of the event log record. The first record written to an event log is record number 1, and other records are numbered sequentially. If the record number reaches the maximum value (2^32^ for the Event Logging API and 2^64^ for the Windows Event Log API), the next record number will be 0. ', - name: 'winlog.record_id', - type: 'keyword', - }, - 'winlog.related_activity_id': { - category: 'winlog', - description: - 'A globally unique identifier that identifies the activity to which control was transferred to. The related events would then have this identifier as their `activity_id` identifier. ', - name: 'winlog.related_activity_id', - type: 'keyword', - }, - 'winlog.opcode': { - category: 'winlog', - description: - 'The opcode defined in the event. Task and opcode are typically used to identify the location in the application from where the event was logged. ', - name: 'winlog.opcode', - type: 'keyword', - }, - 'winlog.provider_guid': { - category: 'winlog', - description: - 'A globally unique identifier that identifies the provider that logged the event. ', - name: 'winlog.provider_guid', - type: 'keyword', - }, - 'winlog.process.pid': { - category: 'winlog', - description: 'The process_id of the Client Server Runtime Process. ', - name: 'winlog.process.pid', - type: 'long', - }, - 'winlog.provider_name': { - category: 'winlog', - description: - 'The source of the event log record (the application or service that logged the record). ', - name: 'winlog.provider_name', - type: 'keyword', - }, - 'winlog.task': { - category: 'winlog', - description: - 'The task defined in the event. Task and opcode are typically used to identify the location in the application from where the event was logged. The category used by the Event Logging API (on pre Windows Vista operating systems) is written to this field. ', - name: 'winlog.task', - type: 'keyword', - }, - 'winlog.time_created': { - category: 'winlog', - description: 'The event creation time. ', - name: 'winlog.time_created', - type: 'date', - }, - 'winlog.process.thread.id': { - category: 'winlog', - name: 'winlog.process.thread.id', - type: 'long', - }, - 'winlog.user_data': { - category: 'winlog', - description: 'The event specific data. This field is mutually exclusive with `event_data`. ', - name: 'winlog.user_data', - type: 'object', - }, - 'winlog.user.identifier': { - category: 'winlog', - description: - 'The Windows security identifier (SID) of the account associated with this event. If Winlogbeat cannot resolve the SID to a name, then the `user.name`, `user.domain`, and `user.type` fields will be omitted from the event. If you discover Winlogbeat not resolving SIDs, review the log for clues as to what the problem may be. ', - example: 'S-1-5-21-3541430928-2051711210-1391384369-1001', - name: 'winlog.user.identifier', - type: 'keyword', - }, - 'winlog.user.name': { - category: 'winlog', - description: 'Name of the user associated with this event. ', - name: 'winlog.user.name', - type: 'keyword', - }, - 'winlog.user.domain': { - category: 'winlog', - description: 'The domain that the account associated with this event is a member of. ', - name: 'winlog.user.domain', - type: 'keyword', - }, - 'winlog.user.type': { - category: 'winlog', - description: 'The type of account associated with this event. ', - name: 'winlog.user.type', - type: 'keyword', - }, - 'winlog.version': { - category: 'winlog', - description: "The version number of the event's definition.", - name: 'winlog.version', - type: 'long', - }, - activity_id: { - category: 'base', - name: 'activity_id', - type: 'alias', - }, - computer_name: { - category: 'base', - name: 'computer_name', - type: 'alias', - }, - event_id: { - category: 'base', - name: 'event_id', - type: 'alias', - }, - keywords: { - category: 'base', - name: 'keywords', - type: 'alias', - }, - log_name: { - category: 'base', - name: 'log_name', - type: 'alias', - }, - message_error: { - category: 'base', - name: 'message_error', - type: 'alias', - }, - record_number: { - category: 'base', - name: 'record_number', - type: 'alias', - }, - related_activity_id: { - category: 'base', - name: 'related_activity_id', - type: 'alias', - }, - opcode: { - category: 'base', - name: 'opcode', - type: 'alias', - }, - provider_guid: { - category: 'base', - name: 'provider_guid', - type: 'alias', - }, - process_id: { - category: 'base', - name: 'process_id', - type: 'alias', - }, - source_name: { - category: 'base', - name: 'source_name', - type: 'alias', - }, - task: { - category: 'base', - name: 'task', - type: 'alias', - }, - thread_id: { - category: 'base', - name: 'thread_id', - type: 'alias', - }, - 'user.identifier': { - category: 'user', - name: 'user.identifier', - type: 'alias', - }, - 'user.type': { - category: 'user', - name: 'user.type', - type: 'alias', - }, - version: { - category: 'base', - name: 'version', - type: 'alias', - }, - xml: { - category: 'base', - name: 'xml', - type: 'alias', - }, - 'powershell.id': { - category: 'powershell', - description: 'Shell Id.', - example: 'Microsoft Powershell', - name: 'powershell.id', - type: 'keyword', - }, - 'powershell.pipeline_id': { - category: 'powershell', - description: 'Pipeline id.', - example: '1', - name: 'powershell.pipeline_id', - type: 'keyword', - }, - 'powershell.runspace_id': { - category: 'powershell', - description: 'Runspace id.', - example: '4fa9074d-45ab-4e53-9195-e91981ac2bbb', - name: 'powershell.runspace_id', - type: 'keyword', - }, - 'powershell.sequence': { - category: 'powershell', - description: 'Sequence number of the powershell execution.', - example: 1, - name: 'powershell.sequence', - type: 'long', - }, - 'powershell.total': { - category: 'powershell', - description: 'Total number of messages in the sequence.', - example: 10, - name: 'powershell.total', - type: 'long', - }, - 'powershell.command.path': { - category: 'powershell', - description: 'Path of the executed command.', - example: 'C:\\Windows\\system32\\cmd.exe', - name: 'powershell.command.path', - type: 'keyword', - }, - 'powershell.command.name': { - category: 'powershell', - description: 'Name of the executed command.', - example: 'cmd.exe', - name: 'powershell.command.name', - type: 'keyword', - }, - 'powershell.command.type': { - category: 'powershell', - description: 'Type of the executed command.', - example: 'Application', - name: 'powershell.command.type', - type: 'keyword', - }, - 'powershell.command.value': { - category: 'powershell', - description: 'The invoked command.', - example: 'Import-LocalizedData LocalizedData -filename ArchiveResources', - name: 'powershell.command.value', - type: 'text', - }, - 'powershell.command.invocation_details': { - category: 'powershell', - description: 'An array of objects containing detailed information of the executed command. ', - name: 'powershell.command.invocation_details', - type: 'array', - }, - 'powershell.command.invocation_details.type': { - category: 'powershell', - description: 'The type of detail.', - example: 'CommandInvocation', - name: 'powershell.command.invocation_details.type', - type: 'keyword', - }, - 'powershell.command.invocation_details.related_command': { - category: 'powershell', - description: 'The command to which the detail is related to.', - example: 'Add-Type', - name: 'powershell.command.invocation_details.related_command', - type: 'keyword', - }, - 'powershell.command.invocation_details.name': { - category: 'powershell', - description: 'Only used for ParameterBinding detail type. Indicates the parameter name. ', - example: 'AssemblyName', - name: 'powershell.command.invocation_details.name', - type: 'keyword', - }, - 'powershell.command.invocation_details.value': { - category: 'powershell', - description: 'The value of the detail. The meaning of it will depend on the detail type. ', - example: 'System.IO.Compression.FileSystem', - name: 'powershell.command.invocation_details.value', - type: 'text', - }, - 'powershell.connected_user.domain': { - category: 'powershell', - description: 'User domain.', - example: 'VAGRANT', - name: 'powershell.connected_user.domain', - type: 'keyword', - }, - 'powershell.connected_user.name': { - category: 'powershell', - description: 'User name.', - example: 'vagrant', - name: 'powershell.connected_user.name', - type: 'keyword', - }, - 'powershell.engine.version': { - category: 'powershell', - description: 'Version of the PowerShell engine version used to execute the command.', - example: '5.1.17763.1007', - name: 'powershell.engine.version', - type: 'keyword', - }, - 'powershell.engine.previous_state': { - category: 'powershell', - description: 'Previous state of the PowerShell engine. ', - example: 'Available', - name: 'powershell.engine.previous_state', - type: 'keyword', - }, - 'powershell.engine.new_state': { - category: 'powershell', - description: 'New state of the PowerShell engine. ', - example: 'Stopped', - name: 'powershell.engine.new_state', - type: 'keyword', - }, - 'powershell.file.script_block_id': { - category: 'powershell', - description: 'Id of the executed script block.', - example: '50d2dbda-7361-4926-a94d-d9eadfdb43fa', - name: 'powershell.file.script_block_id', - type: 'keyword', - }, - 'powershell.file.script_block_text': { - category: 'powershell', - description: 'Text of the executed script block. ', - example: '.\\a_script.ps1', - name: 'powershell.file.script_block_text', - type: 'text', - }, - 'powershell.process.executable_version': { - category: 'powershell', - description: 'Version of the engine hosting process executable.', - example: '5.1.17763.1007', - name: 'powershell.process.executable_version', - type: 'keyword', - }, - 'powershell.provider.new_state': { - category: 'powershell', - description: 'New state of the PowerShell provider. ', - example: 'Active', - name: 'powershell.provider.new_state', - type: 'keyword', - }, - 'powershell.provider.name': { - category: 'powershell', - description: 'Provider name. ', - example: 'Variable', - name: 'powershell.provider.name', - type: 'keyword', - }, - 'winlog.logon.type': { - category: 'winlog', - description: - 'Logon type name. This is the descriptive version of the `winlog.event_data.LogonType` ordinal. This is an enrichment added by the Security module. ', - example: 'RemoteInteractive', - name: 'winlog.logon.type', - type: 'keyword', - }, - 'winlog.logon.id': { - category: 'winlog', - description: - 'Logon ID that can be used to associate this logon with other events related to the same logon session. ', - name: 'winlog.logon.id', - type: 'keyword', - }, - 'winlog.logon.failure.reason': { - category: 'winlog', - description: 'The reason the logon failed. ', - name: 'winlog.logon.failure.reason', - type: 'keyword', - }, - 'winlog.logon.failure.status': { - category: 'winlog', - description: - 'The reason the logon failed. This is textual description based on the value of the hexadecimal `Status` field. ', - name: 'winlog.logon.failure.status', - type: 'keyword', - }, - 'winlog.logon.failure.sub_status': { - category: 'winlog', - description: - 'Additional information about the logon failure. This is a textual description based on the value of the hexidecimal `SubStatus` field. ', - name: 'winlog.logon.failure.sub_status', - type: 'keyword', - }, - 'sysmon.dns.status': { - category: 'sysmon', - description: 'Windows status code returned for the DNS query.', - name: 'sysmon.dns.status', - type: 'keyword', - }, - 'sysmon.file.archived': { - category: 'sysmon', - description: 'Indicates if the deleted file was archived.', - name: 'sysmon.file.archived', - type: 'boolean', - }, - 'sysmon.file.is_executable': { - category: 'sysmon', - description: 'Indicates if the deleted file was an executable.', - name: 'sysmon.file.is_executable', - type: 'boolean', - }, -}; diff --git a/x-pack/plugins/timelines/server/search_strategy/index_fields/index.test.ts b/x-pack/plugins/timelines/server/search_strategy/index_fields/index.test.ts index c4e7f6538d16da..1e3ffd72ece732 100644 --- a/x-pack/plugins/timelines/server/search_strategy/index_fields/index.test.ts +++ b/x-pack/plugins/timelines/server/search_strategy/index_fields/index.test.ts @@ -87,8 +87,7 @@ describe('Index Fields', () => { esTypes: [], }, { - description: - 'Deprecated - use agent.name or agent.id to identify an agent. Hostname of the agent. ', + description: 'Deprecated - use agent.name or agent.id to identify an agent. ', name: 'agent.hostname', searchable: true, type: 'string', @@ -126,7 +125,7 @@ describe('Index Fields', () => { }, { description: - 'Type of the agent. The agent type stays always the same and should be given by the agent used. In case of Filebeat the agent would always be Filebeat also if two Filebeat instances are run on the same machine.', + 'Type of the agent. The agent type always stays the same and should be given by the agent used. In case of Filebeat the agent would always be Filebeat also if two Filebeat instances are run on the same machine.', example: 'filebeat', name: 'agent.type', type: 'string', @@ -252,7 +251,7 @@ describe('Index Fields', () => { { category: 'agent', description: - 'Type of the agent. The agent type stays always the same and should be given by the agent used. In case of Filebeat the agent would always be Filebeat also if two Filebeat instances are run on the same machine.', + 'Type of the agent. The agent type always stays the same and should be given by the agent used. In case of Filebeat the agent would always be Filebeat also if two Filebeat instances are run on the same machine.', example: 'filebeat', name: 'agent.type', type: 'string', @@ -337,8 +336,7 @@ describe('Index Fields', () => { }, { category: 'agent', - description: - 'Deprecated - use agent.name or agent.id to identify an agent. Hostname of the agent. ', + description: 'Deprecated - use agent.name or agent.id to identify an agent. ', name: 'agent.hostname', type: 'string', searchable: true, @@ -426,7 +424,7 @@ describe('Index Fields', () => { { category: 'agent', description: - 'Type of the agent. The agent type stays always the same and should be given by the agent used. In case of Filebeat the agent would always be Filebeat also if two Filebeat instances are run on the same machine.', + 'Type of the agent. The agent type always stays the same and should be given by the agent used. In case of Filebeat the agent would always be Filebeat also if two Filebeat instances are run on the same machine.', example: 'filebeat', name: 'agent.type', type: 'string', @@ -504,7 +502,7 @@ describe('Index Fields', () => { }, { description: - 'Type of the agent. The agent type stays always the same and should be given by the agent used. In case of Filebeat the agent would always be Filebeat also if two Filebeat instances are run on the same machine.', + 'Type of the agent. The agent type always stays the same and should be given by the agent used. In case of Filebeat the agent would always be Filebeat also if two Filebeat instances are run on the same machine.', example: 'filebeat', name: 'agent.type', type: 'string', @@ -641,7 +639,7 @@ describe('Index Fields', () => { }, { description: - 'Type of the agent. The agent type stays always the same and should be given by the agent used. In case of Filebeat the agent would always be Filebeat also if two Filebeat instances are run on the same machine.', + 'Type of the agent. The agent type always stays the same and should be given by the agent used. In case of Filebeat the agent would always be Filebeat also if two Filebeat instances are run on the same machine.', example: 'filebeat', name: 'agent.type', type: 'string', @@ -714,7 +712,7 @@ describe('Index Fields', () => { }, { description: - 'Type of the agent. The agent type stays always the same and should be given by the agent used. In case of Filebeat the agent would always be Filebeat also if two Filebeat instances are run on the same machine.', + 'Type of the agent. The agent type always stays the same and should be given by the agent used. In case of Filebeat the agent would always be Filebeat also if two Filebeat instances are run on the same machine.', example: 'filebeat', name: 'agent.type', type: 'string', diff --git a/x-pack/plugins/timelines/server/utils/beat_schema/fields.ts b/x-pack/plugins/timelines/server/utils/beat_schema/fields.ts index 4f1dc0079b2360..aee466d58c9af1 100644 --- a/x-pack/plugins/timelines/server/utils/beat_schema/fields.ts +++ b/x-pack/plugins/timelines/server/utils/beat_schema/fields.ts @@ -46,7 +46,7 @@ export const fieldsBeat: BeatFields = { 'For log events the message field contains the log message, optimized for viewing in a log viewer. For structured logs without an original message field, other fields can be concatenated to form a human-readable summary of the event. If multiple messages exist, they can be combined into one message.', example: 'Hello World', name: 'message', - type: 'text', + type: 'match_only_text', }, tags: { category: 'base', @@ -55,6 +55,15 @@ export const fieldsBeat: BeatFields = { name: 'tags', type: 'keyword', }, + 'agent.build.original': { + category: 'agent', + description: + 'Extended build information for the agent. This field is intended to contain any build information that a data source may provide, no specific formatting is required.', + example: + 'metricbeat version 7.6.0 (amd64), libbeat 7.6.0 [6a23e8f8f30f5001ba344e4e54d8d9cb82cb107c built 2020-02-05 23:10:10 +0000 UTC]', + name: 'agent.build.original', + type: 'keyword', + }, 'agent.ephemeral_id': { category: 'agent', description: @@ -82,7 +91,7 @@ export const fieldsBeat: BeatFields = { 'agent.type': { category: 'agent', description: - 'Type of the agent. The agent type stays always the same and should be given by the agent used. In case of Filebeat the agent would always be Filebeat also if two Filebeat instances are run on the same machine.', + 'Type of the agent. The agent type always stays the same and should be given by the agent used. In case of Filebeat the agent would always be Filebeat also if two Filebeat instances are run on the same machine.', example: 'filebeat', name: 'agent.type', type: 'keyword', @@ -152,6 +161,13 @@ export const fieldsBeat: BeatFields = { name: 'client.geo.city_name', type: 'keyword', }, + 'client.geo.continent_code': { + category: 'client', + description: "Two-letter code representing continent's name.", + example: 'NA', + name: 'client.geo.continent_code', + type: 'keyword', + }, 'client.geo.continent_name': { category: 'client', description: 'Name of the continent.', @@ -188,6 +204,14 @@ export const fieldsBeat: BeatFields = { name: 'client.geo.name', type: 'keyword', }, + 'client.geo.postal_code': { + category: 'client', + description: + 'Postal code associated with the location. Values appropriate for this field may also be known as a postcode or ZIP code and will vary widely from country to country.', + example: 94040, + name: 'client.geo.postal_code', + type: 'keyword', + }, 'client.geo.region_iso_code': { category: 'client', description: 'Region ISO code.', @@ -202,15 +226,24 @@ export const fieldsBeat: BeatFields = { name: 'client.geo.region_name', type: 'keyword', }, + 'client.geo.timezone': { + category: 'client', + description: 'The time zone of the location, such as IANA time zone name.', + example: 'America/Argentina/Buenos_Aires', + name: 'client.geo.timezone', + type: 'keyword', + }, 'client.ip': { category: 'client', - description: 'IP address of the client. Can be one or multiple IPv4 or IPv6 addresses.', + description: 'IP address of the client (IPv4 or IPv6).', name: 'client.ip', type: 'ip', }, 'client.mac': { category: 'client', - description: 'MAC address of the client.', + description: + 'MAC address of the client. The notation format from RFC 7042 is suggested: Each octet (that is, 8-bit byte) is represented by two [uppercase] hexadecimal digits giving the value of the octet as an unsigned integer. Successive octets are separated by a hyphen.', + example: '00-00-5E-00-53-23', name: 'client.mac', type: 'keyword', }, @@ -246,15 +279,23 @@ export const fieldsBeat: BeatFields = { 'client.registered_domain': { category: 'client', description: - 'The highest registered client domain, stripped of the subdomain. For example, the registered domain for "foo.google.com" is "google.com". This value can be determined precisely with a list like the public suffix list (http://publicsuffix.org). Trying to approximate this by simply taking the last two labels will not work well for TLDs such as "co.uk".', - example: 'google.com', + 'The highest registered client domain, stripped of the subdomain. For example, the registered domain for "foo.example.com" is "example.com". This value can be determined precisely with a list like the public suffix list (http://publicsuffix.org). Trying to approximate this by simply taking the last two labels will not work well for TLDs such as "co.uk".', + example: 'example.com', name: 'client.registered_domain', type: 'keyword', }, + 'client.subdomain': { + category: 'client', + description: + 'The subdomain portion of a fully qualified domain name includes all of the names except the host name under the registered_domain. In a partially qualified domain, or if the the qualification level of the full name cannot be determined, subdomain contains all of the names below the registered domain. For example the subdomain portion of "www.east.mydomain.co.uk" is "east". If the domain has multiple levels of subdomain, such as "sub2.sub1.example.com", the subdomain field should contain "sub2.sub1", with no trailing period.', + example: 'east', + name: 'client.subdomain', + type: 'keyword', + }, 'client.top_level_domain': { category: 'client', description: - 'The effective top level domain (eTLD), also known as the domain suffix, is the last part of the domain name. For example, the top level domain for google.com is "com". This value can be determined precisely with a list like the public suffix list (http://publicsuffix.org). Trying to approximate this by simply taking the last label will not work well for effective TLDs such as "co.uk".', + 'The effective top level domain (eTLD), also known as the domain suffix, is the last part of the domain name. For example, the top level domain for example.com is "com". This value can be determined precisely with a list like the public suffix list (http://publicsuffix.org). Trying to approximate this by simply taking the last label will not work well for effective TLDs such as "co.uk".', example: 'co.uk', name: 'client.top_level_domain', type: 'keyword', @@ -307,17 +348,25 @@ export const fieldsBeat: BeatFields = { }, 'client.user.id': { category: 'client', - description: 'Unique identifiers of the user.', + description: 'Unique identifier of the user.', + example: 'S-1-5-21-202424912787-2692429404-2351956786-1000', name: 'client.user.id', type: 'keyword', }, 'client.user.name': { category: 'client', description: 'Short name or login of the user.', - example: 'albert', + example: 'a.einstein', name: 'client.user.name', type: 'keyword', }, + 'client.user.roles': { + category: 'client', + description: 'Array of user roles at the time of the event.', + example: '["kibana_admin", "reporting_user"]', + name: 'client.user.roles', + type: 'keyword', + }, 'cloud.account.id': { category: 'cloud', description: @@ -326,9 +375,17 @@ export const fieldsBeat: BeatFields = { name: 'cloud.account.id', type: 'keyword', }, + 'cloud.account.name': { + category: 'cloud', + description: + 'The cloud account name or alias used to identify different entities in a multi-tenant environment. Examples: AWS account name, Google Cloud ORG display name.', + example: 'elastic-dev', + name: 'cloud.account.name', + type: 'keyword', + }, 'cloud.availability_zone': { category: 'cloud', - description: 'Availability zone in which this host is running.', + description: 'Availability zone in which this host, resource, or service is located.', example: 'us-east-1c', name: 'cloud.availability_zone', type: 'keyword', @@ -353,6 +410,101 @@ export const fieldsBeat: BeatFields = { name: 'cloud.machine.type', type: 'keyword', }, + 'cloud.origin.account.id': { + category: 'cloud', + description: + 'The cloud account or organization id used to identify different entities in a multi-tenant environment. Examples: AWS account id, Google Cloud ORG Id, or other unique identifier.', + example: 666777888999, + name: 'cloud.origin.account.id', + type: 'keyword', + }, + 'cloud.origin.account.name': { + category: 'cloud', + description: + 'The cloud account name or alias used to identify different entities in a multi-tenant environment. Examples: AWS account name, Google Cloud ORG display name.', + example: 'elastic-dev', + name: 'cloud.origin.account.name', + type: 'keyword', + }, + 'cloud.origin.availability_zone': { + category: 'cloud', + description: 'Availability zone in which this host, resource, or service is located.', + example: 'us-east-1c', + name: 'cloud.origin.availability_zone', + type: 'keyword', + }, + 'cloud.origin.instance.id': { + category: 'cloud', + description: 'Instance ID of the host machine.', + example: 'i-1234567890abcdef0', + name: 'cloud.origin.instance.id', + type: 'keyword', + }, + 'cloud.origin.instance.name': { + category: 'cloud', + description: 'Instance name of the host machine.', + name: 'cloud.origin.instance.name', + type: 'keyword', + }, + 'cloud.origin.machine.type': { + category: 'cloud', + description: 'Machine type of the host machine.', + example: 't2.medium', + name: 'cloud.origin.machine.type', + type: 'keyword', + }, + 'cloud.origin.project.id': { + category: 'cloud', + description: + 'The cloud project identifier. Examples: Google Cloud Project id, Azure Project id.', + example: 'my-project', + name: 'cloud.origin.project.id', + type: 'keyword', + }, + 'cloud.origin.project.name': { + category: 'cloud', + description: 'The cloud project name. Examples: Google Cloud Project name, Azure Project name.', + example: 'my project', + name: 'cloud.origin.project.name', + type: 'keyword', + }, + 'cloud.origin.provider': { + category: 'cloud', + description: 'Name of the cloud provider. Example values are aws, azure, gcp, or digitalocean.', + example: 'aws', + name: 'cloud.origin.provider', + type: 'keyword', + }, + 'cloud.origin.region': { + category: 'cloud', + description: 'Region in which this host, resource, or service is located.', + example: 'us-east-1', + name: 'cloud.origin.region', + type: 'keyword', + }, + 'cloud.origin.service.name': { + category: 'cloud', + description: + 'The cloud service name is intended to distinguish services running on different platforms within a provider, eg AWS EC2 vs Lambda, GCP GCE vs App Engine, Azure VM vs App Server. Examples: app engine, app service, cloud run, fargate, lambda.', + example: 'lambda', + name: 'cloud.origin.service.name', + type: 'keyword', + }, + 'cloud.project.id': { + category: 'cloud', + description: + 'The cloud project identifier. Examples: Google Cloud Project id, Azure Project id.', + example: 'my-project', + name: 'cloud.project.id', + type: 'keyword', + }, + 'cloud.project.name': { + category: 'cloud', + description: 'The cloud project name. Examples: Google Cloud Project name, Azure Project name.', + example: 'my project', + name: 'cloud.project.name', + type: 'keyword', + }, 'cloud.provider': { category: 'cloud', description: 'Name of the cloud provider. Example values are aws, azure, gcp, or digitalocean.', @@ -362,11 +514,107 @@ export const fieldsBeat: BeatFields = { }, 'cloud.region': { category: 'cloud', - description: 'Region in which this host is running.', + description: 'Region in which this host, resource, or service is located.', example: 'us-east-1', name: 'cloud.region', type: 'keyword', }, + 'cloud.service.name': { + category: 'cloud', + description: + 'The cloud service name is intended to distinguish services running on different platforms within a provider, eg AWS EC2 vs Lambda, GCP GCE vs App Engine, Azure VM vs App Server. Examples: app engine, app service, cloud run, fargate, lambda.', + example: 'lambda', + name: 'cloud.service.name', + type: 'keyword', + }, + 'cloud.target.account.id': { + category: 'cloud', + description: + 'The cloud account or organization id used to identify different entities in a multi-tenant environment. Examples: AWS account id, Google Cloud ORG Id, or other unique identifier.', + example: 666777888999, + name: 'cloud.target.account.id', + type: 'keyword', + }, + 'cloud.target.account.name': { + category: 'cloud', + description: + 'The cloud account name or alias used to identify different entities in a multi-tenant environment. Examples: AWS account name, Google Cloud ORG display name.', + example: 'elastic-dev', + name: 'cloud.target.account.name', + type: 'keyword', + }, + 'cloud.target.availability_zone': { + category: 'cloud', + description: 'Availability zone in which this host, resource, or service is located.', + example: 'us-east-1c', + name: 'cloud.target.availability_zone', + type: 'keyword', + }, + 'cloud.target.instance.id': { + category: 'cloud', + description: 'Instance ID of the host machine.', + example: 'i-1234567890abcdef0', + name: 'cloud.target.instance.id', + type: 'keyword', + }, + 'cloud.target.instance.name': { + category: 'cloud', + description: 'Instance name of the host machine.', + name: 'cloud.target.instance.name', + type: 'keyword', + }, + 'cloud.target.machine.type': { + category: 'cloud', + description: 'Machine type of the host machine.', + example: 't2.medium', + name: 'cloud.target.machine.type', + type: 'keyword', + }, + 'cloud.target.project.id': { + category: 'cloud', + description: + 'The cloud project identifier. Examples: Google Cloud Project id, Azure Project id.', + example: 'my-project', + name: 'cloud.target.project.id', + type: 'keyword', + }, + 'cloud.target.project.name': { + category: 'cloud', + description: 'The cloud project name. Examples: Google Cloud Project name, Azure Project name.', + example: 'my project', + name: 'cloud.target.project.name', + type: 'keyword', + }, + 'cloud.target.provider': { + category: 'cloud', + description: 'Name of the cloud provider. Example values are aws, azure, gcp, or digitalocean.', + example: 'aws', + name: 'cloud.target.provider', + type: 'keyword', + }, + 'cloud.target.region': { + category: 'cloud', + description: 'Region in which this host, resource, or service is located.', + example: 'us-east-1', + name: 'cloud.target.region', + type: 'keyword', + }, + 'cloud.target.service.name': { + category: 'cloud', + description: + 'The cloud service name is intended to distinguish services running on different platforms within a provider, eg AWS EC2 vs Lambda, GCP GCE vs App Engine, Azure VM vs App Server. Examples: app engine, app service, cloud run, fargate, lambda.', + example: 'lambda', + name: 'cloud.target.service.name', + type: 'keyword', + }, + 'code_signature.digest_algorithm': { + category: 'code_signature', + description: + 'The hashing algorithm used to sign the process. This value can distinguish signatures when a file is signed multiple times by the same signer but with a different digest algorithm.', + example: 'sha256', + name: 'code_signature.digest_algorithm', + type: 'keyword', + }, 'code_signature.exists': { category: 'code_signature', description: 'Boolean to capture if a signature is present.', @@ -374,6 +622,14 @@ export const fieldsBeat: BeatFields = { name: 'code_signature.exists', type: 'boolean', }, + 'code_signature.signing_id': { + category: 'code_signature', + description: + 'The identifier used to sign the process. This is used to identify the application manufactured by a software vendor. The field is relevant to Apple *OS only.', + example: 'com.apple.xpc.proxy', + name: 'code_signature.signing_id', + type: 'keyword', + }, 'code_signature.status': { category: 'code_signature', description: @@ -389,6 +645,21 @@ export const fieldsBeat: BeatFields = { name: 'code_signature.subject_name', type: 'keyword', }, + 'code_signature.team_id': { + category: 'code_signature', + description: + 'The team identifier used to sign the process. This is used to identify the team or vendor of a software product. The field is relevant to Apple *OS only.', + example: 'EQHXZ8M8AV', + name: 'code_signature.team_id', + type: 'keyword', + }, + 'code_signature.timestamp': { + category: 'code_signature', + description: 'Date and time when the code signature was generated and signed.', + example: '2021-01-01T12:10:30Z', + name: 'code_signature.timestamp', + type: 'date', + }, 'code_signature.trusted': { category: 'code_signature', description: @@ -442,6 +713,30 @@ export const fieldsBeat: BeatFields = { name: 'container.runtime', type: 'keyword', }, + 'data_stream.dataset': { + category: 'data_stream', + description: + 'The field can contain anything that makes sense to signify the source of the data. Examples include `nginx.access`, `prometheus`, `endpoint` etc. For data streams that otherwise fit, but that do not have dataset set we use the value "generic" for the dataset value. `event.dataset` should have the same value as `data_stream.dataset`. Beyond the Elasticsearch data stream naming criteria noted above, the `dataset` value has additional restrictions: * Must not contain `-` * No longer than 100 characters', + example: 'nginx.access', + name: 'data_stream.dataset', + type: 'constant_keyword', + }, + 'data_stream.namespace': { + category: 'data_stream', + description: + 'A user defined namespace. Namespaces are useful to allow grouping of data. Many users already organize their indices this way, and the data stream naming scheme now provides this best practice as a default. Many users will populate this field with `default`. If no value is used, it falls back to `default`. Beyond the Elasticsearch index naming criteria noted above, `namespace` value has the additional restrictions: * Must not contain `-` * No longer than 100 characters', + example: 'production', + name: 'data_stream.namespace', + type: 'constant_keyword', + }, + 'data_stream.type': { + category: 'data_stream', + description: + 'An overarching type for the data stream. Currently allowed values are "logs" and "metrics". We expect to also add "traces" and "synthetics" in the near future.', + example: 'logs', + name: 'data_stream.type', + type: 'constant_keyword', + }, 'destination.address': { category: 'destination', description: @@ -485,6 +780,13 @@ export const fieldsBeat: BeatFields = { name: 'destination.geo.city_name', type: 'keyword', }, + 'destination.geo.continent_code': { + category: 'destination', + description: "Two-letter code representing continent's name.", + example: 'NA', + name: 'destination.geo.continent_code', + type: 'keyword', + }, 'destination.geo.continent_name': { category: 'destination', description: 'Name of the continent.', @@ -521,6 +823,14 @@ export const fieldsBeat: BeatFields = { name: 'destination.geo.name', type: 'keyword', }, + 'destination.geo.postal_code': { + category: 'destination', + description: + 'Postal code associated with the location. Values appropriate for this field may also be known as a postcode or ZIP code and will vary widely from country to country.', + example: 94040, + name: 'destination.geo.postal_code', + type: 'keyword', + }, 'destination.geo.region_iso_code': { category: 'destination', description: 'Region ISO code.', @@ -535,15 +845,24 @@ export const fieldsBeat: BeatFields = { name: 'destination.geo.region_name', type: 'keyword', }, + 'destination.geo.timezone': { + category: 'destination', + description: 'The time zone of the location, such as IANA time zone name.', + example: 'America/Argentina/Buenos_Aires', + name: 'destination.geo.timezone', + type: 'keyword', + }, 'destination.ip': { category: 'destination', - description: 'IP address of the destination. Can be one or multiple IPv4 or IPv6 addresses.', + description: 'IP address of the destination (IPv4 or IPv6).', name: 'destination.ip', type: 'ip', }, 'destination.mac': { category: 'destination', - description: 'MAC address of the destination.', + description: + 'MAC address of the destination. The notation format from RFC 7042 is suggested: Each octet (that is, 8-bit byte) is represented by two [uppercase] hexadecimal digits giving the value of the octet as an unsigned integer. Successive octets are separated by a hyphen.', + example: '00-00-5E-00-53-23', name: 'destination.mac', type: 'keyword', }, @@ -579,15 +898,23 @@ export const fieldsBeat: BeatFields = { 'destination.registered_domain': { category: 'destination', description: - 'The highest registered destination domain, stripped of the subdomain. For example, the registered domain for "foo.google.com" is "google.com". This value can be determined precisely with a list like the public suffix list (http://publicsuffix.org). Trying to approximate this by simply taking the last two labels will not work well for TLDs such as "co.uk".', - example: 'google.com', + 'The highest registered destination domain, stripped of the subdomain. For example, the registered domain for "foo.example.com" is "example.com". This value can be determined precisely with a list like the public suffix list (http://publicsuffix.org). Trying to approximate this by simply taking the last two labels will not work well for TLDs such as "co.uk".', + example: 'example.com', name: 'destination.registered_domain', type: 'keyword', }, + 'destination.subdomain': { + category: 'destination', + description: + 'The subdomain portion of a fully qualified domain name includes all of the names except the host name under the registered_domain. In a partially qualified domain, or if the the qualification level of the full name cannot be determined, subdomain contains all of the names below the registered domain. For example the subdomain portion of "www.east.mydomain.co.uk" is "east". If the domain has multiple levels of subdomain, such as "sub2.sub1.example.com", the subdomain field should contain "sub2.sub1", with no trailing period.', + example: 'east', + name: 'destination.subdomain', + type: 'keyword', + }, 'destination.top_level_domain': { category: 'destination', description: - 'The effective top level domain (eTLD), also known as the domain suffix, is the last part of the domain name. For example, the top level domain for google.com is "com". This value can be determined precisely with a list like the public suffix list (http://publicsuffix.org). Trying to approximate this by simply taking the last label will not work well for effective TLDs such as "co.uk".', + 'The effective top level domain (eTLD), also known as the domain suffix, is the last part of the domain name. For example, the top level domain for example.com is "com". This value can be determined precisely with a list like the public suffix list (http://publicsuffix.org). Trying to approximate this by simply taking the last label will not work well for effective TLDs such as "co.uk".', example: 'co.uk', name: 'destination.top_level_domain', type: 'keyword', @@ -640,17 +967,33 @@ export const fieldsBeat: BeatFields = { }, 'destination.user.id': { category: 'destination', - description: 'Unique identifiers of the user.', + description: 'Unique identifier of the user.', + example: 'S-1-5-21-202424912787-2692429404-2351956786-1000', name: 'destination.user.id', type: 'keyword', }, 'destination.user.name': { category: 'destination', description: 'Short name or login of the user.', - example: 'albert', + example: 'a.einstein', name: 'destination.user.name', type: 'keyword', }, + 'destination.user.roles': { + category: 'destination', + description: 'Array of user roles at the time of the event.', + example: '["kibana_admin", "reporting_user"]', + name: 'destination.user.roles', + type: 'keyword', + }, + 'dll.code_signature.digest_algorithm': { + category: 'dll', + description: + 'The hashing algorithm used to sign the process. This value can distinguish signatures when a file is signed multiple times by the same signer but with a different digest algorithm.', + example: 'sha256', + name: 'dll.code_signature.digest_algorithm', + type: 'keyword', + }, 'dll.code_signature.exists': { category: 'dll', description: 'Boolean to capture if a signature is present.', @@ -658,6 +1001,14 @@ export const fieldsBeat: BeatFields = { name: 'dll.code_signature.exists', type: 'boolean', }, + 'dll.code_signature.signing_id': { + category: 'dll', + description: + 'The identifier used to sign the process. This is used to identify the application manufactured by a software vendor. The field is relevant to Apple *OS only.', + example: 'com.apple.xpc.proxy', + name: 'dll.code_signature.signing_id', + type: 'keyword', + }, 'dll.code_signature.status': { category: 'dll', description: @@ -673,6 +1024,21 @@ export const fieldsBeat: BeatFields = { name: 'dll.code_signature.subject_name', type: 'keyword', }, + 'dll.code_signature.team_id': { + category: 'dll', + description: + 'The team identifier used to sign the process. This is used to identify the team or vendor of a software product. The field is relevant to Apple *OS only.', + example: 'EQHXZ8M8AV', + name: 'dll.code_signature.team_id', + type: 'keyword', + }, + 'dll.code_signature.timestamp': { + category: 'dll', + description: 'Date and time when the code signature was generated and signed.', + example: '2021-01-01T12:10:30Z', + name: 'dll.code_signature.timestamp', + type: 'date', + }, 'dll.code_signature.trusted': { category: 'dll', description: @@ -713,6 +1079,12 @@ export const fieldsBeat: BeatFields = { name: 'dll.hash.sha512', type: 'keyword', }, + 'dll.hash.ssdeep': { + category: 'dll', + description: 'SSDEEP hash.', + name: 'dll.hash.ssdeep', + type: 'keyword', + }, 'dll.name': { category: 'dll', description: 'Name of the library. This generally maps to the name of the file on disk.', @@ -727,6 +1099,13 @@ export const fieldsBeat: BeatFields = { name: 'dll.path', type: 'keyword', }, + 'dll.pe.architecture': { + category: 'dll', + description: 'CPU architecture target for the file.', + example: 'x64', + name: 'dll.pe.architecture', + type: 'keyword', + }, 'dll.pe.company': { category: 'dll', description: 'Internal company name of the file, provided at compile-time.', @@ -748,6 +1127,14 @@ export const fieldsBeat: BeatFields = { name: 'dll.pe.file_version', type: 'keyword', }, + 'dll.pe.imphash': { + category: 'dll', + description: + 'A hash of the imports in a PE file. An imphash -- or import hash -- can be used to fingerprint binaries even after recompilation or other code-level transformations have occurred, which would change more traditional hash values. Learn more at https://www.fireeye.com/blog/threat-research/2014/01/tracking-malware-import-hashing.html.', + example: '0c6803c4e922103c4dca5963aad36ddf', + name: 'dll.pe.imphash', + type: 'keyword', + }, 'dll.pe.original_file_name': { category: 'dll', description: 'Internal name of the file, provided at compile-time.', @@ -788,7 +1175,7 @@ export const fieldsBeat: BeatFields = { category: 'dns', description: "The domain name to which this resource record pertains. If a chain of CNAME is being resolved, each answer's `name` should be the one that corresponds with the answer's `data`. It should not simply be the original `question.name` repeated.", - example: 'www.google.com', + example: 'www.example.com', name: 'dns.answers.name', type: 'keyword', }, @@ -811,7 +1198,7 @@ export const fieldsBeat: BeatFields = { category: 'dns', description: 'Array of 2 letter DNS header flags. Expected values are: AA, TC, RD, RA, AD, CD, DO.', - example: '["RD","RA"]', + example: '["RD", "RA"]', name: 'dns.header_flags', type: 'keyword', }, @@ -842,15 +1229,15 @@ export const fieldsBeat: BeatFields = { category: 'dns', description: 'The name being queried. If the name field contains non-printable characters (below 32 or above 126), those characters should be represented as escaped base 10 integers (\\DDD). Back slashes and quotes should be escaped. Tabs, carriage returns, and line feeds should be converted to \\t, \\r, and \\n respectively.', - example: 'www.google.com', + example: 'www.example.com', name: 'dns.question.name', type: 'keyword', }, 'dns.question.registered_domain': { category: 'dns', description: - 'The highest registered domain, stripped of the subdomain. For example, the registered domain for "foo.google.com" is "google.com". This value can be determined precisely with a list like the public suffix list (http://publicsuffix.org). Trying to approximate this by simply taking the last two labels will not work well for TLDs such as "co.uk".', - example: 'google.com', + 'The highest registered domain, stripped of the subdomain. For example, the registered domain for "foo.example.com" is "example.com". This value can be determined precisely with a list like the public suffix list (http://publicsuffix.org). Trying to approximate this by simply taking the last two labels will not work well for TLDs such as "co.uk".', + example: 'example.com', name: 'dns.question.registered_domain', type: 'keyword', }, @@ -865,7 +1252,7 @@ export const fieldsBeat: BeatFields = { 'dns.question.top_level_domain': { category: 'dns', description: - 'The effective top level domain (eTLD), also known as the domain suffix, is the last part of the domain name. For example, the top level domain for google.com is "com". This value can be determined precisely with a list like the public suffix list (http://publicsuffix.org). Trying to approximate this by simply taking the last label will not work well for effective TLDs such as "co.uk".', + 'The effective top level domain (eTLD), also known as the domain suffix, is the last part of the domain name. For example, the top level domain for example.com is "com". This value can be determined precisely with a list like the public suffix list (http://publicsuffix.org). Trying to approximate this by simply taking the last label will not work well for effective TLDs such as "co.uk".', example: 'co.uk', name: 'dns.question.top_level_domain', type: 'keyword', @@ -881,7 +1268,7 @@ export const fieldsBeat: BeatFields = { category: 'dns', description: 'Array containing all IPs seen in `answers.data`. The `answers` array can be difficult to use, because of the variety of data formats it can contain. Extracting all IP addresses seen in there to `dns.resolved_ip` makes it possible to index them as IP addresses, and makes them easier to visualize and query for.', - example: '["10.10.10.10","10.10.10.11"]', + example: '["10.10.10.10", "10.10.10.11"]', name: 'dns.resolved_ip', type: 'ip', }, @@ -908,6 +1295,192 @@ export const fieldsBeat: BeatFields = { name: 'ecs.version', type: 'keyword', }, + 'elf.architecture': { + category: 'elf', + description: 'Machine architecture of the ELF file.', + example: 'x86-64', + name: 'elf.architecture', + type: 'keyword', + }, + 'elf.byte_order': { + category: 'elf', + description: 'Byte sequence of ELF file.', + example: 'Little Endian', + name: 'elf.byte_order', + type: 'keyword', + }, + 'elf.cpu_type': { + category: 'elf', + description: 'CPU type of the ELF file.', + example: 'Intel', + name: 'elf.cpu_type', + type: 'keyword', + }, + 'elf.creation_date': { + category: 'elf', + description: + "Extracted when possible from the file's metadata. Indicates when it was built or compiled. It can also be faked by malware creators.", + name: 'elf.creation_date', + type: 'date', + }, + 'elf.exports': { + category: 'elf', + description: 'List of exported element names and types.', + name: 'elf.exports', + type: 'flattened', + }, + 'elf.header.abi_version': { + category: 'elf', + description: 'Version of the ELF Application Binary Interface (ABI).', + name: 'elf.header.abi_version', + type: 'keyword', + }, + 'elf.header.class': { + category: 'elf', + description: 'Header class of the ELF file.', + name: 'elf.header.class', + type: 'keyword', + }, + 'elf.header.data': { + category: 'elf', + description: 'Data table of the ELF header.', + name: 'elf.header.data', + type: 'keyword', + }, + 'elf.header.entrypoint': { + category: 'elf', + description: 'Header entrypoint of the ELF file.', + name: 'elf.header.entrypoint', + type: 'long', + format: 'string', + }, + 'elf.header.object_version': { + category: 'elf', + description: '"0x1" for original ELF files.', + name: 'elf.header.object_version', + type: 'keyword', + }, + 'elf.header.os_abi': { + category: 'elf', + description: 'Application Binary Interface (ABI) of the Linux OS.', + name: 'elf.header.os_abi', + type: 'keyword', + }, + 'elf.header.type': { + category: 'elf', + description: 'Header type of the ELF file.', + name: 'elf.header.type', + type: 'keyword', + }, + 'elf.header.version': { + category: 'elf', + description: 'Version of the ELF header.', + name: 'elf.header.version', + type: 'keyword', + }, + 'elf.imports': { + category: 'elf', + description: 'List of imported element names and types.', + name: 'elf.imports', + type: 'flattened', + }, + 'elf.sections': { + category: 'elf', + description: + 'An array containing an object for each section of the ELF file. The keys that should be present in these objects are defined by sub-fields underneath `elf.sections.*`.', + name: 'elf.sections', + type: 'nested', + }, + 'elf.sections.chi2': { + category: 'elf', + description: 'Chi-square probability distribution of the section.', + name: 'elf.sections.chi2', + type: 'long', + format: 'number', + }, + 'elf.sections.entropy': { + category: 'elf', + description: 'Shannon entropy calculation from the section.', + name: 'elf.sections.entropy', + type: 'long', + format: 'number', + }, + 'elf.sections.flags': { + category: 'elf', + description: 'ELF Section List flags.', + name: 'elf.sections.flags', + type: 'keyword', + }, + 'elf.sections.name': { + category: 'elf', + description: 'ELF Section List name.', + name: 'elf.sections.name', + type: 'keyword', + }, + 'elf.sections.physical_offset': { + category: 'elf', + description: 'ELF Section List offset.', + name: 'elf.sections.physical_offset', + type: 'keyword', + }, + 'elf.sections.physical_size': { + category: 'elf', + description: 'ELF Section List physical size.', + name: 'elf.sections.physical_size', + type: 'long', + format: 'bytes', + }, + 'elf.sections.type': { + category: 'elf', + description: 'ELF Section List type.', + name: 'elf.sections.type', + type: 'keyword', + }, + 'elf.sections.virtual_address': { + category: 'elf', + description: 'ELF Section List virtual address.', + name: 'elf.sections.virtual_address', + type: 'long', + format: 'string', + }, + 'elf.sections.virtual_size': { + category: 'elf', + description: 'ELF Section List virtual size.', + name: 'elf.sections.virtual_size', + type: 'long', + format: 'string', + }, + 'elf.segments': { + category: 'elf', + description: + 'An array containing an object for each segment of the ELF file. The keys that should be present in these objects are defined by sub-fields underneath `elf.segments.*`.', + name: 'elf.segments', + type: 'nested', + }, + 'elf.segments.sections': { + category: 'elf', + description: 'ELF object segment sections.', + name: 'elf.segments.sections', + type: 'keyword', + }, + 'elf.segments.type': { + category: 'elf', + description: 'ELF object segment type.', + name: 'elf.segments.type', + type: 'keyword', + }, + 'elf.shared_libraries': { + category: 'elf', + description: 'List of shared libraries used by this ELF object.', + name: 'elf.shared_libraries', + type: 'keyword', + }, + 'elf.telfhash': { + category: 'elf', + description: 'telfhash symbol hash for ELF file.', + name: 'elf.telfhash', + type: 'keyword', + }, 'error.code': { category: 'error', description: 'Error code describing the error.', @@ -924,13 +1497,13 @@ export const fieldsBeat: BeatFields = { category: 'error', description: 'Error message.', name: 'error.message', - type: 'text', + type: 'match_only_text', }, 'error.stack_trace': { category: 'error', description: 'The stack trace of this error in plain text.', name: 'error.stack_trace', - type: 'keyword', + type: 'wildcard', }, 'error.type': { category: 'error', @@ -947,6 +1520,14 @@ export const fieldsBeat: BeatFields = { name: 'event.action', type: 'keyword', }, + 'event.agent_id_status': { + category: 'event', + description: + "Agents are normally responsible for populating the `agent.id` field value. If the system receiving events is capable of validating the value based on authentication information for the client then this field can be used to reflect the outcome of that validation. For example if the agent's connection is authenticated with mTLS and the client cert contains the ID of the agent to which the cert was issued then the `agent.id` value in events can be checked against the certificate. If the values match then `event.agent_id_status: verified` is added to the event, otherwise one of the other allowed values should be used. If no validation is performed then the field should be omitted. The allowed values are: `verified` - The `agent.id` field value matches expected value obtained from auth metadata. `mismatch` - The `agent.id` field value does not match the expected value obtained from auth metadata. `missing` - There was no `agent.id` field in the event to validate. `auth_metadata_missing` - There was no auth metadata or it was missing information about the agent ID.", + example: 'verified', + name: 'event.agent_id_status', + type: 'keyword', + }, 'event.category': { category: 'event', description: @@ -1036,7 +1617,7 @@ export const fieldsBeat: BeatFields = { 'event.original': { category: 'event', description: - 'Raw text message of entire event. Used to demonstrate log integrity. This field is not indexed and doc_values are disabled. It cannot be searched, but it can be retrieved from `_source`.', + 'Raw text message of entire event. Used to demonstrate log integrity or where the full log message (before splitting it up in multiple parts) may be required, e.g. for reindex. This field is not indexed and doc_values are disabled. It cannot be searched, but it can be retrieved from `_source`. If users wish to override this and index this field, please see `Field data types` in the `Elasticsearch Reference`.', example: 'Sep 19 08:26:10 host CEF:0|Security| threatmanager|1.0|100| worm successfully stopped|10|src=10.0.0.1 dst=2.1.2.2spt=1232', name: 'event.original', @@ -1058,11 +1639,19 @@ export const fieldsBeat: BeatFields = { name: 'event.provider', type: 'keyword', }, + 'event.reason': { + category: 'event', + description: + 'Reason why this event happened, according to the source. This describes the why of a particular action or outcome captured in the event. Where `event.action` captures the action from the event, `event.reason` describes why that action was taken. For example, a web proxy with an `event.action` which denied the request may also populate `event.reason` with the reason why (e.g. `blocked site`).', + example: 'Terminated an unexpected process', + name: 'event.reason', + type: 'keyword', + }, 'event.reference': { category: 'event', description: - 'Reference URL linking to additional information about this event. This URL links to a static definition of the this event. Alert events, indicated by `event.kind:alert`, are a common use case for this field.', - example: 'https://system.vendor.com/event/#0001234', + 'Reference URL linking to additional information about this event. This URL links to a static definition of this event. Alert events, indicated by `event.kind:alert`, are a common use case for this field.', + example: 'https://system.example.com/event/#0001234', name: 'event.reference', type: 'keyword', }, @@ -1121,11 +1710,45 @@ export const fieldsBeat: BeatFields = { 'event.url': { category: 'event', description: - 'URL linking to an external system to continue investigation of this event. This URL links to another system where in-depth investigation of the specific occurence of this event can take place. Alert events, indicated by `event.kind:alert`, are a common use case for this field.', - example: 'https://mysystem.mydomain.com/alert/5271dedb-f5b0-4218-87f0-4ac4870a38fe', + 'URL linking to an external system to continue investigation of this event. This URL links to another system where in-depth investigation of the specific occurrence of this event can take place. Alert events, indicated by `event.kind:alert`, are a common use case for this field.', + example: 'https://mysystem.example.com/alert/5271dedb-f5b0-4218-87f0-4ac4870a38fe', name: 'event.url', type: 'keyword', }, + 'faas.coldstart': { + category: 'faas', + description: 'Boolean value indicating a cold start of a function.', + name: 'faas.coldstart', + type: 'boolean', + }, + 'faas.execution': { + category: 'faas', + description: 'The execution ID of the current function execution.', + example: 'af9d5aa4-a685-4c5f-a22b-444f80b3cc28', + name: 'faas.execution', + type: 'keyword', + }, + 'faas.trigger': { + category: 'faas', + description: 'Details about the function trigger.', + name: 'faas.trigger', + type: 'nested', + }, + 'faas.trigger.request_id': { + category: 'faas', + description: 'The ID of the trigger request , message, event, etc.', + example: 123456789, + name: 'faas.trigger.request_id', + type: 'keyword', + }, + 'faas.trigger.type': { + category: 'faas', + description: + 'The trigger for the function execution. Expected values are: * http * pubsub * datasource * timer * other', + example: 'http', + name: 'faas.trigger.type', + type: 'keyword', + }, 'file.accessed': { category: 'file', description: @@ -1141,6 +1764,14 @@ export const fieldsBeat: BeatFields = { name: 'file.attributes', type: 'keyword', }, + 'file.code_signature.digest_algorithm': { + category: 'file', + description: + 'The hashing algorithm used to sign the process. This value can distinguish signatures when a file is signed multiple times by the same signer but with a different digest algorithm.', + example: 'sha256', + name: 'file.code_signature.digest_algorithm', + type: 'keyword', + }, 'file.code_signature.exists': { category: 'file', description: 'Boolean to capture if a signature is present.', @@ -1148,6 +1779,14 @@ export const fieldsBeat: BeatFields = { name: 'file.code_signature.exists', type: 'boolean', }, + 'file.code_signature.signing_id': { + category: 'file', + description: + 'The identifier used to sign the process. This is used to identify the application manufactured by a software vendor. The field is relevant to Apple *OS only.', + example: 'com.apple.xpc.proxy', + name: 'file.code_signature.signing_id', + type: 'keyword', + }, 'file.code_signature.status': { category: 'file', description: @@ -1163,6 +1802,21 @@ export const fieldsBeat: BeatFields = { name: 'file.code_signature.subject_name', type: 'keyword', }, + 'file.code_signature.team_id': { + category: 'file', + description: + 'The team identifier used to sign the process. This is used to identify the team or vendor of a software product. The field is relevant to Apple *OS only.', + example: 'EQHXZ8M8AV', + name: 'file.code_signature.team_id', + type: 'keyword', + }, + 'file.code_signature.timestamp': { + category: 'file', + description: 'Date and time when the code signature was generated and signed.', + example: '2021-01-01T12:10:30Z', + name: 'file.code_signature.timestamp', + type: 'date', + }, 'file.code_signature.trusted': { category: 'file', description: @@ -1215,13 +1869,208 @@ export const fieldsBeat: BeatFields = { name: 'file.drive_letter', type: 'keyword', }, + 'file.elf.architecture': { + category: 'file', + description: 'Machine architecture of the ELF file.', + example: 'x86-64', + name: 'file.elf.architecture', + type: 'keyword', + }, + 'file.elf.byte_order': { + category: 'file', + description: 'Byte sequence of ELF file.', + example: 'Little Endian', + name: 'file.elf.byte_order', + type: 'keyword', + }, + 'file.elf.cpu_type': { + category: 'file', + description: 'CPU type of the ELF file.', + example: 'Intel', + name: 'file.elf.cpu_type', + type: 'keyword', + }, + 'file.elf.creation_date': { + category: 'file', + description: + "Extracted when possible from the file's metadata. Indicates when it was built or compiled. It can also be faked by malware creators.", + name: 'file.elf.creation_date', + type: 'date', + }, + 'file.elf.exports': { + category: 'file', + description: 'List of exported element names and types.', + name: 'file.elf.exports', + type: 'flattened', + }, + 'file.elf.header.abi_version': { + category: 'file', + description: 'Version of the ELF Application Binary Interface (ABI).', + name: 'file.elf.header.abi_version', + type: 'keyword', + }, + 'file.elf.header.class': { + category: 'file', + description: 'Header class of the ELF file.', + name: 'file.elf.header.class', + type: 'keyword', + }, + 'file.elf.header.data': { + category: 'file', + description: 'Data table of the ELF header.', + name: 'file.elf.header.data', + type: 'keyword', + }, + 'file.elf.header.entrypoint': { + category: 'file', + description: 'Header entrypoint of the ELF file.', + name: 'file.elf.header.entrypoint', + type: 'long', + format: 'string', + }, + 'file.elf.header.object_version': { + category: 'file', + description: '"0x1" for original ELF files.', + name: 'file.elf.header.object_version', + type: 'keyword', + }, + 'file.elf.header.os_abi': { + category: 'file', + description: 'Application Binary Interface (ABI) of the Linux OS.', + name: 'file.elf.header.os_abi', + type: 'keyword', + }, + 'file.elf.header.type': { + category: 'file', + description: 'Header type of the ELF file.', + name: 'file.elf.header.type', + type: 'keyword', + }, + 'file.elf.header.version': { + category: 'file', + description: 'Version of the ELF header.', + name: 'file.elf.header.version', + type: 'keyword', + }, + 'file.elf.imports': { + category: 'file', + description: 'List of imported element names and types.', + name: 'file.elf.imports', + type: 'flattened', + }, + 'file.elf.sections': { + category: 'file', + description: + 'An array containing an object for each section of the ELF file. The keys that should be present in these objects are defined by sub-fields underneath `elf.sections.*`.', + name: 'file.elf.sections', + type: 'nested', + }, + 'file.elf.sections.chi2': { + category: 'file', + description: 'Chi-square probability distribution of the section.', + name: 'file.elf.sections.chi2', + type: 'long', + format: 'number', + }, + 'file.elf.sections.entropy': { + category: 'file', + description: 'Shannon entropy calculation from the section.', + name: 'file.elf.sections.entropy', + type: 'long', + format: 'number', + }, + 'file.elf.sections.flags': { + category: 'file', + description: 'ELF Section List flags.', + name: 'file.elf.sections.flags', + type: 'keyword', + }, + 'file.elf.sections.name': { + category: 'file', + description: 'ELF Section List name.', + name: 'file.elf.sections.name', + type: 'keyword', + }, + 'file.elf.sections.physical_offset': { + category: 'file', + description: 'ELF Section List offset.', + name: 'file.elf.sections.physical_offset', + type: 'keyword', + }, + 'file.elf.sections.physical_size': { + category: 'file', + description: 'ELF Section List physical size.', + name: 'file.elf.sections.physical_size', + type: 'long', + format: 'bytes', + }, + 'file.elf.sections.type': { + category: 'file', + description: 'ELF Section List type.', + name: 'file.elf.sections.type', + type: 'keyword', + }, + 'file.elf.sections.virtual_address': { + category: 'file', + description: 'ELF Section List virtual address.', + name: 'file.elf.sections.virtual_address', + type: 'long', + format: 'string', + }, + 'file.elf.sections.virtual_size': { + category: 'file', + description: 'ELF Section List virtual size.', + name: 'file.elf.sections.virtual_size', + type: 'long', + format: 'string', + }, + 'file.elf.segments': { + category: 'file', + description: + 'An array containing an object for each segment of the ELF file. The keys that should be present in these objects are defined by sub-fields underneath `elf.segments.*`.', + name: 'file.elf.segments', + type: 'nested', + }, + 'file.elf.segments.sections': { + category: 'file', + description: 'ELF object segment sections.', + name: 'file.elf.segments.sections', + type: 'keyword', + }, + 'file.elf.segments.type': { + category: 'file', + description: 'ELF object segment type.', + name: 'file.elf.segments.type', + type: 'keyword', + }, + 'file.elf.shared_libraries': { + category: 'file', + description: 'List of shared libraries used by this ELF object.', + name: 'file.elf.shared_libraries', + type: 'keyword', + }, + 'file.elf.telfhash': { + category: 'file', + description: 'telfhash symbol hash for ELF file.', + name: 'file.elf.telfhash', + type: 'keyword', + }, 'file.extension': { category: 'file', - description: 'File extension.', + description: + 'File extension, excluding the leading dot. Note that when the file name has multiple extensions (example.tar.gz), only the last one should be captured ("gz", not "tar.gz").', example: 'png', name: 'file.extension', type: 'keyword', }, + 'file.fork_name': { + category: 'file', + description: + 'A fork is additional data associated with a filesystem object. On Linux, a resource fork is used to store additional data with a filesystem object. A file always has at least one fork for the data portion, and additional forks may exist. On NTFS, this is analogous to an Alternate Data Stream (ADS), and the default data stream for a file is just called $DATA. Zone.Identifier is commonly used by Windows to track contents downloaded from the Internet. An ADS is typically of the form: `C:\\path\\to\\filename.extension:some_fork_name`, and `some_fork_name` is the value that should populate `fork_name`. `filename.extension` should populate `file.name`, and `extension` should populate `file.extension`. The full path, `file.path`, will include the fork name.', + example: 'Zone.Identifer', + name: 'file.fork_name', + type: 'keyword', + }, 'file.gid': { category: 'file', description: 'Primary group ID (GID) of the file.', @@ -1260,6 +2109,12 @@ export const fieldsBeat: BeatFields = { name: 'file.hash.sha512', type: 'keyword', }, + 'file.hash.ssdeep': { + category: 'file', + description: 'SSDEEP hash.', + name: 'file.hash.ssdeep', + type: 'keyword', + }, 'file.inode': { category: 'file', description: 'Inode representing the file in the filesystem.', @@ -1309,6 +2164,13 @@ export const fieldsBeat: BeatFields = { name: 'file.path', type: 'keyword', }, + 'file.pe.architecture': { + category: 'file', + description: 'CPU architecture target for the file.', + example: 'x64', + name: 'file.pe.architecture', + type: 'keyword', + }, 'file.pe.company': { category: 'file', description: 'Internal company name of the file, provided at compile-time.', @@ -1330,6 +2192,14 @@ export const fieldsBeat: BeatFields = { name: 'file.pe.file_version', type: 'keyword', }, + 'file.pe.imphash': { + category: 'file', + description: + 'A hash of the imports in a PE file. An imphash -- or import hash -- can be used to fingerprint binaries even after recompilation or other code-level transformations have occurred, which would change more traditional hash values. Learn more at https://www.fireeye.com/blog/threat-research/2014/01/tracking-malware-import-hashing.html.', + example: '0c6803c4e922103c4dca5963aad36ddf', + name: 'file.pe.imphash', + type: 'keyword', + }, 'file.pe.original_file_name': { category: 'file', description: 'Internal name of the file, provided at compile-time.', @@ -1371,6 +2241,177 @@ export const fieldsBeat: BeatFields = { name: 'file.uid', type: 'keyword', }, + 'file.x509.alternative_names': { + category: 'file', + description: + 'List of subject alternative names (SAN). Name types vary by certificate authority and certificate type but commonly contain IP addresses, DNS names (and wildcards), and email addresses.', + example: '*.elastic.co', + name: 'file.x509.alternative_names', + type: 'keyword', + }, + 'file.x509.issuer.common_name': { + category: 'file', + description: 'List of common name (CN) of issuing certificate authority.', + example: 'Example SHA2 High Assurance Server CA', + name: 'file.x509.issuer.common_name', + type: 'keyword', + }, + 'file.x509.issuer.country': { + category: 'file', + description: 'List of country (C) codes', + example: 'US', + name: 'file.x509.issuer.country', + type: 'keyword', + }, + 'file.x509.issuer.distinguished_name': { + category: 'file', + description: 'Distinguished name (DN) of issuing certificate authority.', + example: 'C=US, O=Example Inc, OU=www.example.com, CN=Example SHA2 High Assurance Server CA', + name: 'file.x509.issuer.distinguished_name', + type: 'keyword', + }, + 'file.x509.issuer.locality': { + category: 'file', + description: 'List of locality names (L)', + example: 'Mountain View', + name: 'file.x509.issuer.locality', + type: 'keyword', + }, + 'file.x509.issuer.organization': { + category: 'file', + description: 'List of organizations (O) of issuing certificate authority.', + example: 'Example Inc', + name: 'file.x509.issuer.organization', + type: 'keyword', + }, + 'file.x509.issuer.organizational_unit': { + category: 'file', + description: 'List of organizational units (OU) of issuing certificate authority.', + example: 'www.example.com', + name: 'file.x509.issuer.organizational_unit', + type: 'keyword', + }, + 'file.x509.issuer.state_or_province': { + category: 'file', + description: 'List of state or province names (ST, S, or P)', + example: 'California', + name: 'file.x509.issuer.state_or_province', + type: 'keyword', + }, + 'file.x509.not_after': { + category: 'file', + description: 'Time at which the certificate is no longer considered valid.', + example: '"2020-07-16T03:15:39.000Z"', + name: 'file.x509.not_after', + type: 'date', + }, + 'file.x509.not_before': { + category: 'file', + description: 'Time at which the certificate is first considered valid.', + example: '"2019-08-16T01:40:25.000Z"', + name: 'file.x509.not_before', + type: 'date', + }, + 'file.x509.public_key_algorithm': { + category: 'file', + description: 'Algorithm used to generate the public key.', + example: 'RSA', + name: 'file.x509.public_key_algorithm', + type: 'keyword', + }, + 'file.x509.public_key_curve': { + category: 'file', + description: + 'The curve used by the elliptic curve public key algorithm. This is algorithm specific.', + example: 'nistp521', + name: 'file.x509.public_key_curve', + type: 'keyword', + }, + 'file.x509.public_key_exponent': { + category: 'file', + description: 'Exponent used to derive the public key. This is algorithm specific.', + example: 65537, + name: 'file.x509.public_key_exponent', + type: 'long', + }, + 'file.x509.public_key_size': { + category: 'file', + description: 'The size of the public key space in bits.', + example: 2048, + name: 'file.x509.public_key_size', + type: 'long', + }, + 'file.x509.serial_number': { + category: 'file', + description: + 'Unique serial number issued by the certificate authority. For consistency, if this value is alphanumeric, it should be formatted without colons and uppercase characters.', + example: '55FBB9C7DEBF09809D12CCAA', + name: 'file.x509.serial_number', + type: 'keyword', + }, + 'file.x509.signature_algorithm': { + category: 'file', + description: + 'Identifier for certificate signature algorithm. We recommend using names found in Go Lang Crypto library. See https://github.com/golang/go/blob/go1.14/src/crypto/x509/x509.go#L337-L353.', + example: 'SHA256-RSA', + name: 'file.x509.signature_algorithm', + type: 'keyword', + }, + 'file.x509.subject.common_name': { + category: 'file', + description: 'List of common names (CN) of subject.', + example: 'shared.global.example.net', + name: 'file.x509.subject.common_name', + type: 'keyword', + }, + 'file.x509.subject.country': { + category: 'file', + description: 'List of country (C) code', + example: 'US', + name: 'file.x509.subject.country', + type: 'keyword', + }, + 'file.x509.subject.distinguished_name': { + category: 'file', + description: 'Distinguished name (DN) of the certificate subject entity.', + example: 'C=US, ST=California, L=San Francisco, O=Example, Inc., CN=shared.global.example.net', + name: 'file.x509.subject.distinguished_name', + type: 'keyword', + }, + 'file.x509.subject.locality': { + category: 'file', + description: 'List of locality names (L)', + example: 'San Francisco', + name: 'file.x509.subject.locality', + type: 'keyword', + }, + 'file.x509.subject.organization': { + category: 'file', + description: 'List of organizations (O) of subject.', + example: 'Example, Inc.', + name: 'file.x509.subject.organization', + type: 'keyword', + }, + 'file.x509.subject.organizational_unit': { + category: 'file', + description: 'List of organizational units (OU) of subject.', + name: 'file.x509.subject.organizational_unit', + type: 'keyword', + }, + 'file.x509.subject.state_or_province': { + category: 'file', + description: 'List of state or province names (ST, S, or P)', + example: 'California', + name: 'file.x509.subject.state_or_province', + type: 'keyword', + }, + 'file.x509.version_number': { + category: 'file', + description: 'Version of x509 format.', + example: 3, + name: 'file.x509.version_number', + type: 'keyword', + }, 'geo.city_name': { category: 'geo', description: 'City name.', @@ -1378,6 +2419,13 @@ export const fieldsBeat: BeatFields = { name: 'geo.city_name', type: 'keyword', }, + 'geo.continent_code': { + category: 'geo', + description: "Two-letter code representing continent's name.", + example: 'NA', + name: 'geo.continent_code', + type: 'keyword', + }, 'geo.continent_name': { category: 'geo', description: 'Name of the continent.', @@ -1414,6 +2462,14 @@ export const fieldsBeat: BeatFields = { name: 'geo.name', type: 'keyword', }, + 'geo.postal_code': { + category: 'geo', + description: + 'Postal code associated with the location. Values appropriate for this field may also be known as a postcode or ZIP code and will vary widely from country to country.', + example: 94040, + name: 'geo.postal_code', + type: 'keyword', + }, 'geo.region_iso_code': { category: 'geo', description: 'Region ISO code.', @@ -1428,6 +2484,13 @@ export const fieldsBeat: BeatFields = { name: 'geo.region_name', type: 'keyword', }, + 'geo.timezone': { + category: 'geo', + description: 'The time zone of the location, such as IANA time zone name.', + example: 'America/Argentina/Buenos_Aires', + name: 'geo.timezone', + type: 'keyword', + }, 'group.domain': { category: 'group', description: @@ -1471,6 +2534,12 @@ export const fieldsBeat: BeatFields = { name: 'hash.sha512', type: 'keyword', }, + 'hash.ssdeep': { + category: 'hash', + description: 'SSDEEP hash.', + name: 'hash.ssdeep', + type: 'keyword', + }, 'host.architecture': { category: 'host', description: 'Operating system architecture.', @@ -1478,6 +2547,27 @@ export const fieldsBeat: BeatFields = { name: 'host.architecture', type: 'keyword', }, + 'host.cpu.usage': { + category: 'host', + description: + 'Percent CPU used which is normalized by the number of CPU cores and it ranges from 0 to 1. Scaling factor: 1000. For example: For a two core host, this value should be the average of the two cores, between 0 and 1.', + name: 'host.cpu.usage', + type: 'scaled_float', + }, + 'host.disk.read.bytes': { + category: 'host', + description: + 'The total number of bytes (gauge) read successfully (aggregated from all disks) since the last metric collection.', + name: 'host.disk.read.bytes', + type: 'long', + }, + 'host.disk.write.bytes': { + category: 'host', + description: + 'The total number of bytes (gauge) written successfully (aggregated from all disks) since the last metric collection.', + name: 'host.disk.write.bytes', + type: 'long', + }, 'host.domain': { category: 'host', description: @@ -1493,6 +2583,13 @@ export const fieldsBeat: BeatFields = { name: 'host.geo.city_name', type: 'keyword', }, + 'host.geo.continent_code': { + category: 'host', + description: "Two-letter code representing continent's name.", + example: 'NA', + name: 'host.geo.continent_code', + type: 'keyword', + }, 'host.geo.continent_name': { category: 'host', description: 'Name of the continent.', @@ -1529,6 +2626,14 @@ export const fieldsBeat: BeatFields = { name: 'host.geo.name', type: 'keyword', }, + 'host.geo.postal_code': { + category: 'host', + description: + 'Postal code associated with the location. Values appropriate for this field may also be known as a postcode or ZIP code and will vary widely from country to country.', + example: 94040, + name: 'host.geo.postal_code', + type: 'keyword', + }, 'host.geo.region_iso_code': { category: 'host', description: 'Region ISO code.', @@ -1543,6 +2648,13 @@ export const fieldsBeat: BeatFields = { name: 'host.geo.region_name', type: 'keyword', }, + 'host.geo.timezone': { + category: 'host', + description: 'The time zone of the location, such as IANA time zone name.', + example: 'America/Argentina/Buenos_Aires', + name: 'host.geo.timezone', + type: 'keyword', + }, 'host.hostname': { category: 'host', description: @@ -1565,7 +2677,9 @@ export const fieldsBeat: BeatFields = { }, 'host.mac': { category: 'host', - description: 'Host mac addresses.', + description: + 'Host MAC addresses. The notation format from RFC 7042 is suggested: Each octet (that is, 8-bit byte) is represented by two [uppercase] hexadecimal digits giving the value of the octet as an unsigned integer. Successive octets are separated by a hyphen.', + example: '["00-00-5E-00-53-23", "00-00-5E-00-53-24"]', name: 'host.mac', type: 'keyword', }, @@ -1576,6 +2690,34 @@ export const fieldsBeat: BeatFields = { name: 'host.name', type: 'keyword', }, + 'host.network.egress.bytes': { + category: 'host', + description: + 'The number of bytes (gauge) sent out on all network interfaces by the host since the last metric collection.', + name: 'host.network.egress.bytes', + type: 'long', + }, + 'host.network.egress.packets': { + category: 'host', + description: + 'The number of packets (gauge) sent out on all network interfaces by the host since the last metric collection.', + name: 'host.network.egress.packets', + type: 'long', + }, + 'host.network.ingress.bytes': { + category: 'host', + description: + 'The number of bytes received (gauge) on all network interfaces by the host since the last metric collection.', + name: 'host.network.ingress.bytes', + type: 'long', + }, + 'host.network.ingress.packets': { + category: 'host', + description: + 'The number of packets (gauge) received on all network interfaces by the host since the last metric collection.', + name: 'host.network.ingress.packets', + type: 'long', + }, 'host.os.family': { category: 'host', description: 'OS family (such as redhat, debian, freebsd, windows).', @@ -1611,6 +2753,14 @@ export const fieldsBeat: BeatFields = { name: 'host.os.platform', type: 'keyword', }, + 'host.os.type': { + category: 'host', + description: + "Use the `os.type` field to categorize the operating system into one of the broad commercial families. One of these following values should be used (lowercase): linux, macos, unix, windows. If the OS you're dealing with is not in the list, the field should not be populated. Please let us know by opening an issue with ECS, to propose its addition.", + example: 'macos', + name: 'host.os.type', + type: 'keyword', + }, 'host.os.version': { category: 'host', description: 'Operating system version as a raw string.', @@ -1632,65 +2782,6 @@ export const fieldsBeat: BeatFields = { name: 'host.uptime', type: 'long', }, - 'host.user.domain': { - category: 'host', - description: - 'Name of the directory the user is a member of. For example, an LDAP or Active Directory domain name.', - name: 'host.user.domain', - type: 'keyword', - }, - 'host.user.email': { - category: 'host', - description: 'User email address.', - name: 'host.user.email', - type: 'keyword', - }, - 'host.user.full_name': { - category: 'host', - description: "User's full name, if available.", - example: 'Albert Einstein', - name: 'host.user.full_name', - type: 'keyword', - }, - 'host.user.group.domain': { - category: 'host', - description: - 'Name of the directory the group is a member of. For example, an LDAP or Active Directory domain name.', - name: 'host.user.group.domain', - type: 'keyword', - }, - 'host.user.group.id': { - category: 'host', - description: 'Unique identifier for the group on the system/platform.', - name: 'host.user.group.id', - type: 'keyword', - }, - 'host.user.group.name': { - category: 'host', - description: 'Name of the group.', - name: 'host.user.group.name', - type: 'keyword', - }, - 'host.user.hash': { - category: 'host', - description: - 'Unique user hash to correlate information for a user in anonymized form. Useful if `user.id` or `user.name` contain confidential information and cannot be used.', - name: 'host.user.hash', - type: 'keyword', - }, - 'host.user.id': { - category: 'host', - description: 'Unique identifiers of the user.', - name: 'host.user.id', - type: 'keyword', - }, - 'host.user.name': { - category: 'host', - description: 'Short name or login of the user.', - example: 'albert', - name: 'host.user.name', - type: 'keyword', - }, 'http.request.body.bytes': { category: 'http', description: 'Size in bytes of the request body.', @@ -1704,7 +2795,7 @@ export const fieldsBeat: BeatFields = { description: 'The full HTTP request body.', example: 'Hello world', name: 'http.request.body.content', - type: 'keyword', + type: 'wildcard', }, 'http.request.bytes': { category: 'http', @@ -1714,14 +2805,30 @@ export const fieldsBeat: BeatFields = { type: 'long', format: 'bytes', }, + 'http.request.id': { + category: 'http', + description: + 'A unique identifier for each HTTP request to correlate logs between clients and servers in transactions. The id may be contained in a non-standard HTTP header, such as `X-Request-ID` or `X-Correlation-ID`.', + example: '123e4567-e89b-12d3-a456-426614174000', + name: 'http.request.id', + type: 'keyword', + }, 'http.request.method': { category: 'http', description: - 'HTTP request method. The field value must be normalized to lowercase for querying. See the documentation section "Implementing ECS".', - example: 'get, post, put', + 'HTTP request method. The value should retain its casing from the original event. For example, `GET`, `get`, and `GeT` are all considered valid values for this field.', + example: 'POST', name: 'http.request.method', type: 'keyword', }, + 'http.request.mime_type': { + category: 'http', + description: + "Mime type of the body of the request. This value must only be populated based on the content of the request body, not on the `Content-Type` header. Comparing the mime type of a request with the request's Content-Type header can be helpful in detecting threats or misconfigured clients.", + example: 'image/gif', + name: 'http.request.mime_type', + type: 'keyword', + }, 'http.request.referrer': { category: 'http', description: 'Referrer for this HTTP request.', @@ -1742,7 +2849,7 @@ export const fieldsBeat: BeatFields = { description: 'The full HTTP response body.', example: 'Hello world', name: 'http.response.body.content', - type: 'keyword', + type: 'wildcard', }, 'http.response.bytes': { category: 'http', @@ -1752,6 +2859,14 @@ export const fieldsBeat: BeatFields = { type: 'long', format: 'bytes', }, + 'http.response.mime_type': { + category: 'http', + description: + "Mime type of the body of the response. This value must only be populated based on the content of the response body, not on the `Content-Type` header. Comparing the mime type of a response with the response's Content-Type header can be helpful in detecting misconfigured servers.", + example: 'image/gif', + name: 'http.response.mime_type', + type: 'keyword', + }, 'http.response.status_code': { category: 'http', description: 'HTTP response status code.', @@ -1789,6 +2904,14 @@ export const fieldsBeat: BeatFields = { name: 'interface.name', type: 'keyword', }, + 'log.file.path': { + category: 'log', + description: + "Full path to the log file this event came from, including the file name. It should include the drive letter, when appropriate. If the event wasn't read from a log file, do not populate this field.", + example: '/var/log/fun-times.log', + name: 'log.file.path', + type: 'keyword', + }, 'log.level': { category: 'log', description: @@ -1811,12 +2934,12 @@ export const fieldsBeat: BeatFields = { 'The line number of the file containing the source code which originated the log event.', example: 42, name: 'log.origin.file.line', - type: 'integer', + type: 'long', }, 'log.origin.file.name': { category: 'log', description: - 'The name of the file containing the source code which originated the log event. Note that this is not the name of the log file.', + 'The name of the file containing the source code which originated the log event. Note that this field is not meant to capture the log file. The correct field to capture the log file is `log.file.path`.', example: 'Bootstrap.java', name: 'log.origin.file.name', type: 'keyword', @@ -1828,14 +2951,6 @@ export const fieldsBeat: BeatFields = { name: 'log.origin.function', type: 'keyword', }, - 'log.original': { - category: 'log', - description: - "This is the original log message and contains the full log message before splitting it up in multiple parts. In contrast to the `message` field which can contain an extracted part of the log message, this field contains the original, full log message. It can have already some modifications applied like encoding or new lines removed to clean up the log message. This field is not indexed and doc_values are disabled so it can't be queried but the value can be retrieved from `_source`.", - example: 'Sep 19 08:26:10 localhost My log', - name: 'log.original', - type: 'keyword', - }, 'log.syslog': { category: 'log', description: @@ -1887,7 +3002,7 @@ export const fieldsBeat: BeatFields = { 'network.application': { category: 'network', description: - 'A name given to an application level protocol. This can be arbitrarily assigned for things like microservices, but also apply to things like skype, icq, facebook, twitter. This would be used in situations where the vendor or service can be decoded such as from the source/dest IP owners, ports, or wire format. The field value must be normalized to lowercase for querying. See the documentation section "Implementing ECS".', + "When a specific application or service is identified from network connection details (source/dest IPs, ports, certificates, or wire format), this field captures the application's or service's name. For example, the original event identifies the network connection being from a specific web service in a `https` network connection, like `facebook` or `twitter`. The field value must be normalized to lowercase for querying.", example: 'aim', name: 'network.application', type: 'keyword', @@ -1912,7 +3027,7 @@ export const fieldsBeat: BeatFields = { 'network.direction': { category: 'network', description: - "Direction of the network traffic. Recommended values are: * inbound * outbound * internal * external * unknown When mapping events from a host-based monitoring context, populate this field from the host's point of view. When mapping events from a network or perimeter-based monitoring context, populate this field from the point of view of your network perimeter.", + 'Direction of the network traffic. Recommended values are: * ingress * egress * inbound * outbound * internal * external * unknown When mapping events from a host-based monitoring context, populate this field from the host\'s point of view, using the values "ingress" or "egress". When mapping events from a network or perimeter-based monitoring context, populate this field from the point of view of the network perimeter, using the values "inbound", "outbound", "internal" or "external". Note that "internal" is not crossing perimeter boundaries, and is meant to describe communication between two hosts within the perimeter. Note also that "external" is meant to describe traffic between two hosts that are external to the perimeter. This could for example be useful for ISPs or VPN service providers.', example: 'inbound', name: 'network.direction', type: 'keyword', @@ -1935,7 +3050,7 @@ export const fieldsBeat: BeatFields = { 'network.inner': { category: 'network', description: - 'Network.inner fields are added in addition to network.vlan fields to describe the innermost VLAN when q-in-q VLAN tagging is present. Allowed fields include vlan.id and vlan.name. Inner vlan fields are typically used when sending traffic with multiple 802.1q encapsulations to a network sensor (e.g. Zeek, Wireshark.)', + 'Network.inner fields are added in addition to network.vlan fields to describe the innermost VLAN when q-in-q VLAN tagging is present. Allowed fields include vlan.id and vlan.name. Inner vlan fields are typically used when sending traffic with multiple 802.1q encapsulations to a network sensor (e.g. Zeek, Wireshark.)', name: 'network.inner', type: 'object', }, @@ -1971,7 +3086,7 @@ export const fieldsBeat: BeatFields = { 'network.protocol': { category: 'network', description: - 'L7 Network protocol name. ex. http, lumberjack, transport protocol. The field value must be normalized to lowercase for querying. See the documentation section "Implementing ECS".', + 'In the OSI Model this would be the Application Layer protocol. For example, `http`, `dns`, or `ssh`. The field value must be normalized to lowercase for querying.', example: 'http', name: 'network.protocol', type: 'keyword', @@ -1979,7 +3094,7 @@ export const fieldsBeat: BeatFields = { 'network.transport': { category: 'network', description: - 'Same as network.iana_number, but instead using the Keyword name of the transport layer (udp, tcp, ipv6-icmp, etc.) The field value must be normalized to lowercase for querying. See the documentation section "Implementing ECS".', + 'Same as network.iana_number, but instead using the Keyword name of the transport layer (udp, tcp, ipv6-icmp, etc.) The field value must be normalized to lowercase for querying.', example: 'tcp', name: 'network.transport', type: 'keyword', @@ -1987,7 +3102,7 @@ export const fieldsBeat: BeatFields = { 'network.type': { category: 'network', description: - 'In the OSI Model this would be the Network Layer. ipv4, ipv6, ipsec, pim, etc The field value must be normalized to lowercase for querying. See the documentation section "Implementing ECS".', + 'In the OSI Model this would be the Network Layer. ipv4, ipv6, ipsec, pim, etc The field value must be normalized to lowercase for querying.', example: 'ipv4', name: 'network.type', type: 'keyword', @@ -2009,7 +3124,7 @@ export const fieldsBeat: BeatFields = { 'observer.egress': { category: 'observer', description: - 'Observer.egress holds information like interface number and name, vlan, and zone information to classify egress traffic. Single armed monitoring such as a network sensor on a span port should only use observer.ingress to categorize traffic.', + 'Observer.egress holds information like interface number and name, vlan, and zone information to classify egress traffic. Single armed monitoring such as a network sensor on a span port should only use observer.ingress to categorize traffic.', name: 'observer.egress', type: 'object', }, @@ -2052,7 +3167,7 @@ export const fieldsBeat: BeatFields = { 'observer.egress.zone': { category: 'observer', description: - 'Network zone of outbound traffic as reported by the observer to categorize the destination area of egress traffic, e.g. Internal, External, DMZ, HR, Legal, etc.', + 'Network zone of outbound traffic as reported by the observer to categorize the destination area of egress traffic, e.g. Internal, External, DMZ, HR, Legal, etc.', example: 'Public_Internet', name: 'observer.egress.zone', type: 'keyword', @@ -2064,6 +3179,13 @@ export const fieldsBeat: BeatFields = { name: 'observer.geo.city_name', type: 'keyword', }, + 'observer.geo.continent_code': { + category: 'observer', + description: "Two-letter code representing continent's name.", + example: 'NA', + name: 'observer.geo.continent_code', + type: 'keyword', + }, 'observer.geo.continent_name': { category: 'observer', description: 'Name of the continent.', @@ -2100,6 +3222,14 @@ export const fieldsBeat: BeatFields = { name: 'observer.geo.name', type: 'keyword', }, + 'observer.geo.postal_code': { + category: 'observer', + description: + 'Postal code associated with the location. Values appropriate for this field may also be known as a postcode or ZIP code and will vary widely from country to country.', + example: 94040, + name: 'observer.geo.postal_code', + type: 'keyword', + }, 'observer.geo.region_iso_code': { category: 'observer', description: 'Region ISO code.', @@ -2114,6 +3244,13 @@ export const fieldsBeat: BeatFields = { name: 'observer.geo.region_name', type: 'keyword', }, + 'observer.geo.timezone': { + category: 'observer', + description: 'The time zone of the location, such as IANA time zone name.', + example: 'America/Argentina/Buenos_Aires', + name: 'observer.geo.timezone', + type: 'keyword', + }, 'observer.hostname': { category: 'observer', description: 'Hostname of the observer.', @@ -2123,7 +3260,7 @@ export const fieldsBeat: BeatFields = { 'observer.ingress': { category: 'observer', description: - 'Observer.ingress holds information like interface number and name, vlan, and zone information to classify ingress traffic. Single armed monitoring such as a network sensor on a span port should only use observer.ingress to categorize traffic.', + 'Observer.ingress holds information like interface number and name, vlan, and zone information to classify ingress traffic. Single armed monitoring such as a network sensor on a span port should only use observer.ingress to categorize traffic.', name: 'observer.ingress', type: 'object', }, @@ -2166,7 +3303,7 @@ export const fieldsBeat: BeatFields = { 'observer.ingress.zone': { category: 'observer', description: - 'Network zone of incoming traffic as reported by the observer to categorize the source area of ingress traffic. e.g. internal, External, DMZ, HR, Legal, etc.', + 'Network zone of incoming traffic as reported by the observer to categorize the source area of ingress traffic. e.g. internal, External, DMZ, HR, Legal, etc.', example: 'DMZ', name: 'observer.ingress.zone', type: 'keyword', @@ -2179,7 +3316,9 @@ export const fieldsBeat: BeatFields = { }, 'observer.mac': { category: 'observer', - description: 'MAC addresses of the observer', + description: + 'MAC addresses of the observer. The notation format from RFC 7042 is suggested: Each octet (that is, 8-bit byte) is represented by two [uppercase] hexadecimal digits giving the value of the octet as an unsigned integer. Successive octets are separated by a hyphen.', + example: '["00-00-5E-00-53-23", "00-00-5E-00-53-24"]', name: 'observer.mac', type: 'keyword', }, @@ -2226,6 +3365,14 @@ export const fieldsBeat: BeatFields = { name: 'observer.os.platform', type: 'keyword', }, + 'observer.os.type': { + category: 'observer', + description: + "Use the `os.type` field to categorize the operating system into one of the broad commercial families. One of these following values should be used (lowercase): linux, macos, unix, windows. If the OS you're dealing with is not in the list, the field should not be populated. Please let us know by opening an issue with ECS, to propose its addition.", + example: 'macos', + name: 'observer.os.type', + type: 'keyword', + }, 'observer.os.version': { category: 'observer', description: 'Operating system version as a raw string.', @@ -2267,6 +3414,66 @@ export const fieldsBeat: BeatFields = { name: 'observer.version', type: 'keyword', }, + 'orchestrator.api_version': { + category: 'orchestrator', + description: 'API version being used to carry out the action', + example: 'v1beta1', + name: 'orchestrator.api_version', + type: 'keyword', + }, + 'orchestrator.cluster.name': { + category: 'orchestrator', + description: 'Name of the cluster.', + name: 'orchestrator.cluster.name', + type: 'keyword', + }, + 'orchestrator.cluster.url': { + category: 'orchestrator', + description: 'URL of the API used to manage the cluster.', + name: 'orchestrator.cluster.url', + type: 'keyword', + }, + 'orchestrator.cluster.version': { + category: 'orchestrator', + description: 'The version of the cluster.', + name: 'orchestrator.cluster.version', + type: 'keyword', + }, + 'orchestrator.namespace': { + category: 'orchestrator', + description: 'Namespace in which the action is taking place.', + example: 'kube-system', + name: 'orchestrator.namespace', + type: 'keyword', + }, + 'orchestrator.organization': { + category: 'orchestrator', + description: 'Organization affected by the event (for multi-tenant orchestrator setups).', + example: 'elastic', + name: 'orchestrator.organization', + type: 'keyword', + }, + 'orchestrator.resource.name': { + category: 'orchestrator', + description: 'Name of the resource being acted upon.', + example: 'test-pod-cdcws', + name: 'orchestrator.resource.name', + type: 'keyword', + }, + 'orchestrator.resource.type': { + category: 'orchestrator', + description: 'Type of resource being acted upon.', + example: 'service', + name: 'orchestrator.resource.type', + type: 'keyword', + }, + 'orchestrator.type': { + category: 'orchestrator', + description: 'Orchestrator cluster type (e.g. kubernetes, nomad or cloudfoundry).', + example: 'kubernetes', + name: 'orchestrator.type', + type: 'keyword', + }, 'organization.id': { category: 'organization', description: 'Unique identifier for the organization.', @@ -2314,6 +3521,14 @@ export const fieldsBeat: BeatFields = { name: 'os.platform', type: 'keyword', }, + 'os.type': { + category: 'os', + description: + "Use the `os.type` field to categorize the operating system into one of the broad commercial families. One of these following values should be used (lowercase): linux, macos, unix, windows. If the OS you're dealing with is not in the list, the field should not be populated. Please let us know by opening an issue with ECS, to propose its addition.", + example: 'macos', + name: 'os.type', + type: 'keyword', + }, 'os.version': { category: 'os', description: 'Operating system version as a raw string.', @@ -2415,6 +3630,13 @@ export const fieldsBeat: BeatFields = { name: 'package.version', type: 'keyword', }, + 'pe.architecture': { + category: 'pe', + description: 'CPU architecture target for the file.', + example: 'x64', + name: 'pe.architecture', + type: 'keyword', + }, 'pe.company': { category: 'pe', description: 'Internal company name of the file, provided at compile-time.', @@ -2436,6 +3658,14 @@ export const fieldsBeat: BeatFields = { name: 'pe.file_version', type: 'keyword', }, + 'pe.imphash': { + category: 'pe', + description: + 'A hash of the imports in a PE file. An imphash -- or import hash -- can be used to fingerprint binaries even after recompilation or other code-level transformations have occurred, which would change more traditional hash values. Learn more at https://www.fireeye.com/blog/threat-research/2014/01/tracking-malware-import-hashing.html.', + example: '0c6803c4e922103c4dca5963aad36ddf', + name: 'pe.imphash', + type: 'keyword', + }, 'pe.original_file_name': { category: 'pe', description: 'Internal name of the file, provided at compile-time.', @@ -2454,7 +3684,7 @@ export const fieldsBeat: BeatFields = { category: 'process', description: 'Array of process arguments, starting with the absolute path to the executable. May be filtered to protect sensitive information.', - example: '["/usr/bin/ssh","-l","user","10.0.0.16"]', + example: '["/usr/bin/ssh", "-l", "user", "10.0.0.16"]', name: 'process.args', type: 'keyword', }, @@ -2466,6 +3696,14 @@ export const fieldsBeat: BeatFields = { name: 'process.args_count', type: 'long', }, + 'process.code_signature.digest_algorithm': { + category: 'process', + description: + 'The hashing algorithm used to sign the process. This value can distinguish signatures when a file is signed multiple times by the same signer but with a different digest algorithm.', + example: 'sha256', + name: 'process.code_signature.digest_algorithm', + type: 'keyword', + }, 'process.code_signature.exists': { category: 'process', description: 'Boolean to capture if a signature is present.', @@ -2473,6 +3711,14 @@ export const fieldsBeat: BeatFields = { name: 'process.code_signature.exists', type: 'boolean', }, + 'process.code_signature.signing_id': { + category: 'process', + description: + 'The identifier used to sign the process. This is used to identify the application manufactured by a software vendor. The field is relevant to Apple *OS only.', + example: 'com.apple.xpc.proxy', + name: 'process.code_signature.signing_id', + type: 'keyword', + }, 'process.code_signature.status': { category: 'process', description: @@ -2488,6 +3734,21 @@ export const fieldsBeat: BeatFields = { name: 'process.code_signature.subject_name', type: 'keyword', }, + 'process.code_signature.team_id': { + category: 'process', + description: + 'The team identifier used to sign the process. This is used to identify the team or vendor of a software product. The field is relevant to Apple *OS only.', + example: 'EQHXZ8M8AV', + name: 'process.code_signature.team_id', + type: 'keyword', + }, + 'process.code_signature.timestamp': { + category: 'process', + description: 'Date and time when the code signature was generated and signed.', + example: '2021-01-01T12:10:30Z', + name: 'process.code_signature.timestamp', + type: 'date', + }, 'process.code_signature.trusted': { category: 'process', description: @@ -2510,8 +3771,201 @@ export const fieldsBeat: BeatFields = { 'Full command line that started the process, including the absolute path to the executable, and all arguments. Some arguments may be filtered to protect sensitive information.', example: '/usr/bin/ssh -l user 10.0.0.16', name: 'process.command_line', + type: 'wildcard', + }, + 'process.elf.architecture': { + category: 'process', + description: 'Machine architecture of the ELF file.', + example: 'x86-64', + name: 'process.elf.architecture', type: 'keyword', }, + 'process.elf.byte_order': { + category: 'process', + description: 'Byte sequence of ELF file.', + example: 'Little Endian', + name: 'process.elf.byte_order', + type: 'keyword', + }, + 'process.elf.cpu_type': { + category: 'process', + description: 'CPU type of the ELF file.', + example: 'Intel', + name: 'process.elf.cpu_type', + type: 'keyword', + }, + 'process.elf.creation_date': { + category: 'process', + description: + "Extracted when possible from the file's metadata. Indicates when it was built or compiled. It can also be faked by malware creators.", + name: 'process.elf.creation_date', + type: 'date', + }, + 'process.elf.exports': { + category: 'process', + description: 'List of exported element names and types.', + name: 'process.elf.exports', + type: 'flattened', + }, + 'process.elf.header.abi_version': { + category: 'process', + description: 'Version of the ELF Application Binary Interface (ABI).', + name: 'process.elf.header.abi_version', + type: 'keyword', + }, + 'process.elf.header.class': { + category: 'process', + description: 'Header class of the ELF file.', + name: 'process.elf.header.class', + type: 'keyword', + }, + 'process.elf.header.data': { + category: 'process', + description: 'Data table of the ELF header.', + name: 'process.elf.header.data', + type: 'keyword', + }, + 'process.elf.header.entrypoint': { + category: 'process', + description: 'Header entrypoint of the ELF file.', + name: 'process.elf.header.entrypoint', + type: 'long', + format: 'string', + }, + 'process.elf.header.object_version': { + category: 'process', + description: '"0x1" for original ELF files.', + name: 'process.elf.header.object_version', + type: 'keyword', + }, + 'process.elf.header.os_abi': { + category: 'process', + description: 'Application Binary Interface (ABI) of the Linux OS.', + name: 'process.elf.header.os_abi', + type: 'keyword', + }, + 'process.elf.header.type': { + category: 'process', + description: 'Header type of the ELF file.', + name: 'process.elf.header.type', + type: 'keyword', + }, + 'process.elf.header.version': { + category: 'process', + description: 'Version of the ELF header.', + name: 'process.elf.header.version', + type: 'keyword', + }, + 'process.elf.imports': { + category: 'process', + description: 'List of imported element names and types.', + name: 'process.elf.imports', + type: 'flattened', + }, + 'process.elf.sections': { + category: 'process', + description: + 'An array containing an object for each section of the ELF file. The keys that should be present in these objects are defined by sub-fields underneath `elf.sections.*`.', + name: 'process.elf.sections', + type: 'nested', + }, + 'process.elf.sections.chi2': { + category: 'process', + description: 'Chi-square probability distribution of the section.', + name: 'process.elf.sections.chi2', + type: 'long', + format: 'number', + }, + 'process.elf.sections.entropy': { + category: 'process', + description: 'Shannon entropy calculation from the section.', + name: 'process.elf.sections.entropy', + type: 'long', + format: 'number', + }, + 'process.elf.sections.flags': { + category: 'process', + description: 'ELF Section List flags.', + name: 'process.elf.sections.flags', + type: 'keyword', + }, + 'process.elf.sections.name': { + category: 'process', + description: 'ELF Section List name.', + name: 'process.elf.sections.name', + type: 'keyword', + }, + 'process.elf.sections.physical_offset': { + category: 'process', + description: 'ELF Section List offset.', + name: 'process.elf.sections.physical_offset', + type: 'keyword', + }, + 'process.elf.sections.physical_size': { + category: 'process', + description: 'ELF Section List physical size.', + name: 'process.elf.sections.physical_size', + type: 'long', + format: 'bytes', + }, + 'process.elf.sections.type': { + category: 'process', + description: 'ELF Section List type.', + name: 'process.elf.sections.type', + type: 'keyword', + }, + 'process.elf.sections.virtual_address': { + category: 'process', + description: 'ELF Section List virtual address.', + name: 'process.elf.sections.virtual_address', + type: 'long', + format: 'string', + }, + 'process.elf.sections.virtual_size': { + category: 'process', + description: 'ELF Section List virtual size.', + name: 'process.elf.sections.virtual_size', + type: 'long', + format: 'string', + }, + 'process.elf.segments': { + category: 'process', + description: + 'An array containing an object for each segment of the ELF file. The keys that should be present in these objects are defined by sub-fields underneath `elf.segments.*`.', + name: 'process.elf.segments', + type: 'nested', + }, + 'process.elf.segments.sections': { + category: 'process', + description: 'ELF object segment sections.', + name: 'process.elf.segments.sections', + type: 'keyword', + }, + 'process.elf.segments.type': { + category: 'process', + description: 'ELF object segment type.', + name: 'process.elf.segments.type', + type: 'keyword', + }, + 'process.elf.shared_libraries': { + category: 'process', + description: 'List of shared libraries used by this ELF object.', + name: 'process.elf.shared_libraries', + type: 'keyword', + }, + 'process.elf.telfhash': { + category: 'process', + description: 'telfhash symbol hash for ELF file.', + name: 'process.elf.telfhash', + type: 'keyword', + }, + 'process.end': { + category: 'process', + description: 'The time the process ended.', + example: '2016-05-23T08:05:34.853Z', + name: 'process.end', + type: 'date', + }, 'process.entity_id': { category: 'process', description: @@ -2559,6 +4013,12 @@ export const fieldsBeat: BeatFields = { name: 'process.hash.sha512', type: 'keyword', }, + 'process.hash.ssdeep': { + category: 'process', + description: 'SSDEEP hash.', + name: 'process.hash.ssdeep', + type: 'keyword', + }, 'process.name': { category: 'process', description: 'Process name. Sometimes called program name or similar.', @@ -2568,8 +4028,9 @@ export const fieldsBeat: BeatFields = { }, 'process.parent.args': { category: 'process', - description: 'Array of process arguments. May be filtered to protect sensitive information.', - example: '["ssh","-l","user","10.0.0.16"]', + description: + 'Array of process arguments, starting with the absolute path to the executable. May be filtered to protect sensitive information.', + example: '["/usr/bin/ssh", "-l", "user", "10.0.0.16"]', name: 'process.parent.args', type: 'keyword', }, @@ -2581,6 +4042,14 @@ export const fieldsBeat: BeatFields = { name: 'process.parent.args_count', type: 'long', }, + 'process.parent.code_signature.digest_algorithm': { + category: 'process', + description: + 'The hashing algorithm used to sign the process. This value can distinguish signatures when a file is signed multiple times by the same signer but with a different digest algorithm.', + example: 'sha256', + name: 'process.parent.code_signature.digest_algorithm', + type: 'keyword', + }, 'process.parent.code_signature.exists': { category: 'process', description: 'Boolean to capture if a signature is present.', @@ -2588,6 +4057,14 @@ export const fieldsBeat: BeatFields = { name: 'process.parent.code_signature.exists', type: 'boolean', }, + 'process.parent.code_signature.signing_id': { + category: 'process', + description: + 'The identifier used to sign the process. This is used to identify the application manufactured by a software vendor. The field is relevant to Apple *OS only.', + example: 'com.apple.xpc.proxy', + name: 'process.parent.code_signature.signing_id', + type: 'keyword', + }, 'process.parent.code_signature.status': { category: 'process', description: @@ -2603,6 +4080,21 @@ export const fieldsBeat: BeatFields = { name: 'process.parent.code_signature.subject_name', type: 'keyword', }, + 'process.parent.code_signature.team_id': { + category: 'process', + description: + 'The team identifier used to sign the process. This is used to identify the team or vendor of a software product. The field is relevant to Apple *OS only.', + example: 'EQHXZ8M8AV', + name: 'process.parent.code_signature.team_id', + type: 'keyword', + }, + 'process.parent.code_signature.timestamp': { + category: 'process', + description: 'Date and time when the code signature was generated and signed.', + example: '2021-01-01T12:10:30Z', + name: 'process.parent.code_signature.timestamp', + type: 'date', + }, 'process.parent.code_signature.trusted': { category: 'process', description: @@ -2625,8 +4117,201 @@ export const fieldsBeat: BeatFields = { 'Full command line that started the process, including the absolute path to the executable, and all arguments. Some arguments may be filtered to protect sensitive information.', example: '/usr/bin/ssh -l user 10.0.0.16', name: 'process.parent.command_line', + type: 'wildcard', + }, + 'process.parent.elf.architecture': { + category: 'process', + description: 'Machine architecture of the ELF file.', + example: 'x86-64', + name: 'process.parent.elf.architecture', + type: 'keyword', + }, + 'process.parent.elf.byte_order': { + category: 'process', + description: 'Byte sequence of ELF file.', + example: 'Little Endian', + name: 'process.parent.elf.byte_order', + type: 'keyword', + }, + 'process.parent.elf.cpu_type': { + category: 'process', + description: 'CPU type of the ELF file.', + example: 'Intel', + name: 'process.parent.elf.cpu_type', + type: 'keyword', + }, + 'process.parent.elf.creation_date': { + category: 'process', + description: + "Extracted when possible from the file's metadata. Indicates when it was built or compiled. It can also be faked by malware creators.", + name: 'process.parent.elf.creation_date', + type: 'date', + }, + 'process.parent.elf.exports': { + category: 'process', + description: 'List of exported element names and types.', + name: 'process.parent.elf.exports', + type: 'flattened', + }, + 'process.parent.elf.header.abi_version': { + category: 'process', + description: 'Version of the ELF Application Binary Interface (ABI).', + name: 'process.parent.elf.header.abi_version', + type: 'keyword', + }, + 'process.parent.elf.header.class': { + category: 'process', + description: 'Header class of the ELF file.', + name: 'process.parent.elf.header.class', + type: 'keyword', + }, + 'process.parent.elf.header.data': { + category: 'process', + description: 'Data table of the ELF header.', + name: 'process.parent.elf.header.data', + type: 'keyword', + }, + 'process.parent.elf.header.entrypoint': { + category: 'process', + description: 'Header entrypoint of the ELF file.', + name: 'process.parent.elf.header.entrypoint', + type: 'long', + format: 'string', + }, + 'process.parent.elf.header.object_version': { + category: 'process', + description: '"0x1" for original ELF files.', + name: 'process.parent.elf.header.object_version', + type: 'keyword', + }, + 'process.parent.elf.header.os_abi': { + category: 'process', + description: 'Application Binary Interface (ABI) of the Linux OS.', + name: 'process.parent.elf.header.os_abi', + type: 'keyword', + }, + 'process.parent.elf.header.type': { + category: 'process', + description: 'Header type of the ELF file.', + name: 'process.parent.elf.header.type', + type: 'keyword', + }, + 'process.parent.elf.header.version': { + category: 'process', + description: 'Version of the ELF header.', + name: 'process.parent.elf.header.version', + type: 'keyword', + }, + 'process.parent.elf.imports': { + category: 'process', + description: 'List of imported element names and types.', + name: 'process.parent.elf.imports', + type: 'flattened', + }, + 'process.parent.elf.sections': { + category: 'process', + description: + 'An array containing an object for each section of the ELF file. The keys that should be present in these objects are defined by sub-fields underneath `elf.sections.*`.', + name: 'process.parent.elf.sections', + type: 'nested', + }, + 'process.parent.elf.sections.chi2': { + category: 'process', + description: 'Chi-square probability distribution of the section.', + name: 'process.parent.elf.sections.chi2', + type: 'long', + format: 'number', + }, + 'process.parent.elf.sections.entropy': { + category: 'process', + description: 'Shannon entropy calculation from the section.', + name: 'process.parent.elf.sections.entropy', + type: 'long', + format: 'number', + }, + 'process.parent.elf.sections.flags': { + category: 'process', + description: 'ELF Section List flags.', + name: 'process.parent.elf.sections.flags', + type: 'keyword', + }, + 'process.parent.elf.sections.name': { + category: 'process', + description: 'ELF Section List name.', + name: 'process.parent.elf.sections.name', + type: 'keyword', + }, + 'process.parent.elf.sections.physical_offset': { + category: 'process', + description: 'ELF Section List offset.', + name: 'process.parent.elf.sections.physical_offset', + type: 'keyword', + }, + 'process.parent.elf.sections.physical_size': { + category: 'process', + description: 'ELF Section List physical size.', + name: 'process.parent.elf.sections.physical_size', + type: 'long', + format: 'bytes', + }, + 'process.parent.elf.sections.type': { + category: 'process', + description: 'ELF Section List type.', + name: 'process.parent.elf.sections.type', + type: 'keyword', + }, + 'process.parent.elf.sections.virtual_address': { + category: 'process', + description: 'ELF Section List virtual address.', + name: 'process.parent.elf.sections.virtual_address', + type: 'long', + format: 'string', + }, + 'process.parent.elf.sections.virtual_size': { + category: 'process', + description: 'ELF Section List virtual size.', + name: 'process.parent.elf.sections.virtual_size', + type: 'long', + format: 'string', + }, + 'process.parent.elf.segments': { + category: 'process', + description: + 'An array containing an object for each segment of the ELF file. The keys that should be present in these objects are defined by sub-fields underneath `elf.segments.*`.', + name: 'process.parent.elf.segments', + type: 'nested', + }, + 'process.parent.elf.segments.sections': { + category: 'process', + description: 'ELF object segment sections.', + name: 'process.parent.elf.segments.sections', type: 'keyword', }, + 'process.parent.elf.segments.type': { + category: 'process', + description: 'ELF object segment type.', + name: 'process.parent.elf.segments.type', + type: 'keyword', + }, + 'process.parent.elf.shared_libraries': { + category: 'process', + description: 'List of shared libraries used by this ELF object.', + name: 'process.parent.elf.shared_libraries', + type: 'keyword', + }, + 'process.parent.elf.telfhash': { + category: 'process', + description: 'telfhash symbol hash for ELF file.', + name: 'process.parent.elf.telfhash', + type: 'keyword', + }, + 'process.parent.end': { + category: 'process', + description: 'The time the process ended.', + example: '2016-05-23T08:05:34.853Z', + name: 'process.parent.end', + type: 'date', + }, 'process.parent.entity_id': { category: 'process', description: @@ -2674,6 +4359,12 @@ export const fieldsBeat: BeatFields = { name: 'process.parent.hash.sha512', type: 'keyword', }, + 'process.parent.hash.ssdeep': { + category: 'process', + description: 'SSDEEP hash.', + name: 'process.parent.hash.ssdeep', + type: 'keyword', + }, 'process.parent.name': { category: 'process', description: 'Process name. Sometimes called program name or similar.', @@ -2681,6 +4372,56 @@ export const fieldsBeat: BeatFields = { name: 'process.parent.name', type: 'keyword', }, + 'process.parent.pe.architecture': { + category: 'process', + description: 'CPU architecture target for the file.', + example: 'x64', + name: 'process.parent.pe.architecture', + type: 'keyword', + }, + 'process.parent.pe.company': { + category: 'process', + description: 'Internal company name of the file, provided at compile-time.', + example: 'Microsoft Corporation', + name: 'process.parent.pe.company', + type: 'keyword', + }, + 'process.parent.pe.description': { + category: 'process', + description: 'Internal description of the file, provided at compile-time.', + example: 'Paint', + name: 'process.parent.pe.description', + type: 'keyword', + }, + 'process.parent.pe.file_version': { + category: 'process', + description: 'Internal version of the file, provided at compile-time.', + example: '6.3.9600.17415', + name: 'process.parent.pe.file_version', + type: 'keyword', + }, + 'process.parent.pe.imphash': { + category: 'process', + description: + 'A hash of the imports in a PE file. An imphash -- or import hash -- can be used to fingerprint binaries even after recompilation or other code-level transformations have occurred, which would change more traditional hash values. Learn more at https://www.fireeye.com/blog/threat-research/2014/01/tracking-malware-import-hashing.html.', + example: '0c6803c4e922103c4dca5963aad36ddf', + name: 'process.parent.pe.imphash', + type: 'keyword', + }, + 'process.parent.pe.original_file_name': { + category: 'process', + description: 'Internal name of the file, provided at compile-time.', + example: 'MSPAINT.EXE', + name: 'process.parent.pe.original_file_name', + type: 'keyword', + }, + 'process.parent.pe.product': { + category: 'process', + description: 'Internal product name of the file, provided at compile-time.', + example: 'Microsoft® Windows® Operating System', + name: 'process.parent.pe.product', + type: 'keyword', + }, 'process.parent.pgid': { category: 'process', description: 'Identifier of the group of processes the process belongs to.', @@ -2696,14 +4437,6 @@ export const fieldsBeat: BeatFields = { type: 'long', format: 'string', }, - 'process.parent.ppid': { - category: 'process', - description: "Parent process' pid.", - example: 4241, - name: 'process.parent.ppid', - type: 'long', - format: 'string', - }, 'process.parent.start': { category: 'process', description: 'The time the process started.', @@ -2747,6 +4480,13 @@ export const fieldsBeat: BeatFields = { name: 'process.parent.working_directory', type: 'keyword', }, + 'process.pe.architecture': { + category: 'process', + description: 'CPU architecture target for the file.', + example: 'x64', + name: 'process.pe.architecture', + type: 'keyword', + }, 'process.pe.company': { category: 'process', description: 'Internal company name of the file, provided at compile-time.', @@ -2768,6 +4508,14 @@ export const fieldsBeat: BeatFields = { name: 'process.pe.file_version', type: 'keyword', }, + 'process.pe.imphash': { + category: 'process', + description: + 'A hash of the imports in a PE file. An imphash -- or import hash -- can be used to fingerprint binaries even after recompilation or other code-level transformations have occurred, which would change more traditional hash values. Learn more at https://www.fireeye.com/blog/threat-research/2014/01/tracking-malware-import-hashing.html.', + example: '0c6803c4e922103c4dca5963aad36ddf', + name: 'process.pe.imphash', + type: 'keyword', + }, 'process.pe.original_file_name': { category: 'process', description: 'Internal name of the file, provided at compile-time.', @@ -2797,14 +4545,6 @@ export const fieldsBeat: BeatFields = { type: 'long', format: 'string', }, - 'process.ppid': { - category: 'process', - description: "Parent process' pid.", - example: 4241, - name: 'process.ppid', - type: 'long', - format: 'string', - }, 'process.start': { category: 'process', description: 'The time the process started.', @@ -2862,7 +4602,7 @@ export const fieldsBeat: BeatFields = { 'Content when writing string types. Populated as an array when writing string data to the registry. For single string registry types (REG_SZ, REG_EXPAND_SZ), this should be an array with one string. For sequences of string with REG_MULTI_SZ, this array will be variable length. For numeric data, such as REG_DWORD and REG_QWORD, this should be populated with the decimal representation (e.g `"1"`).', example: '["C:\\rta\\red_ttp\\bin\\myapp.exe"]', name: 'registry.data.strings', - type: 'keyword', + type: 'wildcard', }, 'registry.data.type': { category: 'registry', @@ -2908,6 +4648,13 @@ export const fieldsBeat: BeatFields = { name: 'related.hash', type: 'keyword', }, + 'related.hosts': { + category: 'related', + description: + 'All hostnames or other host identifiers seen on your event. Example identifiers include FQDNs, domain names, workstation names, or aliases.', + name: 'related.hosts', + type: 'keyword', + }, 'related.ip': { category: 'related', description: 'All of the IPs seen on your event.', @@ -2916,7 +4663,7 @@ export const fieldsBeat: BeatFields = { }, 'related.user': { category: 'related', - description: 'All the user names seen on your event.', + description: 'All the user names or other user identifiers seen on the event.', name: 'related.user', type: 'keyword', }, @@ -3040,6 +4787,13 @@ export const fieldsBeat: BeatFields = { name: 'server.geo.city_name', type: 'keyword', }, + 'server.geo.continent_code': { + category: 'server', + description: "Two-letter code representing continent's name.", + example: 'NA', + name: 'server.geo.continent_code', + type: 'keyword', + }, 'server.geo.continent_name': { category: 'server', description: 'Name of the continent.', @@ -3076,6 +4830,14 @@ export const fieldsBeat: BeatFields = { name: 'server.geo.name', type: 'keyword', }, + 'server.geo.postal_code': { + category: 'server', + description: + 'Postal code associated with the location. Values appropriate for this field may also be known as a postcode or ZIP code and will vary widely from country to country.', + example: 94040, + name: 'server.geo.postal_code', + type: 'keyword', + }, 'server.geo.region_iso_code': { category: 'server', description: 'Region ISO code.', @@ -3090,15 +4852,24 @@ export const fieldsBeat: BeatFields = { name: 'server.geo.region_name', type: 'keyword', }, + 'server.geo.timezone': { + category: 'server', + description: 'The time zone of the location, such as IANA time zone name.', + example: 'America/Argentina/Buenos_Aires', + name: 'server.geo.timezone', + type: 'keyword', + }, 'server.ip': { category: 'server', - description: 'IP address of the server. Can be one or multiple IPv4 or IPv6 addresses.', + description: 'IP address of the server (IPv4 or IPv6).', name: 'server.ip', type: 'ip', }, 'server.mac': { category: 'server', - description: 'MAC address of the server.', + description: + 'MAC address of the server. The notation format from RFC 7042 is suggested: Each octet (that is, 8-bit byte) is represented by two [uppercase] hexadecimal digits giving the value of the octet as an unsigned integer. Successive octets are separated by a hyphen.', + example: '00-00-5E-00-53-23', name: 'server.mac', type: 'keyword', }, @@ -3134,15 +4905,23 @@ export const fieldsBeat: BeatFields = { 'server.registered_domain': { category: 'server', description: - 'The highest registered server domain, stripped of the subdomain. For example, the registered domain for "foo.google.com" is "google.com". This value can be determined precisely with a list like the public suffix list (http://publicsuffix.org). Trying to approximate this by simply taking the last two labels will not work well for TLDs such as "co.uk".', - example: 'google.com', + 'The highest registered server domain, stripped of the subdomain. For example, the registered domain for "foo.example.com" is "example.com". This value can be determined precisely with a list like the public suffix list (http://publicsuffix.org). Trying to approximate this by simply taking the last two labels will not work well for TLDs such as "co.uk".', + example: 'example.com', name: 'server.registered_domain', type: 'keyword', }, + 'server.subdomain': { + category: 'server', + description: + 'The subdomain portion of a fully qualified domain name includes all of the names except the host name under the registered_domain. In a partially qualified domain, or if the the qualification level of the full name cannot be determined, subdomain contains all of the names below the registered domain. For example the subdomain portion of "www.east.mydomain.co.uk" is "east". If the domain has multiple levels of subdomain, such as "sub2.sub1.example.com", the subdomain field should contain "sub2.sub1", with no trailing period.', + example: 'east', + name: 'server.subdomain', + type: 'keyword', + }, 'server.top_level_domain': { category: 'server', description: - 'The effective top level domain (eTLD), also known as the domain suffix, is the last part of the domain name. For example, the top level domain for google.com is "com". This value can be determined precisely with a list like the public suffix list (http://publicsuffix.org). Trying to approximate this by simply taking the last label will not work well for effective TLDs such as "co.uk".', + 'The effective top level domain (eTLD), also known as the domain suffix, is the last part of the domain name. For example, the top level domain for example.com is "com". This value can be determined precisely with a list like the public suffix list (http://publicsuffix.org). Trying to approximate this by simply taking the last label will not work well for effective TLDs such as "co.uk".', example: 'co.uk', name: 'server.top_level_domain', type: 'keyword', @@ -3195,17 +4974,41 @@ export const fieldsBeat: BeatFields = { }, 'server.user.id': { category: 'server', - description: 'Unique identifiers of the user.', + description: 'Unique identifier of the user.', + example: 'S-1-5-21-202424912787-2692429404-2351956786-1000', name: 'server.user.id', type: 'keyword', }, 'server.user.name': { category: 'server', description: 'Short name or login of the user.', - example: 'albert', + example: 'a.einstein', name: 'server.user.name', type: 'keyword', }, + 'server.user.roles': { + category: 'server', + description: 'Array of user roles at the time of the event.', + example: '["kibana_admin", "reporting_user"]', + name: 'server.user.roles', + type: 'keyword', + }, + 'service.address': { + category: 'service', + description: + 'Address where data about this service was collected from. This should be a URI, network address (ipv4:port or [ipv6]:port) or a resource path (sockets).', + example: '172.26.0.2:5432', + name: 'service.address', + type: 'keyword', + }, + 'service.environment': { + category: 'service', + description: + 'Identifies the environment where the service is running. If the same service runs in different environments (production, staging, QA, development, etc.), the environment can identify other instances of the same service. Can also group services and applications from the same environment.', + example: 'production', + name: 'service.environment', + type: 'keyword', + }, 'service.ephemeral_id': { category: 'service', description: @@ -3238,12 +5041,152 @@ export const fieldsBeat: BeatFields = { name: 'service.node.name', type: 'keyword', }, + 'service.origin.address': { + category: 'service', + description: + 'Address where data about this service was collected from. This should be a URI, network address (ipv4:port or [ipv6]:port) or a resource path (sockets).', + example: '172.26.0.2:5432', + name: 'service.origin.address', + type: 'keyword', + }, + 'service.origin.environment': { + category: 'service', + description: + 'Identifies the environment where the service is running. If the same service runs in different environments (production, staging, QA, development, etc.), the environment can identify other instances of the same service. Can also group services and applications from the same environment.', + example: 'production', + name: 'service.origin.environment', + type: 'keyword', + }, + 'service.origin.ephemeral_id': { + category: 'service', + description: + 'Ephemeral identifier of this service (if one exists). This id normally changes across restarts, but `service.id` does not.', + example: '8a4f500f', + name: 'service.origin.ephemeral_id', + type: 'keyword', + }, + 'service.origin.id': { + category: 'service', + description: + 'Unique identifier of the running service. If the service is comprised of many nodes, the `service.id` should be the same for all nodes. This id should uniquely identify the service. This makes it possible to correlate logs and metrics for one specific service, no matter which particular node emitted the event. Note that if you need to see the events from one specific host of the service, you should filter on that `host.name` or `host.id` instead.', + example: 'd37e5ebfe0ae6c4972dbe9f0174a1637bb8247f6', + name: 'service.origin.id', + type: 'keyword', + }, + 'service.origin.name': { + category: 'service', + description: + 'Name of the service data is collected from. The name of the service is normally user given. This allows for distributed services that run on multiple hosts to correlate the related instances based on the name. In the case of Elasticsearch the `service.name` could contain the cluster name. For Beats the `service.name` is by default a copy of the `service.type` field if no name is specified.', + example: 'elasticsearch-metrics', + name: 'service.origin.name', + type: 'keyword', + }, + 'service.origin.node.name': { + category: 'service', + description: + "Name of a service node. This allows for two nodes of the same service running on the same host to be differentiated. Therefore, `service.node.name` should typically be unique across nodes of a given service. In the case of Elasticsearch, the `service.node.name` could contain the unique node name within the Elasticsearch cluster. In cases where the service doesn't have the concept of a node name, the host name or container name can be used to distinguish running instances that make up this service. If those do not provide uniqueness (e.g. multiple instances of the service running on the same host) - the node name can be manually set.", + example: 'instance-0000000016', + name: 'service.origin.node.name', + type: 'keyword', + }, + 'service.origin.state': { + category: 'service', + description: 'Current state of the service.', + name: 'service.origin.state', + type: 'keyword', + }, + 'service.origin.type': { + category: 'service', + description: + 'The type of the service data is collected from. The type can be used to group and correlate logs and metrics from one service type. Example: If logs or metrics are collected from Elasticsearch, `service.type` would be `elasticsearch`.', + example: 'elasticsearch', + name: 'service.origin.type', + type: 'keyword', + }, + 'service.origin.version': { + category: 'service', + description: + 'Version of the service the data was collected from. This allows to look at a data set only for a specific version of a service.', + example: '3.2.4', + name: 'service.origin.version', + type: 'keyword', + }, 'service.state': { category: 'service', description: 'Current state of the service.', name: 'service.state', type: 'keyword', }, + 'service.target.address': { + category: 'service', + description: + 'Address where data about this service was collected from. This should be a URI, network address (ipv4:port or [ipv6]:port) or a resource path (sockets).', + example: '172.26.0.2:5432', + name: 'service.target.address', + type: 'keyword', + }, + 'service.target.environment': { + category: 'service', + description: + 'Identifies the environment where the service is running. If the same service runs in different environments (production, staging, QA, development, etc.), the environment can identify other instances of the same service. Can also group services and applications from the same environment.', + example: 'production', + name: 'service.target.environment', + type: 'keyword', + }, + 'service.target.ephemeral_id': { + category: 'service', + description: + 'Ephemeral identifier of this service (if one exists). This id normally changes across restarts, but `service.id` does not.', + example: '8a4f500f', + name: 'service.target.ephemeral_id', + type: 'keyword', + }, + 'service.target.id': { + category: 'service', + description: + 'Unique identifier of the running service. If the service is comprised of many nodes, the `service.id` should be the same for all nodes. This id should uniquely identify the service. This makes it possible to correlate logs and metrics for one specific service, no matter which particular node emitted the event. Note that if you need to see the events from one specific host of the service, you should filter on that `host.name` or `host.id` instead.', + example: 'd37e5ebfe0ae6c4972dbe9f0174a1637bb8247f6', + name: 'service.target.id', + type: 'keyword', + }, + 'service.target.name': { + category: 'service', + description: + 'Name of the service data is collected from. The name of the service is normally user given. This allows for distributed services that run on multiple hosts to correlate the related instances based on the name. In the case of Elasticsearch the `service.name` could contain the cluster name. For Beats the `service.name` is by default a copy of the `service.type` field if no name is specified.', + example: 'elasticsearch-metrics', + name: 'service.target.name', + type: 'keyword', + }, + 'service.target.node.name': { + category: 'service', + description: + "Name of a service node. This allows for two nodes of the same service running on the same host to be differentiated. Therefore, `service.node.name` should typically be unique across nodes of a given service. In the case of Elasticsearch, the `service.node.name` could contain the unique node name within the Elasticsearch cluster. In cases where the service doesn't have the concept of a node name, the host name or container name can be used to distinguish running instances that make up this service. If those do not provide uniqueness (e.g. multiple instances of the service running on the same host) - the node name can be manually set.", + example: 'instance-0000000016', + name: 'service.target.node.name', + type: 'keyword', + }, + 'service.target.state': { + category: 'service', + description: 'Current state of the service.', + name: 'service.target.state', + type: 'keyword', + }, + 'service.target.type': { + category: 'service', + description: + 'The type of the service data is collected from. The type can be used to group and correlate logs and metrics from one service type. Example: If logs or metrics are collected from Elasticsearch, `service.type` would be `elasticsearch`.', + example: 'elasticsearch', + name: 'service.target.type', + type: 'keyword', + }, + 'service.target.version': { + category: 'service', + description: + 'Version of the service the data was collected from. This allows to look at a data set only for a specific version of a service.', + example: '3.2.4', + name: 'service.target.version', + type: 'keyword', + }, 'service.type': { category: 'service', description: @@ -3303,6 +5246,13 @@ export const fieldsBeat: BeatFields = { name: 'source.geo.city_name', type: 'keyword', }, + 'source.geo.continent_code': { + category: 'source', + description: "Two-letter code representing continent's name.", + example: 'NA', + name: 'source.geo.continent_code', + type: 'keyword', + }, 'source.geo.continent_name': { category: 'source', description: 'Name of the continent.', @@ -3339,6 +5289,14 @@ export const fieldsBeat: BeatFields = { name: 'source.geo.name', type: 'keyword', }, + 'source.geo.postal_code': { + category: 'source', + description: + 'Postal code associated with the location. Values appropriate for this field may also be known as a postcode or ZIP code and will vary widely from country to country.', + example: 94040, + name: 'source.geo.postal_code', + type: 'keyword', + }, 'source.geo.region_iso_code': { category: 'source', description: 'Region ISO code.', @@ -3353,15 +5311,24 @@ export const fieldsBeat: BeatFields = { name: 'source.geo.region_name', type: 'keyword', }, + 'source.geo.timezone': { + category: 'source', + description: 'The time zone of the location, such as IANA time zone name.', + example: 'America/Argentina/Buenos_Aires', + name: 'source.geo.timezone', + type: 'keyword', + }, 'source.ip': { category: 'source', - description: 'IP address of the source. Can be one or multiple IPv4 or IPv6 addresses.', + description: 'IP address of the source (IPv4 or IPv6).', name: 'source.ip', type: 'ip', }, 'source.mac': { category: 'source', - description: 'MAC address of the source.', + description: + 'MAC address of the source. The notation format from RFC 7042 is suggested: Each octet (that is, 8-bit byte) is represented by two [uppercase] hexadecimal digits giving the value of the octet as an unsigned integer. Successive octets are separated by a hyphen.', + example: '00-00-5E-00-53-23', name: 'source.mac', type: 'keyword', }, @@ -3397,15 +5364,23 @@ export const fieldsBeat: BeatFields = { 'source.registered_domain': { category: 'source', description: - 'The highest registered source domain, stripped of the subdomain. For example, the registered domain for "foo.google.com" is "google.com". This value can be determined precisely with a list like the public suffix list (http://publicsuffix.org). Trying to approximate this by simply taking the last two labels will not work well for TLDs such as "co.uk".', - example: 'google.com', + 'The highest registered source domain, stripped of the subdomain. For example, the registered domain for "foo.example.com" is "example.com". This value can be determined precisely with a list like the public suffix list (http://publicsuffix.org). Trying to approximate this by simply taking the last two labels will not work well for TLDs such as "co.uk".', + example: 'example.com', name: 'source.registered_domain', type: 'keyword', }, + 'source.subdomain': { + category: 'source', + description: + 'The subdomain portion of a fully qualified domain name includes all of the names except the host name under the registered_domain. In a partially qualified domain, or if the the qualification level of the full name cannot be determined, subdomain contains all of the names below the registered domain. For example the subdomain portion of "www.east.mydomain.co.uk" is "east". If the domain has multiple levels of subdomain, such as "sub2.sub1.example.com", the subdomain field should contain "sub2.sub1", with no trailing period.', + example: 'east', + name: 'source.subdomain', + type: 'keyword', + }, 'source.top_level_domain': { category: 'source', description: - 'The effective top level domain (eTLD), also known as the domain suffix, is the last part of the domain name. For example, the top level domain for google.com is "com". This value can be determined precisely with a list like the public suffix list (http://publicsuffix.org). Trying to approximate this by simply taking the last label will not work well for effective TLDs such as "co.uk".', + 'The effective top level domain (eTLD), also known as the domain suffix, is the last part of the domain name. For example, the top level domain for example.com is "com". This value can be determined precisely with a list like the public suffix list (http://publicsuffix.org). Trying to approximate this by simply taking the last label will not work well for effective TLDs such as "co.uk".', example: 'co.uk', name: 'source.top_level_domain', type: 'keyword', @@ -3458,27055 +5433,38765 @@ export const fieldsBeat: BeatFields = { }, 'source.user.id': { category: 'source', - description: 'Unique identifiers of the user.', + description: 'Unique identifier of the user.', + example: 'S-1-5-21-202424912787-2692429404-2351956786-1000', name: 'source.user.id', type: 'keyword', }, 'source.user.name': { category: 'source', description: 'Short name or login of the user.', - example: 'albert', + example: 'a.einstein', name: 'source.user.name', type: 'keyword', }, - 'threat.framework': { - category: 'threat', - description: - 'Name of the threat framework used to further categorize and classify the tactic and technique of the reported threat. Framework classification can be provided by detecting systems, evaluated at ingest time, or retrospectively tagged to events.', - example: 'MITRE ATT&CK', - name: 'threat.framework', + 'source.user.roles': { + category: 'source', + description: 'Array of user roles at the time of the event.', + example: '["kibana_admin", "reporting_user"]', + name: 'source.user.roles', type: 'keyword', }, - 'threat.tactic.id': { + 'threat.enrichments': { category: 'threat', description: - 'The id of tactic used by this threat. You can use the Mitre ATT&CK Matrix Tactic categorization, for example. (ex. https://attack.mitre.org/tactics/TA0040/ )', - example: 'TA0040', - name: 'threat.tactic.id', - type: 'keyword', + 'A list of associated indicators objects enriching the event, and the context of that association/enrichment.', + name: 'threat.enrichments', + type: 'nested', }, - 'threat.tactic.name': { + 'threat.enrichments.indicator': { category: 'threat', - description: - 'Name of the type of tactic used by this threat. You can use the Mitre ATT&CK Matrix Tactic categorization, for example. (ex. https://attack.mitre.org/tactics/TA0040/ )', - example: 'impact', - name: 'threat.tactic.name', - type: 'keyword', + description: 'Object containing associated indicators enriching the event.', + name: 'threat.enrichments.indicator', + type: 'object', }, - 'threat.tactic.reference': { + 'threat.enrichments.indicator.as.number': { category: 'threat', description: - 'The reference url of tactic used by this threat. You can use the Mitre ATT&CK Matrix Tactic categorization, for example. (ex. https://attack.mitre.org/tactics/TA0040/ )', - example: 'https://attack.mitre.org/tactics/TA0040/', - name: 'threat.tactic.reference', - type: 'keyword', + 'Unique number allocated to the autonomous system. The autonomous system number (ASN) uniquely identifies each network on the Internet.', + example: 15169, + name: 'threat.enrichments.indicator.as.number', + type: 'long', }, - 'threat.technique.id': { + 'threat.enrichments.indicator.as.organization.name': { category: 'threat', - description: - 'The id of technique used by this tactic. You can use the Mitre ATT&CK Matrix Tactic categorization, for example. (ex. https://attack.mitre.org/techniques/T1499/ )', - example: 'T1499', - name: 'threat.technique.id', + description: 'Organization name.', + example: 'Google LLC', + name: 'threat.enrichments.indicator.as.organization.name', type: 'keyword', }, - 'threat.technique.name': { + 'threat.enrichments.indicator.confidence': { category: 'threat', description: - 'The name of technique used by this tactic. You can use the Mitre ATT&CK Matrix Tactic categorization, for example. (ex. https://attack.mitre.org/techniques/T1499/ )', - example: 'endpoint denial of service', - name: 'threat.technique.name', + 'Identifies the vendor-neutral confidence rating using the None/Low/Medium/High scale defined in Appendix A of the STIX 2.1 framework. Vendor-specific confidence scales may be added as custom fields. Expected values are: * Not Specified * None * Low * Medium * High', + example: 'Medium', + name: 'threat.enrichments.indicator.confidence', type: 'keyword', }, - 'threat.technique.reference': { + 'threat.enrichments.indicator.description': { category: 'threat', - description: - 'The reference url of technique used by this tactic. You can use the Mitre ATT&CK Matrix Tactic categorization, for example. (ex. https://attack.mitre.org/techniques/T1499/ )', - example: 'https://attack.mitre.org/techniques/T1499/', - name: 'threat.technique.reference', + description: 'Describes the type of action conducted by the threat.', + example: 'IP x.x.x.x was observed delivering the Angler EK.', + name: 'threat.enrichments.indicator.description', type: 'keyword', }, - 'tls.cipher': { - category: 'tls', - description: 'String indicating the cipher used during the current connection.', - example: 'TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256', - name: 'tls.cipher', + 'threat.enrichments.indicator.email.address': { + category: 'threat', + description: 'Identifies a threat indicator as an email address (irrespective of direction).', + example: 'phish@example.com', + name: 'threat.enrichments.indicator.email.address', type: 'keyword', }, - 'tls.client.certificate': { - category: 'tls', + 'threat.enrichments.indicator.file.accessed': { + category: 'threat', description: - 'PEM-encoded stand-alone certificate offered by the client. This is usually mutually-exclusive of `client.certificate_chain` since this value also exists in that list.', - example: 'MII...', - name: 'tls.client.certificate', - type: 'keyword', + 'Last time the file was accessed. Note that not all filesystems keep track of access time.', + name: 'threat.enrichments.indicator.file.accessed', + type: 'date', }, - 'tls.client.certificate_chain': { - category: 'tls', + 'threat.enrichments.indicator.file.attributes': { + category: 'threat', description: - 'Array of PEM-encoded certificates that make up the certificate chain offered by the client. This is usually mutually-exclusive of `client.certificate` since that value should be the first certificate in the chain.', - example: '["MII...","MII..."]', - name: 'tls.client.certificate_chain', + "Array of file attributes. Attributes names will vary by platform. Here's a non-exhaustive list of values that are expected in this field: archive, compressed, directory, encrypted, execute, hidden, read, readonly, system, write.", + example: '["readonly", "system"]', + name: 'threat.enrichments.indicator.file.attributes', type: 'keyword', }, - 'tls.client.hash.md5': { - category: 'tls', + 'threat.enrichments.indicator.file.code_signature.digest_algorithm': { + category: 'threat', description: - 'Certificate fingerprint using the MD5 digest of DER-encoded version of certificate offered by the client. For consistency with other hash values, this value should be formatted as an uppercase hash.', - example: '0F76C7F2C55BFD7D8E8B8F4BFBF0C9EC', - name: 'tls.client.hash.md5', + 'The hashing algorithm used to sign the process. This value can distinguish signatures when a file is signed multiple times by the same signer but with a different digest algorithm.', + example: 'sha256', + name: 'threat.enrichments.indicator.file.code_signature.digest_algorithm', type: 'keyword', }, - 'tls.client.hash.sha1': { - category: 'tls', + 'threat.enrichments.indicator.file.code_signature.exists': { + category: 'threat', + description: 'Boolean to capture if a signature is present.', + example: 'true', + name: 'threat.enrichments.indicator.file.code_signature.exists', + type: 'boolean', + }, + 'threat.enrichments.indicator.file.code_signature.signing_id': { + category: 'threat', description: - 'Certificate fingerprint using the SHA1 digest of DER-encoded version of certificate offered by the client. For consistency with other hash values, this value should be formatted as an uppercase hash.', - example: '9E393D93138888D288266C2D915214D1D1CCEB2A', - name: 'tls.client.hash.sha1', + 'The identifier used to sign the process. This is used to identify the application manufactured by a software vendor. The field is relevant to Apple *OS only.', + example: 'com.apple.xpc.proxy', + name: 'threat.enrichments.indicator.file.code_signature.signing_id', type: 'keyword', }, - 'tls.client.hash.sha256': { - category: 'tls', + 'threat.enrichments.indicator.file.code_signature.status': { + category: 'threat', description: - 'Certificate fingerprint using the SHA256 digest of DER-encoded version of certificate offered by the client. For consistency with other hash values, this value should be formatted as an uppercase hash.', - example: '0687F666A054EF17A08E2F2162EAB4CBC0D265E1D7875BE74BF3C712CA92DAF0', - name: 'tls.client.hash.sha256', + 'Additional information about the certificate status. This is useful for logging cryptographic errors with the certificate validity or trust status. Leave unpopulated if the validity or trust of the certificate was unchecked.', + example: 'ERROR_UNTRUSTED_ROOT', + name: 'threat.enrichments.indicator.file.code_signature.status', type: 'keyword', }, - 'tls.client.issuer': { - category: 'tls', - description: - 'Distinguished name of subject of the issuer of the x.509 certificate presented by the client.', - example: 'CN=MyDomain Root CA, OU=Infrastructure Team, DC=mydomain, DC=com', - name: 'tls.client.issuer', + 'threat.enrichments.indicator.file.code_signature.subject_name': { + category: 'threat', + description: 'Subject name of the code signer', + example: 'Microsoft Corporation', + name: 'threat.enrichments.indicator.file.code_signature.subject_name', type: 'keyword', }, - 'tls.client.ja3': { - category: 'tls', - description: 'A hash that identifies clients based on how they perform an SSL/TLS handshake.', - example: 'd4e5b18d6b55c71272893221c96ba240', - name: 'tls.client.ja3', + 'threat.enrichments.indicator.file.code_signature.team_id': { + category: 'threat', + description: + 'The team identifier used to sign the process. This is used to identify the team or vendor of a software product. The field is relevant to Apple *OS only.', + example: 'EQHXZ8M8AV', + name: 'threat.enrichments.indicator.file.code_signature.team_id', type: 'keyword', }, - 'tls.client.not_after': { - category: 'tls', - description: 'Date/Time indicating when client certificate is no longer considered valid.', - example: '2021-01-01T00:00:00.000Z', - name: 'tls.client.not_after', + 'threat.enrichments.indicator.file.code_signature.timestamp': { + category: 'threat', + description: 'Date and time when the code signature was generated and signed.', + example: '2021-01-01T12:10:30Z', + name: 'threat.enrichments.indicator.file.code_signature.timestamp', type: 'date', }, - 'tls.client.not_before': { - category: 'tls', - description: 'Date/Time indicating when client certificate is first considered valid.', - example: '1970-01-01T00:00:00.000Z', - name: 'tls.client.not_before', + 'threat.enrichments.indicator.file.code_signature.trusted': { + category: 'threat', + description: + 'Stores the trust status of the certificate chain. Validating the trust of the certificate chain may be complicated, and this field should only be populated by tools that actively check the status.', + example: 'true', + name: 'threat.enrichments.indicator.file.code_signature.trusted', + type: 'boolean', + }, + 'threat.enrichments.indicator.file.code_signature.valid': { + category: 'threat', + description: + 'Boolean to capture if the digital signature is verified against the binary content. Leave unpopulated if a certificate was unchecked.', + example: 'true', + name: 'threat.enrichments.indicator.file.code_signature.valid', + type: 'boolean', + }, + 'threat.enrichments.indicator.file.created': { + category: 'threat', + description: 'File creation time. Note that not all filesystems store the creation time.', + name: 'threat.enrichments.indicator.file.created', type: 'date', }, - 'tls.client.server_name': { - category: 'tls', + 'threat.enrichments.indicator.file.ctime': { + category: 'threat', description: - 'Also called an SNI, this tells the server which hostname to which the client is attempting to connect. When this value is available, it should get copied to `destination.domain`.', - example: 'www.elastic.co', - name: 'tls.client.server_name', + 'Last time the file attributes or metadata changed. Note that changes to the file content will update `mtime`. This implies `ctime` will be adjusted at the same time, since `mtime` is an attribute of the file.', + name: 'threat.enrichments.indicator.file.ctime', + type: 'date', + }, + 'threat.enrichments.indicator.file.device': { + category: 'threat', + description: 'Device that is the source of the file.', + example: 'sda', + name: 'threat.enrichments.indicator.file.device', type: 'keyword', }, - 'tls.client.subject': { - category: 'tls', - description: 'Distinguished name of subject of the x.509 certificate presented by the client.', - example: 'CN=myclient, OU=Documentation Team, DC=mydomain, DC=com', - name: 'tls.client.subject', + 'threat.enrichments.indicator.file.directory': { + category: 'threat', + description: + 'Directory where the file is located. It should include the drive letter, when appropriate.', + example: '/home/alice', + name: 'threat.enrichments.indicator.file.directory', type: 'keyword', }, - 'tls.client.supported_ciphers': { - category: 'tls', - description: 'Array of ciphers offered by the client during the client hello.', - example: - '["TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384","TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384","..."]', - name: 'tls.client.supported_ciphers', + 'threat.enrichments.indicator.file.drive_letter': { + category: 'threat', + description: + 'Drive letter where the file is located. This field is only relevant on Windows. The value should be uppercase, and not include the colon.', + example: 'C', + name: 'threat.enrichments.indicator.file.drive_letter', type: 'keyword', }, - 'tls.curve': { - category: 'tls', - description: 'String indicating the curve used for the given cipher, when applicable.', - example: 'secp256r1', - name: 'tls.curve', + 'threat.enrichments.indicator.file.elf.architecture': { + category: 'threat', + description: 'Machine architecture of the ELF file.', + example: 'x86-64', + name: 'threat.enrichments.indicator.file.elf.architecture', type: 'keyword', }, - 'tls.established': { - category: 'tls', - description: - 'Boolean flag indicating if the TLS negotiation was successful and transitioned to an encrypted tunnel.', - name: 'tls.established', - type: 'boolean', + 'threat.enrichments.indicator.file.elf.byte_order': { + category: 'threat', + description: 'Byte sequence of ELF file.', + example: 'Little Endian', + name: 'threat.enrichments.indicator.file.elf.byte_order', + type: 'keyword', }, - 'tls.next_protocol': { - category: 'tls', - description: - 'String indicating the protocol being tunneled. Per the values in the IANA registry (https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids), this string should be lower case.', - example: 'http/1.1', - name: 'tls.next_protocol', + 'threat.enrichments.indicator.file.elf.cpu_type': { + category: 'threat', + description: 'CPU type of the ELF file.', + example: 'Intel', + name: 'threat.enrichments.indicator.file.elf.cpu_type', type: 'keyword', }, - 'tls.resumed': { - category: 'tls', + 'threat.enrichments.indicator.file.elf.creation_date': { + category: 'threat', description: - 'Boolean flag indicating if this TLS connection was resumed from an existing TLS negotiation.', - name: 'tls.resumed', - type: 'boolean', + "Extracted when possible from the file's metadata. Indicates when it was built or compiled. It can also be faked by malware creators.", + name: 'threat.enrichments.indicator.file.elf.creation_date', + type: 'date', }, - 'tls.server.certificate': { - category: 'tls', - description: - 'PEM-encoded stand-alone certificate offered by the server. This is usually mutually-exclusive of `server.certificate_chain` since this value also exists in that list.', - example: 'MII...', - name: 'tls.server.certificate', + 'threat.enrichments.indicator.file.elf.exports': { + category: 'threat', + description: 'List of exported element names and types.', + name: 'threat.enrichments.indicator.file.elf.exports', + type: 'flattened', + }, + 'threat.enrichments.indicator.file.elf.header.abi_version': { + category: 'threat', + description: 'Version of the ELF Application Binary Interface (ABI).', + name: 'threat.enrichments.indicator.file.elf.header.abi_version', type: 'keyword', }, - 'tls.server.certificate_chain': { - category: 'tls', - description: - 'Array of PEM-encoded certificates that make up the certificate chain offered by the server. This is usually mutually-exclusive of `server.certificate` since that value should be the first certificate in the chain.', - example: '["MII...","MII..."]', - name: 'tls.server.certificate_chain', + 'threat.enrichments.indicator.file.elf.header.class': { + category: 'threat', + description: 'Header class of the ELF file.', + name: 'threat.enrichments.indicator.file.elf.header.class', type: 'keyword', }, - 'tls.server.hash.md5': { - category: 'tls', - description: - 'Certificate fingerprint using the MD5 digest of DER-encoded version of certificate offered by the server. For consistency with other hash values, this value should be formatted as an uppercase hash.', - example: '0F76C7F2C55BFD7D8E8B8F4BFBF0C9EC', - name: 'tls.server.hash.md5', + 'threat.enrichments.indicator.file.elf.header.data': { + category: 'threat', + description: 'Data table of the ELF header.', + name: 'threat.enrichments.indicator.file.elf.header.data', type: 'keyword', }, - 'tls.server.hash.sha1': { - category: 'tls', - description: - 'Certificate fingerprint using the SHA1 digest of DER-encoded version of certificate offered by the server. For consistency with other hash values, this value should be formatted as an uppercase hash.', - example: '9E393D93138888D288266C2D915214D1D1CCEB2A', - name: 'tls.server.hash.sha1', + 'threat.enrichments.indicator.file.elf.header.entrypoint': { + category: 'threat', + description: 'Header entrypoint of the ELF file.', + name: 'threat.enrichments.indicator.file.elf.header.entrypoint', + type: 'long', + format: 'string', + }, + 'threat.enrichments.indicator.file.elf.header.object_version': { + category: 'threat', + description: '"0x1" for original ELF files.', + name: 'threat.enrichments.indicator.file.elf.header.object_version', type: 'keyword', }, - 'tls.server.hash.sha256': { - category: 'tls', - description: - 'Certificate fingerprint using the SHA256 digest of DER-encoded version of certificate offered by the server. For consistency with other hash values, this value should be formatted as an uppercase hash.', - example: '0687F666A054EF17A08E2F2162EAB4CBC0D265E1D7875BE74BF3C712CA92DAF0', - name: 'tls.server.hash.sha256', + 'threat.enrichments.indicator.file.elf.header.os_abi': { + category: 'threat', + description: 'Application Binary Interface (ABI) of the Linux OS.', + name: 'threat.enrichments.indicator.file.elf.header.os_abi', type: 'keyword', }, - 'tls.server.issuer': { - category: 'tls', - description: 'Subject of the issuer of the x.509 certificate presented by the server.', - example: 'CN=MyDomain Root CA, OU=Infrastructure Team, DC=mydomain, DC=com', - name: 'tls.server.issuer', + 'threat.enrichments.indicator.file.elf.header.type': { + category: 'threat', + description: 'Header type of the ELF file.', + name: 'threat.enrichments.indicator.file.elf.header.type', type: 'keyword', }, - 'tls.server.ja3s': { - category: 'tls', - description: 'A hash that identifies servers based on how they perform an SSL/TLS handshake.', - example: '394441ab65754e2207b1e1b457b3641d', - name: 'tls.server.ja3s', + 'threat.enrichments.indicator.file.elf.header.version': { + category: 'threat', + description: 'Version of the ELF header.', + name: 'threat.enrichments.indicator.file.elf.header.version', type: 'keyword', }, - 'tls.server.not_after': { - category: 'tls', - description: 'Timestamp indicating when server certificate is no longer considered valid.', - example: '2021-01-01T00:00:00.000Z', - name: 'tls.server.not_after', - type: 'date', + 'threat.enrichments.indicator.file.elf.imports': { + category: 'threat', + description: 'List of imported element names and types.', + name: 'threat.enrichments.indicator.file.elf.imports', + type: 'flattened', }, - 'tls.server.not_before': { - category: 'tls', - description: 'Timestamp indicating when server certificate is first considered valid.', - example: '1970-01-01T00:00:00.000Z', - name: 'tls.server.not_before', - type: 'date', + 'threat.enrichments.indicator.file.elf.sections': { + category: 'threat', + description: + 'An array containing an object for each section of the ELF file. The keys that should be present in these objects are defined by sub-fields underneath `elf.sections.*`.', + name: 'threat.enrichments.indicator.file.elf.sections', + type: 'nested', }, - 'tls.server.subject': { - category: 'tls', - description: 'Subject of the x.509 certificate presented by the server.', - example: 'CN=www.mydomain.com, OU=Infrastructure Team, DC=mydomain, DC=com', - name: 'tls.server.subject', + 'threat.enrichments.indicator.file.elf.sections.chi2': { + category: 'threat', + description: 'Chi-square probability distribution of the section.', + name: 'threat.enrichments.indicator.file.elf.sections.chi2', + type: 'long', + format: 'number', + }, + 'threat.enrichments.indicator.file.elf.sections.entropy': { + category: 'threat', + description: 'Shannon entropy calculation from the section.', + name: 'threat.enrichments.indicator.file.elf.sections.entropy', + type: 'long', + format: 'number', + }, + 'threat.enrichments.indicator.file.elf.sections.flags': { + category: 'threat', + description: 'ELF Section List flags.', + name: 'threat.enrichments.indicator.file.elf.sections.flags', type: 'keyword', }, - 'tls.version': { - category: 'tls', - description: 'Numeric part of the version parsed from the original string.', - example: '1.2', - name: 'tls.version', + 'threat.enrichments.indicator.file.elf.sections.name': { + category: 'threat', + description: 'ELF Section List name.', + name: 'threat.enrichments.indicator.file.elf.sections.name', type: 'keyword', }, - 'tls.version_protocol': { - category: 'tls', - description: 'Normalized lowercase protocol name parsed from original string.', - example: 'tls', - name: 'tls.version_protocol', + 'threat.enrichments.indicator.file.elf.sections.physical_offset': { + category: 'threat', + description: 'ELF Section List offset.', + name: 'threat.enrichments.indicator.file.elf.sections.physical_offset', type: 'keyword', }, - 'tracing.trace.id': { - category: 'tracing', - description: - 'Unique identifier of the trace. A trace groups multiple events like transactions that belong together. For example, a user request handled by multiple inter-connected services.', - example: '4bf92f3577b34da6a3ce929d0e0e4736', - name: 'tracing.trace.id', + 'threat.enrichments.indicator.file.elf.sections.physical_size': { + category: 'threat', + description: 'ELF Section List physical size.', + name: 'threat.enrichments.indicator.file.elf.sections.physical_size', + type: 'long', + format: 'bytes', + }, + 'threat.enrichments.indicator.file.elf.sections.type': { + category: 'threat', + description: 'ELF Section List type.', + name: 'threat.enrichments.indicator.file.elf.sections.type', type: 'keyword', }, - 'tracing.transaction.id': { - category: 'tracing', + 'threat.enrichments.indicator.file.elf.sections.virtual_address': { + category: 'threat', + description: 'ELF Section List virtual address.', + name: 'threat.enrichments.indicator.file.elf.sections.virtual_address', + type: 'long', + format: 'string', + }, + 'threat.enrichments.indicator.file.elf.sections.virtual_size': { + category: 'threat', + description: 'ELF Section List virtual size.', + name: 'threat.enrichments.indicator.file.elf.sections.virtual_size', + type: 'long', + format: 'string', + }, + 'threat.enrichments.indicator.file.elf.segments': { + category: 'threat', description: - 'Unique identifier of the transaction. A transaction is the highest level of work measured within a service, such as a request to a server.', - example: '00f067aa0ba902b7', - name: 'tracing.transaction.id', + 'An array containing an object for each segment of the ELF file. The keys that should be present in these objects are defined by sub-fields underneath `elf.segments.*`.', + name: 'threat.enrichments.indicator.file.elf.segments', + type: 'nested', + }, + 'threat.enrichments.indicator.file.elf.segments.sections': { + category: 'threat', + description: 'ELF object segment sections.', + name: 'threat.enrichments.indicator.file.elf.segments.sections', type: 'keyword', }, - 'url.domain': { - category: 'url', - description: - 'Domain of the url, such as "www.elastic.co". In some cases a URL may refer to an IP and/or port directly, without a domain name. In this case, the IP address would go to the `domain` field.', - example: 'www.elastic.co', - name: 'url.domain', + 'threat.enrichments.indicator.file.elf.segments.type': { + category: 'threat', + description: 'ELF object segment type.', + name: 'threat.enrichments.indicator.file.elf.segments.type', type: 'keyword', }, - 'url.extension': { - category: 'url', + 'threat.enrichments.indicator.file.elf.shared_libraries': { + category: 'threat', + description: 'List of shared libraries used by this ELF object.', + name: 'threat.enrichments.indicator.file.elf.shared_libraries', + type: 'keyword', + }, + 'threat.enrichments.indicator.file.elf.telfhash': { + category: 'threat', + description: 'telfhash symbol hash for ELF file.', + name: 'threat.enrichments.indicator.file.elf.telfhash', + type: 'keyword', + }, + 'threat.enrichments.indicator.file.extension': { + category: 'threat', description: - 'The field contains the file extension from the original request url. The file extension is only set if it exists, as not every url has a file extension. The leading period must not be included. For example, the value must be "png", not ".png".', + 'File extension, excluding the leading dot. Note that when the file name has multiple extensions (example.tar.gz), only the last one should be captured ("gz", not "tar.gz").', example: 'png', - name: 'url.extension', + name: 'threat.enrichments.indicator.file.extension', type: 'keyword', }, - 'url.fragment': { - category: 'url', + 'threat.enrichments.indicator.file.fork_name': { + category: 'threat', description: - 'Portion of the url after the `#`, such as "top". The `#` is not part of the fragment.', - name: 'url.fragment', + 'A fork is additional data associated with a filesystem object. On Linux, a resource fork is used to store additional data with a filesystem object. A file always has at least one fork for the data portion, and additional forks may exist. On NTFS, this is analogous to an Alternate Data Stream (ADS), and the default data stream for a file is just called $DATA. Zone.Identifier is commonly used by Windows to track contents downloaded from the Internet. An ADS is typically of the form: `C:\\path\\to\\filename.extension:some_fork_name`, and `some_fork_name` is the value that should populate `fork_name`. `filename.extension` should populate `file.name`, and `extension` should populate `file.extension`. The full path, `file.path`, will include the fork name.', + example: 'Zone.Identifer', + name: 'threat.enrichments.indicator.file.fork_name', type: 'keyword', }, - 'url.full': { - category: 'url', - description: - 'If full URLs are important to your use case, they should be stored in `url.full`, whether this field is reconstructed or present in the event source.', - example: 'https://www.elastic.co:443/search?q=elasticsearch#top', - name: 'url.full', + 'threat.enrichments.indicator.file.gid': { + category: 'threat', + description: 'Primary group ID (GID) of the file.', + example: '1001', + name: 'threat.enrichments.indicator.file.gid', type: 'keyword', }, - 'url.original': { - category: 'url', - description: - 'Unmodified original url as seen in the event source. Note that in network monitoring, the observed URL may be a full URL, whereas in access logs, the URL is often just represented as a path. This field is meant to represent the URL as it was observed, complete or not.', - example: 'https://www.elastic.co:443/search?q=elasticsearch#top or /search?q=elasticsearch', - name: 'url.original', + 'threat.enrichments.indicator.file.group': { + category: 'threat', + description: 'Primary group name of the file.', + example: 'alice', + name: 'threat.enrichments.indicator.file.group', type: 'keyword', }, - 'url.password': { - category: 'url', - description: 'Password of the request.', - name: 'url.password', + 'threat.enrichments.indicator.file.hash.md5': { + category: 'threat', + description: 'MD5 hash.', + name: 'threat.enrichments.indicator.file.hash.md5', type: 'keyword', }, - 'url.path': { - category: 'url', - description: 'Path of the request, such as "/search".', - name: 'url.path', + 'threat.enrichments.indicator.file.hash.sha1': { + category: 'threat', + description: 'SHA1 hash.', + name: 'threat.enrichments.indicator.file.hash.sha1', type: 'keyword', }, - 'url.port': { - category: 'url', - description: 'Port of the request, such as 443.', - example: 443, - name: 'url.port', - type: 'long', - format: 'string', + 'threat.enrichments.indicator.file.hash.sha256': { + category: 'threat', + description: 'SHA256 hash.', + name: 'threat.enrichments.indicator.file.hash.sha256', + type: 'keyword', }, - 'url.query': { - category: 'url', - description: - 'The query field describes the query string of the request, such as "q=elasticsearch". The `?` is excluded from the query string. If a URL contains no `?`, there is no query field. If there is a `?` but no query, the query field exists with an empty string. The `exists` query can be used to differentiate between the two cases.', - name: 'url.query', + 'threat.enrichments.indicator.file.hash.sha512': { + category: 'threat', + description: 'SHA512 hash.', + name: 'threat.enrichments.indicator.file.hash.sha512', type: 'keyword', }, - 'url.registered_domain': { - category: 'url', - description: - 'The highest registered url domain, stripped of the subdomain. For example, the registered domain for "foo.google.com" is "google.com". This value can be determined precisely with a list like the public suffix list (http://publicsuffix.org). Trying to approximate this by simply taking the last two labels will not work well for TLDs such as "co.uk".', - example: 'google.com', - name: 'url.registered_domain', + 'threat.enrichments.indicator.file.hash.ssdeep': { + category: 'threat', + description: 'SSDEEP hash.', + name: 'threat.enrichments.indicator.file.hash.ssdeep', type: 'keyword', }, - 'url.scheme': { - category: 'url', - description: 'Scheme of the request, such as "https". Note: The `:` is not part of the scheme.', - example: 'https', - name: 'url.scheme', + 'threat.enrichments.indicator.file.inode': { + category: 'threat', + description: 'Inode representing the file in the filesystem.', + example: '256383', + name: 'threat.enrichments.indicator.file.inode', type: 'keyword', }, - 'url.top_level_domain': { - category: 'url', + 'threat.enrichments.indicator.file.mime_type': { + category: 'threat', description: - 'The effective top level domain (eTLD), also known as the domain suffix, is the last part of the domain name. For example, the top level domain for google.com is "com". This value can be determined precisely with a list like the public suffix list (http://publicsuffix.org). Trying to approximate this by simply taking the last label will not work well for effective TLDs such as "co.uk".', - example: 'co.uk', - name: 'url.top_level_domain', + 'MIME type should identify the format of the file or stream of bytes using https://www.iana.org/assignments/media-types/media-types.xhtml[IANA official types], where possible. When more than one type is applicable, the most specific type should be used.', + name: 'threat.enrichments.indicator.file.mime_type', type: 'keyword', }, - 'url.username': { - category: 'url', - description: 'Username of the request.', - name: 'url.username', + 'threat.enrichments.indicator.file.mode': { + category: 'threat', + description: 'Mode of the file in octal representation.', + example: '0640', + name: 'threat.enrichments.indicator.file.mode', type: 'keyword', }, - 'user.domain': { - category: 'user', - description: - 'Name of the directory the user is a member of. For example, an LDAP or Active Directory domain name.', - name: 'user.domain', - type: 'keyword', + 'threat.enrichments.indicator.file.mtime': { + category: 'threat', + description: 'Last time the file content was modified.', + name: 'threat.enrichments.indicator.file.mtime', + type: 'date', }, - 'user.email': { - category: 'user', - description: 'User email address.', - name: 'user.email', + 'threat.enrichments.indicator.file.name': { + category: 'threat', + description: 'Name of the file including the extension, without the directory.', + example: 'example.png', + name: 'threat.enrichments.indicator.file.name', type: 'keyword', }, - 'user.full_name': { - category: 'user', - description: "User's full name, if available.", - example: 'Albert Einstein', - name: 'user.full_name', + 'threat.enrichments.indicator.file.owner': { + category: 'threat', + description: "File owner's username.", + example: 'alice', + name: 'threat.enrichments.indicator.file.owner', type: 'keyword', }, - 'user.group.domain': { - category: 'user', + 'threat.enrichments.indicator.file.path': { + category: 'threat', description: - 'Name of the directory the group is a member of. For example, an LDAP or Active Directory domain name.', - name: 'user.group.domain', + 'Full path to the file, including the file name. It should include the drive letter, when appropriate.', + example: '/home/alice/example.png', + name: 'threat.enrichments.indicator.file.path', type: 'keyword', }, - 'user.group.id': { - category: 'user', - description: 'Unique identifier for the group on the system/platform.', - name: 'user.group.id', + 'threat.enrichments.indicator.file.pe.architecture': { + category: 'threat', + description: 'CPU architecture target for the file.', + example: 'x64', + name: 'threat.enrichments.indicator.file.pe.architecture', type: 'keyword', }, - 'user.group.name': { - category: 'user', - description: 'Name of the group.', - name: 'user.group.name', + 'threat.enrichments.indicator.file.pe.company': { + category: 'threat', + description: 'Internal company name of the file, provided at compile-time.', + example: 'Microsoft Corporation', + name: 'threat.enrichments.indicator.file.pe.company', type: 'keyword', }, - 'user.hash': { - category: 'user', - description: - 'Unique user hash to correlate information for a user in anonymized form. Useful if `user.id` or `user.name` contain confidential information and cannot be used.', - name: 'user.hash', + 'threat.enrichments.indicator.file.pe.description': { + category: 'threat', + description: 'Internal description of the file, provided at compile-time.', + example: 'Paint', + name: 'threat.enrichments.indicator.file.pe.description', type: 'keyword', }, - 'user.id': { - category: 'user', - description: 'Unique identifiers of the user.', - name: 'user.id', + 'threat.enrichments.indicator.file.pe.file_version': { + category: 'threat', + description: 'Internal version of the file, provided at compile-time.', + example: '6.3.9600.17415', + name: 'threat.enrichments.indicator.file.pe.file_version', type: 'keyword', }, - 'user.name': { - category: 'user', - description: 'Short name or login of the user.', - example: 'albert', - name: 'user.name', + 'threat.enrichments.indicator.file.pe.imphash': { + category: 'threat', + description: + 'A hash of the imports in a PE file. An imphash -- or import hash -- can be used to fingerprint binaries even after recompilation or other code-level transformations have occurred, which would change more traditional hash values. Learn more at https://www.fireeye.com/blog/threat-research/2014/01/tracking-malware-import-hashing.html.', + example: '0c6803c4e922103c4dca5963aad36ddf', + name: 'threat.enrichments.indicator.file.pe.imphash', type: 'keyword', }, - 'user_agent.device.name': { - category: 'user_agent', - description: 'Name of the device.', - example: 'iPhone', - name: 'user_agent.device.name', + 'threat.enrichments.indicator.file.pe.original_file_name': { + category: 'threat', + description: 'Internal name of the file, provided at compile-time.', + example: 'MSPAINT.EXE', + name: 'threat.enrichments.indicator.file.pe.original_file_name', type: 'keyword', }, - 'user_agent.name': { - category: 'user_agent', - description: 'Name of the user agent.', - example: 'Safari', - name: 'user_agent.name', + 'threat.enrichments.indicator.file.pe.product': { + category: 'threat', + description: 'Internal product name of the file, provided at compile-time.', + example: 'Microsoft® Windows® Operating System', + name: 'threat.enrichments.indicator.file.pe.product', type: 'keyword', }, - 'user_agent.original': { - category: 'user_agent', - description: 'Unparsed user_agent string.', - example: - 'Mozilla/5.0 (iPhone; CPU iPhone OS 12_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0 Mobile/15E148 Safari/604.1', - name: 'user_agent.original', - type: 'keyword', + 'threat.enrichments.indicator.file.size': { + category: 'threat', + description: 'File size in bytes. Only relevant when `file.type` is "file".', + example: 16384, + name: 'threat.enrichments.indicator.file.size', + type: 'long', }, - 'user_agent.os.family': { - category: 'user_agent', - description: 'OS family (such as redhat, debian, freebsd, windows).', - example: 'debian', - name: 'user_agent.os.family', + 'threat.enrichments.indicator.file.target_path': { + category: 'threat', + description: 'Target path for symlinks.', + name: 'threat.enrichments.indicator.file.target_path', type: 'keyword', }, - 'user_agent.os.full': { - category: 'user_agent', - description: 'Operating system name, including the version or code name.', - example: 'Mac OS Mojave', - name: 'user_agent.os.full', + 'threat.enrichments.indicator.file.type': { + category: 'threat', + description: 'File type (file, dir, or symlink).', + example: 'file', + name: 'threat.enrichments.indicator.file.type', type: 'keyword', }, - 'user_agent.os.kernel': { - category: 'user_agent', - description: 'Operating system kernel version as a raw string.', - example: '4.4.0-112-generic', - name: 'user_agent.os.kernel', + 'threat.enrichments.indicator.file.uid': { + category: 'threat', + description: 'The user ID (UID) or security identifier (SID) of the file owner.', + example: '1001', + name: 'threat.enrichments.indicator.file.uid', type: 'keyword', }, - 'user_agent.os.name': { - category: 'user_agent', - description: 'Operating system name, without the version.', - example: 'Mac OS X', - name: 'user_agent.os.name', + 'threat.enrichments.indicator.file.x509.alternative_names': { + category: 'threat', + description: + 'List of subject alternative names (SAN). Name types vary by certificate authority and certificate type but commonly contain IP addresses, DNS names (and wildcards), and email addresses.', + example: '*.elastic.co', + name: 'threat.enrichments.indicator.file.x509.alternative_names', type: 'keyword', }, - 'user_agent.os.platform': { - category: 'user_agent', - description: 'Operating system platform (such centos, ubuntu, windows).', - example: 'darwin', - name: 'user_agent.os.platform', + 'threat.enrichments.indicator.file.x509.issuer.common_name': { + category: 'threat', + description: 'List of common name (CN) of issuing certificate authority.', + example: 'Example SHA2 High Assurance Server CA', + name: 'threat.enrichments.indicator.file.x509.issuer.common_name', type: 'keyword', }, - 'user_agent.os.version': { - category: 'user_agent', - description: 'Operating system version as a raw string.', - example: '10.14.1', - name: 'user_agent.os.version', + 'threat.enrichments.indicator.file.x509.issuer.country': { + category: 'threat', + description: 'List of country (C) codes', + example: 'US', + name: 'threat.enrichments.indicator.file.x509.issuer.country', type: 'keyword', }, - 'user_agent.version': { - category: 'user_agent', - description: 'Version of the user agent.', - example: 12, - name: 'user_agent.version', + 'threat.enrichments.indicator.file.x509.issuer.distinguished_name': { + category: 'threat', + description: 'Distinguished name (DN) of issuing certificate authority.', + example: 'C=US, O=Example Inc, OU=www.example.com, CN=Example SHA2 High Assurance Server CA', + name: 'threat.enrichments.indicator.file.x509.issuer.distinguished_name', type: 'keyword', }, - 'vlan.id': { - category: 'vlan', - description: 'VLAN ID as reported by the observer.', - example: 10, - name: 'vlan.id', + 'threat.enrichments.indicator.file.x509.issuer.locality': { + category: 'threat', + description: 'List of locality names (L)', + example: 'Mountain View', + name: 'threat.enrichments.indicator.file.x509.issuer.locality', type: 'keyword', }, - 'vlan.name': { - category: 'vlan', - description: 'Optional VLAN name as reported by the observer.', - example: 'outside', - name: 'vlan.name', + 'threat.enrichments.indicator.file.x509.issuer.organization': { + category: 'threat', + description: 'List of organizations (O) of issuing certificate authority.', + example: 'Example Inc', + name: 'threat.enrichments.indicator.file.x509.issuer.organization', type: 'keyword', }, - 'vulnerability.category': { - category: 'vulnerability', - description: - 'The type of system or architecture that the vulnerability affects. These may be platform-specific (for example, Debian or SUSE) or general (for example, Database or Firewall). For example (https://qualysguard.qualys.com/qwebhelp/fo_portal/knowledgebase/vulnerability_categories.htm[Qualys vulnerability categories]) This field must be an array.', - example: '["Firewall"]', - name: 'vulnerability.category', + 'threat.enrichments.indicator.file.x509.issuer.organizational_unit': { + category: 'threat', + description: 'List of organizational units (OU) of issuing certificate authority.', + example: 'www.example.com', + name: 'threat.enrichments.indicator.file.x509.issuer.organizational_unit', type: 'keyword', }, - 'vulnerability.classification': { - category: 'vulnerability', - description: - 'The classification of the vulnerability scoring system. For example (https://www.first.org/cvss/)', - example: 'CVSS', - name: 'vulnerability.classification', + 'threat.enrichments.indicator.file.x509.issuer.state_or_province': { + category: 'threat', + description: 'List of state or province names (ST, S, or P)', + example: 'California', + name: 'threat.enrichments.indicator.file.x509.issuer.state_or_province', type: 'keyword', }, - 'vulnerability.description': { - category: 'vulnerability', - description: - 'The description of the vulnerability that provides additional context of the vulnerability. For example (https://cve.mitre.org/about/faqs.html#cve_entry_descriptions_created[Common Vulnerabilities and Exposure CVE description])', - example: 'In macOS before 2.12.6, there is a vulnerability in the RPC...', - name: 'vulnerability.description', + 'threat.enrichments.indicator.file.x509.not_after': { + category: 'threat', + description: 'Time at which the certificate is no longer considered valid.', + example: '"2020-07-16T03:15:39.000Z"', + name: 'threat.enrichments.indicator.file.x509.not_after', + type: 'date', + }, + 'threat.enrichments.indicator.file.x509.not_before': { + category: 'threat', + description: 'Time at which the certificate is first considered valid.', + example: '"2019-08-16T01:40:25.000Z"', + name: 'threat.enrichments.indicator.file.x509.not_before', + type: 'date', + }, + 'threat.enrichments.indicator.file.x509.public_key_algorithm': { + category: 'threat', + description: 'Algorithm used to generate the public key.', + example: 'RSA', + name: 'threat.enrichments.indicator.file.x509.public_key_algorithm', type: 'keyword', }, - 'vulnerability.enumeration': { - category: 'vulnerability', + 'threat.enrichments.indicator.file.x509.public_key_curve': { + category: 'threat', description: - 'The type of identifier used for this vulnerability. For example (https://cve.mitre.org/about/)', - example: 'CVE', - name: 'vulnerability.enumeration', + 'The curve used by the elliptic curve public key algorithm. This is algorithm specific.', + example: 'nistp521', + name: 'threat.enrichments.indicator.file.x509.public_key_curve', type: 'keyword', }, - 'vulnerability.id': { - category: 'vulnerability', + 'threat.enrichments.indicator.file.x509.public_key_exponent': { + category: 'threat', + description: 'Exponent used to derive the public key. This is algorithm specific.', + example: 65537, + name: 'threat.enrichments.indicator.file.x509.public_key_exponent', + type: 'long', + }, + 'threat.enrichments.indicator.file.x509.public_key_size': { + category: 'threat', + description: 'The size of the public key space in bits.', + example: 2048, + name: 'threat.enrichments.indicator.file.x509.public_key_size', + type: 'long', + }, + 'threat.enrichments.indicator.file.x509.serial_number': { + category: 'threat', description: - 'The identification (ID) is the number portion of a vulnerability entry. It includes a unique identification number for the vulnerability. For example (https://cve.mitre.org/about/faqs.html#what_is_cve_id)[Common Vulnerabilities and Exposure CVE ID]', - example: 'CVE-2019-00001', - name: 'vulnerability.id', + 'Unique serial number issued by the certificate authority. For consistency, if this value is alphanumeric, it should be formatted without colons and uppercase characters.', + example: '55FBB9C7DEBF09809D12CCAA', + name: 'threat.enrichments.indicator.file.x509.serial_number', type: 'keyword', }, - 'vulnerability.reference': { - category: 'vulnerability', + 'threat.enrichments.indicator.file.x509.signature_algorithm': { + category: 'threat', description: - 'A resource that provides additional information, context, and mitigations for the identified vulnerability.', - example: 'https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-6111', - name: 'vulnerability.reference', + 'Identifier for certificate signature algorithm. We recommend using names found in Go Lang Crypto library. See https://github.com/golang/go/blob/go1.14/src/crypto/x509/x509.go#L337-L353.', + example: 'SHA256-RSA', + name: 'threat.enrichments.indicator.file.x509.signature_algorithm', type: 'keyword', }, - 'vulnerability.report_id': { - category: 'vulnerability', - description: 'The report or scan identification number.', - example: 20191018.0001, - name: 'vulnerability.report_id', + 'threat.enrichments.indicator.file.x509.subject.common_name': { + category: 'threat', + description: 'List of common names (CN) of subject.', + example: 'shared.global.example.net', + name: 'threat.enrichments.indicator.file.x509.subject.common_name', type: 'keyword', }, - 'vulnerability.scanner.vendor': { - category: 'vulnerability', - description: 'The name of the vulnerability scanner vendor.', - example: 'Tenable', - name: 'vulnerability.scanner.vendor', + 'threat.enrichments.indicator.file.x509.subject.country': { + category: 'threat', + description: 'List of country (C) code', + example: 'US', + name: 'threat.enrichments.indicator.file.x509.subject.country', type: 'keyword', }, - 'vulnerability.score.base': { - category: 'vulnerability', - description: - 'Scores can range from 0.0 to 10.0, with 10.0 being the most severe. Base scores cover an assessment for exploitability metrics (attack vector, complexity, privileges, and user interaction), impact metrics (confidentiality, integrity, and availability), and scope. For example (https://www.first.org/cvss/specification-document)', - example: 5.5, - name: 'vulnerability.score.base', - type: 'float', - }, - 'vulnerability.score.environmental': { - category: 'vulnerability', - description: - 'Scores can range from 0.0 to 10.0, with 10.0 being the most severe. Environmental scores cover an assessment for any modified Base metrics, confidentiality, integrity, and availability requirements. For example (https://www.first.org/cvss/specification-document)', - example: 5.5, - name: 'vulnerability.score.environmental', - type: 'float', + 'threat.enrichments.indicator.file.x509.subject.distinguished_name': { + category: 'threat', + description: 'Distinguished name (DN) of the certificate subject entity.', + example: 'C=US, ST=California, L=San Francisco, O=Example, Inc., CN=shared.global.example.net', + name: 'threat.enrichments.indicator.file.x509.subject.distinguished_name', + type: 'keyword', }, - 'vulnerability.score.temporal': { - category: 'vulnerability', - description: - 'Scores can range from 0.0 to 10.0, with 10.0 being the most severe. Temporal scores cover an assessment for code maturity, remediation level, and confidence. For example (https://www.first.org/cvss/specification-document)', - name: 'vulnerability.score.temporal', - type: 'float', + 'threat.enrichments.indicator.file.x509.subject.locality': { + category: 'threat', + description: 'List of locality names (L)', + example: 'San Francisco', + name: 'threat.enrichments.indicator.file.x509.subject.locality', + type: 'keyword', }, - 'vulnerability.score.version': { - category: 'vulnerability', - description: - 'The National Vulnerability Database (NVD) provides qualitative severity rankings of "Low", "Medium", and "High" for CVSS v2.0 base score ranges in addition to the severity ratings for CVSS v3.0 as they are defined in the CVSS v3.0 specification. CVSS is owned and managed by FIRST.Org, Inc. (FIRST), a US-based non-profit organization, whose mission is to help computer security incident response teams across the world. For example (https://nvd.nist.gov/vuln-metrics/cvss)', - example: 2, - name: 'vulnerability.score.version', + 'threat.enrichments.indicator.file.x509.subject.organization': { + category: 'threat', + description: 'List of organizations (O) of subject.', + example: 'Example, Inc.', + name: 'threat.enrichments.indicator.file.x509.subject.organization', type: 'keyword', }, - 'vulnerability.severity': { - category: 'vulnerability', - description: - 'The severity of the vulnerability can help with metrics and internal prioritization regarding remediation. For example (https://nvd.nist.gov/vuln-metrics/cvss)', - example: 'Critical', - name: 'vulnerability.severity', + 'threat.enrichments.indicator.file.x509.subject.organizational_unit': { + category: 'threat', + description: 'List of organizational units (OU) of subject.', + name: 'threat.enrichments.indicator.file.x509.subject.organizational_unit', type: 'keyword', }, - 'agent.hostname': { - category: 'agent', - description: - 'Deprecated - use agent.name or agent.id to identify an agent. Hostname of the agent. ', - name: 'agent.hostname', + 'threat.enrichments.indicator.file.x509.subject.state_or_province': { + category: 'threat', + description: 'List of state or province names (ST, S, or P)', + example: 'California', + name: 'threat.enrichments.indicator.file.x509.subject.state_or_province', type: 'keyword', }, - 'beat.timezone': { - category: 'beat', - name: 'beat.timezone', - type: 'alias', + 'threat.enrichments.indicator.file.x509.version_number': { + category: 'threat', + description: 'Version of x509 format.', + example: 3, + name: 'threat.enrichments.indicator.file.x509.version_number', + type: 'keyword', }, - fields: { - category: 'base', - description: 'Contains user configurable fields. ', - name: 'fields', - type: 'object', + 'threat.enrichments.indicator.first_seen': { + category: 'threat', + description: + 'The date and time when intelligence source first reported sighting this indicator.', + example: '2020-11-05T17:25:47.000Z', + name: 'threat.enrichments.indicator.first_seen', + type: 'date', }, - 'beat.name': { - category: 'beat', - name: 'beat.name', - type: 'alias', + 'threat.enrichments.indicator.geo.city_name': { + category: 'threat', + description: 'City name.', + example: 'Montreal', + name: 'threat.enrichments.indicator.geo.city_name', + type: 'keyword', }, - 'beat.hostname': { - category: 'beat', - name: 'beat.hostname', - type: 'alias', + 'threat.enrichments.indicator.geo.continent_code': { + category: 'threat', + description: "Two-letter code representing continent's name.", + example: 'NA', + name: 'threat.enrichments.indicator.geo.continent_code', + type: 'keyword', }, - 'timeseries.instance': { - category: 'timeseries', - description: 'Time series instance id', - name: 'timeseries.instance', + 'threat.enrichments.indicator.geo.continent_name': { + category: 'threat', + description: 'Name of the continent.', + example: 'North America', + name: 'threat.enrichments.indicator.geo.continent_name', type: 'keyword', }, - 'cloud.project.id': { - category: 'cloud', - description: 'Name of the project in Google Cloud. ', - example: 'project-x', - name: 'cloud.project.id', + 'threat.enrichments.indicator.geo.country_iso_code': { + category: 'threat', + description: 'Country ISO code.', + example: 'CA', + name: 'threat.enrichments.indicator.geo.country_iso_code', + type: 'keyword', }, - 'cloud.image.id': { - category: 'cloud', - description: 'Image ID for the cloud instance. ', - example: 'ami-abcd1234', - name: 'cloud.image.id', + 'threat.enrichments.indicator.geo.country_name': { + category: 'threat', + description: 'Country name.', + example: 'Canada', + name: 'threat.enrichments.indicator.geo.country_name', + type: 'keyword', }, - 'meta.cloud.provider': { - category: 'meta', - name: 'meta.cloud.provider', - type: 'alias', + 'threat.enrichments.indicator.geo.location': { + category: 'threat', + description: 'Longitude and latitude.', + example: '{ "lon": -73.614830, "lat": 45.505918 }', + name: 'threat.enrichments.indicator.geo.location', + type: 'geo_point', }, - 'meta.cloud.instance_id': { - category: 'meta', - name: 'meta.cloud.instance_id', - type: 'alias', + 'threat.enrichments.indicator.geo.name': { + category: 'threat', + description: + 'User-defined description of a location, at the level of granularity they care about. Could be the name of their data centers, the floor number, if this describes a local physical entity, city names. Not typically used in automated geolocation.', + example: 'boston-dc', + name: 'threat.enrichments.indicator.geo.name', + type: 'keyword', }, - 'meta.cloud.instance_name': { - category: 'meta', - name: 'meta.cloud.instance_name', - type: 'alias', + 'threat.enrichments.indicator.geo.postal_code': { + category: 'threat', + description: + 'Postal code associated with the location. Values appropriate for this field may also be known as a postcode or ZIP code and will vary widely from country to country.', + example: 94040, + name: 'threat.enrichments.indicator.geo.postal_code', + type: 'keyword', }, - 'meta.cloud.machine_type': { - category: 'meta', - name: 'meta.cloud.machine_type', - type: 'alias', + 'threat.enrichments.indicator.geo.region_iso_code': { + category: 'threat', + description: 'Region ISO code.', + example: 'CA-QC', + name: 'threat.enrichments.indicator.geo.region_iso_code', + type: 'keyword', }, - 'meta.cloud.availability_zone': { - category: 'meta', - name: 'meta.cloud.availability_zone', - type: 'alias', + 'threat.enrichments.indicator.geo.region_name': { + category: 'threat', + description: 'Region name.', + example: 'Quebec', + name: 'threat.enrichments.indicator.geo.region_name', + type: 'keyword', }, - 'meta.cloud.project_id': { - category: 'meta', - name: 'meta.cloud.project_id', - type: 'alias', + 'threat.enrichments.indicator.geo.timezone': { + category: 'threat', + description: 'The time zone of the location, such as IANA time zone name.', + example: 'America/Argentina/Buenos_Aires', + name: 'threat.enrichments.indicator.geo.timezone', + type: 'keyword', }, - 'meta.cloud.region': { - category: 'meta', - name: 'meta.cloud.region', - type: 'alias', + 'threat.enrichments.indicator.ip': { + category: 'threat', + description: 'Identifies a threat indicator as an IP address (irrespective of direction).', + example: '1.2.3.4', + name: 'threat.enrichments.indicator.ip', + type: 'ip', }, - 'docker.container.id': { - category: 'docker', - name: 'docker.container.id', - type: 'alias', + 'threat.enrichments.indicator.last_seen': { + category: 'threat', + description: + 'The date and time when intelligence source last reported sighting this indicator.', + example: '2020-11-05T17:25:47.000Z', + name: 'threat.enrichments.indicator.last_seen', + type: 'date', }, - 'docker.container.image': { - category: 'docker', - name: 'docker.container.image', - type: 'alias', + 'threat.enrichments.indicator.marking.tlp': { + category: 'threat', + description: + 'Traffic Light Protocol sharing markings. Recommended values are: * WHITE * GREEN * AMBER * RED', + example: 'White', + name: 'threat.enrichments.indicator.marking.tlp', + type: 'keyword', }, - 'docker.container.name': { - category: 'docker', - name: 'docker.container.name', - type: 'alias', + 'threat.enrichments.indicator.modified_at': { + category: 'threat', + description: + 'The date and time when intelligence source last modified information for this indicator.', + example: '2020-11-05T17:25:47.000Z', + name: 'threat.enrichments.indicator.modified_at', + type: 'date', }, - 'docker.container.labels': { - category: 'docker', - description: 'Image labels. ', - name: 'docker.container.labels', - type: 'object', + 'threat.enrichments.indicator.port': { + category: 'threat', + description: 'Identifies a threat indicator as a port number (irrespective of direction).', + example: 443, + name: 'threat.enrichments.indicator.port', + type: 'long', }, - 'host.containerized': { - category: 'host', - description: 'If the host is a container. ', - name: 'host.containerized', - type: 'boolean', + 'threat.enrichments.indicator.provider': { + category: 'threat', + description: "The name of the indicator's provider.", + example: 'lrz_urlhaus', + name: 'threat.enrichments.indicator.provider', + type: 'keyword', }, - 'host.os.build': { - category: 'host', - description: 'OS build information. ', - example: '18D109', - name: 'host.os.build', + 'threat.enrichments.indicator.reference': { + category: 'threat', + description: 'Reference URL linking to additional information about this indicator.', + example: 'https://system.example.com/indicator/0001234', + name: 'threat.enrichments.indicator.reference', type: 'keyword', }, - 'host.os.codename': { - category: 'host', - description: 'OS codename, if any. ', - example: 'stretch', - name: 'host.os.codename', + 'threat.enrichments.indicator.registry.data.bytes': { + category: 'threat', + description: + 'Original bytes written with base64 encoding. For Windows registry operations, such as SetValueEx and RegQueryValueEx, this corresponds to the data pointed by `lp_data`. This is optional but provides better recoverability and should be populated for REG_BINARY encoded values.', + example: 'ZQBuAC0AVQBTAAAAZQBuAAAAAAA=', + name: 'threat.enrichments.indicator.registry.data.bytes', type: 'keyword', }, - 'kubernetes.pod.name': { - category: 'kubernetes', - description: 'Kubernetes pod name ', - name: 'kubernetes.pod.name', - type: 'keyword', + 'threat.enrichments.indicator.registry.data.strings': { + category: 'threat', + description: + 'Content when writing string types. Populated as an array when writing string data to the registry. For single string registry types (REG_SZ, REG_EXPAND_SZ), this should be an array with one string. For sequences of string with REG_MULTI_SZ, this array will be variable length. For numeric data, such as REG_DWORD and REG_QWORD, this should be populated with the decimal representation (e.g `"1"`).', + example: '["C:\\rta\\red_ttp\\bin\\myapp.exe"]', + name: 'threat.enrichments.indicator.registry.data.strings', + type: 'wildcard', }, - 'kubernetes.pod.uid': { - category: 'kubernetes', - description: 'Kubernetes Pod UID ', - name: 'kubernetes.pod.uid', + 'threat.enrichments.indicator.registry.data.type': { + category: 'threat', + description: 'Standard registry type for encoding contents', + example: 'REG_SZ', + name: 'threat.enrichments.indicator.registry.data.type', type: 'keyword', }, - 'kubernetes.namespace': { - category: 'kubernetes', - description: 'Kubernetes namespace ', - name: 'kubernetes.namespace', + 'threat.enrichments.indicator.registry.hive': { + category: 'threat', + description: 'Abbreviated name for the hive.', + example: 'HKLM', + name: 'threat.enrichments.indicator.registry.hive', type: 'keyword', }, - 'kubernetes.node.name': { - category: 'kubernetes', - description: 'Kubernetes node name ', - name: 'kubernetes.node.name', + 'threat.enrichments.indicator.registry.key': { + category: 'threat', + description: 'Hive-relative path of keys.', + example: + 'SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\winword.exe', + name: 'threat.enrichments.indicator.registry.key', type: 'keyword', }, - 'kubernetes.labels.*': { - category: 'kubernetes', - description: 'Kubernetes labels map ', - name: 'kubernetes.labels.*', - type: 'object', - }, - 'kubernetes.annotations.*': { - category: 'kubernetes', - description: 'Kubernetes annotations map ', - name: 'kubernetes.annotations.*', - type: 'object', - }, - 'kubernetes.replicaset.name': { - category: 'kubernetes', - description: 'Kubernetes replicaset name ', - name: 'kubernetes.replicaset.name', + 'threat.enrichments.indicator.registry.path': { + category: 'threat', + description: 'Full path, including hive, key and value', + example: + 'HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\winword.exe\\Debugger', + name: 'threat.enrichments.indicator.registry.path', type: 'keyword', }, - 'kubernetes.deployment.name': { - category: 'kubernetes', - description: 'Kubernetes deployment name ', - name: 'kubernetes.deployment.name', + 'threat.enrichments.indicator.registry.value': { + category: 'threat', + description: 'Name of the value written.', + example: 'Debugger', + name: 'threat.enrichments.indicator.registry.value', type: 'keyword', }, - 'kubernetes.statefulset.name': { - category: 'kubernetes', - description: 'Kubernetes statefulset name ', - name: 'kubernetes.statefulset.name', - type: 'keyword', + 'threat.enrichments.indicator.scanner_stats': { + category: 'threat', + description: 'Count of AV/EDR vendors that successfully detected malicious file or URL.', + example: 4, + name: 'threat.enrichments.indicator.scanner_stats', + type: 'long', }, - 'kubernetes.container.name': { - category: 'kubernetes', - description: 'Kubernetes container name ', - name: 'kubernetes.container.name', - type: 'keyword', + 'threat.enrichments.indicator.sightings': { + category: 'threat', + description: 'Number of times this indicator was observed conducting threat activity.', + example: 20, + name: 'threat.enrichments.indicator.sightings', + type: 'long', }, - 'kubernetes.container.image': { - category: 'kubernetes', - description: 'Kubernetes container image ', - name: 'kubernetes.container.image', + 'threat.enrichments.indicator.type': { + category: 'threat', + description: + 'Type of indicator as represented by Cyber Observable in STIX 2.0. Recommended values: * autonomous-system * artifact * directory * domain-name * email-addr * file * ipv4-addr * ipv6-addr * mac-addr * mutex * port * process * software * url * user-account * windows-registry-key * x509-certificate', + example: 'ipv4-addr', + name: 'threat.enrichments.indicator.type', type: 'keyword', }, - 'process.exe': { - category: 'process', - name: 'process.exe', - type: 'alias', - }, - 'jolokia.agent.version': { - category: 'jolokia', - description: 'Version number of jolokia agent. ', - name: 'jolokia.agent.version', + 'threat.enrichments.indicator.url.domain': { + category: 'threat', + description: + 'Domain of the url, such as "www.elastic.co". In some cases a URL may refer to an IP and/or port directly, without a domain name. In this case, the IP address would go to the `domain` field. If the URL contains a literal IPv6 address enclosed by `[` and `]` (IETF RFC 2732), the `[` and `]` characters should also be captured in the `domain` field.', + example: 'www.elastic.co', + name: 'threat.enrichments.indicator.url.domain', type: 'keyword', }, - 'jolokia.agent.id': { - category: 'jolokia', + 'threat.enrichments.indicator.url.extension': { + category: 'threat', description: - 'Each agent has a unique id which can be either provided during startup of the agent in form of a configuration parameter or being autodetected. If autodected, the id has several parts: The IP, the process id, hashcode of the agent and its type. ', - name: 'jolokia.agent.id', + 'The field contains the file extension from the original request url, excluding the leading dot. The file extension is only set if it exists, as not every url has a file extension. The leading period must not be included. For example, the value must be "png", not ".png". Note that when the file name has multiple extensions (example.tar.gz), only the last one should be captured ("gz", not "tar.gz").', + example: 'png', + name: 'threat.enrichments.indicator.url.extension', type: 'keyword', }, - 'jolokia.server.product': { - category: 'jolokia', - description: 'The container product if detected. ', - name: 'jolokia.server.product', + 'threat.enrichments.indicator.url.fragment': { + category: 'threat', + description: + 'Portion of the url after the `#`, such as "top". The `#` is not part of the fragment.', + name: 'threat.enrichments.indicator.url.fragment', type: 'keyword', }, - 'jolokia.server.version': { - category: 'jolokia', - description: "The container's version (if detected). ", - name: 'jolokia.server.version', - type: 'keyword', + 'threat.enrichments.indicator.url.full': { + category: 'threat', + description: + 'If full URLs are important to your use case, they should be stored in `url.full`, whether this field is reconstructed or present in the event source.', + example: 'https://www.elastic.co:443/search?q=elasticsearch#top', + name: 'threat.enrichments.indicator.url.full', + type: 'wildcard', }, - 'jolokia.server.vendor': { - category: 'jolokia', - description: 'The vendor of the container the agent is running in. ', - name: 'jolokia.server.vendor', - type: 'keyword', + 'threat.enrichments.indicator.url.original': { + category: 'threat', + description: + 'Unmodified original url as seen in the event source. Note that in network monitoring, the observed URL may be a full URL, whereas in access logs, the URL is often just represented as a path. This field is meant to represent the URL as it was observed, complete or not.', + example: 'https://www.elastic.co:443/search?q=elasticsearch#top or /search?q=elasticsearch', + name: 'threat.enrichments.indicator.url.original', + type: 'wildcard', }, - 'jolokia.url': { - category: 'jolokia', - description: 'The URL how this agent can be contacted. ', - name: 'jolokia.url', + 'threat.enrichments.indicator.url.password': { + category: 'threat', + description: 'Password of the request.', + name: 'threat.enrichments.indicator.url.password', type: 'keyword', }, - 'jolokia.secured': { - category: 'jolokia', - description: 'Whether the agent was configured for authentication or not. ', - name: 'jolokia.secured', - type: 'boolean', - }, - 'file.setuid': { - category: 'file', - description: 'Set if the file has the `setuid` bit set. Omitted otherwise.', - example: 'true', - name: 'file.setuid', - type: 'boolean', + 'threat.enrichments.indicator.url.path': { + category: 'threat', + description: 'Path of the request, such as "/search".', + name: 'threat.enrichments.indicator.url.path', + type: 'wildcard', }, - 'file.setgid': { - category: 'file', - description: 'Set if the file has the `setgid` bit set. Omitted otherwise.', - example: 'true', - name: 'file.setgid', - type: 'boolean', + 'threat.enrichments.indicator.url.port': { + category: 'threat', + description: 'Port of the request, such as 443.', + example: 443, + name: 'threat.enrichments.indicator.url.port', + type: 'long', + format: 'string', }, - 'file.origin': { - category: 'file', + 'threat.enrichments.indicator.url.query': { + category: 'threat', description: - 'An array of strings describing a possible external origin for this file. For example, the URL it was downloaded from. Only supported in macOS, via the kMDItemWhereFroms attribute. Omitted if origin information is not available. ', - name: 'file.origin', - type: 'keyword', - }, - 'file.selinux.user': { - category: 'file', - description: 'The owner of the object.', - name: 'file.selinux.user', + 'The query field describes the query string of the request, such as "q=elasticsearch". The `?` is excluded from the query string. If a URL contains no `?`, there is no query field. If there is a `?` but no query, the query field exists with an empty string. The `exists` query can be used to differentiate between the two cases.', + name: 'threat.enrichments.indicator.url.query', type: 'keyword', }, - 'file.selinux.role': { - category: 'file', - description: "The object's SELinux role.", - name: 'file.selinux.role', + 'threat.enrichments.indicator.url.registered_domain': { + category: 'threat', + description: + 'The highest registered url domain, stripped of the subdomain. For example, the registered domain for "foo.example.com" is "example.com". This value can be determined precisely with a list like the public suffix list (http://publicsuffix.org). Trying to approximate this by simply taking the last two labels will not work well for TLDs such as "co.uk".', + example: 'example.com', + name: 'threat.enrichments.indicator.url.registered_domain', type: 'keyword', }, - 'file.selinux.domain': { - category: 'file', - description: "The object's SELinux domain or type.", - name: 'file.selinux.domain', + 'threat.enrichments.indicator.url.scheme': { + category: 'threat', + description: 'Scheme of the request, such as "https". Note: The `:` is not part of the scheme.', + example: 'https', + name: 'threat.enrichments.indicator.url.scheme', type: 'keyword', }, - 'file.selinux.level': { - category: 'file', - description: "The object's SELinux level.", - example: 's0', - name: 'file.selinux.level', + 'threat.enrichments.indicator.url.subdomain': { + category: 'threat', + description: + 'The subdomain portion of a fully qualified domain name includes all of the names except the host name under the registered_domain. In a partially qualified domain, or if the the qualification level of the full name cannot be determined, subdomain contains all of the names below the registered domain. For example the subdomain portion of "www.east.mydomain.co.uk" is "east". If the domain has multiple levels of subdomain, such as "sub2.sub1.example.com", the subdomain field should contain "sub2.sub1", with no trailing period.', + example: 'east', + name: 'threat.enrichments.indicator.url.subdomain', type: 'keyword', }, - 'user.audit.id': { - category: 'user', - description: 'Audit user ID.', - name: 'user.audit.id', + 'threat.enrichments.indicator.url.top_level_domain': { + category: 'threat', + description: + 'The effective top level domain (eTLD), also known as the domain suffix, is the last part of the domain name. For example, the top level domain for example.com is "com". This value can be determined precisely with a list like the public suffix list (http://publicsuffix.org). Trying to approximate this by simply taking the last label will not work well for effective TLDs such as "co.uk".', + example: 'co.uk', + name: 'threat.enrichments.indicator.url.top_level_domain', type: 'keyword', }, - 'user.audit.name': { - category: 'user', - description: 'Audit user name.', - name: 'user.audit.name', + 'threat.enrichments.indicator.url.username': { + category: 'threat', + description: 'Username of the request.', + name: 'threat.enrichments.indicator.url.username', type: 'keyword', }, - 'user.effective.id': { - category: 'user', - description: 'Effective user ID.', - name: 'user.effective.id', + 'threat.enrichments.indicator.x509.alternative_names': { + category: 'threat', + description: + 'List of subject alternative names (SAN). Name types vary by certificate authority and certificate type but commonly contain IP addresses, DNS names (and wildcards), and email addresses.', + example: '*.elastic.co', + name: 'threat.enrichments.indicator.x509.alternative_names', type: 'keyword', }, - 'user.effective.name': { - category: 'user', - description: 'Effective user name.', - name: 'user.effective.name', + 'threat.enrichments.indicator.x509.issuer.common_name': { + category: 'threat', + description: 'List of common name (CN) of issuing certificate authority.', + example: 'Example SHA2 High Assurance Server CA', + name: 'threat.enrichments.indicator.x509.issuer.common_name', type: 'keyword', }, - 'user.effective.group.id': { - category: 'user', - description: 'Effective group ID.', - name: 'user.effective.group.id', + 'threat.enrichments.indicator.x509.issuer.country': { + category: 'threat', + description: 'List of country (C) codes', + example: 'US', + name: 'threat.enrichments.indicator.x509.issuer.country', type: 'keyword', }, - 'user.effective.group.name': { - category: 'user', - description: 'Effective group name.', - name: 'user.effective.group.name', + 'threat.enrichments.indicator.x509.issuer.distinguished_name': { + category: 'threat', + description: 'Distinguished name (DN) of issuing certificate authority.', + example: 'C=US, O=Example Inc, OU=www.example.com, CN=Example SHA2 High Assurance Server CA', + name: 'threat.enrichments.indicator.x509.issuer.distinguished_name', type: 'keyword', }, - 'user.filesystem.id': { - category: 'user', - description: 'Filesystem user ID.', - name: 'user.filesystem.id', + 'threat.enrichments.indicator.x509.issuer.locality': { + category: 'threat', + description: 'List of locality names (L)', + example: 'Mountain View', + name: 'threat.enrichments.indicator.x509.issuer.locality', type: 'keyword', }, - 'user.filesystem.name': { - category: 'user', - description: 'Filesystem user name.', - name: 'user.filesystem.name', + 'threat.enrichments.indicator.x509.issuer.organization': { + category: 'threat', + description: 'List of organizations (O) of issuing certificate authority.', + example: 'Example Inc', + name: 'threat.enrichments.indicator.x509.issuer.organization', type: 'keyword', }, - 'user.filesystem.group.id': { - category: 'user', - description: 'Filesystem group ID.', - name: 'user.filesystem.group.id', + 'threat.enrichments.indicator.x509.issuer.organizational_unit': { + category: 'threat', + description: 'List of organizational units (OU) of issuing certificate authority.', + example: 'www.example.com', + name: 'threat.enrichments.indicator.x509.issuer.organizational_unit', type: 'keyword', }, - 'user.filesystem.group.name': { - category: 'user', - description: 'Filesystem group name.', - name: 'user.filesystem.group.name', + 'threat.enrichments.indicator.x509.issuer.state_or_province': { + category: 'threat', + description: 'List of state or province names (ST, S, or P)', + example: 'California', + name: 'threat.enrichments.indicator.x509.issuer.state_or_province', type: 'keyword', }, - 'user.saved.id': { - category: 'user', - description: 'Saved user ID.', - name: 'user.saved.id', - type: 'keyword', + 'threat.enrichments.indicator.x509.not_after': { + category: 'threat', + description: 'Time at which the certificate is no longer considered valid.', + example: '"2020-07-16T03:15:39.000Z"', + name: 'threat.enrichments.indicator.x509.not_after', + type: 'date', }, - 'user.saved.name': { - category: 'user', - description: 'Saved user name.', - name: 'user.saved.name', - type: 'keyword', + 'threat.enrichments.indicator.x509.not_before': { + category: 'threat', + description: 'Time at which the certificate is first considered valid.', + example: '"2019-08-16T01:40:25.000Z"', + name: 'threat.enrichments.indicator.x509.not_before', + type: 'date', }, - 'user.saved.group.id': { - category: 'user', - description: 'Saved group ID.', - name: 'user.saved.group.id', + 'threat.enrichments.indicator.x509.public_key_algorithm': { + category: 'threat', + description: 'Algorithm used to generate the public key.', + example: 'RSA', + name: 'threat.enrichments.indicator.x509.public_key_algorithm', type: 'keyword', }, - 'user.saved.group.name': { - category: 'user', - description: 'Saved group name.', - name: 'user.saved.group.name', + 'threat.enrichments.indicator.x509.public_key_curve': { + category: 'threat', + description: + 'The curve used by the elliptic curve public key algorithm. This is algorithm specific.', + example: 'nistp521', + name: 'threat.enrichments.indicator.x509.public_key_curve', type: 'keyword', }, - 'user.auid': { - category: 'user', - name: 'user.auid', - type: 'alias', - }, - 'user.uid': { - category: 'user', - name: 'user.uid', - type: 'alias', - }, - 'user.euid': { - category: 'user', - name: 'user.euid', - type: 'alias', - }, - 'user.fsuid': { - category: 'user', - name: 'user.fsuid', - type: 'alias', - }, - 'user.suid': { - category: 'user', - name: 'user.suid', - type: 'alias', - }, - 'user.gid': { - category: 'user', - name: 'user.gid', - type: 'alias', - }, - 'user.egid': { - category: 'user', - name: 'user.egid', - type: 'alias', - }, - 'user.sgid': { - category: 'user', - name: 'user.sgid', - type: 'alias', - }, - 'user.fsgid': { - category: 'user', - name: 'user.fsgid', - type: 'alias', - }, - 'user.name_map.auid': { - category: 'user', - name: 'user.name_map.auid', - type: 'alias', + 'threat.enrichments.indicator.x509.public_key_exponent': { + category: 'threat', + description: 'Exponent used to derive the public key. This is algorithm specific.', + example: 65537, + name: 'threat.enrichments.indicator.x509.public_key_exponent', + type: 'long', }, - 'user.name_map.uid': { - category: 'user', - name: 'user.name_map.uid', - type: 'alias', + 'threat.enrichments.indicator.x509.public_key_size': { + category: 'threat', + description: 'The size of the public key space in bits.', + example: 2048, + name: 'threat.enrichments.indicator.x509.public_key_size', + type: 'long', }, - 'user.name_map.euid': { - category: 'user', - name: 'user.name_map.euid', - type: 'alias', + 'threat.enrichments.indicator.x509.serial_number': { + category: 'threat', + description: + 'Unique serial number issued by the certificate authority. For consistency, if this value is alphanumeric, it should be formatted without colons and uppercase characters.', + example: '55FBB9C7DEBF09809D12CCAA', + name: 'threat.enrichments.indicator.x509.serial_number', + type: 'keyword', }, - 'user.name_map.fsuid': { - category: 'user', - name: 'user.name_map.fsuid', - type: 'alias', + 'threat.enrichments.indicator.x509.signature_algorithm': { + category: 'threat', + description: + 'Identifier for certificate signature algorithm. We recommend using names found in Go Lang Crypto library. See https://github.com/golang/go/blob/go1.14/src/crypto/x509/x509.go#L337-L353.', + example: 'SHA256-RSA', + name: 'threat.enrichments.indicator.x509.signature_algorithm', + type: 'keyword', }, - 'user.name_map.suid': { - category: 'user', - name: 'user.name_map.suid', - type: 'alias', + 'threat.enrichments.indicator.x509.subject.common_name': { + category: 'threat', + description: 'List of common names (CN) of subject.', + example: 'shared.global.example.net', + name: 'threat.enrichments.indicator.x509.subject.common_name', + type: 'keyword', }, - 'user.name_map.gid': { - category: 'user', - name: 'user.name_map.gid', - type: 'alias', + 'threat.enrichments.indicator.x509.subject.country': { + category: 'threat', + description: 'List of country (C) code', + example: 'US', + name: 'threat.enrichments.indicator.x509.subject.country', + type: 'keyword', }, - 'user.name_map.egid': { - category: 'user', - name: 'user.name_map.egid', - type: 'alias', + 'threat.enrichments.indicator.x509.subject.distinguished_name': { + category: 'threat', + description: 'Distinguished name (DN) of the certificate subject entity.', + example: 'C=US, ST=California, L=San Francisco, O=Example, Inc., CN=shared.global.example.net', + name: 'threat.enrichments.indicator.x509.subject.distinguished_name', + type: 'keyword', }, - 'user.name_map.sgid': { - category: 'user', - name: 'user.name_map.sgid', - type: 'alias', + 'threat.enrichments.indicator.x509.subject.locality': { + category: 'threat', + description: 'List of locality names (L)', + example: 'San Francisco', + name: 'threat.enrichments.indicator.x509.subject.locality', + type: 'keyword', }, - 'user.name_map.fsgid': { - category: 'user', - name: 'user.name_map.fsgid', - type: 'alias', + 'threat.enrichments.indicator.x509.subject.organization': { + category: 'threat', + description: 'List of organizations (O) of subject.', + example: 'Example, Inc.', + name: 'threat.enrichments.indicator.x509.subject.organization', + type: 'keyword', }, - 'user.selinux.user': { - category: 'user', - description: 'account submitted for authentication', - name: 'user.selinux.user', + 'threat.enrichments.indicator.x509.subject.organizational_unit': { + category: 'threat', + description: 'List of organizational units (OU) of subject.', + name: 'threat.enrichments.indicator.x509.subject.organizational_unit', type: 'keyword', }, - 'user.selinux.role': { - category: 'user', - description: "user's SELinux role", - name: 'user.selinux.role', + 'threat.enrichments.indicator.x509.subject.state_or_province': { + category: 'threat', + description: 'List of state or province names (ST, S, or P)', + example: 'California', + name: 'threat.enrichments.indicator.x509.subject.state_or_province', type: 'keyword', }, - 'user.selinux.domain': { - category: 'user', - description: "The actor's SELinux domain or type.", - name: 'user.selinux.domain', + 'threat.enrichments.indicator.x509.version_number': { + category: 'threat', + description: 'Version of x509 format.', + example: 3, + name: 'threat.enrichments.indicator.x509.version_number', type: 'keyword', }, - 'user.selinux.level': { - category: 'user', - description: "The actor's SELinux level.", - example: 's0', - name: 'user.selinux.level', + 'threat.enrichments.matched.atomic': { + category: 'threat', + description: + 'Identifies the atomic indicator value that matched a local environment endpoint or network event.', + example: 'bad-domain.com', + name: 'threat.enrichments.matched.atomic', type: 'keyword', }, - 'user.selinux.category': { - category: 'user', - description: "The actor's SELinux category or compartments.", - name: 'user.selinux.category', + 'threat.enrichments.matched.field': { + category: 'threat', + description: + 'Identifies the field of the atomic indicator that matched a local environment endpoint or network event.', + example: 'file.hash.sha256', + name: 'threat.enrichments.matched.field', type: 'keyword', }, - 'process.cwd': { - category: 'process', - description: 'The current working directory.', - name: 'process.cwd', - type: 'alias', + 'threat.enrichments.matched.id': { + category: 'threat', + description: 'Identifies the _id of the indicator document enriching the event.', + example: 'ff93aee5-86a1-4a61-b0e6-0cdc313d01b5', + name: 'threat.enrichments.matched.id', + type: 'keyword', }, - 'source.path': { - category: 'source', - description: 'This is the path associated with a unix socket.', - name: 'source.path', + 'threat.enrichments.matched.index': { + category: 'threat', + description: 'Identifies the _index of the indicator document enriching the event.', + example: 'filebeat-8.0.0-2021.05.23-000011', + name: 'threat.enrichments.matched.index', type: 'keyword', }, - 'destination.path': { - category: 'destination', - description: 'This is the path associated with a unix socket.', - name: 'destination.path', + 'threat.enrichments.matched.type': { + category: 'threat', + description: + 'Identifies the type of match that caused the event to be enriched with the given indicator', + example: 'indicator_match_rule', + name: 'threat.enrichments.matched.type', type: 'keyword', }, - 'auditd.message_type': { - category: 'auditd', - description: 'The audit message type (e.g. syscall or apparmor_denied). ', - example: 'syscall', - name: 'auditd.message_type', + 'threat.framework': { + category: 'threat', + description: + 'Name of the threat framework used to further categorize and classify the tactic and technique of the reported threat. Framework classification can be provided by detecting systems, evaluated at ingest time, or retrospectively tagged to events.', + example: 'MITRE ATT&CK', + name: 'threat.framework', type: 'keyword', }, - 'auditd.sequence': { - category: 'auditd', + 'threat.group.alias': { + category: 'threat', description: - 'The sequence number of the event as assigned by the kernel. Sequence numbers are stored as a uint32 in the kernel and can rollover. ', - name: 'auditd.sequence', - type: 'long', + 'The alias(es) of the group for a set of related intrusion activity that are tracked by a common name in the security community. While not required, you can use a MITRE ATT&CK® group alias(es).', + example: '[ "Magecart Group 6" ]', + name: 'threat.group.alias', + type: 'keyword', }, - 'auditd.session': { - category: 'auditd', + 'threat.group.id': { + category: 'threat', description: - 'The session ID assigned to a login. All events related to a login session will have the same value. ', - name: 'auditd.session', + 'The id of the group for a set of related intrusion activity that are tracked by a common name in the security community. While not required, you can use a MITRE ATT&CK® group id.', + example: 'G0037', + name: 'threat.group.id', type: 'keyword', }, - 'auditd.result': { - category: 'auditd', - description: 'The result of the audited operation (success/fail).', - example: 'success or fail', - name: 'auditd.result', + 'threat.group.name': { + category: 'threat', + description: + 'The name of the group for a set of related intrusion activity that are tracked by a common name in the security community. While not required, you can use a MITRE ATT&CK® group name.', + example: 'FIN6', + name: 'threat.group.name', type: 'keyword', }, - 'auditd.summary.actor.primary': { - category: 'auditd', + 'threat.group.reference': { + category: 'threat', description: - "The primary identity of the actor. This is the actor's original login ID. It will not change even if the user changes to another account. ", - name: 'auditd.summary.actor.primary', + 'The reference URL of the group for a set of related intrusion activity that are tracked by a common name in the security community. While not required, you can use a MITRE ATT&CK® group reference URL.', + example: 'https://attack.mitre.org/groups/G0037/', + name: 'threat.group.reference', type: 'keyword', }, - 'auditd.summary.actor.secondary': { - category: 'auditd', + 'threat.indicator.as.number': { + category: 'threat', description: - 'The secondary identity of the actor. This is typically the same as the primary, except for when the user has used `su`.', - name: 'auditd.summary.actor.secondary', + 'Unique number allocated to the autonomous system. The autonomous system number (ASN) uniquely identifies each network on the Internet.', + example: 15169, + name: 'threat.indicator.as.number', + type: 'long', + }, + 'threat.indicator.as.organization.name': { + category: 'threat', + description: 'Organization name.', + example: 'Google LLC', + name: 'threat.indicator.as.organization.name', type: 'keyword', }, - 'auditd.summary.object.type': { - category: 'auditd', - description: 'A description of the what the "thing" is (e.g. file, socket, user-session). ', - name: 'auditd.summary.object.type', + 'threat.indicator.confidence': { + category: 'threat', + description: + 'Identifies the vendor-neutral confidence rating using the None/Low/Medium/High scale defined in Appendix A of the STIX 2.1 framework. Vendor-specific confidence scales may be added as custom fields. Expected values are: * Not Specified * None * Low * Medium * High', + example: 'Medium', + name: 'threat.indicator.confidence', type: 'keyword', }, - 'auditd.summary.object.primary': { - category: 'auditd', - description: '', - name: 'auditd.summary.object.primary', + 'threat.indicator.description': { + category: 'threat', + description: 'Describes the type of action conducted by the threat.', + example: 'IP x.x.x.x was observed delivering the Angler EK.', + name: 'threat.indicator.description', type: 'keyword', }, - 'auditd.summary.object.secondary': { - category: 'auditd', - description: '', - name: 'auditd.summary.object.secondary', + 'threat.indicator.email.address': { + category: 'threat', + description: 'Identifies a threat indicator as an email address (irrespective of direction).', + example: 'phish@example.com', + name: 'threat.indicator.email.address', type: 'keyword', }, - 'auditd.summary.how': { - category: 'auditd', + 'threat.indicator.file.accessed': { + category: 'threat', description: - 'This describes how the action was performed. Usually this is the exe or command that was being executed that triggered the event. ', - name: 'auditd.summary.how', - type: 'keyword', + 'Last time the file was accessed. Note that not all filesystems keep track of access time.', + name: 'threat.indicator.file.accessed', + type: 'date', }, - 'auditd.paths.inode': { - category: 'auditd', - description: 'inode number', - name: 'auditd.paths.inode', + 'threat.indicator.file.attributes': { + category: 'threat', + description: + "Array of file attributes. Attributes names will vary by platform. Here's a non-exhaustive list of values that are expected in this field: archive, compressed, directory, encrypted, execute, hidden, read, readonly, system, write.", + example: '["readonly", "system"]', + name: 'threat.indicator.file.attributes', type: 'keyword', }, - 'auditd.paths.dev': { - category: 'auditd', - description: 'device name as found in /dev', - name: 'auditd.paths.dev', + 'threat.indicator.file.code_signature.digest_algorithm': { + category: 'threat', + description: + 'The hashing algorithm used to sign the process. This value can distinguish signatures when a file is signed multiple times by the same signer but with a different digest algorithm.', + example: 'sha256', + name: 'threat.indicator.file.code_signature.digest_algorithm', type: 'keyword', }, - 'auditd.paths.obj_user': { - category: 'auditd', - description: '', - name: 'auditd.paths.obj_user', - type: 'keyword', + 'threat.indicator.file.code_signature.exists': { + category: 'threat', + description: 'Boolean to capture if a signature is present.', + example: 'true', + name: 'threat.indicator.file.code_signature.exists', + type: 'boolean', }, - 'auditd.paths.obj_role': { - category: 'auditd', - description: '', - name: 'auditd.paths.obj_role', + 'threat.indicator.file.code_signature.signing_id': { + category: 'threat', + description: + 'The identifier used to sign the process. This is used to identify the application manufactured by a software vendor. The field is relevant to Apple *OS only.', + example: 'com.apple.xpc.proxy', + name: 'threat.indicator.file.code_signature.signing_id', type: 'keyword', }, - 'auditd.paths.obj_domain': { - category: 'auditd', - description: '', - name: 'auditd.paths.obj_domain', + 'threat.indicator.file.code_signature.status': { + category: 'threat', + description: + 'Additional information about the certificate status. This is useful for logging cryptographic errors with the certificate validity or trust status. Leave unpopulated if the validity or trust of the certificate was unchecked.', + example: 'ERROR_UNTRUSTED_ROOT', + name: 'threat.indicator.file.code_signature.status', type: 'keyword', }, - 'auditd.paths.obj_level': { - category: 'auditd', - description: '', - name: 'auditd.paths.obj_level', + 'threat.indicator.file.code_signature.subject_name': { + category: 'threat', + description: 'Subject name of the code signer', + example: 'Microsoft Corporation', + name: 'threat.indicator.file.code_signature.subject_name', type: 'keyword', }, - 'auditd.paths.objtype': { - category: 'auditd', - description: '', - name: 'auditd.paths.objtype', + 'threat.indicator.file.code_signature.team_id': { + category: 'threat', + description: + 'The team identifier used to sign the process. This is used to identify the team or vendor of a software product. The field is relevant to Apple *OS only.', + example: 'EQHXZ8M8AV', + name: 'threat.indicator.file.code_signature.team_id', type: 'keyword', }, - 'auditd.paths.ouid': { - category: 'auditd', - description: 'file owner user ID', - name: 'auditd.paths.ouid', - type: 'keyword', + 'threat.indicator.file.code_signature.timestamp': { + category: 'threat', + description: 'Date and time when the code signature was generated and signed.', + example: '2021-01-01T12:10:30Z', + name: 'threat.indicator.file.code_signature.timestamp', + type: 'date', }, - 'auditd.paths.rdev': { - category: 'auditd', - description: 'the device identifier (special files only)', - name: 'auditd.paths.rdev', - type: 'keyword', + 'threat.indicator.file.code_signature.trusted': { + category: 'threat', + description: + 'Stores the trust status of the certificate chain. Validating the trust of the certificate chain may be complicated, and this field should only be populated by tools that actively check the status.', + example: 'true', + name: 'threat.indicator.file.code_signature.trusted', + type: 'boolean', }, - 'auditd.paths.nametype': { - category: 'auditd', - description: 'kind of file operation being referenced', - name: 'auditd.paths.nametype', - type: 'keyword', + 'threat.indicator.file.code_signature.valid': { + category: 'threat', + description: + 'Boolean to capture if the digital signature is verified against the binary content. Leave unpopulated if a certificate was unchecked.', + example: 'true', + name: 'threat.indicator.file.code_signature.valid', + type: 'boolean', }, - 'auditd.paths.ogid': { - category: 'auditd', - description: 'file owner group ID', - name: 'auditd.paths.ogid', - type: 'keyword', + 'threat.indicator.file.created': { + category: 'threat', + description: 'File creation time. Note that not all filesystems store the creation time.', + name: 'threat.indicator.file.created', + type: 'date', }, - 'auditd.paths.item': { - category: 'auditd', - description: 'which item is being recorded', - name: 'auditd.paths.item', - type: 'keyword', + 'threat.indicator.file.ctime': { + category: 'threat', + description: + 'Last time the file attributes or metadata changed. Note that changes to the file content will update `mtime`. This implies `ctime` will be adjusted at the same time, since `mtime` is an attribute of the file.', + name: 'threat.indicator.file.ctime', + type: 'date', }, - 'auditd.paths.mode': { - category: 'auditd', - description: 'mode flags on a file', - name: 'auditd.paths.mode', + 'threat.indicator.file.device': { + category: 'threat', + description: 'Device that is the source of the file.', + example: 'sda', + name: 'threat.indicator.file.device', type: 'keyword', }, - 'auditd.paths.name': { - category: 'auditd', - description: 'file name in avcs', - name: 'auditd.paths.name', + 'threat.indicator.file.directory': { + category: 'threat', + description: + 'Directory where the file is located. It should include the drive letter, when appropriate.', + example: '/home/alice', + name: 'threat.indicator.file.directory', type: 'keyword', }, - 'auditd.data.action': { - category: 'auditd', - description: 'netfilter packet disposition', - name: 'auditd.data.action', + 'threat.indicator.file.drive_letter': { + category: 'threat', + description: + 'Drive letter where the file is located. This field is only relevant on Windows. The value should be uppercase, and not include the colon.', + example: 'C', + name: 'threat.indicator.file.drive_letter', type: 'keyword', }, - 'auditd.data.minor': { - category: 'auditd', - description: 'device minor number', - name: 'auditd.data.minor', + 'threat.indicator.file.elf.architecture': { + category: 'threat', + description: 'Machine architecture of the ELF file.', + example: 'x86-64', + name: 'threat.indicator.file.elf.architecture', type: 'keyword', }, - 'auditd.data.acct': { - category: 'auditd', - description: "a user's account name", - name: 'auditd.data.acct', + 'threat.indicator.file.elf.byte_order': { + category: 'threat', + description: 'Byte sequence of ELF file.', + example: 'Little Endian', + name: 'threat.indicator.file.elf.byte_order', type: 'keyword', }, - 'auditd.data.addr': { - category: 'auditd', - description: 'the remote address that the user is connecting from', - name: 'auditd.data.addr', + 'threat.indicator.file.elf.cpu_type': { + category: 'threat', + description: 'CPU type of the ELF file.', + example: 'Intel', + name: 'threat.indicator.file.elf.cpu_type', type: 'keyword', }, - 'auditd.data.cipher': { - category: 'auditd', - description: 'name of crypto cipher selected', - name: 'auditd.data.cipher', - type: 'keyword', + 'threat.indicator.file.elf.creation_date': { + category: 'threat', + description: + "Extracted when possible from the file's metadata. Indicates when it was built or compiled. It can also be faked by malware creators.", + name: 'threat.indicator.file.elf.creation_date', + type: 'date', }, - 'auditd.data.id': { - category: 'auditd', - description: 'during account changes', - name: 'auditd.data.id', - type: 'keyword', + 'threat.indicator.file.elf.exports': { + category: 'threat', + description: 'List of exported element names and types.', + name: 'threat.indicator.file.elf.exports', + type: 'flattened', }, - 'auditd.data.entries': { - category: 'auditd', - description: 'number of entries in the netfilter table', - name: 'auditd.data.entries', + 'threat.indicator.file.elf.header.abi_version': { + category: 'threat', + description: 'Version of the ELF Application Binary Interface (ABI).', + name: 'threat.indicator.file.elf.header.abi_version', type: 'keyword', }, - 'auditd.data.kind': { - category: 'auditd', - description: 'server or client in crypto operation', - name: 'auditd.data.kind', + 'threat.indicator.file.elf.header.class': { + category: 'threat', + description: 'Header class of the ELF file.', + name: 'threat.indicator.file.elf.header.class', type: 'keyword', }, - 'auditd.data.ksize': { - category: 'auditd', - description: 'key size for crypto operation', - name: 'auditd.data.ksize', + 'threat.indicator.file.elf.header.data': { + category: 'threat', + description: 'Data table of the ELF header.', + name: 'threat.indicator.file.elf.header.data', type: 'keyword', }, - 'auditd.data.spid': { - category: 'auditd', - description: 'sent process ID', - name: 'auditd.data.spid', - type: 'keyword', + 'threat.indicator.file.elf.header.entrypoint': { + category: 'threat', + description: 'Header entrypoint of the ELF file.', + name: 'threat.indicator.file.elf.header.entrypoint', + type: 'long', + format: 'string', }, - 'auditd.data.arch': { - category: 'auditd', - description: 'the elf architecture flags', - name: 'auditd.data.arch', + 'threat.indicator.file.elf.header.object_version': { + category: 'threat', + description: '"0x1" for original ELF files.', + name: 'threat.indicator.file.elf.header.object_version', type: 'keyword', }, - 'auditd.data.argc': { - category: 'auditd', - description: 'the number of arguments to an execve syscall', - name: 'auditd.data.argc', + 'threat.indicator.file.elf.header.os_abi': { + category: 'threat', + description: 'Application Binary Interface (ABI) of the Linux OS.', + name: 'threat.indicator.file.elf.header.os_abi', type: 'keyword', }, - 'auditd.data.major': { - category: 'auditd', - description: 'device major number', - name: 'auditd.data.major', + 'threat.indicator.file.elf.header.type': { + category: 'threat', + description: 'Header type of the ELF file.', + name: 'threat.indicator.file.elf.header.type', type: 'keyword', }, - 'auditd.data.unit': { - category: 'auditd', - description: 'systemd unit', - name: 'auditd.data.unit', + 'threat.indicator.file.elf.header.version': { + category: 'threat', + description: 'Version of the ELF header.', + name: 'threat.indicator.file.elf.header.version', type: 'keyword', }, - 'auditd.data.table': { - category: 'auditd', - description: 'netfilter table name', - name: 'auditd.data.table', - type: 'keyword', + 'threat.indicator.file.elf.imports': { + category: 'threat', + description: 'List of imported element names and types.', + name: 'threat.indicator.file.elf.imports', + type: 'flattened', }, - 'auditd.data.terminal': { - category: 'auditd', - description: 'terminal name the user is running programs on', - name: 'auditd.data.terminal', - type: 'keyword', + 'threat.indicator.file.elf.sections': { + category: 'threat', + description: + 'An array containing an object for each section of the ELF file. The keys that should be present in these objects are defined by sub-fields underneath `elf.sections.*`.', + name: 'threat.indicator.file.elf.sections', + type: 'nested', }, - 'auditd.data.grantors': { - category: 'auditd', - description: 'pam modules approving the action', - name: 'auditd.data.grantors', - type: 'keyword', + 'threat.indicator.file.elf.sections.chi2': { + category: 'threat', + description: 'Chi-square probability distribution of the section.', + name: 'threat.indicator.file.elf.sections.chi2', + type: 'long', + format: 'number', }, - 'auditd.data.direction': { - category: 'auditd', - description: 'direction of crypto operation', - name: 'auditd.data.direction', - type: 'keyword', + 'threat.indicator.file.elf.sections.entropy': { + category: 'threat', + description: 'Shannon entropy calculation from the section.', + name: 'threat.indicator.file.elf.sections.entropy', + type: 'long', + format: 'number', }, - 'auditd.data.op': { - category: 'auditd', - description: 'the operation being performed that is audited', - name: 'auditd.data.op', + 'threat.indicator.file.elf.sections.flags': { + category: 'threat', + description: 'ELF Section List flags.', + name: 'threat.indicator.file.elf.sections.flags', type: 'keyword', }, - 'auditd.data.tty': { - category: 'auditd', - description: 'tty udevice the user is running programs on', - name: 'auditd.data.tty', + 'threat.indicator.file.elf.sections.name': { + category: 'threat', + description: 'ELF Section List name.', + name: 'threat.indicator.file.elf.sections.name', type: 'keyword', }, - 'auditd.data.syscall': { - category: 'auditd', - description: 'syscall number in effect when the event occurred', - name: 'auditd.data.syscall', + 'threat.indicator.file.elf.sections.physical_offset': { + category: 'threat', + description: 'ELF Section List offset.', + name: 'threat.indicator.file.elf.sections.physical_offset', type: 'keyword', }, - 'auditd.data.data': { - category: 'auditd', - description: 'TTY text', - name: 'auditd.data.data', - type: 'keyword', + 'threat.indicator.file.elf.sections.physical_size': { + category: 'threat', + description: 'ELF Section List physical size.', + name: 'threat.indicator.file.elf.sections.physical_size', + type: 'long', + format: 'bytes', }, - 'auditd.data.family': { - category: 'auditd', - description: 'netfilter protocol', - name: 'auditd.data.family', + 'threat.indicator.file.elf.sections.type': { + category: 'threat', + description: 'ELF Section List type.', + name: 'threat.indicator.file.elf.sections.type', type: 'keyword', }, - 'auditd.data.mac': { - category: 'auditd', - description: 'crypto MAC algorithm selected', - name: 'auditd.data.mac', - type: 'keyword', + 'threat.indicator.file.elf.sections.virtual_address': { + category: 'threat', + description: 'ELF Section List virtual address.', + name: 'threat.indicator.file.elf.sections.virtual_address', + type: 'long', + format: 'string', }, - 'auditd.data.pfs': { - category: 'auditd', - description: 'perfect forward secrecy method', - name: 'auditd.data.pfs', - type: 'keyword', + 'threat.indicator.file.elf.sections.virtual_size': { + category: 'threat', + description: 'ELF Section List virtual size.', + name: 'threat.indicator.file.elf.sections.virtual_size', + type: 'long', + format: 'string', }, - 'auditd.data.items': { - category: 'auditd', - description: 'the number of path records in the event', - name: 'auditd.data.items', - type: 'keyword', + 'threat.indicator.file.elf.segments': { + category: 'threat', + description: + 'An array containing an object for each segment of the ELF file. The keys that should be present in these objects are defined by sub-fields underneath `elf.segments.*`.', + name: 'threat.indicator.file.elf.segments', + type: 'nested', }, - 'auditd.data.a0': { - category: 'auditd', - description: '', - name: 'auditd.data.a0', + 'threat.indicator.file.elf.segments.sections': { + category: 'threat', + description: 'ELF object segment sections.', + name: 'threat.indicator.file.elf.segments.sections', type: 'keyword', }, - 'auditd.data.a1': { - category: 'auditd', - description: '', - name: 'auditd.data.a1', + 'threat.indicator.file.elf.segments.type': { + category: 'threat', + description: 'ELF object segment type.', + name: 'threat.indicator.file.elf.segments.type', type: 'keyword', }, - 'auditd.data.a2': { - category: 'auditd', - description: '', - name: 'auditd.data.a2', + 'threat.indicator.file.elf.shared_libraries': { + category: 'threat', + description: 'List of shared libraries used by this ELF object.', + name: 'threat.indicator.file.elf.shared_libraries', type: 'keyword', }, - 'auditd.data.a3': { - category: 'auditd', - description: '', - name: 'auditd.data.a3', + 'threat.indicator.file.elf.telfhash': { + category: 'threat', + description: 'telfhash symbol hash for ELF file.', + name: 'threat.indicator.file.elf.telfhash', type: 'keyword', }, - 'auditd.data.hostname': { - category: 'auditd', - description: 'the hostname that the user is connecting from', - name: 'auditd.data.hostname', + 'threat.indicator.file.extension': { + category: 'threat', + description: + 'File extension, excluding the leading dot. Note that when the file name has multiple extensions (example.tar.gz), only the last one should be captured ("gz", not "tar.gz").', + example: 'png', + name: 'threat.indicator.file.extension', type: 'keyword', }, - 'auditd.data.lport': { - category: 'auditd', - description: 'local network port', - name: 'auditd.data.lport', + 'threat.indicator.file.fork_name': { + category: 'threat', + description: + 'A fork is additional data associated with a filesystem object. On Linux, a resource fork is used to store additional data with a filesystem object. A file always has at least one fork for the data portion, and additional forks may exist. On NTFS, this is analogous to an Alternate Data Stream (ADS), and the default data stream for a file is just called $DATA. Zone.Identifier is commonly used by Windows to track contents downloaded from the Internet. An ADS is typically of the form: `C:\\path\\to\\filename.extension:some_fork_name`, and `some_fork_name` is the value that should populate `fork_name`. `filename.extension` should populate `file.name`, and `extension` should populate `file.extension`. The full path, `file.path`, will include the fork name.', + example: 'Zone.Identifer', + name: 'threat.indicator.file.fork_name', type: 'keyword', }, - 'auditd.data.rport': { - category: 'auditd', - description: 'remote port number', - name: 'auditd.data.rport', + 'threat.indicator.file.gid': { + category: 'threat', + description: 'Primary group ID (GID) of the file.', + example: '1001', + name: 'threat.indicator.file.gid', type: 'keyword', }, - 'auditd.data.exit': { - category: 'auditd', - description: 'syscall exit code', - name: 'auditd.data.exit', + 'threat.indicator.file.group': { + category: 'threat', + description: 'Primary group name of the file.', + example: 'alice', + name: 'threat.indicator.file.group', type: 'keyword', }, - 'auditd.data.fp': { - category: 'auditd', - description: 'crypto key finger print', - name: 'auditd.data.fp', + 'threat.indicator.file.hash.md5': { + category: 'threat', + description: 'MD5 hash.', + name: 'threat.indicator.file.hash.md5', type: 'keyword', }, - 'auditd.data.laddr': { - category: 'auditd', - description: 'local network address', - name: 'auditd.data.laddr', + 'threat.indicator.file.hash.sha1': { + category: 'threat', + description: 'SHA1 hash.', + name: 'threat.indicator.file.hash.sha1', type: 'keyword', }, - 'auditd.data.sport': { - category: 'auditd', - description: 'local port number', - name: 'auditd.data.sport', + 'threat.indicator.file.hash.sha256': { + category: 'threat', + description: 'SHA256 hash.', + name: 'threat.indicator.file.hash.sha256', type: 'keyword', }, - 'auditd.data.capability': { - category: 'auditd', - description: 'posix capabilities', - name: 'auditd.data.capability', + 'threat.indicator.file.hash.sha512': { + category: 'threat', + description: 'SHA512 hash.', + name: 'threat.indicator.file.hash.sha512', type: 'keyword', }, - 'auditd.data.nargs': { - category: 'auditd', - description: 'the number of arguments to a socket call', - name: 'auditd.data.nargs', + 'threat.indicator.file.hash.ssdeep': { + category: 'threat', + description: 'SSDEEP hash.', + name: 'threat.indicator.file.hash.ssdeep', type: 'keyword', }, - 'auditd.data.new-enabled': { - category: 'auditd', - description: 'new TTY audit enabled setting', - name: 'auditd.data.new-enabled', + 'threat.indicator.file.inode': { + category: 'threat', + description: 'Inode representing the file in the filesystem.', + example: '256383', + name: 'threat.indicator.file.inode', type: 'keyword', }, - 'auditd.data.audit_backlog_limit': { - category: 'auditd', - description: "audit system's backlog queue size", - name: 'auditd.data.audit_backlog_limit', + 'threat.indicator.file.mime_type': { + category: 'threat', + description: + 'MIME type should identify the format of the file or stream of bytes using https://www.iana.org/assignments/media-types/media-types.xhtml[IANA official types], where possible. When more than one type is applicable, the most specific type should be used.', + name: 'threat.indicator.file.mime_type', type: 'keyword', }, - 'auditd.data.dir': { - category: 'auditd', - description: 'directory name', - name: 'auditd.data.dir', + 'threat.indicator.file.mode': { + category: 'threat', + description: 'Mode of the file in octal representation.', + example: '0640', + name: 'threat.indicator.file.mode', type: 'keyword', }, - 'auditd.data.cap_pe': { - category: 'auditd', - description: 'process effective capability map', - name: 'auditd.data.cap_pe', - type: 'keyword', + 'threat.indicator.file.mtime': { + category: 'threat', + description: 'Last time the file content was modified.', + name: 'threat.indicator.file.mtime', + type: 'date', }, - 'auditd.data.model': { - category: 'auditd', - description: 'security model being used for virt', - name: 'auditd.data.model', + 'threat.indicator.file.name': { + category: 'threat', + description: 'Name of the file including the extension, without the directory.', + example: 'example.png', + name: 'threat.indicator.file.name', type: 'keyword', }, - 'auditd.data.new_pp': { - category: 'auditd', - description: 'new process permitted capability map', - name: 'auditd.data.new_pp', + 'threat.indicator.file.owner': { + category: 'threat', + description: "File owner's username.", + example: 'alice', + name: 'threat.indicator.file.owner', type: 'keyword', }, - 'auditd.data.old-enabled': { - category: 'auditd', - description: 'present TTY audit enabled setting', - name: 'auditd.data.old-enabled', + 'threat.indicator.file.path': { + category: 'threat', + description: + 'Full path to the file, including the file name. It should include the drive letter, when appropriate.', + example: '/home/alice/example.png', + name: 'threat.indicator.file.path', type: 'keyword', }, - 'auditd.data.oauid': { - category: 'auditd', - description: "object's login user ID", - name: 'auditd.data.oauid', + 'threat.indicator.file.pe.architecture': { + category: 'threat', + description: 'CPU architecture target for the file.', + example: 'x64', + name: 'threat.indicator.file.pe.architecture', type: 'keyword', }, - 'auditd.data.old': { - category: 'auditd', - description: 'old value', - name: 'auditd.data.old', + 'threat.indicator.file.pe.company': { + category: 'threat', + description: 'Internal company name of the file, provided at compile-time.', + example: 'Microsoft Corporation', + name: 'threat.indicator.file.pe.company', type: 'keyword', }, - 'auditd.data.banners': { - category: 'auditd', - description: 'banners used on printed page', - name: 'auditd.data.banners', + 'threat.indicator.file.pe.description': { + category: 'threat', + description: 'Internal description of the file, provided at compile-time.', + example: 'Paint', + name: 'threat.indicator.file.pe.description', type: 'keyword', }, - 'auditd.data.feature': { - category: 'auditd', - description: 'kernel feature being changed', - name: 'auditd.data.feature', + 'threat.indicator.file.pe.file_version': { + category: 'threat', + description: 'Internal version of the file, provided at compile-time.', + example: '6.3.9600.17415', + name: 'threat.indicator.file.pe.file_version', type: 'keyword', }, - 'auditd.data.vm-ctx': { - category: 'auditd', - description: "the vm's context string", - name: 'auditd.data.vm-ctx', + 'threat.indicator.file.pe.imphash': { + category: 'threat', + description: + 'A hash of the imports in a PE file. An imphash -- or import hash -- can be used to fingerprint binaries even after recompilation or other code-level transformations have occurred, which would change more traditional hash values. Learn more at https://www.fireeye.com/blog/threat-research/2014/01/tracking-malware-import-hashing.html.', + example: '0c6803c4e922103c4dca5963aad36ddf', + name: 'threat.indicator.file.pe.imphash', type: 'keyword', }, - 'auditd.data.opid': { - category: 'auditd', - description: "object's process ID", - name: 'auditd.data.opid', + 'threat.indicator.file.pe.original_file_name': { + category: 'threat', + description: 'Internal name of the file, provided at compile-time.', + example: 'MSPAINT.EXE', + name: 'threat.indicator.file.pe.original_file_name', type: 'keyword', }, - 'auditd.data.seperms': { - category: 'auditd', - description: 'SELinux permissions being used', - name: 'auditd.data.seperms', + 'threat.indicator.file.pe.product': { + category: 'threat', + description: 'Internal product name of the file, provided at compile-time.', + example: 'Microsoft® Windows® Operating System', + name: 'threat.indicator.file.pe.product', type: 'keyword', }, - 'auditd.data.seresult': { - category: 'auditd', - description: 'SELinux AVC decision granted/denied', - name: 'auditd.data.seresult', - type: 'keyword', + 'threat.indicator.file.size': { + category: 'threat', + description: 'File size in bytes. Only relevant when `file.type` is "file".', + example: 16384, + name: 'threat.indicator.file.size', + type: 'long', }, - 'auditd.data.new-rng': { - category: 'auditd', - description: 'device name of rng being added from a vm', - name: 'auditd.data.new-rng', + 'threat.indicator.file.target_path': { + category: 'threat', + description: 'Target path for symlinks.', + name: 'threat.indicator.file.target_path', type: 'keyword', }, - 'auditd.data.old-net': { - category: 'auditd', - description: 'present MAC address assigned to vm', - name: 'auditd.data.old-net', + 'threat.indicator.file.type': { + category: 'threat', + description: 'File type (file, dir, or symlink).', + example: 'file', + name: 'threat.indicator.file.type', type: 'keyword', }, - 'auditd.data.sigev_signo': { - category: 'auditd', - description: 'signal number', - name: 'auditd.data.sigev_signo', + 'threat.indicator.file.uid': { + category: 'threat', + description: 'The user ID (UID) or security identifier (SID) of the file owner.', + example: '1001', + name: 'threat.indicator.file.uid', type: 'keyword', }, - 'auditd.data.ino': { - category: 'auditd', - description: 'inode number', - name: 'auditd.data.ino', + 'threat.indicator.file.x509.alternative_names': { + category: 'threat', + description: + 'List of subject alternative names (SAN). Name types vary by certificate authority and certificate type but commonly contain IP addresses, DNS names (and wildcards), and email addresses.', + example: '*.elastic.co', + name: 'threat.indicator.file.x509.alternative_names', type: 'keyword', }, - 'auditd.data.old_enforcing': { - category: 'auditd', - description: 'old MAC enforcement status', - name: 'auditd.data.old_enforcing', + 'threat.indicator.file.x509.issuer.common_name': { + category: 'threat', + description: 'List of common name (CN) of issuing certificate authority.', + example: 'Example SHA2 High Assurance Server CA', + name: 'threat.indicator.file.x509.issuer.common_name', type: 'keyword', }, - 'auditd.data.old-vcpu': { - category: 'auditd', - description: 'present number of CPU cores', - name: 'auditd.data.old-vcpu', + 'threat.indicator.file.x509.issuer.country': { + category: 'threat', + description: 'List of country (C) codes', + example: 'US', + name: 'threat.indicator.file.x509.issuer.country', type: 'keyword', }, - 'auditd.data.range': { - category: 'auditd', - description: "user's SE Linux range", - name: 'auditd.data.range', + 'threat.indicator.file.x509.issuer.distinguished_name': { + category: 'threat', + description: 'Distinguished name (DN) of issuing certificate authority.', + example: 'C=US, O=Example Inc, OU=www.example.com, CN=Example SHA2 High Assurance Server CA', + name: 'threat.indicator.file.x509.issuer.distinguished_name', type: 'keyword', }, - 'auditd.data.res': { - category: 'auditd', - description: 'result of the audited operation(success/fail)', - name: 'auditd.data.res', + 'threat.indicator.file.x509.issuer.locality': { + category: 'threat', + description: 'List of locality names (L)', + example: 'Mountain View', + name: 'threat.indicator.file.x509.issuer.locality', type: 'keyword', }, - 'auditd.data.added': { - category: 'auditd', - description: 'number of new files detected', - name: 'auditd.data.added', + 'threat.indicator.file.x509.issuer.organization': { + category: 'threat', + description: 'List of organizations (O) of issuing certificate authority.', + example: 'Example Inc', + name: 'threat.indicator.file.x509.issuer.organization', type: 'keyword', }, - 'auditd.data.fam': { - category: 'auditd', - description: 'socket address family', - name: 'auditd.data.fam', + 'threat.indicator.file.x509.issuer.organizational_unit': { + category: 'threat', + description: 'List of organizational units (OU) of issuing certificate authority.', + example: 'www.example.com', + name: 'threat.indicator.file.x509.issuer.organizational_unit', type: 'keyword', }, - 'auditd.data.nlnk-pid': { - category: 'auditd', - description: 'pid of netlink packet sender', - name: 'auditd.data.nlnk-pid', + 'threat.indicator.file.x509.issuer.state_or_province': { + category: 'threat', + description: 'List of state or province names (ST, S, or P)', + example: 'California', + name: 'threat.indicator.file.x509.issuer.state_or_province', type: 'keyword', }, - 'auditd.data.subj': { - category: 'auditd', - description: "lspp subject's context string", - name: 'auditd.data.subj', - type: 'keyword', + 'threat.indicator.file.x509.not_after': { + category: 'threat', + description: 'Time at which the certificate is no longer considered valid.', + example: '"2020-07-16T03:15:39.000Z"', + name: 'threat.indicator.file.x509.not_after', + type: 'date', }, - 'auditd.data.a[0-3]': { - category: 'auditd', - description: 'the arguments to a syscall', - name: 'auditd.data.a[0-3]', + 'threat.indicator.file.x509.not_before': { + category: 'threat', + description: 'Time at which the certificate is first considered valid.', + example: '"2019-08-16T01:40:25.000Z"', + name: 'threat.indicator.file.x509.not_before', + type: 'date', + }, + 'threat.indicator.file.x509.public_key_algorithm': { + category: 'threat', + description: 'Algorithm used to generate the public key.', + example: 'RSA', + name: 'threat.indicator.file.x509.public_key_algorithm', type: 'keyword', }, - 'auditd.data.cgroup': { - category: 'auditd', - description: 'path to cgroup in sysfs', - name: 'auditd.data.cgroup', + 'threat.indicator.file.x509.public_key_curve': { + category: 'threat', + description: + 'The curve used by the elliptic curve public key algorithm. This is algorithm specific.', + example: 'nistp521', + name: 'threat.indicator.file.x509.public_key_curve', type: 'keyword', }, - 'auditd.data.kernel': { - category: 'auditd', - description: "kernel's version number", - name: 'auditd.data.kernel', + 'threat.indicator.file.x509.public_key_exponent': { + category: 'threat', + description: 'Exponent used to derive the public key. This is algorithm specific.', + example: 65537, + name: 'threat.indicator.file.x509.public_key_exponent', + type: 'long', + }, + 'threat.indicator.file.x509.public_key_size': { + category: 'threat', + description: 'The size of the public key space in bits.', + example: 2048, + name: 'threat.indicator.file.x509.public_key_size', + type: 'long', + }, + 'threat.indicator.file.x509.serial_number': { + category: 'threat', + description: + 'Unique serial number issued by the certificate authority. For consistency, if this value is alphanumeric, it should be formatted without colons and uppercase characters.', + example: '55FBB9C7DEBF09809D12CCAA', + name: 'threat.indicator.file.x509.serial_number', type: 'keyword', }, - 'auditd.data.ocomm': { - category: 'auditd', - description: "object's command line name", - name: 'auditd.data.ocomm', + 'threat.indicator.file.x509.signature_algorithm': { + category: 'threat', + description: + 'Identifier for certificate signature algorithm. We recommend using names found in Go Lang Crypto library. See https://github.com/golang/go/blob/go1.14/src/crypto/x509/x509.go#L337-L353.', + example: 'SHA256-RSA', + name: 'threat.indicator.file.x509.signature_algorithm', type: 'keyword', }, - 'auditd.data.new-net': { - category: 'auditd', - description: 'MAC address being assigned to vm', - name: 'auditd.data.new-net', + 'threat.indicator.file.x509.subject.common_name': { + category: 'threat', + description: 'List of common names (CN) of subject.', + example: 'shared.global.example.net', + name: 'threat.indicator.file.x509.subject.common_name', type: 'keyword', }, - 'auditd.data.permissive': { - category: 'auditd', - description: 'SELinux is in permissive mode', - name: 'auditd.data.permissive', + 'threat.indicator.file.x509.subject.country': { + category: 'threat', + description: 'List of country (C) code', + example: 'US', + name: 'threat.indicator.file.x509.subject.country', type: 'keyword', }, - 'auditd.data.class': { - category: 'auditd', - description: 'resource class assigned to vm', - name: 'auditd.data.class', + 'threat.indicator.file.x509.subject.distinguished_name': { + category: 'threat', + description: 'Distinguished name (DN) of the certificate subject entity.', + example: 'C=US, ST=California, L=San Francisco, O=Example, Inc., CN=shared.global.example.net', + name: 'threat.indicator.file.x509.subject.distinguished_name', type: 'keyword', }, - 'auditd.data.compat': { - category: 'auditd', - description: 'is_compat_task result', - name: 'auditd.data.compat', + 'threat.indicator.file.x509.subject.locality': { + category: 'threat', + description: 'List of locality names (L)', + example: 'San Francisco', + name: 'threat.indicator.file.x509.subject.locality', type: 'keyword', }, - 'auditd.data.fi': { - category: 'auditd', - description: 'file assigned inherited capability map', - name: 'auditd.data.fi', + 'threat.indicator.file.x509.subject.organization': { + category: 'threat', + description: 'List of organizations (O) of subject.', + example: 'Example, Inc.', + name: 'threat.indicator.file.x509.subject.organization', type: 'keyword', }, - 'auditd.data.changed': { - category: 'auditd', - description: 'number of changed files', - name: 'auditd.data.changed', + 'threat.indicator.file.x509.subject.organizational_unit': { + category: 'threat', + description: 'List of organizational units (OU) of subject.', + name: 'threat.indicator.file.x509.subject.organizational_unit', type: 'keyword', }, - 'auditd.data.msg': { - category: 'auditd', - description: 'the payload of the audit record', - name: 'auditd.data.msg', + 'threat.indicator.file.x509.subject.state_or_province': { + category: 'threat', + description: 'List of state or province names (ST, S, or P)', + example: 'California', + name: 'threat.indicator.file.x509.subject.state_or_province', type: 'keyword', }, - 'auditd.data.dport': { - category: 'auditd', - description: 'remote port number', - name: 'auditd.data.dport', + 'threat.indicator.file.x509.version_number': { + category: 'threat', + description: 'Version of x509 format.', + example: 3, + name: 'threat.indicator.file.x509.version_number', type: 'keyword', }, - 'auditd.data.new-seuser': { - category: 'auditd', - description: 'new SELinux user', - name: 'auditd.data.new-seuser', + 'threat.indicator.first_seen': { + category: 'threat', + description: + 'The date and time when intelligence source first reported sighting this indicator.', + example: '2020-11-05T17:25:47.000Z', + name: 'threat.indicator.first_seen', + type: 'date', + }, + 'threat.indicator.geo.city_name': { + category: 'threat', + description: 'City name.', + example: 'Montreal', + name: 'threat.indicator.geo.city_name', type: 'keyword', }, - 'auditd.data.invalid_context': { - category: 'auditd', - description: 'SELinux context', - name: 'auditd.data.invalid_context', + 'threat.indicator.geo.continent_code': { + category: 'threat', + description: "Two-letter code representing continent's name.", + example: 'NA', + name: 'threat.indicator.geo.continent_code', type: 'keyword', }, - 'auditd.data.dmac': { - category: 'auditd', - description: 'remote MAC address', - name: 'auditd.data.dmac', + 'threat.indicator.geo.continent_name': { + category: 'threat', + description: 'Name of the continent.', + example: 'North America', + name: 'threat.indicator.geo.continent_name', type: 'keyword', }, - 'auditd.data.ipx-net': { - category: 'auditd', - description: 'IPX network number', - name: 'auditd.data.ipx-net', + 'threat.indicator.geo.country_iso_code': { + category: 'threat', + description: 'Country ISO code.', + example: 'CA', + name: 'threat.indicator.geo.country_iso_code', type: 'keyword', }, - 'auditd.data.iuid': { - category: 'auditd', - description: "ipc object's user ID", - name: 'auditd.data.iuid', + 'threat.indicator.geo.country_name': { + category: 'threat', + description: 'Country name.', + example: 'Canada', + name: 'threat.indicator.geo.country_name', type: 'keyword', }, - 'auditd.data.macproto': { - category: 'auditd', - description: 'ethernet packet type ID field', - name: 'auditd.data.macproto', + 'threat.indicator.geo.location': { + category: 'threat', + description: 'Longitude and latitude.', + example: '{ "lon": -73.614830, "lat": 45.505918 }', + name: 'threat.indicator.geo.location', + type: 'geo_point', + }, + 'threat.indicator.geo.name': { + category: 'threat', + description: + 'User-defined description of a location, at the level of granularity they care about. Could be the name of their data centers, the floor number, if this describes a local physical entity, city names. Not typically used in automated geolocation.', + example: 'boston-dc', + name: 'threat.indicator.geo.name', type: 'keyword', }, - 'auditd.data.obj': { - category: 'auditd', - description: 'lspp object context string', - name: 'auditd.data.obj', + 'threat.indicator.geo.postal_code': { + category: 'threat', + description: + 'Postal code associated with the location. Values appropriate for this field may also be known as a postcode or ZIP code and will vary widely from country to country.', + example: 94040, + name: 'threat.indicator.geo.postal_code', type: 'keyword', }, - 'auditd.data.ipid': { - category: 'auditd', - description: 'IP datagram fragment identifier', - name: 'auditd.data.ipid', + 'threat.indicator.geo.region_iso_code': { + category: 'threat', + description: 'Region ISO code.', + example: 'CA-QC', + name: 'threat.indicator.geo.region_iso_code', type: 'keyword', }, - 'auditd.data.new-fs': { - category: 'auditd', - description: 'file system being added to vm', - name: 'auditd.data.new-fs', + 'threat.indicator.geo.region_name': { + category: 'threat', + description: 'Region name.', + example: 'Quebec', + name: 'threat.indicator.geo.region_name', type: 'keyword', }, - 'auditd.data.vm-pid': { - category: 'auditd', - description: "vm's process ID", - name: 'auditd.data.vm-pid', + 'threat.indicator.geo.timezone': { + category: 'threat', + description: 'The time zone of the location, such as IANA time zone name.', + example: 'America/Argentina/Buenos_Aires', + name: 'threat.indicator.geo.timezone', type: 'keyword', }, - 'auditd.data.cap_pi': { - category: 'auditd', - description: 'process inherited capability map', - name: 'auditd.data.cap_pi', + 'threat.indicator.ip': { + category: 'threat', + description: 'Identifies a threat indicator as an IP address (irrespective of direction).', + example: '1.2.3.4', + name: 'threat.indicator.ip', + type: 'ip', + }, + 'threat.indicator.last_seen': { + category: 'threat', + description: + 'The date and time when intelligence source last reported sighting this indicator.', + example: '2020-11-05T17:25:47.000Z', + name: 'threat.indicator.last_seen', + type: 'date', + }, + 'threat.indicator.marking.tlp': { + category: 'threat', + description: + 'Traffic Light Protocol sharing markings. Recommended values are: * WHITE * GREEN * AMBER * RED', + example: 'WHITE', + name: 'threat.indicator.marking.tlp', type: 'keyword', }, - 'auditd.data.old-auid': { - category: 'auditd', - description: 'previous auid value', - name: 'auditd.data.old-auid', + 'threat.indicator.modified_at': { + category: 'threat', + description: + 'The date and time when intelligence source last modified information for this indicator.', + example: '2020-11-05T17:25:47.000Z', + name: 'threat.indicator.modified_at', + type: 'date', + }, + 'threat.indicator.port': { + category: 'threat', + description: 'Identifies a threat indicator as a port number (irrespective of direction).', + example: 443, + name: 'threat.indicator.port', + type: 'long', + }, + 'threat.indicator.provider': { + category: 'threat', + description: "The name of the indicator's provider.", + example: 'lrz_urlhaus', + name: 'threat.indicator.provider', type: 'keyword', }, - 'auditd.data.oses': { - category: 'auditd', - description: "object's session ID", - name: 'auditd.data.oses', + 'threat.indicator.reference': { + category: 'threat', + description: 'Reference URL linking to additional information about this indicator.', + example: 'https://system.example.com/indicator/0001234', + name: 'threat.indicator.reference', type: 'keyword', }, - 'auditd.data.fd': { - category: 'auditd', - description: 'file descriptor number', - name: 'auditd.data.fd', + 'threat.indicator.registry.data.bytes': { + category: 'threat', + description: + 'Original bytes written with base64 encoding. For Windows registry operations, such as SetValueEx and RegQueryValueEx, this corresponds to the data pointed by `lp_data`. This is optional but provides better recoverability and should be populated for REG_BINARY encoded values.', + example: 'ZQBuAC0AVQBTAAAAZQBuAAAAAAA=', + name: 'threat.indicator.registry.data.bytes', type: 'keyword', }, - 'auditd.data.igid': { - category: 'auditd', - description: "ipc object's group ID", - name: 'auditd.data.igid', + 'threat.indicator.registry.data.strings': { + category: 'threat', + description: + 'Content when writing string types. Populated as an array when writing string data to the registry. For single string registry types (REG_SZ, REG_EXPAND_SZ), this should be an array with one string. For sequences of string with REG_MULTI_SZ, this array will be variable length. For numeric data, such as REG_DWORD and REG_QWORD, this should be populated with the decimal representation (e.g `"1"`).', + example: '["C:\\rta\\red_ttp\\bin\\myapp.exe"]', + name: 'threat.indicator.registry.data.strings', + type: 'wildcard', + }, + 'threat.indicator.registry.data.type': { + category: 'threat', + description: 'Standard registry type for encoding contents', + example: 'REG_SZ', + name: 'threat.indicator.registry.data.type', type: 'keyword', }, - 'auditd.data.new-disk': { - category: 'auditd', - description: 'disk being added to vm', - name: 'auditd.data.new-disk', + 'threat.indicator.registry.hive': { + category: 'threat', + description: 'Abbreviated name for the hive.', + example: 'HKLM', + name: 'threat.indicator.registry.hive', type: 'keyword', }, - 'auditd.data.parent': { - category: 'auditd', - description: 'the inode number of the parent file', - name: 'auditd.data.parent', + 'threat.indicator.registry.key': { + category: 'threat', + description: 'Hive-relative path of keys.', + example: + 'SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\winword.exe', + name: 'threat.indicator.registry.key', type: 'keyword', }, - 'auditd.data.len': { - category: 'auditd', - description: 'length', - name: 'auditd.data.len', + 'threat.indicator.registry.path': { + category: 'threat', + description: 'Full path, including hive, key and value', + example: + 'HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\winword.exe\\Debugger', + name: 'threat.indicator.registry.path', type: 'keyword', }, - 'auditd.data.oflag': { - category: 'auditd', - description: 'open syscall flags', - name: 'auditd.data.oflag', + 'threat.indicator.registry.value': { + category: 'threat', + description: 'Name of the value written.', + example: 'Debugger', + name: 'threat.indicator.registry.value', type: 'keyword', }, - 'auditd.data.uuid': { - category: 'auditd', - description: 'a UUID', - name: 'auditd.data.uuid', + 'threat.indicator.scanner_stats': { + category: 'threat', + description: 'Count of AV/EDR vendors that successfully detected malicious file or URL.', + example: 4, + name: 'threat.indicator.scanner_stats', + type: 'long', + }, + 'threat.indicator.sightings': { + category: 'threat', + description: 'Number of times this indicator was observed conducting threat activity.', + example: 20, + name: 'threat.indicator.sightings', + type: 'long', + }, + 'threat.indicator.type': { + category: 'threat', + description: + 'Type of indicator as represented by Cyber Observable in STIX 2.0. Recommended values: * autonomous-system * artifact * directory * domain-name * email-addr * file * ipv4-addr * ipv6-addr * mac-addr * mutex * port * process * software * url * user-account * windows-registry-key * x509-certificate', + example: 'ipv4-addr', + name: 'threat.indicator.type', type: 'keyword', }, - 'auditd.data.code': { - category: 'auditd', - description: 'seccomp action code', - name: 'auditd.data.code', + 'threat.indicator.url.domain': { + category: 'threat', + description: + 'Domain of the url, such as "www.elastic.co". In some cases a URL may refer to an IP and/or port directly, without a domain name. In this case, the IP address would go to the `domain` field. If the URL contains a literal IPv6 address enclosed by `[` and `]` (IETF RFC 2732), the `[` and `]` characters should also be captured in the `domain` field.', + example: 'www.elastic.co', + name: 'threat.indicator.url.domain', type: 'keyword', }, - 'auditd.data.nlnk-grp': { - category: 'auditd', - description: 'netlink group number', - name: 'auditd.data.nlnk-grp', + 'threat.indicator.url.extension': { + category: 'threat', + description: + 'The field contains the file extension from the original request url, excluding the leading dot. The file extension is only set if it exists, as not every url has a file extension. The leading period must not be included. For example, the value must be "png", not ".png". Note that when the file name has multiple extensions (example.tar.gz), only the last one should be captured ("gz", not "tar.gz").', + example: 'png', + name: 'threat.indicator.url.extension', type: 'keyword', }, - 'auditd.data.cap_fp': { - category: 'auditd', - description: 'file permitted capability map', - name: 'auditd.data.cap_fp', + 'threat.indicator.url.fragment': { + category: 'threat', + description: + 'Portion of the url after the `#`, such as "top". The `#` is not part of the fragment.', + name: 'threat.indicator.url.fragment', type: 'keyword', }, - 'auditd.data.new-mem': { - category: 'auditd', - description: 'new amount of memory in KB', - name: 'auditd.data.new-mem', + 'threat.indicator.url.full': { + category: 'threat', + description: + 'If full URLs are important to your use case, they should be stored in `url.full`, whether this field is reconstructed or present in the event source.', + example: 'https://www.elastic.co:443/search?q=elasticsearch#top', + name: 'threat.indicator.url.full', + type: 'wildcard', + }, + 'threat.indicator.url.original': { + category: 'threat', + description: + 'Unmodified original url as seen in the event source. Note that in network monitoring, the observed URL may be a full URL, whereas in access logs, the URL is often just represented as a path. This field is meant to represent the URL as it was observed, complete or not.', + example: 'https://www.elastic.co:443/search?q=elasticsearch#top or /search?q=elasticsearch', + name: 'threat.indicator.url.original', + type: 'wildcard', + }, + 'threat.indicator.url.password': { + category: 'threat', + description: 'Password of the request.', + name: 'threat.indicator.url.password', type: 'keyword', }, - 'auditd.data.seperm': { - category: 'auditd', - description: 'SELinux permission being decided on', - name: 'auditd.data.seperm', + 'threat.indicator.url.path': { + category: 'threat', + description: 'Path of the request, such as "/search".', + name: 'threat.indicator.url.path', + type: 'wildcard', + }, + 'threat.indicator.url.port': { + category: 'threat', + description: 'Port of the request, such as 443.', + example: 443, + name: 'threat.indicator.url.port', + type: 'long', + format: 'string', + }, + 'threat.indicator.url.query': { + category: 'threat', + description: + 'The query field describes the query string of the request, such as "q=elasticsearch". The `?` is excluded from the query string. If a URL contains no `?`, there is no query field. If there is a `?` but no query, the query field exists with an empty string. The `exists` query can be used to differentiate between the two cases.', + name: 'threat.indicator.url.query', type: 'keyword', }, - 'auditd.data.enforcing': { - category: 'auditd', - description: 'new MAC enforcement status', - name: 'auditd.data.enforcing', + 'threat.indicator.url.registered_domain': { + category: 'threat', + description: + 'The highest registered url domain, stripped of the subdomain. For example, the registered domain for "foo.example.com" is "example.com". This value can be determined precisely with a list like the public suffix list (http://publicsuffix.org). Trying to approximate this by simply taking the last two labels will not work well for TLDs such as "co.uk".', + example: 'example.com', + name: 'threat.indicator.url.registered_domain', type: 'keyword', }, - 'auditd.data.new-chardev': { - category: 'auditd', - description: 'new character device being assigned to vm', - name: 'auditd.data.new-chardev', + 'threat.indicator.url.scheme': { + category: 'threat', + description: 'Scheme of the request, such as "https". Note: The `:` is not part of the scheme.', + example: 'https', + name: 'threat.indicator.url.scheme', type: 'keyword', }, - 'auditd.data.old-rng': { - category: 'auditd', - description: 'device name of rng being removed from a vm', - name: 'auditd.data.old-rng', + 'threat.indicator.url.subdomain': { + category: 'threat', + description: + 'The subdomain portion of a fully qualified domain name includes all of the names except the host name under the registered_domain. In a partially qualified domain, or if the the qualification level of the full name cannot be determined, subdomain contains all of the names below the registered domain. For example the subdomain portion of "www.east.mydomain.co.uk" is "east". If the domain has multiple levels of subdomain, such as "sub2.sub1.example.com", the subdomain field should contain "sub2.sub1", with no trailing period.', + example: 'east', + name: 'threat.indicator.url.subdomain', type: 'keyword', }, - 'auditd.data.outif': { - category: 'auditd', - description: 'out interface number', - name: 'auditd.data.outif', + 'threat.indicator.url.top_level_domain': { + category: 'threat', + description: + 'The effective top level domain (eTLD), also known as the domain suffix, is the last part of the domain name. For example, the top level domain for example.com is "com". This value can be determined precisely with a list like the public suffix list (http://publicsuffix.org). Trying to approximate this by simply taking the last label will not work well for effective TLDs such as "co.uk".', + example: 'co.uk', + name: 'threat.indicator.url.top_level_domain', type: 'keyword', }, - 'auditd.data.cmd': { - category: 'auditd', - description: 'command being executed', - name: 'auditd.data.cmd', + 'threat.indicator.url.username': { + category: 'threat', + description: 'Username of the request.', + name: 'threat.indicator.url.username', type: 'keyword', }, - 'auditd.data.hook': { - category: 'auditd', - description: 'netfilter hook that packet came from', - name: 'auditd.data.hook', + 'threat.indicator.x509.alternative_names': { + category: 'threat', + description: + 'List of subject alternative names (SAN). Name types vary by certificate authority and certificate type but commonly contain IP addresses, DNS names (and wildcards), and email addresses.', + example: '*.elastic.co', + name: 'threat.indicator.x509.alternative_names', type: 'keyword', }, - 'auditd.data.new-level': { - category: 'auditd', - description: 'new run level', - name: 'auditd.data.new-level', + 'threat.indicator.x509.issuer.common_name': { + category: 'threat', + description: 'List of common name (CN) of issuing certificate authority.', + example: 'Example SHA2 High Assurance Server CA', + name: 'threat.indicator.x509.issuer.common_name', type: 'keyword', }, - 'auditd.data.sauid': { - category: 'auditd', - description: 'sent login user ID', - name: 'auditd.data.sauid', + 'threat.indicator.x509.issuer.country': { + category: 'threat', + description: 'List of country (C) codes', + example: 'US', + name: 'threat.indicator.x509.issuer.country', type: 'keyword', }, - 'auditd.data.sig': { - category: 'auditd', - description: 'signal number', - name: 'auditd.data.sig', + 'threat.indicator.x509.issuer.distinguished_name': { + category: 'threat', + description: 'Distinguished name (DN) of issuing certificate authority.', + example: 'C=US, O=Example Inc, OU=www.example.com, CN=Example SHA2 High Assurance Server CA', + name: 'threat.indicator.x509.issuer.distinguished_name', type: 'keyword', }, - 'auditd.data.audit_backlog_wait_time': { - category: 'auditd', - description: "audit system's backlog wait time", - name: 'auditd.data.audit_backlog_wait_time', + 'threat.indicator.x509.issuer.locality': { + category: 'threat', + description: 'List of locality names (L)', + example: 'Mountain View', + name: 'threat.indicator.x509.issuer.locality', type: 'keyword', }, - 'auditd.data.printer': { - category: 'auditd', - description: 'printer name', - name: 'auditd.data.printer', + 'threat.indicator.x509.issuer.organization': { + category: 'threat', + description: 'List of organizations (O) of issuing certificate authority.', + example: 'Example Inc', + name: 'threat.indicator.x509.issuer.organization', type: 'keyword', }, - 'auditd.data.old-mem': { - category: 'auditd', - description: 'present amount of memory in KB', - name: 'auditd.data.old-mem', + 'threat.indicator.x509.issuer.organizational_unit': { + category: 'threat', + description: 'List of organizational units (OU) of issuing certificate authority.', + example: 'www.example.com', + name: 'threat.indicator.x509.issuer.organizational_unit', type: 'keyword', }, - 'auditd.data.perm': { - category: 'auditd', - description: 'the file permission being used', - name: 'auditd.data.perm', + 'threat.indicator.x509.issuer.state_or_province': { + category: 'threat', + description: 'List of state or province names (ST, S, or P)', + example: 'California', + name: 'threat.indicator.x509.issuer.state_or_province', type: 'keyword', }, - 'auditd.data.old_pi': { - category: 'auditd', - description: 'old process inherited capability map', - name: 'auditd.data.old_pi', + 'threat.indicator.x509.not_after': { + category: 'threat', + description: 'Time at which the certificate is no longer considered valid.', + example: '"2020-07-16T03:15:39.000Z"', + name: 'threat.indicator.x509.not_after', + type: 'date', + }, + 'threat.indicator.x509.not_before': { + category: 'threat', + description: 'Time at which the certificate is first considered valid.', + example: '"2019-08-16T01:40:25.000Z"', + name: 'threat.indicator.x509.not_before', + type: 'date', + }, + 'threat.indicator.x509.public_key_algorithm': { + category: 'threat', + description: 'Algorithm used to generate the public key.', + example: 'RSA', + name: 'threat.indicator.x509.public_key_algorithm', type: 'keyword', }, - 'auditd.data.state': { - category: 'auditd', - description: 'audit daemon configuration resulting state', - name: 'auditd.data.state', + 'threat.indicator.x509.public_key_curve': { + category: 'threat', + description: + 'The curve used by the elliptic curve public key algorithm. This is algorithm specific.', + example: 'nistp521', + name: 'threat.indicator.x509.public_key_curve', type: 'keyword', }, - 'auditd.data.format': { - category: 'auditd', - description: "audit log's format", - name: 'auditd.data.format', + 'threat.indicator.x509.public_key_exponent': { + category: 'threat', + description: 'Exponent used to derive the public key. This is algorithm specific.', + example: 65537, + name: 'threat.indicator.x509.public_key_exponent', + type: 'long', + }, + 'threat.indicator.x509.public_key_size': { + category: 'threat', + description: 'The size of the public key space in bits.', + example: 2048, + name: 'threat.indicator.x509.public_key_size', + type: 'long', + }, + 'threat.indicator.x509.serial_number': { + category: 'threat', + description: + 'Unique serial number issued by the certificate authority. For consistency, if this value is alphanumeric, it should be formatted without colons and uppercase characters.', + example: '55FBB9C7DEBF09809D12CCAA', + name: 'threat.indicator.x509.serial_number', type: 'keyword', }, - 'auditd.data.new_gid': { - category: 'auditd', - description: 'new group ID being assigned', - name: 'auditd.data.new_gid', + 'threat.indicator.x509.signature_algorithm': { + category: 'threat', + description: + 'Identifier for certificate signature algorithm. We recommend using names found in Go Lang Crypto library. See https://github.com/golang/go/blob/go1.14/src/crypto/x509/x509.go#L337-L353.', + example: 'SHA256-RSA', + name: 'threat.indicator.x509.signature_algorithm', type: 'keyword', }, - 'auditd.data.tcontext': { - category: 'auditd', - description: "the target's or object's context string", - name: 'auditd.data.tcontext', + 'threat.indicator.x509.subject.common_name': { + category: 'threat', + description: 'List of common names (CN) of subject.', + example: 'shared.global.example.net', + name: 'threat.indicator.x509.subject.common_name', type: 'keyword', }, - 'auditd.data.maj': { - category: 'auditd', - description: 'device major number', - name: 'auditd.data.maj', + 'threat.indicator.x509.subject.country': { + category: 'threat', + description: 'List of country (C) code', + example: 'US', + name: 'threat.indicator.x509.subject.country', type: 'keyword', }, - 'auditd.data.watch': { - category: 'auditd', - description: 'file name in a watch record', - name: 'auditd.data.watch', + 'threat.indicator.x509.subject.distinguished_name': { + category: 'threat', + description: 'Distinguished name (DN) of the certificate subject entity.', + example: 'C=US, ST=California, L=San Francisco, O=Example, Inc., CN=shared.global.example.net', + name: 'threat.indicator.x509.subject.distinguished_name', type: 'keyword', }, - 'auditd.data.device': { - category: 'auditd', - description: 'device name', - name: 'auditd.data.device', + 'threat.indicator.x509.subject.locality': { + category: 'threat', + description: 'List of locality names (L)', + example: 'San Francisco', + name: 'threat.indicator.x509.subject.locality', type: 'keyword', }, - 'auditd.data.grp': { - category: 'auditd', - description: 'group name', - name: 'auditd.data.grp', + 'threat.indicator.x509.subject.organization': { + category: 'threat', + description: 'List of organizations (O) of subject.', + example: 'Example, Inc.', + name: 'threat.indicator.x509.subject.organization', type: 'keyword', }, - 'auditd.data.bool': { - category: 'auditd', - description: 'name of SELinux boolean', - name: 'auditd.data.bool', + 'threat.indicator.x509.subject.organizational_unit': { + category: 'threat', + description: 'List of organizational units (OU) of subject.', + name: 'threat.indicator.x509.subject.organizational_unit', type: 'keyword', }, - 'auditd.data.icmp_type': { - category: 'auditd', - description: 'type of icmp message', - name: 'auditd.data.icmp_type', + 'threat.indicator.x509.subject.state_or_province': { + category: 'threat', + description: 'List of state or province names (ST, S, or P)', + example: 'California', + name: 'threat.indicator.x509.subject.state_or_province', type: 'keyword', }, - 'auditd.data.new_lock': { - category: 'auditd', - description: 'new value of feature lock', - name: 'auditd.data.new_lock', + 'threat.indicator.x509.version_number': { + category: 'threat', + description: 'Version of x509 format.', + example: 3, + name: 'threat.indicator.x509.version_number', type: 'keyword', }, - 'auditd.data.old_prom': { - category: 'auditd', - description: 'network promiscuity flag', - name: 'auditd.data.old_prom', + 'threat.software.alias': { + category: 'threat', + description: + 'The alias(es) of the software for a set of related intrusion activity that are tracked by a common name in the security community. While not required, you can use a MITRE ATT&CK® associated software description.', + example: '[ "X-Agent" ]', + name: 'threat.software.alias', type: 'keyword', }, - 'auditd.data.acl': { - category: 'auditd', - description: 'access mode of resource assigned to vm', - name: 'auditd.data.acl', + 'threat.software.id': { + category: 'threat', + description: + 'The id of the software used by this threat to conduct behavior commonly modeled using MITRE ATT&CK®. While not required, you can use a MITRE ATT&CK® software id.', + example: 'S0552', + name: 'threat.software.id', type: 'keyword', }, - 'auditd.data.ip': { - category: 'auditd', - description: 'network address of a printer', - name: 'auditd.data.ip', + 'threat.software.name': { + category: 'threat', + description: + 'The name of the software used by this threat to conduct behavior commonly modeled using MITRE ATT&CK®. While not required, you can use a MITRE ATT&CK® software name.', + example: 'AdFind', + name: 'threat.software.name', type: 'keyword', }, - 'auditd.data.new_pi': { - category: 'auditd', - description: 'new process inherited capability map', - name: 'auditd.data.new_pi', + 'threat.software.platforms': { + category: 'threat', + description: + 'The platforms of the software used by this threat to conduct behavior commonly modeled using MITRE ATT&CK®. Recommended Values: * AWS * Azure * Azure AD * GCP * Linux * macOS * Network * Office 365 * SaaS * Windows While not required, you can use a MITRE ATT&CK® software platforms.', + example: '[ "Windows" ]', + name: 'threat.software.platforms', type: 'keyword', }, - 'auditd.data.default-context': { - category: 'auditd', - description: 'default MAC context', - name: 'auditd.data.default-context', + 'threat.software.reference': { + category: 'threat', + description: + 'The reference URL of the software used by this threat to conduct behavior commonly modeled using MITRE ATT&CK®. While not required, you can use a MITRE ATT&CK® software reference URL.', + example: 'https://attack.mitre.org/software/S0552/', + name: 'threat.software.reference', type: 'keyword', }, - 'auditd.data.inode_gid': { - category: 'auditd', - description: "group ID of the inode's owner", - name: 'auditd.data.inode_gid', + 'threat.software.type': { + category: 'threat', + description: + 'The type of software used by this threat to conduct behavior commonly modeled using MITRE ATT&CK®. Recommended values * Malware * Tool While not required, you can use a MITRE ATT&CK® software type.', + example: 'Tool', + name: 'threat.software.type', type: 'keyword', }, - 'auditd.data.new-log_passwd': { - category: 'auditd', - description: 'new value for TTY password logging', - name: 'auditd.data.new-log_passwd', + 'threat.tactic.id': { + category: 'threat', + description: + 'The id of tactic used by this threat. You can use a MITRE ATT&CK® tactic, for example. (ex. https://attack.mitre.org/tactics/TA0002/ )', + example: 'TA0002', + name: 'threat.tactic.id', type: 'keyword', }, - 'auditd.data.new_pe': { - category: 'auditd', - description: 'new process effective capability map', - name: 'auditd.data.new_pe', + 'threat.tactic.name': { + category: 'threat', + description: + 'Name of the type of tactic used by this threat. You can use a MITRE ATT&CK® tactic, for example. (ex. https://attack.mitre.org/tactics/TA0002/)', + example: 'Execution', + name: 'threat.tactic.name', type: 'keyword', }, - 'auditd.data.selected-context': { - category: 'auditd', - description: 'new MAC context assigned to session', - name: 'auditd.data.selected-context', + 'threat.tactic.reference': { + category: 'threat', + description: + 'The reference url of tactic used by this threat. You can use a MITRE ATT&CK® tactic, for example. (ex. https://attack.mitre.org/tactics/TA0002/ )', + example: 'https://attack.mitre.org/tactics/TA0002/', + name: 'threat.tactic.reference', type: 'keyword', }, - 'auditd.data.cap_fver': { - category: 'auditd', - description: 'file system capabilities version number', - name: 'auditd.data.cap_fver', + 'threat.technique.id': { + category: 'threat', + description: + 'The id of technique used by this threat. You can use a MITRE ATT&CK® technique, for example. (ex. https://attack.mitre.org/techniques/T1059/)', + example: 'T1059', + name: 'threat.technique.id', type: 'keyword', }, - 'auditd.data.file': { - category: 'auditd', - description: 'file name', - name: 'auditd.data.file', + 'threat.technique.name': { + category: 'threat', + description: + 'The name of technique used by this threat. You can use a MITRE ATT&CK® technique, for example. (ex. https://attack.mitre.org/techniques/T1059/)', + example: 'Command and Scripting Interpreter', + name: 'threat.technique.name', type: 'keyword', }, - 'auditd.data.net': { - category: 'auditd', - description: 'network MAC address', - name: 'auditd.data.net', + 'threat.technique.reference': { + category: 'threat', + description: + 'The reference url of technique used by this threat. You can use a MITRE ATT&CK® technique, for example. (ex. https://attack.mitre.org/techniques/T1059/)', + example: 'https://attack.mitre.org/techniques/T1059/', + name: 'threat.technique.reference', type: 'keyword', }, - 'auditd.data.virt': { - category: 'auditd', - description: 'kind of virtualization being referenced', - name: 'auditd.data.virt', + 'threat.technique.subtechnique.id': { + category: 'threat', + description: + 'The full id of subtechnique used by this threat. You can use a MITRE ATT&CK® subtechnique, for example. (ex. https://attack.mitre.org/techniques/T1059/001/)', + example: 'T1059.001', + name: 'threat.technique.subtechnique.id', type: 'keyword', }, - 'auditd.data.cap_pp': { - category: 'auditd', - description: 'process permitted capability map', - name: 'auditd.data.cap_pp', + 'threat.technique.subtechnique.name': { + category: 'threat', + description: + 'The name of subtechnique used by this threat. You can use a MITRE ATT&CK® subtechnique, for example. (ex. https://attack.mitre.org/techniques/T1059/001/)', + example: 'PowerShell', + name: 'threat.technique.subtechnique.name', type: 'keyword', }, - 'auditd.data.old-range': { - category: 'auditd', - description: 'present SELinux range', - name: 'auditd.data.old-range', + 'threat.technique.subtechnique.reference': { + category: 'threat', + description: + 'The reference url of subtechnique used by this threat. You can use a MITRE ATT&CK® subtechnique, for example. (ex. https://attack.mitre.org/techniques/T1059/001/)', + example: 'https://attack.mitre.org/techniques/T1059/001/', + name: 'threat.technique.subtechnique.reference', type: 'keyword', }, - 'auditd.data.resrc': { - category: 'auditd', - description: 'resource being assigned', - name: 'auditd.data.resrc', + 'tls.cipher': { + category: 'tls', + description: 'String indicating the cipher used during the current connection.', + example: 'TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256', + name: 'tls.cipher', type: 'keyword', }, - 'auditd.data.new-range': { - category: 'auditd', - description: 'new SELinux range', - name: 'auditd.data.new-range', + 'tls.client.certificate': { + category: 'tls', + description: + 'PEM-encoded stand-alone certificate offered by the client. This is usually mutually-exclusive of `client.certificate_chain` since this value also exists in that list.', + example: 'MII...', + name: 'tls.client.certificate', type: 'keyword', }, - 'auditd.data.obj_gid': { - category: 'auditd', - description: 'group ID of object', - name: 'auditd.data.obj_gid', + 'tls.client.certificate_chain': { + category: 'tls', + description: + 'Array of PEM-encoded certificates that make up the certificate chain offered by the client. This is usually mutually-exclusive of `client.certificate` since that value should be the first certificate in the chain.', + example: '["MII...", "MII..."]', + name: 'tls.client.certificate_chain', type: 'keyword', }, - 'auditd.data.proto': { - category: 'auditd', - description: 'network protocol', - name: 'auditd.data.proto', + 'tls.client.hash.md5': { + category: 'tls', + description: + 'Certificate fingerprint using the MD5 digest of DER-encoded version of certificate offered by the client. For consistency with other hash values, this value should be formatted as an uppercase hash.', + example: '0F76C7F2C55BFD7D8E8B8F4BFBF0C9EC', + name: 'tls.client.hash.md5', type: 'keyword', }, - 'auditd.data.old-disk': { - category: 'auditd', - description: 'disk being removed from vm', - name: 'auditd.data.old-disk', + 'tls.client.hash.sha1': { + category: 'tls', + description: + 'Certificate fingerprint using the SHA1 digest of DER-encoded version of certificate offered by the client. For consistency with other hash values, this value should be formatted as an uppercase hash.', + example: '9E393D93138888D288266C2D915214D1D1CCEB2A', + name: 'tls.client.hash.sha1', type: 'keyword', }, - 'auditd.data.audit_failure': { - category: 'auditd', - description: "audit system's failure mode", - name: 'auditd.data.audit_failure', + 'tls.client.hash.sha256': { + category: 'tls', + description: + 'Certificate fingerprint using the SHA256 digest of DER-encoded version of certificate offered by the client. For consistency with other hash values, this value should be formatted as an uppercase hash.', + example: '0687F666A054EF17A08E2F2162EAB4CBC0D265E1D7875BE74BF3C712CA92DAF0', + name: 'tls.client.hash.sha256', type: 'keyword', }, - 'auditd.data.inif': { - category: 'auditd', - description: 'in interface number', - name: 'auditd.data.inif', + 'tls.client.issuer': { + category: 'tls', + description: + 'Distinguished name of subject of the issuer of the x.509 certificate presented by the client.', + example: 'CN=Example Root CA, OU=Infrastructure Team, DC=example, DC=com', + name: 'tls.client.issuer', type: 'keyword', }, - 'auditd.data.vm': { - category: 'auditd', - description: 'virtual machine name', - name: 'auditd.data.vm', + 'tls.client.ja3': { + category: 'tls', + description: 'A hash that identifies clients based on how they perform an SSL/TLS handshake.', + example: 'd4e5b18d6b55c71272893221c96ba240', + name: 'tls.client.ja3', type: 'keyword', }, - 'auditd.data.flags': { - category: 'auditd', - description: 'mmap syscall flags', - name: 'auditd.data.flags', - type: 'keyword', + 'tls.client.not_after': { + category: 'tls', + description: 'Date/Time indicating when client certificate is no longer considered valid.', + example: '2021-01-01T00:00:00.000Z', + name: 'tls.client.not_after', + type: 'date', }, - 'auditd.data.nlnk-fam': { - category: 'auditd', - description: 'netlink protocol number', - name: 'auditd.data.nlnk-fam', - type: 'keyword', + 'tls.client.not_before': { + category: 'tls', + description: 'Date/Time indicating when client certificate is first considered valid.', + example: '1970-01-01T00:00:00.000Z', + name: 'tls.client.not_before', + type: 'date', }, - 'auditd.data.old-fs': { - category: 'auditd', - description: 'file system being removed from vm', - name: 'auditd.data.old-fs', + 'tls.client.server_name': { + category: 'tls', + description: + 'Also called an SNI, this tells the server which hostname to which the client is attempting to connect to. When this value is available, it should get copied to `destination.domain`.', + example: 'www.elastic.co', + name: 'tls.client.server_name', type: 'keyword', }, - 'auditd.data.old-ses': { - category: 'auditd', - description: 'previous ses value', - name: 'auditd.data.old-ses', + 'tls.client.subject': { + category: 'tls', + description: 'Distinguished name of subject of the x.509 certificate presented by the client.', + example: 'CN=myclient, OU=Documentation Team, DC=example, DC=com', + name: 'tls.client.subject', type: 'keyword', }, - 'auditd.data.seqno': { - category: 'auditd', - description: 'sequence number', - name: 'auditd.data.seqno', + 'tls.client.supported_ciphers': { + category: 'tls', + description: 'Array of ciphers offered by the client during the client hello.', + example: + '["TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", "..."]', + name: 'tls.client.supported_ciphers', type: 'keyword', }, - 'auditd.data.fver': { - category: 'auditd', - description: 'file system capabilities version number', - name: 'auditd.data.fver', + 'tls.client.x509.alternative_names': { + category: 'tls', + description: + 'List of subject alternative names (SAN). Name types vary by certificate authority and certificate type but commonly contain IP addresses, DNS names (and wildcards), and email addresses.', + example: '*.elastic.co', + name: 'tls.client.x509.alternative_names', type: 'keyword', }, - 'auditd.data.qbytes': { - category: 'auditd', - description: 'ipc objects quantity of bytes', - name: 'auditd.data.qbytes', + 'tls.client.x509.issuer.common_name': { + category: 'tls', + description: 'List of common name (CN) of issuing certificate authority.', + example: 'Example SHA2 High Assurance Server CA', + name: 'tls.client.x509.issuer.common_name', type: 'keyword', }, - 'auditd.data.seuser': { - category: 'auditd', - description: "user's SE Linux user acct", - name: 'auditd.data.seuser', + 'tls.client.x509.issuer.country': { + category: 'tls', + description: 'List of country (C) codes', + example: 'US', + name: 'tls.client.x509.issuer.country', type: 'keyword', }, - 'auditd.data.cap_fe': { - category: 'auditd', - description: 'file assigned effective capability map', - name: 'auditd.data.cap_fe', + 'tls.client.x509.issuer.distinguished_name': { + category: 'tls', + description: 'Distinguished name (DN) of issuing certificate authority.', + example: 'C=US, O=Example Inc, OU=www.example.com, CN=Example SHA2 High Assurance Server CA', + name: 'tls.client.x509.issuer.distinguished_name', type: 'keyword', }, - 'auditd.data.new-vcpu': { - category: 'auditd', - description: 'new number of CPU cores', - name: 'auditd.data.new-vcpu', + 'tls.client.x509.issuer.locality': { + category: 'tls', + description: 'List of locality names (L)', + example: 'Mountain View', + name: 'tls.client.x509.issuer.locality', type: 'keyword', }, - 'auditd.data.old-level': { - category: 'auditd', - description: 'old run level', - name: 'auditd.data.old-level', + 'tls.client.x509.issuer.organization': { + category: 'tls', + description: 'List of organizations (O) of issuing certificate authority.', + example: 'Example Inc', + name: 'tls.client.x509.issuer.organization', type: 'keyword', }, - 'auditd.data.old_pp': { - category: 'auditd', - description: 'old process permitted capability map', - name: 'auditd.data.old_pp', + 'tls.client.x509.issuer.organizational_unit': { + category: 'tls', + description: 'List of organizational units (OU) of issuing certificate authority.', + example: 'www.example.com', + name: 'tls.client.x509.issuer.organizational_unit', type: 'keyword', }, - 'auditd.data.daddr': { - category: 'auditd', - description: 'remote IP address', - name: 'auditd.data.daddr', + 'tls.client.x509.issuer.state_or_province': { + category: 'tls', + description: 'List of state or province names (ST, S, or P)', + example: 'California', + name: 'tls.client.x509.issuer.state_or_province', type: 'keyword', }, - 'auditd.data.old-role': { - category: 'auditd', - description: 'present SELinux role', - name: 'auditd.data.old-role', - type: 'keyword', + 'tls.client.x509.not_after': { + category: 'tls', + description: 'Time at which the certificate is no longer considered valid.', + example: '"2020-07-16T03:15:39.000Z"', + name: 'tls.client.x509.not_after', + type: 'date', }, - 'auditd.data.ioctlcmd': { - category: 'auditd', - description: 'The request argument to the ioctl syscall', - name: 'auditd.data.ioctlcmd', - type: 'keyword', + 'tls.client.x509.not_before': { + category: 'tls', + description: 'Time at which the certificate is first considered valid.', + example: '"2019-08-16T01:40:25.000Z"', + name: 'tls.client.x509.not_before', + type: 'date', }, - 'auditd.data.smac': { - category: 'auditd', - description: 'local MAC address', - name: 'auditd.data.smac', + 'tls.client.x509.public_key_algorithm': { + category: 'tls', + description: 'Algorithm used to generate the public key.', + example: 'RSA', + name: 'tls.client.x509.public_key_algorithm', type: 'keyword', }, - 'auditd.data.apparmor': { - category: 'auditd', - description: 'apparmor event information', - name: 'auditd.data.apparmor', + 'tls.client.x509.public_key_curve': { + category: 'tls', + description: + 'The curve used by the elliptic curve public key algorithm. This is algorithm specific.', + example: 'nistp521', + name: 'tls.client.x509.public_key_curve', type: 'keyword', }, - 'auditd.data.fe': { - category: 'auditd', - description: 'file assigned effective capability map', - name: 'auditd.data.fe', - type: 'keyword', + 'tls.client.x509.public_key_exponent': { + category: 'tls', + description: 'Exponent used to derive the public key. This is algorithm specific.', + example: 65537, + name: 'tls.client.x509.public_key_exponent', + type: 'long', }, - 'auditd.data.perm_mask': { - category: 'auditd', - description: 'file permission mask that triggered a watch event', - name: 'auditd.data.perm_mask', - type: 'keyword', + 'tls.client.x509.public_key_size': { + category: 'tls', + description: 'The size of the public key space in bits.', + example: 2048, + name: 'tls.client.x509.public_key_size', + type: 'long', }, - 'auditd.data.ses': { - category: 'auditd', - description: 'login session ID', - name: 'auditd.data.ses', + 'tls.client.x509.serial_number': { + category: 'tls', + description: + 'Unique serial number issued by the certificate authority. For consistency, if this value is alphanumeric, it should be formatted without colons and uppercase characters.', + example: '55FBB9C7DEBF09809D12CCAA', + name: 'tls.client.x509.serial_number', type: 'keyword', }, - 'auditd.data.cap_fi': { - category: 'auditd', - description: 'file inherited capability map', - name: 'auditd.data.cap_fi', + 'tls.client.x509.signature_algorithm': { + category: 'tls', + description: + 'Identifier for certificate signature algorithm. We recommend using names found in Go Lang Crypto library. See https://github.com/golang/go/blob/go1.14/src/crypto/x509/x509.go#L337-L353.', + example: 'SHA256-RSA', + name: 'tls.client.x509.signature_algorithm', type: 'keyword', }, - 'auditd.data.obj_uid': { - category: 'auditd', - description: 'user ID of object', - name: 'auditd.data.obj_uid', + 'tls.client.x509.subject.common_name': { + category: 'tls', + description: 'List of common names (CN) of subject.', + example: 'shared.global.example.net', + name: 'tls.client.x509.subject.common_name', type: 'keyword', }, - 'auditd.data.reason': { - category: 'auditd', - description: 'text string denoting a reason for the action', - name: 'auditd.data.reason', + 'tls.client.x509.subject.country': { + category: 'tls', + description: 'List of country (C) code', + example: 'US', + name: 'tls.client.x509.subject.country', type: 'keyword', }, - 'auditd.data.list': { - category: 'auditd', - description: "the audit system's filter list number", - name: 'auditd.data.list', + 'tls.client.x509.subject.distinguished_name': { + category: 'tls', + description: 'Distinguished name (DN) of the certificate subject entity.', + example: 'C=US, ST=California, L=San Francisco, O=Example, Inc., CN=shared.global.example.net', + name: 'tls.client.x509.subject.distinguished_name', type: 'keyword', }, - 'auditd.data.old_lock': { - category: 'auditd', - description: 'present value of feature lock', - name: 'auditd.data.old_lock', + 'tls.client.x509.subject.locality': { + category: 'tls', + description: 'List of locality names (L)', + example: 'San Francisco', + name: 'tls.client.x509.subject.locality', type: 'keyword', }, - 'auditd.data.bus': { - category: 'auditd', - description: 'name of subsystem bus a vm resource belongs to', - name: 'auditd.data.bus', + 'tls.client.x509.subject.organization': { + category: 'tls', + description: 'List of organizations (O) of subject.', + example: 'Example, Inc.', + name: 'tls.client.x509.subject.organization', type: 'keyword', }, - 'auditd.data.old_pe': { - category: 'auditd', - description: 'old process effective capability map', - name: 'auditd.data.old_pe', + 'tls.client.x509.subject.organizational_unit': { + category: 'tls', + description: 'List of organizational units (OU) of subject.', + name: 'tls.client.x509.subject.organizational_unit', type: 'keyword', }, - 'auditd.data.new-role': { - category: 'auditd', - description: 'new SELinux role', - name: 'auditd.data.new-role', + 'tls.client.x509.subject.state_or_province': { + category: 'tls', + description: 'List of state or province names (ST, S, or P)', + example: 'California', + name: 'tls.client.x509.subject.state_or_province', type: 'keyword', }, - 'auditd.data.prom': { - category: 'auditd', - description: 'network promiscuity flag', - name: 'auditd.data.prom', + 'tls.client.x509.version_number': { + category: 'tls', + description: 'Version of x509 format.', + example: 3, + name: 'tls.client.x509.version_number', type: 'keyword', }, - 'auditd.data.uri': { - category: 'auditd', - description: 'URI pointing to a printer', - name: 'auditd.data.uri', + 'tls.curve': { + category: 'tls', + description: 'String indicating the curve used for the given cipher, when applicable.', + example: 'secp256r1', + name: 'tls.curve', type: 'keyword', }, - 'auditd.data.audit_enabled': { - category: 'auditd', - description: "audit systems's enable/disable status", - name: 'auditd.data.audit_enabled', - type: 'keyword', + 'tls.established': { + category: 'tls', + description: + 'Boolean flag indicating if the TLS negotiation was successful and transitioned to an encrypted tunnel.', + name: 'tls.established', + type: 'boolean', }, - 'auditd.data.old-log_passwd': { - category: 'auditd', - description: 'present value for TTY password logging', - name: 'auditd.data.old-log_passwd', + 'tls.next_protocol': { + category: 'tls', + description: + 'String indicating the protocol being tunneled. Per the values in the IANA registry (https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids), this string should be lower case.', + example: 'http/1.1', + name: 'tls.next_protocol', type: 'keyword', }, - 'auditd.data.old-seuser': { - category: 'auditd', - description: 'present SELinux user', - name: 'auditd.data.old-seuser', - type: 'keyword', + 'tls.resumed': { + category: 'tls', + description: + 'Boolean flag indicating if this TLS connection was resumed from an existing TLS negotiation.', + name: 'tls.resumed', + type: 'boolean', }, - 'auditd.data.per': { - category: 'auditd', - description: 'linux personality', - name: 'auditd.data.per', + 'tls.server.certificate': { + category: 'tls', + description: + 'PEM-encoded stand-alone certificate offered by the server. This is usually mutually-exclusive of `server.certificate_chain` since this value also exists in that list.', + example: 'MII...', + name: 'tls.server.certificate', type: 'keyword', }, - 'auditd.data.scontext': { - category: 'auditd', - description: "the subject's context string", - name: 'auditd.data.scontext', + 'tls.server.certificate_chain': { + category: 'tls', + description: + 'Array of PEM-encoded certificates that make up the certificate chain offered by the server. This is usually mutually-exclusive of `server.certificate` since that value should be the first certificate in the chain.', + example: '["MII...", "MII..."]', + name: 'tls.server.certificate_chain', type: 'keyword', }, - 'auditd.data.tclass': { - category: 'auditd', - description: "target's object classification", - name: 'auditd.data.tclass', + 'tls.server.hash.md5': { + category: 'tls', + description: + 'Certificate fingerprint using the MD5 digest of DER-encoded version of certificate offered by the server. For consistency with other hash values, this value should be formatted as an uppercase hash.', + example: '0F76C7F2C55BFD7D8E8B8F4BFBF0C9EC', + name: 'tls.server.hash.md5', type: 'keyword', }, - 'auditd.data.ver': { - category: 'auditd', - description: "audit daemon's version number", - name: 'auditd.data.ver', + 'tls.server.hash.sha1': { + category: 'tls', + description: + 'Certificate fingerprint using the SHA1 digest of DER-encoded version of certificate offered by the server. For consistency with other hash values, this value should be formatted as an uppercase hash.', + example: '9E393D93138888D288266C2D915214D1D1CCEB2A', + name: 'tls.server.hash.sha1', type: 'keyword', }, - 'auditd.data.new': { - category: 'auditd', - description: 'value being set in feature', - name: 'auditd.data.new', + 'tls.server.hash.sha256': { + category: 'tls', + description: + 'Certificate fingerprint using the SHA256 digest of DER-encoded version of certificate offered by the server. For consistency with other hash values, this value should be formatted as an uppercase hash.', + example: '0687F666A054EF17A08E2F2162EAB4CBC0D265E1D7875BE74BF3C712CA92DAF0', + name: 'tls.server.hash.sha256', type: 'keyword', }, - 'auditd.data.val': { - category: 'auditd', - description: 'generic value associated with the operation', - name: 'auditd.data.val', + 'tls.server.issuer': { + category: 'tls', + description: 'Subject of the issuer of the x.509 certificate presented by the server.', + example: 'CN=Example Root CA, OU=Infrastructure Team, DC=example, DC=com', + name: 'tls.server.issuer', type: 'keyword', }, - 'auditd.data.img-ctx': { - category: 'auditd', - description: "the vm's disk image context string", - name: 'auditd.data.img-ctx', + 'tls.server.ja3s': { + category: 'tls', + description: 'A hash that identifies servers based on how they perform an SSL/TLS handshake.', + example: '394441ab65754e2207b1e1b457b3641d', + name: 'tls.server.ja3s', type: 'keyword', }, - 'auditd.data.old-chardev': { - category: 'auditd', - description: 'present character device assigned to vm', - name: 'auditd.data.old-chardev', + 'tls.server.not_after': { + category: 'tls', + description: 'Timestamp indicating when server certificate is no longer considered valid.', + example: '2021-01-01T00:00:00.000Z', + name: 'tls.server.not_after', + type: 'date', + }, + 'tls.server.not_before': { + category: 'tls', + description: 'Timestamp indicating when server certificate is first considered valid.', + example: '1970-01-01T00:00:00.000Z', + name: 'tls.server.not_before', + type: 'date', + }, + 'tls.server.subject': { + category: 'tls', + description: 'Subject of the x.509 certificate presented by the server.', + example: 'CN=www.example.com, OU=Infrastructure Team, DC=example, DC=com', + name: 'tls.server.subject', type: 'keyword', }, - 'auditd.data.old_val': { - category: 'auditd', - description: 'current value of SELinux boolean', - name: 'auditd.data.old_val', + 'tls.server.x509.alternative_names': { + category: 'tls', + description: + 'List of subject alternative names (SAN). Name types vary by certificate authority and certificate type but commonly contain IP addresses, DNS names (and wildcards), and email addresses.', + example: '*.elastic.co', + name: 'tls.server.x509.alternative_names', type: 'keyword', }, - 'auditd.data.success': { - category: 'auditd', - description: 'whether the syscall was successful or not', - name: 'auditd.data.success', + 'tls.server.x509.issuer.common_name': { + category: 'tls', + description: 'List of common name (CN) of issuing certificate authority.', + example: 'Example SHA2 High Assurance Server CA', + name: 'tls.server.x509.issuer.common_name', type: 'keyword', }, - 'auditd.data.inode_uid': { - category: 'auditd', - description: "user ID of the inode's owner", - name: 'auditd.data.inode_uid', + 'tls.server.x509.issuer.country': { + category: 'tls', + description: 'List of country (C) codes', + example: 'US', + name: 'tls.server.x509.issuer.country', type: 'keyword', }, - 'auditd.data.removed': { - category: 'auditd', - description: 'number of deleted files', - name: 'auditd.data.removed', + 'tls.server.x509.issuer.distinguished_name': { + category: 'tls', + description: 'Distinguished name (DN) of issuing certificate authority.', + example: 'C=US, O=Example Inc, OU=www.example.com, CN=Example SHA2 High Assurance Server CA', + name: 'tls.server.x509.issuer.distinguished_name', type: 'keyword', }, - 'auditd.data.socket.port': { - category: 'auditd', - description: 'The port number.', - name: 'auditd.data.socket.port', + 'tls.server.x509.issuer.locality': { + category: 'tls', + description: 'List of locality names (L)', + example: 'Mountain View', + name: 'tls.server.x509.issuer.locality', type: 'keyword', }, - 'auditd.data.socket.saddr': { - category: 'auditd', - description: 'The raw socket address structure.', - name: 'auditd.data.socket.saddr', + 'tls.server.x509.issuer.organization': { + category: 'tls', + description: 'List of organizations (O) of issuing certificate authority.', + example: 'Example Inc', + name: 'tls.server.x509.issuer.organization', type: 'keyword', }, - 'auditd.data.socket.addr': { - category: 'auditd', - description: 'The remote address.', - name: 'auditd.data.socket.addr', + 'tls.server.x509.issuer.organizational_unit': { + category: 'tls', + description: 'List of organizational units (OU) of issuing certificate authority.', + example: 'www.example.com', + name: 'tls.server.x509.issuer.organizational_unit', type: 'keyword', }, - 'auditd.data.socket.family': { - category: 'auditd', - description: 'The socket family (unix, ipv4, ipv6, netlink).', - example: 'unix', - name: 'auditd.data.socket.family', + 'tls.server.x509.issuer.state_or_province': { + category: 'tls', + description: 'List of state or province names (ST, S, or P)', + example: 'California', + name: 'tls.server.x509.issuer.state_or_province', type: 'keyword', }, - 'auditd.data.socket.path': { - category: 'auditd', - description: 'This is the path associated with a unix socket.', - name: 'auditd.data.socket.path', + 'tls.server.x509.not_after': { + category: 'tls', + description: 'Time at which the certificate is no longer considered valid.', + example: '"2020-07-16T03:15:39.000Z"', + name: 'tls.server.x509.not_after', + type: 'date', + }, + 'tls.server.x509.not_before': { + category: 'tls', + description: 'Time at which the certificate is first considered valid.', + example: '"2019-08-16T01:40:25.000Z"', + name: 'tls.server.x509.not_before', + type: 'date', + }, + 'tls.server.x509.public_key_algorithm': { + category: 'tls', + description: 'Algorithm used to generate the public key.', + example: 'RSA', + name: 'tls.server.x509.public_key_algorithm', type: 'keyword', }, - 'auditd.messages': { - category: 'auditd', + 'tls.server.x509.public_key_curve': { + category: 'tls', description: - 'An ordered list of the raw messages received from the kernel that were used to construct this document. This field is present if an error occurred processing the data or if `include_raw_message` is set in the config. ', - name: 'auditd.messages', - type: 'alias', + 'The curve used by the elliptic curve public key algorithm. This is algorithm specific.', + example: 'nistp521', + name: 'tls.server.x509.public_key_curve', + type: 'keyword', }, - 'auditd.warnings': { - category: 'auditd', - description: - 'The warnings generated by the Beat during the construction of the event. These are disabled by default and are used for development and debug purposes only. ', - name: 'auditd.warnings', - type: 'alias', + 'tls.server.x509.public_key_exponent': { + category: 'tls', + description: 'Exponent used to derive the public key. This is algorithm specific.', + example: 65537, + name: 'tls.server.x509.public_key_exponent', + type: 'long', }, - 'geoip.continent_name': { - category: 'geoip', - description: 'The name of the continent. ', - name: 'geoip.continent_name', - type: 'keyword', + 'tls.server.x509.public_key_size': { + category: 'tls', + description: 'The size of the public key space in bits.', + example: 2048, + name: 'tls.server.x509.public_key_size', + type: 'long', }, - 'geoip.city_name': { - category: 'geoip', - description: 'The name of the city. ', - name: 'geoip.city_name', + 'tls.server.x509.serial_number': { + category: 'tls', + description: + 'Unique serial number issued by the certificate authority. For consistency, if this value is alphanumeric, it should be formatted without colons and uppercase characters.', + example: '55FBB9C7DEBF09809D12CCAA', + name: 'tls.server.x509.serial_number', type: 'keyword', }, - 'geoip.region_name': { - category: 'geoip', - description: 'The name of the region. ', - name: 'geoip.region_name', + 'tls.server.x509.signature_algorithm': { + category: 'tls', + description: + 'Identifier for certificate signature algorithm. We recommend using names found in Go Lang Crypto library. See https://github.com/golang/go/blob/go1.14/src/crypto/x509/x509.go#L337-L353.', + example: 'SHA256-RSA', + name: 'tls.server.x509.signature_algorithm', type: 'keyword', }, - 'geoip.country_iso_code': { - category: 'geoip', - description: 'Country ISO code. ', - name: 'geoip.country_iso_code', + 'tls.server.x509.subject.common_name': { + category: 'tls', + description: 'List of common names (CN) of subject.', + example: 'shared.global.example.net', + name: 'tls.server.x509.subject.common_name', type: 'keyword', }, - 'geoip.location': { - category: 'geoip', - description: 'The longitude and latitude. ', - name: 'geoip.location', - type: 'geo_point', + 'tls.server.x509.subject.country': { + category: 'tls', + description: 'List of country (C) code', + example: 'US', + name: 'tls.server.x509.subject.country', + type: 'keyword', }, - 'hash.blake2b_256': { - category: 'hash', - description: 'BLAKE2b-256 hash of the file.', - name: 'hash.blake2b_256', + 'tls.server.x509.subject.distinguished_name': { + category: 'tls', + description: 'Distinguished name (DN) of the certificate subject entity.', + example: 'C=US, ST=California, L=San Francisco, O=Example, Inc., CN=shared.global.example.net', + name: 'tls.server.x509.subject.distinguished_name', type: 'keyword', }, - 'hash.blake2b_384': { - category: 'hash', - description: 'BLAKE2b-384 hash of the file.', - name: 'hash.blake2b_384', + 'tls.server.x509.subject.locality': { + category: 'tls', + description: 'List of locality names (L)', + example: 'San Francisco', + name: 'tls.server.x509.subject.locality', type: 'keyword', }, - 'hash.blake2b_512': { - category: 'hash', - description: 'BLAKE2b-512 hash of the file.', - name: 'hash.blake2b_512', + 'tls.server.x509.subject.organization': { + category: 'tls', + description: 'List of organizations (O) of subject.', + example: 'Example, Inc.', + name: 'tls.server.x509.subject.organization', type: 'keyword', }, - 'hash.sha224': { - category: 'hash', - description: 'SHA224 hash of the file.', - name: 'hash.sha224', + 'tls.server.x509.subject.organizational_unit': { + category: 'tls', + description: 'List of organizational units (OU) of subject.', + name: 'tls.server.x509.subject.organizational_unit', type: 'keyword', }, - 'hash.sha384': { - category: 'hash', - description: 'SHA384 hash of the file.', - name: 'hash.sha384', + 'tls.server.x509.subject.state_or_province': { + category: 'tls', + description: 'List of state or province names (ST, S, or P)', + example: 'California', + name: 'tls.server.x509.subject.state_or_province', type: 'keyword', }, - 'hash.sha3_224': { - category: 'hash', - description: 'SHA3_224 hash of the file.', - name: 'hash.sha3_224', + 'tls.server.x509.version_number': { + category: 'tls', + description: 'Version of x509 format.', + example: 3, + name: 'tls.server.x509.version_number', type: 'keyword', }, - 'hash.sha3_256': { - category: 'hash', - description: 'SHA3_256 hash of the file.', - name: 'hash.sha3_256', + 'tls.version': { + category: 'tls', + description: 'Numeric part of the version parsed from the original string.', + example: '1.2', + name: 'tls.version', type: 'keyword', }, - 'hash.sha3_384': { - category: 'hash', - description: 'SHA3_384 hash of the file.', - name: 'hash.sha3_384', + 'tls.version_protocol': { + category: 'tls', + description: 'Normalized lowercase protocol name parsed from original string.', + example: 'tls', + name: 'tls.version_protocol', type: 'keyword', }, - 'hash.sha3_512': { - category: 'hash', - description: 'SHA3_512 hash of the file.', - name: 'hash.sha3_512', + 'span.id': { + category: 'span', + description: + 'Unique identifier of the span within the scope of its trace. A span represents an operation within a transaction, such as a request to another service, or a database query.', + example: '3ff9a8981b7ccd5a', + name: 'span.id', type: 'keyword', }, - 'hash.sha512_224': { - category: 'hash', - description: 'SHA512/224 hash of the file.', - name: 'hash.sha512_224', + 'trace.id': { + category: 'trace', + description: + 'Unique identifier of the trace. A trace groups multiple events like transactions that belong together. For example, a user request handled by multiple inter-connected services.', + example: '4bf92f3577b34da6a3ce929d0e0e4736', + name: 'trace.id', type: 'keyword', }, - 'hash.sha512_256': { - category: 'hash', - description: 'SHA512/256 hash of the file.', - name: 'hash.sha512_256', + 'transaction.id': { + category: 'transaction', + description: + 'Unique identifier of the transaction within the scope of its trace. A transaction is the highest level of work measured within a service, such as a request to a server.', + example: '00f067aa0ba902b7', + name: 'transaction.id', type: 'keyword', }, - 'hash.xxh64': { - category: 'hash', - description: 'XX64 hash of the file.', - name: 'hash.xxh64', + 'url.domain': { + category: 'url', + description: + 'Domain of the url, such as "www.elastic.co". In some cases a URL may refer to an IP and/or port directly, without a domain name. In this case, the IP address would go to the `domain` field. If the URL contains a literal IPv6 address enclosed by `[` and `]` (IETF RFC 2732), the `[` and `]` characters should also be captured in the `domain` field.', + example: 'www.elastic.co', + name: 'url.domain', type: 'keyword', }, - 'event.origin': { - category: 'event', + 'url.extension': { + category: 'url', description: - 'Origin of the event. This can be a file path (e.g. `/var/log/log.1`), or the name of the system component that supplied the data (e.g. `netlink`). ', - name: 'event.origin', + 'The field contains the file extension from the original request url, excluding the leading dot. The file extension is only set if it exists, as not every url has a file extension. The leading period must not be included. For example, the value must be "png", not ".png". Note that when the file name has multiple extensions (example.tar.gz), only the last one should be captured ("gz", not "tar.gz").', + example: 'png', + name: 'url.extension', type: 'keyword', }, - 'user.entity_id': { - category: 'user', + 'url.fragment': { + category: 'url', description: - 'ID uniquely identifying the user on a host. It is computed as a SHA-256 hash of the host ID, user ID, and user name. ', - name: 'user.entity_id', + 'Portion of the url after the `#`, such as "top". The `#` is not part of the fragment.', + name: 'url.fragment', type: 'keyword', }, - 'user.terminal': { - category: 'user', - description: 'Terminal of the user. ', - name: 'user.terminal', + 'url.full': { + category: 'url', + description: + 'If full URLs are important to your use case, they should be stored in `url.full`, whether this field is reconstructed or present in the event source.', + example: 'https://www.elastic.co:443/search?q=elasticsearch#top', + name: 'url.full', + type: 'wildcard', + }, + 'url.original': { + category: 'url', + description: + 'Unmodified original url as seen in the event source. Note that in network monitoring, the observed URL may be a full URL, whereas in access logs, the URL is often just represented as a path. This field is meant to represent the URL as it was observed, complete or not.', + example: 'https://www.elastic.co:443/search?q=elasticsearch#top or /search?q=elasticsearch', + name: 'url.original', + type: 'wildcard', + }, + 'url.password': { + category: 'url', + description: 'Password of the request.', + name: 'url.password', type: 'keyword', }, - 'process.hash.blake2b_256': { - category: 'process', - description: 'BLAKE2b-256 hash of the executable.', - name: 'process.hash.blake2b_256', + 'url.path': { + category: 'url', + description: 'Path of the request, such as "/search".', + name: 'url.path', + type: 'wildcard', + }, + 'url.port': { + category: 'url', + description: 'Port of the request, such as 443.', + example: 443, + name: 'url.port', + type: 'long', + format: 'string', + }, + 'url.query': { + category: 'url', + description: + 'The query field describes the query string of the request, such as "q=elasticsearch". The `?` is excluded from the query string. If a URL contains no `?`, there is no query field. If there is a `?` but no query, the query field exists with an empty string. The `exists` query can be used to differentiate between the two cases.', + name: 'url.query', type: 'keyword', }, - 'process.hash.blake2b_384': { - category: 'process', - description: 'BLAKE2b-384 hash of the executable.', - name: 'process.hash.blake2b_384', + 'url.registered_domain': { + category: 'url', + description: + 'The highest registered url domain, stripped of the subdomain. For example, the registered domain for "foo.example.com" is "example.com". This value can be determined precisely with a list like the public suffix list (http://publicsuffix.org). Trying to approximate this by simply taking the last two labels will not work well for TLDs such as "co.uk".', + example: 'example.com', + name: 'url.registered_domain', type: 'keyword', }, - 'process.hash.blake2b_512': { - category: 'process', - description: 'BLAKE2b-512 hash of the executable.', - name: 'process.hash.blake2b_512', + 'url.scheme': { + category: 'url', + description: 'Scheme of the request, such as "https". Note: The `:` is not part of the scheme.', + example: 'https', + name: 'url.scheme', type: 'keyword', }, - 'process.hash.sha224': { - category: 'process', - description: 'SHA224 hash of the executable.', - name: 'process.hash.sha224', + 'url.subdomain': { + category: 'url', + description: + 'The subdomain portion of a fully qualified domain name includes all of the names except the host name under the registered_domain. In a partially qualified domain, or if the the qualification level of the full name cannot be determined, subdomain contains all of the names below the registered domain. For example the subdomain portion of "www.east.mydomain.co.uk" is "east". If the domain has multiple levels of subdomain, such as "sub2.sub1.example.com", the subdomain field should contain "sub2.sub1", with no trailing period.', + example: 'east', + name: 'url.subdomain', type: 'keyword', }, - 'process.hash.sha384': { - category: 'process', - description: 'SHA384 hash of the executable.', - name: 'process.hash.sha384', + 'url.top_level_domain': { + category: 'url', + description: + 'The effective top level domain (eTLD), also known as the domain suffix, is the last part of the domain name. For example, the top level domain for example.com is "com". This value can be determined precisely with a list like the public suffix list (http://publicsuffix.org). Trying to approximate this by simply taking the last label will not work well for effective TLDs such as "co.uk".', + example: 'co.uk', + name: 'url.top_level_domain', type: 'keyword', }, - 'process.hash.sha3_224': { - category: 'process', - description: 'SHA3_224 hash of the executable.', - name: 'process.hash.sha3_224', + 'url.username': { + category: 'url', + description: 'Username of the request.', + name: 'url.username', type: 'keyword', }, - 'process.hash.sha3_256': { - category: 'process', - description: 'SHA3_256 hash of the executable.', - name: 'process.hash.sha3_256', + 'user.changes.domain': { + category: 'user', + description: + 'Name of the directory the user is a member of. For example, an LDAP or Active Directory domain name.', + name: 'user.changes.domain', type: 'keyword', }, - 'process.hash.sha3_384': { - category: 'process', - description: 'SHA3_384 hash of the executable.', - name: 'process.hash.sha3_384', + 'user.changes.email': { + category: 'user', + description: 'User email address.', + name: 'user.changes.email', type: 'keyword', }, - 'process.hash.sha3_512': { - category: 'process', - description: 'SHA3_512 hash of the executable.', - name: 'process.hash.sha3_512', + 'user.changes.full_name': { + category: 'user', + description: "User's full name, if available.", + example: 'Albert Einstein', + name: 'user.changes.full_name', type: 'keyword', }, - 'process.hash.sha512_224': { - category: 'process', - description: 'SHA512/224 hash of the executable.', - name: 'process.hash.sha512_224', + 'user.changes.group.domain': { + category: 'user', + description: + 'Name of the directory the group is a member of. For example, an LDAP or Active Directory domain name.', + name: 'user.changes.group.domain', type: 'keyword', }, - 'process.hash.sha512_256': { - category: 'process', - description: 'SHA512/256 hash of the executable.', - name: 'process.hash.sha512_256', + 'user.changes.group.id': { + category: 'user', + description: 'Unique identifier for the group on the system/platform.', + name: 'user.changes.group.id', type: 'keyword', }, - 'process.hash.xxh64': { - category: 'process', - description: 'XX64 hash of the executable.', - name: 'process.hash.xxh64', + 'user.changes.group.name': { + category: 'user', + description: 'Name of the group.', + name: 'user.changes.group.name', type: 'keyword', }, - 'socket.entity_id': { - category: 'socket', + 'user.changes.hash': { + category: 'user', description: - 'ID uniquely identifying the socket. It is computed as a SHA-256 hash of the host ID, socket inode, local IP, local port, remote IP, and remote port. ', - name: 'socket.entity_id', + 'Unique user hash to correlate information for a user in anonymized form. Useful if `user.id` or `user.name` contain confidential information and cannot be used.', + name: 'user.changes.hash', type: 'keyword', }, - 'system.audit.host.uptime': { - category: 'system', - description: 'Uptime in nanoseconds. ', - name: 'system.audit.host.uptime', - type: 'long', - format: 'duration', + 'user.changes.id': { + category: 'user', + description: 'Unique identifier of the user.', + example: 'S-1-5-21-202424912787-2692429404-2351956786-1000', + name: 'user.changes.id', + type: 'keyword', }, - 'system.audit.host.boottime': { - category: 'system', - description: 'Boot time. ', - name: 'system.audit.host.boottime', - type: 'date', + 'user.changes.name': { + category: 'user', + description: 'Short name or login of the user.', + example: 'a.einstein', + name: 'user.changes.name', + type: 'keyword', }, - 'system.audit.host.containerized': { - category: 'system', - description: 'Set if host is a container. ', - name: 'system.audit.host.containerized', - type: 'boolean', + 'user.changes.roles': { + category: 'user', + description: 'Array of user roles at the time of the event.', + example: '["kibana_admin", "reporting_user"]', + name: 'user.changes.roles', + type: 'keyword', }, - 'system.audit.host.timezone.name': { - category: 'system', - description: 'Name of the timezone of the host, e.g. BST. ', - name: 'system.audit.host.timezone.name', + 'user.domain': { + category: 'user', + description: + 'Name of the directory the user is a member of. For example, an LDAP or Active Directory domain name.', + name: 'user.domain', type: 'keyword', }, - 'system.audit.host.timezone.offset.sec': { - category: 'system', - description: 'Timezone offset in seconds. ', - name: 'system.audit.host.timezone.offset.sec', - type: 'long', + 'user.effective.domain': { + category: 'user', + description: + 'Name of the directory the user is a member of. For example, an LDAP or Active Directory domain name.', + name: 'user.effective.domain', + type: 'keyword', }, - 'system.audit.host.hostname': { - category: 'system', - description: 'Hostname. ', - name: 'system.audit.host.hostname', + 'user.effective.email': { + category: 'user', + description: 'User email address.', + name: 'user.effective.email', type: 'keyword', }, - 'system.audit.host.id': { - category: 'system', - description: 'Host ID. ', - name: 'system.audit.host.id', + 'user.effective.full_name': { + category: 'user', + description: "User's full name, if available.", + example: 'Albert Einstein', + name: 'user.effective.full_name', type: 'keyword', }, - 'system.audit.host.architecture': { - category: 'system', - description: 'Host architecture (e.g. x86_64). ', - name: 'system.audit.host.architecture', + 'user.effective.group.domain': { + category: 'user', + description: + 'Name of the directory the group is a member of. For example, an LDAP or Active Directory domain name.', + name: 'user.effective.group.domain', type: 'keyword', }, - 'system.audit.host.mac': { - category: 'system', - description: 'MAC addresses. ', - name: 'system.audit.host.mac', + 'user.effective.group.id': { + category: 'user', + description: 'Unique identifier for the group on the system/platform.', + name: 'user.effective.group.id', type: 'keyword', }, - 'system.audit.host.ip': { - category: 'system', - description: 'IP addresses. ', - name: 'system.audit.host.ip', - type: 'ip', + 'user.effective.group.name': { + category: 'user', + description: 'Name of the group.', + name: 'user.effective.group.name', + type: 'keyword', }, - 'system.audit.host.os.codename': { - category: 'system', - description: 'OS codename, if any (e.g. stretch). ', - name: 'system.audit.host.os.codename', + 'user.effective.hash': { + category: 'user', + description: + 'Unique user hash to correlate information for a user in anonymized form. Useful if `user.id` or `user.name` contain confidential information and cannot be used.', + name: 'user.effective.hash', type: 'keyword', }, - 'system.audit.host.os.platform': { - category: 'system', - description: 'OS platform (e.g. centos, ubuntu, windows). ', - name: 'system.audit.host.os.platform', + 'user.effective.id': { + category: 'user', + description: 'Unique identifier of the user.', + example: 'S-1-5-21-202424912787-2692429404-2351956786-1000', + name: 'user.effective.id', type: 'keyword', }, - 'system.audit.host.os.name': { - category: 'system', - description: 'OS name (e.g. Mac OS X). ', - name: 'system.audit.host.os.name', + 'user.effective.name': { + category: 'user', + description: 'Short name or login of the user.', + example: 'a.einstein', + name: 'user.effective.name', type: 'keyword', }, - 'system.audit.host.os.family': { - category: 'system', - description: 'OS family (e.g. redhat, debian, freebsd, windows). ', - name: 'system.audit.host.os.family', + 'user.effective.roles': { + category: 'user', + description: 'Array of user roles at the time of the event.', + example: '["kibana_admin", "reporting_user"]', + name: 'user.effective.roles', type: 'keyword', }, - 'system.audit.host.os.version': { - category: 'system', - description: 'OS version. ', - name: 'system.audit.host.os.version', + 'user.email': { + category: 'user', + description: 'User email address.', + name: 'user.email', type: 'keyword', }, - 'system.audit.host.os.kernel': { - category: 'system', - description: "The operating system's kernel version. ", - name: 'system.audit.host.os.kernel', + 'user.full_name': { + category: 'user', + description: "User's full name, if available.", + example: 'Albert Einstein', + name: 'user.full_name', type: 'keyword', }, - 'system.audit.package.entity_id': { - category: 'system', + 'user.group.domain': { + category: 'user', description: - 'ID uniquely identifying the package. It is computed as a SHA-256 hash of the host ID, package name, and package version. ', - name: 'system.audit.package.entity_id', + 'Name of the directory the group is a member of. For example, an LDAP or Active Directory domain name.', + name: 'user.group.domain', type: 'keyword', }, - 'system.audit.package.name': { - category: 'system', - description: 'Package name. ', - name: 'system.audit.package.name', + 'user.group.id': { + category: 'user', + description: 'Unique identifier for the group on the system/platform.', + name: 'user.group.id', type: 'keyword', }, - 'system.audit.package.version': { - category: 'system', - description: 'Package version. ', - name: 'system.audit.package.version', + 'user.group.name': { + category: 'user', + description: 'Name of the group.', + name: 'user.group.name', type: 'keyword', }, - 'system.audit.package.release': { - category: 'system', - description: 'Package release. ', - name: 'system.audit.package.release', + 'user.hash': { + category: 'user', + description: + 'Unique user hash to correlate information for a user in anonymized form. Useful if `user.id` or `user.name` contain confidential information and cannot be used.', + name: 'user.hash', type: 'keyword', }, - 'system.audit.package.arch': { - category: 'system', - description: 'Package architecture. ', - name: 'system.audit.package.arch', + 'user.id': { + category: 'user', + description: 'Unique identifier of the user.', + example: 'S-1-5-21-202424912787-2692429404-2351956786-1000', + name: 'user.id', type: 'keyword', }, - 'system.audit.package.license': { - category: 'system', - description: 'Package license. ', - name: 'system.audit.package.license', + 'user.name': { + category: 'user', + description: 'Short name or login of the user.', + example: 'a.einstein', + name: 'user.name', type: 'keyword', }, - 'system.audit.package.installtime': { - category: 'system', - description: 'Package install time. ', - name: 'system.audit.package.installtime', - type: 'date', + 'user.roles': { + category: 'user', + description: 'Array of user roles at the time of the event.', + example: '["kibana_admin", "reporting_user"]', + name: 'user.roles', + type: 'keyword', }, - 'system.audit.package.size': { - category: 'system', - description: 'Package size. ', - name: 'system.audit.package.size', - type: 'long', + 'user.target.domain': { + category: 'user', + description: + 'Name of the directory the user is a member of. For example, an LDAP or Active Directory domain name.', + name: 'user.target.domain', + type: 'keyword', }, - 'system.audit.package.summary': { - category: 'system', - description: 'Package summary. ', - name: 'system.audit.package.summary', + 'user.target.email': { + category: 'user', + description: 'User email address.', + name: 'user.target.email', + type: 'keyword', }, - 'system.audit.package.url': { - category: 'system', - description: 'Package URL. ', - name: 'system.audit.package.url', + 'user.target.full_name': { + category: 'user', + description: "User's full name, if available.", + example: 'Albert Einstein', + name: 'user.target.full_name', type: 'keyword', }, - 'system.audit.user.name': { - category: 'system', - description: 'User name. ', - name: 'system.audit.user.name', + 'user.target.group.domain': { + category: 'user', + description: + 'Name of the directory the group is a member of. For example, an LDAP or Active Directory domain name.', + name: 'user.target.group.domain', type: 'keyword', }, - 'system.audit.user.uid': { - category: 'system', - description: 'User ID. ', - name: 'system.audit.user.uid', + 'user.target.group.id': { + category: 'user', + description: 'Unique identifier for the group on the system/platform.', + name: 'user.target.group.id', type: 'keyword', }, - 'system.audit.user.gid': { - category: 'system', - description: 'Group ID. ', - name: 'system.audit.user.gid', + 'user.target.group.name': { + category: 'user', + description: 'Name of the group.', + name: 'user.target.group.name', type: 'keyword', }, - 'system.audit.user.dir': { - category: 'system', - description: "User's home directory. ", - name: 'system.audit.user.dir', + 'user.target.hash': { + category: 'user', + description: + 'Unique user hash to correlate information for a user in anonymized form. Useful if `user.id` or `user.name` contain confidential information and cannot be used.', + name: 'user.target.hash', type: 'keyword', }, - 'system.audit.user.shell': { - category: 'system', - description: 'Program to run at login. ', - name: 'system.audit.user.shell', + 'user.target.id': { + category: 'user', + description: 'Unique identifier of the user.', + example: 'S-1-5-21-202424912787-2692429404-2351956786-1000', + name: 'user.target.id', type: 'keyword', }, - 'system.audit.user.user_information': { - category: 'system', - description: 'General user information. On Linux, this is the gecos field. ', - name: 'system.audit.user.user_information', + 'user.target.name': { + category: 'user', + description: 'Short name or login of the user.', + example: 'a.einstein', + name: 'user.target.name', type: 'keyword', }, - 'system.audit.user.group.name': { - category: 'system', - description: 'Group name. ', - name: 'system.audit.user.group.name', + 'user.target.roles': { + category: 'user', + description: 'Array of user roles at the time of the event.', + example: '["kibana_admin", "reporting_user"]', + name: 'user.target.roles', type: 'keyword', }, - 'system.audit.user.group.gid': { - category: 'system', - description: 'Group ID. ', - name: 'system.audit.user.group.gid', - type: 'integer', + 'user_agent.device.name': { + category: 'user_agent', + description: 'Name of the device.', + example: 'iPhone', + name: 'user_agent.device.name', + type: 'keyword', }, - 'system.audit.user.password.type': { - category: 'system', - description: - "A user's password type. Possible values are `shadow_password` (the password hash is in the shadow file), `password_disabled`, `no_password` (this is dangerous as anyone can log in), and `crypt_password` (when the password field in /etc/passwd seems to contain an encrypted password). ", - name: 'system.audit.user.password.type', + 'user_agent.name': { + category: 'user_agent', + description: 'Name of the user agent.', + example: 'Safari', + name: 'user_agent.name', type: 'keyword', }, - 'system.audit.user.password.last_changed': { - category: 'system', - description: "The day the user's password was last changed. ", - name: 'system.audit.user.password.last_changed', - type: 'date', + 'user_agent.original': { + category: 'user_agent', + description: 'Unparsed user_agent string.', + example: + 'Mozilla/5.0 (iPhone; CPU iPhone OS 12_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0 Mobile/15E148 Safari/604.1', + name: 'user_agent.original', + type: 'keyword', }, - 'log.file.path': { - category: 'log', - description: - 'The file from which the line was read. This field contains the absolute path to the file. For example: `/var/log/system.log`. ', - name: 'log.file.path', + 'user_agent.os.family': { + category: 'user_agent', + description: 'OS family (such as redhat, debian, freebsd, windows).', + example: 'debian', + name: 'user_agent.os.family', type: 'keyword', }, - 'log.source.address': { - category: 'log', - description: 'Source address from which the log event was read / sent from. ', - name: 'log.source.address', + 'user_agent.os.full': { + category: 'user_agent', + description: 'Operating system name, including the version or code name.', + example: 'Mac OS Mojave', + name: 'user_agent.os.full', type: 'keyword', }, - 'log.offset': { - category: 'log', - description: 'The file offset the reported line starts at. ', - name: 'log.offset', - type: 'long', + 'user_agent.os.kernel': { + category: 'user_agent', + description: 'Operating system kernel version as a raw string.', + example: '4.4.0-112-generic', + name: 'user_agent.os.kernel', + type: 'keyword', }, - stream: { - category: 'base', - description: "Log stream when reading container logs, can be 'stdout' or 'stderr' ", - name: 'stream', + 'user_agent.os.name': { + category: 'user_agent', + description: 'Operating system name, without the version.', + example: 'Mac OS X', + name: 'user_agent.os.name', type: 'keyword', }, - 'input.type': { - category: 'input', + 'user_agent.os.platform': { + category: 'user_agent', + description: 'Operating system platform (such centos, ubuntu, windows).', + example: 'darwin', + name: 'user_agent.os.platform', + type: 'keyword', + }, + 'user_agent.os.type': { + category: 'user_agent', description: - 'The input type from which the event was generated. This field is set to the value specified for the `type` option in the input section of the Filebeat config file. ', - name: 'input.type', + "Use the `os.type` field to categorize the operating system into one of the broad commercial families. One of these following values should be used (lowercase): linux, macos, unix, windows. If the OS you're dealing with is not in the list, the field should not be populated. Please let us know by opening an issue with ECS, to propose its addition.", + example: 'macos', + name: 'user_agent.os.type', + type: 'keyword', }, - 'syslog.facility': { - category: 'syslog', - description: 'The facility extracted from the priority. ', - name: 'syslog.facility', - type: 'long', + 'user_agent.os.version': { + category: 'user_agent', + description: 'Operating system version as a raw string.', + example: '10.14.1', + name: 'user_agent.os.version', + type: 'keyword', }, - 'syslog.priority': { - category: 'syslog', - description: 'The priority of the syslog event. ', - name: 'syslog.priority', - type: 'long', + 'user_agent.version': { + category: 'user_agent', + description: 'Version of the user agent.', + example: 12, + name: 'user_agent.version', + type: 'keyword', }, - 'syslog.severity_label': { - category: 'syslog', - description: 'The human readable severity. ', - name: 'syslog.severity_label', + 'vlan.id': { + category: 'vlan', + description: 'VLAN ID as reported by the observer.', + example: 10, + name: 'vlan.id', type: 'keyword', }, - 'syslog.facility_label': { - category: 'syslog', - description: 'The human readable facility. ', - name: 'syslog.facility_label', + 'vlan.name': { + category: 'vlan', + description: 'Optional VLAN name as reported by the observer.', + example: 'outside', + name: 'vlan.name', type: 'keyword', }, - 'process.program': { - category: 'process', - description: 'The name of the program. ', - name: 'process.program', + 'vulnerability.category': { + category: 'vulnerability', + description: + 'The type of system or architecture that the vulnerability affects. These may be platform-specific (for example, Debian or SUSE) or general (for example, Database or Firewall). For example (https://qualysguard.qualys.com/qwebhelp/fo_portal/knowledgebase/vulnerability_categories.htm[Qualys vulnerability categories]) This field must be an array.', + example: '["Firewall"]', + name: 'vulnerability.category', type: 'keyword', }, - 'log.flags': { - category: 'log', - description: 'This field contains the flags of the event. ', - name: 'log.flags', + 'vulnerability.classification': { + category: 'vulnerability', + description: + 'The classification of the vulnerability scoring system. For example (https://www.first.org/cvss/)', + example: 'CVSS', + name: 'vulnerability.classification', + type: 'keyword', }, - 'http.response.content_length': { - category: 'http', - name: 'http.response.content_length', - type: 'alias', + 'vulnerability.description': { + category: 'vulnerability', + description: + 'The description of the vulnerability that provides additional context of the vulnerability. For example (https://cve.mitre.org/about/faqs.html#cve_entry_descriptions_created[Common Vulnerabilities and Exposure CVE description])', + example: 'In macOS before 2.12.6, there is a vulnerability in the RPC...', + name: 'vulnerability.description', + type: 'keyword', }, - 'user_agent.os.full_name': { - category: 'user_agent', - name: 'user_agent.os.full_name', + 'vulnerability.enumeration': { + category: 'vulnerability', + description: + 'The type of identifier used for this vulnerability. For example (https://cve.mitre.org/about/)', + example: 'CVE', + name: 'vulnerability.enumeration', type: 'keyword', }, - 'fileset.name': { - category: 'fileset', - description: 'The Filebeat fileset that generated this event. ', - name: 'fileset.name', + 'vulnerability.id': { + category: 'vulnerability', + description: + 'The identification (ID) is the number portion of a vulnerability entry. It includes a unique identification number for the vulnerability. For example (https://cve.mitre.org/about/faqs.html#what_is_cve_id)[Common Vulnerabilities and Exposure CVE ID]', + example: 'CVE-2019-00001', + name: 'vulnerability.id', type: 'keyword', }, - 'fileset.module': { - category: 'fileset', - name: 'fileset.module', - type: 'alias', + 'vulnerability.reference': { + category: 'vulnerability', + description: + 'A resource that provides additional information, context, and mitigations for the identified vulnerability.', + example: 'https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-6111', + name: 'vulnerability.reference', + type: 'keyword', }, - read_timestamp: { - category: 'base', - name: 'read_timestamp', - type: 'alias', + 'vulnerability.report_id': { + category: 'vulnerability', + description: 'The report or scan identification number.', + example: 20191018.0001, + name: 'vulnerability.report_id', + type: 'keyword', }, - 'docker.attrs': { - category: 'docker', + 'vulnerability.scanner.vendor': { + category: 'vulnerability', + description: 'The name of the vulnerability scanner vendor.', + example: 'Tenable', + name: 'vulnerability.scanner.vendor', + type: 'keyword', + }, + 'vulnerability.score.base': { + category: 'vulnerability', description: - "docker.attrs contains labels and environment variables written by docker's JSON File logging driver. These fields are only available when they are configured in the logging driver options. ", - name: 'docker.attrs', - type: 'object', + 'Scores can range from 0.0 to 10.0, with 10.0 being the most severe. Base scores cover an assessment for exploitability metrics (attack vector, complexity, privileges, and user interaction), impact metrics (confidentiality, integrity, and availability), and scope. For example (https://www.first.org/cvss/specification-document)', + example: 5.5, + name: 'vulnerability.score.base', + type: 'float', }, - 'icmp.code': { - category: 'icmp', - description: 'ICMP code. ', - name: 'icmp.code', + 'vulnerability.score.environmental': { + category: 'vulnerability', + description: + 'Scores can range from 0.0 to 10.0, with 10.0 being the most severe. Environmental scores cover an assessment for any modified Base metrics, confidentiality, integrity, and availability requirements. For example (https://www.first.org/cvss/specification-document)', + example: 5.5, + name: 'vulnerability.score.environmental', + type: 'float', + }, + 'vulnerability.score.temporal': { + category: 'vulnerability', + description: + 'Scores can range from 0.0 to 10.0, with 10.0 being the most severe. Temporal scores cover an assessment for code maturity, remediation level, and confidence. For example (https://www.first.org/cvss/specification-document)', + name: 'vulnerability.score.temporal', + type: 'float', + }, + 'vulnerability.score.version': { + category: 'vulnerability', + description: + 'The National Vulnerability Database (NVD) provides qualitative severity rankings of "Low", "Medium", and "High" for CVSS v2.0 base score ranges in addition to the severity ratings for CVSS v3.0 as they are defined in the CVSS v3.0 specification. CVSS is owned and managed by FIRST.Org, Inc. (FIRST), a US-based non-profit organization, whose mission is to help computer security incident response teams across the world. For example (https://nvd.nist.gov/vuln-metrics/cvss)', + example: 2, + name: 'vulnerability.score.version', type: 'keyword', }, - 'icmp.type': { - category: 'icmp', - description: 'ICMP type. ', - name: 'icmp.type', + 'vulnerability.severity': { + category: 'vulnerability', + description: + 'The severity of the vulnerability can help with metrics and internal prioritization regarding remediation. For example (https://nvd.nist.gov/vuln-metrics/cvss)', + example: 'Critical', + name: 'vulnerability.severity', type: 'keyword', }, - 'igmp.type': { - category: 'igmp', - description: 'IGMP type. ', - name: 'igmp.type', + 'x509.alternative_names': { + category: 'x509', + description: + 'List of subject alternative names (SAN). Name types vary by certificate authority and certificate type but commonly contain IP addresses, DNS names (and wildcards), and email addresses.', + example: '*.elastic.co', + name: 'x509.alternative_names', type: 'keyword', }, - 'azure.eventhub': { - category: 'azure', - description: 'Name of the eventhub. ', - name: 'azure.eventhub', + 'x509.issuer.common_name': { + category: 'x509', + description: 'List of common name (CN) of issuing certificate authority.', + example: 'Example SHA2 High Assurance Server CA', + name: 'x509.issuer.common_name', type: 'keyword', }, - 'azure.offset': { - category: 'azure', - description: 'The offset. ', - name: 'azure.offset', - type: 'long', + 'x509.issuer.country': { + category: 'x509', + description: 'List of country (C) codes', + example: 'US', + name: 'x509.issuer.country', + type: 'keyword', }, - 'azure.enqueued_time': { - category: 'azure', - description: 'The enqueued time. ', - name: 'azure.enqueued_time', - type: 'date', + 'x509.issuer.distinguished_name': { + category: 'x509', + description: 'Distinguished name (DN) of issuing certificate authority.', + example: 'C=US, O=Example Inc, OU=www.example.com, CN=Example SHA2 High Assurance Server CA', + name: 'x509.issuer.distinguished_name', + type: 'keyword', }, - 'azure.partition_id': { - category: 'azure', - description: 'The partition id. ', - name: 'azure.partition_id', - type: 'long', + 'x509.issuer.locality': { + category: 'x509', + description: 'List of locality names (L)', + example: 'Mountain View', + name: 'x509.issuer.locality', + type: 'keyword', }, - 'azure.consumer_group': { - category: 'azure', - description: 'The consumer group. ', - name: 'azure.consumer_group', + 'x509.issuer.organization': { + category: 'x509', + description: 'List of organizations (O) of issuing certificate authority.', + example: 'Example Inc', + name: 'x509.issuer.organization', type: 'keyword', }, - 'azure.sequence_number': { - category: 'azure', - description: 'The sequence number. ', - name: 'azure.sequence_number', - type: 'long', + 'x509.issuer.organizational_unit': { + category: 'x509', + description: 'List of organizational units (OU) of issuing certificate authority.', + example: 'www.example.com', + name: 'x509.issuer.organizational_unit', + type: 'keyword', }, - 'kafka.topic': { - category: 'kafka', - description: 'Kafka topic ', - name: 'kafka.topic', + 'x509.issuer.state_or_province': { + category: 'x509', + description: 'List of state or province names (ST, S, or P)', + example: 'California', + name: 'x509.issuer.state_or_province', type: 'keyword', }, - 'kafka.partition': { - category: 'kafka', - description: 'Kafka partition number ', - name: 'kafka.partition', - type: 'long', + 'x509.not_after': { + category: 'x509', + description: 'Time at which the certificate is no longer considered valid.', + example: '"2020-07-16T03:15:39.000Z"', + name: 'x509.not_after', + type: 'date', }, - 'kafka.offset': { - category: 'kafka', - description: 'Kafka offset of this message ', - name: 'kafka.offset', - type: 'long', + 'x509.not_before': { + category: 'x509', + description: 'Time at which the certificate is first considered valid.', + example: '"2019-08-16T01:40:25.000Z"', + name: 'x509.not_before', + type: 'date', }, - 'kafka.key': { - category: 'kafka', - description: 'Kafka key, corresponding to the Kafka value stored in the message ', - name: 'kafka.key', + 'x509.public_key_algorithm': { + category: 'x509', + description: 'Algorithm used to generate the public key.', + example: 'RSA', + name: 'x509.public_key_algorithm', type: 'keyword', }, - 'kafka.block_timestamp': { - category: 'kafka', - description: 'Kafka outer (compressed) block timestamp ', - name: 'kafka.block_timestamp', - type: 'date', - }, - 'kafka.headers': { - category: 'kafka', + 'x509.public_key_curve': { + category: 'x509', description: - 'An array of Kafka header strings for this message, in the form ": ". ', - name: 'kafka.headers', - type: 'array', + 'The curve used by the elliptic curve public key algorithm. This is algorithm specific.', + example: 'nistp521', + name: 'x509.public_key_curve', + type: 'keyword', }, - 'apache2.access.remote_ip': { - category: 'apache2', - name: 'apache2.access.remote_ip', - type: 'alias', + 'x509.public_key_exponent': { + category: 'x509', + description: 'Exponent used to derive the public key. This is algorithm specific.', + example: 65537, + name: 'x509.public_key_exponent', + type: 'long', }, - 'apache2.access.ssl.protocol': { - category: 'apache2', - name: 'apache2.access.ssl.protocol', - type: 'alias', + 'x509.public_key_size': { + category: 'x509', + description: 'The size of the public key space in bits.', + example: 2048, + name: 'x509.public_key_size', + type: 'long', }, - 'apache2.access.ssl.cipher': { - category: 'apache2', - name: 'apache2.access.ssl.cipher', - type: 'alias', + 'x509.serial_number': { + category: 'x509', + description: + 'Unique serial number issued by the certificate authority. For consistency, if this value is alphanumeric, it should be formatted without colons and uppercase characters.', + example: '55FBB9C7DEBF09809D12CCAA', + name: 'x509.serial_number', + type: 'keyword', }, - 'apache2.access.body_sent.bytes': { - category: 'apache2', - name: 'apache2.access.body_sent.bytes', - type: 'alias', + 'x509.signature_algorithm': { + category: 'x509', + description: + 'Identifier for certificate signature algorithm. We recommend using names found in Go Lang Crypto library. See https://github.com/golang/go/blob/go1.14/src/crypto/x509/x509.go#L337-L353.', + example: 'SHA256-RSA', + name: 'x509.signature_algorithm', + type: 'keyword', }, - 'apache2.access.user_name': { - category: 'apache2', - name: 'apache2.access.user_name', - type: 'alias', + 'x509.subject.common_name': { + category: 'x509', + description: 'List of common names (CN) of subject.', + example: 'shared.global.example.net', + name: 'x509.subject.common_name', + type: 'keyword', }, - 'apache2.access.method': { - category: 'apache2', - name: 'apache2.access.method', - type: 'alias', + 'x509.subject.country': { + category: 'x509', + description: 'List of country (C) code', + example: 'US', + name: 'x509.subject.country', + type: 'keyword', }, - 'apache2.access.url': { - category: 'apache2', - name: 'apache2.access.url', - type: 'alias', + 'x509.subject.distinguished_name': { + category: 'x509', + description: 'Distinguished name (DN) of the certificate subject entity.', + example: 'C=US, ST=California, L=San Francisco, O=Example, Inc., CN=shared.global.example.net', + name: 'x509.subject.distinguished_name', + type: 'keyword', }, - 'apache2.access.http_version': { - category: 'apache2', - name: 'apache2.access.http_version', - type: 'alias', + 'x509.subject.locality': { + category: 'x509', + description: 'List of locality names (L)', + example: 'San Francisco', + name: 'x509.subject.locality', + type: 'keyword', }, - 'apache2.access.response_code': { - category: 'apache2', - name: 'apache2.access.response_code', - type: 'alias', + 'x509.subject.organization': { + category: 'x509', + description: 'List of organizations (O) of subject.', + example: 'Example, Inc.', + name: 'x509.subject.organization', + type: 'keyword', }, - 'apache2.access.referrer': { - category: 'apache2', - name: 'apache2.access.referrer', - type: 'alias', + 'x509.subject.organizational_unit': { + category: 'x509', + description: 'List of organizational units (OU) of subject.', + name: 'x509.subject.organizational_unit', + type: 'keyword', }, - 'apache2.access.agent': { - category: 'apache2', - name: 'apache2.access.agent', - type: 'alias', + 'x509.subject.state_or_province': { + category: 'x509', + description: 'List of state or province names (ST, S, or P)', + example: 'California', + name: 'x509.subject.state_or_province', + type: 'keyword', }, - 'apache2.access.user_agent.device': { - category: 'apache2', - name: 'apache2.access.user_agent.device', - type: 'alias', + 'x509.version_number': { + category: 'x509', + description: 'Version of x509 format.', + example: 3, + name: 'x509.version_number', + type: 'keyword', }, - 'apache2.access.user_agent.name': { - category: 'apache2', - name: 'apache2.access.user_agent.name', + 'agent.hostname': { + category: 'agent', + description: 'Deprecated - use agent.name or agent.id to identify an agent. ', + name: 'agent.hostname', type: 'alias', }, - 'apache2.access.user_agent.os': { - category: 'apache2', - name: 'apache2.access.user_agent.os', + 'beat.timezone': { + category: 'beat', + name: 'beat.timezone', type: 'alias', }, - 'apache2.access.user_agent.os_name': { - category: 'apache2', - name: 'apache2.access.user_agent.os_name', - type: 'alias', + fields: { + category: 'base', + description: 'Contains user configurable fields. ', + name: 'fields', + type: 'object', }, - 'apache2.access.user_agent.original': { - category: 'apache2', - name: 'apache2.access.user_agent.original', + 'beat.name': { + category: 'beat', + name: 'beat.name', type: 'alias', }, - 'apache2.access.geoip.continent_name': { - category: 'apache2', - name: 'apache2.access.geoip.continent_name', + 'beat.hostname': { + category: 'beat', + name: 'beat.hostname', type: 'alias', }, - 'apache2.access.geoip.country_iso_code': { - category: 'apache2', - name: 'apache2.access.geoip.country_iso_code', + 'timeseries.instance': { + category: 'timeseries', + description: 'Time series instance id', + name: 'timeseries.instance', + type: 'keyword', + }, + 'cloud.image.id': { + category: 'cloud', + description: 'Image ID for the cloud instance. ', + example: 'ami-abcd1234', + name: 'cloud.image.id', + }, + 'meta.cloud.provider': { + category: 'meta', + name: 'meta.cloud.provider', type: 'alias', }, - 'apache2.access.geoip.location': { - category: 'apache2', - name: 'apache2.access.geoip.location', + 'meta.cloud.instance_id': { + category: 'meta', + name: 'meta.cloud.instance_id', type: 'alias', }, - 'apache2.access.geoip.region_name': { - category: 'apache2', - name: 'apache2.access.geoip.region_name', + 'meta.cloud.instance_name': { + category: 'meta', + name: 'meta.cloud.instance_name', type: 'alias', }, - 'apache2.access.geoip.city_name': { - category: 'apache2', - name: 'apache2.access.geoip.city_name', + 'meta.cloud.machine_type': { + category: 'meta', + name: 'meta.cloud.machine_type', type: 'alias', }, - 'apache2.access.geoip.region_iso_code': { - category: 'apache2', - name: 'apache2.access.geoip.region_iso_code', + 'meta.cloud.availability_zone': { + category: 'meta', + name: 'meta.cloud.availability_zone', type: 'alias', }, - 'apache2.error.level': { - category: 'apache2', - name: 'apache2.error.level', + 'meta.cloud.project_id': { + category: 'meta', + name: 'meta.cloud.project_id', type: 'alias', }, - 'apache2.error.message': { - category: 'apache2', - name: 'apache2.error.message', + 'meta.cloud.region': { + category: 'meta', + name: 'meta.cloud.region', type: 'alias', }, - 'apache2.error.pid': { - category: 'apache2', - name: 'apache2.error.pid', + 'docker.container.id': { + category: 'docker', + name: 'docker.container.id', type: 'alias', }, - 'apache2.error.tid': { - category: 'apache2', - name: 'apache2.error.tid', + 'docker.container.image': { + category: 'docker', + name: 'docker.container.image', type: 'alias', }, - 'apache2.error.module': { - category: 'apache2', - name: 'apache2.error.module', + 'docker.container.name': { + category: 'docker', + name: 'docker.container.name', type: 'alias', }, - 'apache.access.ssl.protocol': { - category: 'apache', - description: 'SSL protocol version. ', - name: 'apache.access.ssl.protocol', + 'docker.container.labels': { + category: 'docker', + description: 'Image labels. ', + name: 'docker.container.labels', + type: 'object', + }, + 'host.containerized': { + category: 'host', + description: 'If the host is a container. ', + name: 'host.containerized', + type: 'boolean', + }, + 'host.os.build': { + category: 'host', + description: 'OS build information. ', + example: '18D109', + name: 'host.os.build', type: 'keyword', }, - 'apache.access.ssl.cipher': { - category: 'apache', - description: 'SSL cipher name. ', - name: 'apache.access.ssl.cipher', + 'host.os.codename': { + category: 'host', + description: 'OS codename, if any. ', + example: 'stretch', + name: 'host.os.codename', type: 'keyword', }, - 'apache.error.module': { - category: 'apache', - description: 'The module producing the logged message. ', - name: 'apache.error.module', + 'kubernetes.pod.name': { + category: 'kubernetes', + description: 'Kubernetes pod name ', + name: 'kubernetes.pod.name', type: 'keyword', }, - 'user.audit.group.id': { - category: 'user', - description: 'Unique identifier for the group on the system/platform. ', - name: 'user.audit.group.id', + 'kubernetes.pod.uid': { + category: 'kubernetes', + description: 'Kubernetes Pod UID ', + name: 'kubernetes.pod.uid', type: 'keyword', }, - 'user.audit.group.name': { - category: 'user', - description: 'Name of the group. ', - name: 'user.audit.group.name', + 'kubernetes.pod.ip': { + category: 'kubernetes', + description: 'Kubernetes Pod IP ', + name: 'kubernetes.pod.ip', + type: 'ip', + }, + 'kubernetes.namespace': { + category: 'kubernetes', + description: 'Kubernetes namespace ', + name: 'kubernetes.namespace', type: 'keyword', }, - 'user.owner.id': { - category: 'user', - description: 'One or multiple unique identifiers of the user. ', - name: 'user.owner.id', + 'kubernetes.node.name': { + category: 'kubernetes', + description: 'Kubernetes node name ', + name: 'kubernetes.node.name', type: 'keyword', }, - 'user.owner.name': { - category: 'user', - description: 'Short name or login of the user. ', - example: 'albert', - name: 'user.owner.name', + 'kubernetes.node.hostname': { + category: 'kubernetes', + description: 'Kubernetes hostname as reported by the node’s kernel ', + name: 'kubernetes.node.hostname', type: 'keyword', }, - 'user.owner.group.id': { - category: 'user', - description: 'Unique identifier for the group on the system/platform. ', - name: 'user.owner.group.id', + 'kubernetes.labels.*': { + category: 'kubernetes', + description: 'Kubernetes labels map ', + name: 'kubernetes.labels.*', + type: 'object', + }, + 'kubernetes.annotations.*': { + category: 'kubernetes', + description: 'Kubernetes annotations map ', + name: 'kubernetes.annotations.*', + type: 'object', + }, + 'kubernetes.selectors.*': { + category: 'kubernetes', + description: 'Kubernetes selectors map ', + name: 'kubernetes.selectors.*', + type: 'object', + }, + 'kubernetes.replicaset.name': { + category: 'kubernetes', + description: 'Kubernetes replicaset name ', + name: 'kubernetes.replicaset.name', type: 'keyword', }, - 'user.owner.group.name': { - category: 'user', - description: 'Name of the group. ', - name: 'user.owner.group.name', + 'kubernetes.deployment.name': { + category: 'kubernetes', + description: 'Kubernetes deployment name ', + name: 'kubernetes.deployment.name', type: 'keyword', }, - 'auditd.log.old_auid': { - category: 'auditd', - description: - 'For login events this is the old audit ID used for the user prior to this login. ', - name: 'auditd.log.old_auid', + 'kubernetes.statefulset.name': { + category: 'kubernetes', + description: 'Kubernetes statefulset name ', + name: 'kubernetes.statefulset.name', + type: 'keyword', }, - 'auditd.log.new_auid': { - category: 'auditd', - description: - 'For login events this is the new audit ID. The audit ID can be used to trace future events to the user even if their identity changes (like becoming root). ', - name: 'auditd.log.new_auid', + 'kubernetes.container.name': { + category: 'kubernetes', + description: 'Kubernetes container name (different than the name from the runtime) ', + name: 'kubernetes.container.name', + type: 'keyword', }, - 'auditd.log.old_ses': { - category: 'auditd', - description: - 'For login events this is the old session ID used for the user prior to this login. ', - name: 'auditd.log.old_ses', + 'process.exe': { + category: 'process', + name: 'process.exe', + type: 'alias', }, - 'auditd.log.new_ses': { - category: 'auditd', + 'process.owner.id': { + category: 'process', + description: 'Unique identifier of the user.', + name: 'process.owner.id', + type: 'keyword', + }, + 'process.owner.name': { + category: 'process', + description: 'Short name or login of the user.', + example: 'albert', + name: 'process.owner.name', + type: 'keyword', + }, + 'jolokia.agent.version': { + category: 'jolokia', + description: 'Version number of jolokia agent. ', + name: 'jolokia.agent.version', + type: 'keyword', + }, + 'jolokia.agent.id': { + category: 'jolokia', description: - 'For login events this is the new session ID. It can be used to tie a user to future events by session ID. ', - name: 'auditd.log.new_ses', + 'Each agent has a unique id which can be either provided during startup of the agent in form of a configuration parameter or being autodetected. If autodected, the id has several parts: The IP, the process id, hashcode of the agent and its type. ', + name: 'jolokia.agent.id', + type: 'keyword', }, - 'auditd.log.sequence': { - category: 'auditd', - description: 'The audit event sequence number. ', - name: 'auditd.log.sequence', - type: 'long', + 'jolokia.server.product': { + category: 'jolokia', + description: 'The container product if detected. ', + name: 'jolokia.server.product', + type: 'keyword', }, - 'auditd.log.items': { - category: 'auditd', - description: 'The number of items in an event. ', - name: 'auditd.log.items', + 'jolokia.server.version': { + category: 'jolokia', + description: "The container's version (if detected). ", + name: 'jolokia.server.version', + type: 'keyword', }, - 'auditd.log.item': { - category: 'auditd', + 'jolokia.server.vendor': { + category: 'jolokia', + description: 'The vendor of the container the agent is running in. ', + name: 'jolokia.server.vendor', + type: 'keyword', + }, + 'jolokia.url': { + category: 'jolokia', + description: 'The URL how this agent can be contacted. ', + name: 'jolokia.url', + type: 'keyword', + }, + 'jolokia.secured': { + category: 'jolokia', + description: 'Whether the agent was configured for authentication or not. ', + name: 'jolokia.secured', + type: 'boolean', + }, + 'file.setuid': { + category: 'file', + description: 'Set if the file has the `setuid` bit set. Omitted otherwise.', + example: 'true', + name: 'file.setuid', + type: 'boolean', + }, + 'file.setgid': { + category: 'file', + description: 'Set if the file has the `setgid` bit set. Omitted otherwise.', + example: 'true', + name: 'file.setgid', + type: 'boolean', + }, + 'file.origin': { + category: 'file', description: - 'The item field indicates which item out of the total number of items. This number is zero-based; a value of 0 means it is the first item. ', - name: 'auditd.log.item', + 'An array of strings describing a possible external origin for this file. For example, the URL it was downloaded from. Only supported in macOS, via the kMDItemWhereFroms attribute. Omitted if origin information is not available. ', + name: 'file.origin', + type: 'keyword', }, - 'auditd.log.tty': { - category: 'auditd', - name: 'auditd.log.tty', + 'file.selinux.user': { + category: 'file', + description: 'The owner of the object.', + name: 'file.selinux.user', type: 'keyword', }, - 'auditd.log.a0': { - category: 'auditd', - description: 'The first argument to the system call. ', - name: 'auditd.log.a0', + 'file.selinux.role': { + category: 'file', + description: "The object's SELinux role.", + name: 'file.selinux.role', + type: 'keyword', }, - 'auditd.log.addr': { - category: 'auditd', - name: 'auditd.log.addr', - type: 'ip', + 'file.selinux.domain': { + category: 'file', + description: "The object's SELinux domain or type.", + name: 'file.selinux.domain', + type: 'keyword', }, - 'auditd.log.rport': { - category: 'auditd', - name: 'auditd.log.rport', - type: 'long', + 'file.selinux.level': { + category: 'file', + description: "The object's SELinux level.", + example: 's0', + name: 'file.selinux.level', + type: 'keyword', }, - 'auditd.log.laddr': { - category: 'auditd', - name: 'auditd.log.laddr', - type: 'ip', + 'user.audit.id': { + category: 'user', + description: 'Audit user ID.', + name: 'user.audit.id', + type: 'keyword', }, - 'auditd.log.lport': { - category: 'auditd', - name: 'auditd.log.lport', - type: 'long', + 'user.audit.name': { + category: 'user', + description: 'Audit user name.', + name: 'user.audit.name', + type: 'keyword', }, - 'auditd.log.acct': { - category: 'auditd', - name: 'auditd.log.acct', - type: 'alias', + 'user.filesystem.id': { + category: 'user', + description: 'Filesystem user ID.', + name: 'user.filesystem.id', + type: 'keyword', }, - 'auditd.log.pid': { - category: 'auditd', - name: 'auditd.log.pid', - type: 'alias', + 'user.filesystem.name': { + category: 'user', + description: 'Filesystem user name.', + name: 'user.filesystem.name', + type: 'keyword', }, - 'auditd.log.ppid': { - category: 'auditd', - name: 'auditd.log.ppid', - type: 'alias', + 'user.filesystem.group.id': { + category: 'user', + description: 'Filesystem group ID.', + name: 'user.filesystem.group.id', + type: 'keyword', }, - 'auditd.log.res': { - category: 'auditd', - name: 'auditd.log.res', - type: 'alias', + 'user.filesystem.group.name': { + category: 'user', + description: 'Filesystem group name.', + name: 'user.filesystem.group.name', + type: 'keyword', }, - 'auditd.log.record_type': { - category: 'auditd', - name: 'auditd.log.record_type', - type: 'alias', + 'user.saved.id': { + category: 'user', + description: 'Saved user ID.', + name: 'user.saved.id', + type: 'keyword', }, - 'auditd.log.geoip.continent_name': { - category: 'auditd', - name: 'auditd.log.geoip.continent_name', - type: 'alias', + 'user.saved.name': { + category: 'user', + description: 'Saved user name.', + name: 'user.saved.name', + type: 'keyword', }, - 'auditd.log.geoip.country_iso_code': { - category: 'auditd', - name: 'auditd.log.geoip.country_iso_code', - type: 'alias', + 'user.saved.group.id': { + category: 'user', + description: 'Saved group ID.', + name: 'user.saved.group.id', + type: 'keyword', }, - 'auditd.log.geoip.location': { - category: 'auditd', - name: 'auditd.log.geoip.location', - type: 'alias', + 'user.saved.group.name': { + category: 'user', + description: 'Saved group name.', + name: 'user.saved.group.name', + type: 'keyword', }, - 'auditd.log.geoip.region_name': { - category: 'auditd', - name: 'auditd.log.geoip.region_name', + 'user.auid': { + category: 'user', + name: 'user.auid', type: 'alias', }, - 'auditd.log.geoip.city_name': { - category: 'auditd', - name: 'auditd.log.geoip.city_name', + 'user.uid': { + category: 'user', + name: 'user.uid', type: 'alias', }, - 'auditd.log.geoip.region_iso_code': { - category: 'auditd', - name: 'auditd.log.geoip.region_iso_code', + 'user.fsuid': { + category: 'user', + name: 'user.fsuid', type: 'alias', }, - 'auditd.log.arch': { - category: 'auditd', - name: 'auditd.log.arch', + 'user.suid': { + category: 'user', + name: 'user.suid', type: 'alias', }, - 'auditd.log.gid': { - category: 'auditd', - name: 'auditd.log.gid', + 'user.gid': { + category: 'user', + name: 'user.gid', type: 'alias', }, - 'auditd.log.uid': { - category: 'auditd', - name: 'auditd.log.uid', + 'user.sgid': { + category: 'user', + name: 'user.sgid', type: 'alias', }, - 'auditd.log.agid': { - category: 'auditd', - name: 'auditd.log.agid', + 'user.fsgid': { + category: 'user', + name: 'user.fsgid', type: 'alias', }, - 'auditd.log.auid': { - category: 'auditd', - name: 'auditd.log.auid', + 'user.name_map.auid': { + category: 'user', + name: 'user.name_map.auid', type: 'alias', }, - 'auditd.log.fsgid': { - category: 'auditd', - name: 'auditd.log.fsgid', + 'user.name_map.uid': { + category: 'user', + name: 'user.name_map.uid', type: 'alias', }, - 'auditd.log.fsuid': { - category: 'auditd', - name: 'auditd.log.fsuid', + 'user.name_map.fsuid': { + category: 'user', + name: 'user.name_map.fsuid', type: 'alias', }, - 'auditd.log.egid': { - category: 'auditd', - name: 'auditd.log.egid', + 'user.name_map.suid': { + category: 'user', + name: 'user.name_map.suid', type: 'alias', }, - 'auditd.log.euid': { - category: 'auditd', - name: 'auditd.log.euid', + 'user.name_map.gid': { + category: 'user', + name: 'user.name_map.gid', type: 'alias', }, - 'auditd.log.sgid': { - category: 'auditd', - name: 'auditd.log.sgid', + 'user.name_map.sgid': { + category: 'user', + name: 'user.name_map.sgid', type: 'alias', }, - 'auditd.log.suid': { - category: 'auditd', - name: 'auditd.log.suid', + 'user.name_map.fsgid': { + category: 'user', + name: 'user.name_map.fsgid', type: 'alias', }, - 'auditd.log.ogid': { - category: 'auditd', - name: 'auditd.log.ogid', + 'user.selinux.user': { + category: 'user', + description: 'account submitted for authentication', + name: 'user.selinux.user', + type: 'keyword', + }, + 'user.selinux.role': { + category: 'user', + description: "user's SELinux role", + name: 'user.selinux.role', + type: 'keyword', + }, + 'user.selinux.domain': { + category: 'user', + description: "The actor's SELinux domain or type.", + name: 'user.selinux.domain', + type: 'keyword', + }, + 'user.selinux.level': { + category: 'user', + description: "The actor's SELinux level.", + example: 's0', + name: 'user.selinux.level', + type: 'keyword', + }, + 'user.selinux.category': { + category: 'user', + description: "The actor's SELinux category or compartments.", + name: 'user.selinux.category', + type: 'keyword', + }, + 'process.cwd': { + category: 'process', + description: 'The current working directory.', + name: 'process.cwd', type: 'alias', }, - 'auditd.log.ouid': { + 'source.path': { + category: 'source', + description: 'This is the path associated with a unix socket.', + name: 'source.path', + type: 'keyword', + }, + 'destination.path': { + category: 'destination', + description: 'This is the path associated with a unix socket.', + name: 'destination.path', + type: 'keyword', + }, + 'auditd.message_type': { category: 'auditd', - name: 'auditd.log.ouid', - type: 'alias', + description: 'The audit message type (e.g. syscall or apparmor_denied). ', + example: 'syscall', + name: 'auditd.message_type', + type: 'keyword', }, - 'auditd.log.comm': { + 'auditd.sequence': { category: 'auditd', - name: 'auditd.log.comm', - type: 'alias', + description: + 'The sequence number of the event as assigned by the kernel. Sequence numbers are stored as a uint32 in the kernel and can rollover. ', + name: 'auditd.sequence', + type: 'long', }, - 'auditd.log.exe': { + 'auditd.session': { category: 'auditd', - name: 'auditd.log.exe', - type: 'alias', + description: + 'The session ID assigned to a login. All events related to a login session will have the same value. ', + name: 'auditd.session', + type: 'keyword', }, - 'auditd.log.terminal': { + 'auditd.result': { category: 'auditd', - name: 'auditd.log.terminal', - type: 'alias', + description: 'The result of the audited operation (success/fail).', + example: 'success or fail', + name: 'auditd.result', + type: 'keyword', }, - 'auditd.log.msg': { + 'auditd.summary.actor.primary': { category: 'auditd', - name: 'auditd.log.msg', - type: 'alias', + description: + "The primary identity of the actor. This is the actor's original login ID. It will not change even if the user changes to another account. ", + name: 'auditd.summary.actor.primary', + type: 'keyword', }, - 'auditd.log.src': { + 'auditd.summary.actor.secondary': { category: 'auditd', - name: 'auditd.log.src', - type: 'alias', + description: + 'The secondary identity of the actor. This is typically the same as the primary, except for when the user has used `su`.', + name: 'auditd.summary.actor.secondary', + type: 'keyword', }, - 'auditd.log.dst': { + 'auditd.summary.object.type': { category: 'auditd', - name: 'auditd.log.dst', - type: 'alias', + description: 'A description of the what the "thing" is (e.g. file, socket, user-session). ', + name: 'auditd.summary.object.type', + type: 'keyword', }, - 'elasticsearch.component': { - category: 'elasticsearch', - description: 'Elasticsearch component from where the log event originated', - example: 'o.e.c.m.MetaDataCreateIndexService', - name: 'elasticsearch.component', + 'auditd.summary.object.primary': { + category: 'auditd', + description: '', + name: 'auditd.summary.object.primary', type: 'keyword', }, - 'elasticsearch.cluster.uuid': { - category: 'elasticsearch', - description: 'UUID of the cluster', - example: 'GmvrbHlNTiSVYiPf8kxg9g', - name: 'elasticsearch.cluster.uuid', + 'auditd.summary.object.secondary': { + category: 'auditd', + description: '', + name: 'auditd.summary.object.secondary', type: 'keyword', }, - 'elasticsearch.cluster.name': { - category: 'elasticsearch', - description: 'Name of the cluster', - example: 'docker-cluster', - name: 'elasticsearch.cluster.name', + 'auditd.summary.how': { + category: 'auditd', + description: + 'This describes how the action was performed. Usually this is the exe or command that was being executed that triggered the event. ', + name: 'auditd.summary.how', type: 'keyword', }, - 'elasticsearch.node.id': { - category: 'elasticsearch', - description: 'ID of the node', - example: 'DSiWcTyeThWtUXLB9J0BMw', - name: 'elasticsearch.node.id', + 'auditd.paths.inode': { + category: 'auditd', + description: 'inode number', + name: 'auditd.paths.inode', type: 'keyword', }, - 'elasticsearch.node.name': { - category: 'elasticsearch', - description: 'Name of the node', - example: 'vWNJsZ3', - name: 'elasticsearch.node.name', + 'auditd.paths.dev': { + category: 'auditd', + description: 'device name as found in /dev', + name: 'auditd.paths.dev', type: 'keyword', }, - 'elasticsearch.index.name': { - category: 'elasticsearch', - description: 'Index name', - example: 'filebeat-test-input', - name: 'elasticsearch.index.name', + 'auditd.paths.obj_user': { + category: 'auditd', + description: '', + name: 'auditd.paths.obj_user', type: 'keyword', }, - 'elasticsearch.index.id': { - category: 'elasticsearch', - description: 'Index id', - example: 'aOGgDwbURfCV57AScqbCgw', - name: 'elasticsearch.index.id', + 'auditd.paths.obj_role': { + category: 'auditd', + description: '', + name: 'auditd.paths.obj_role', type: 'keyword', }, - 'elasticsearch.shard.id': { - category: 'elasticsearch', - description: 'Id of the shard', - example: '0', - name: 'elasticsearch.shard.id', + 'auditd.paths.obj_domain': { + category: 'auditd', + description: '', + name: 'auditd.paths.obj_domain', type: 'keyword', }, - 'elasticsearch.audit.layer': { - category: 'elasticsearch', - description: 'The layer from which this event originated: rest, transport or ip_filter', - example: 'rest', - name: 'elasticsearch.audit.layer', + 'auditd.paths.obj_level': { + category: 'auditd', + description: '', + name: 'auditd.paths.obj_level', type: 'keyword', }, - 'elasticsearch.audit.event_type': { - category: 'elasticsearch', - description: - 'The type of event that occurred: anonymous_access_denied, authentication_failed, access_denied, access_granted, connection_granted, connection_denied, tampered_request, run_as_granted, run_as_denied', - example: 'access_granted', - name: 'elasticsearch.audit.event_type', + 'auditd.paths.objtype': { + category: 'auditd', + description: '', + name: 'auditd.paths.objtype', type: 'keyword', }, - 'elasticsearch.audit.origin.type': { - category: 'elasticsearch', - description: - 'Where the request originated: rest (request originated from a REST API request), transport (request was received on the transport channel), local_node (the local node issued the request)', - example: 'local_node', - name: 'elasticsearch.audit.origin.type', + 'auditd.paths.ouid': { + category: 'auditd', + description: 'file owner user ID', + name: 'auditd.paths.ouid', type: 'keyword', }, - 'elasticsearch.audit.realm': { - category: 'elasticsearch', - description: 'The authentication realm the authentication was validated against', - name: 'elasticsearch.audit.realm', + 'auditd.paths.rdev': { + category: 'auditd', + description: 'the device identifier (special files only)', + name: 'auditd.paths.rdev', type: 'keyword', }, - 'elasticsearch.audit.user.realm': { - category: 'elasticsearch', - description: "The user's authentication realm, if authenticated", - name: 'elasticsearch.audit.user.realm', + 'auditd.paths.nametype': { + category: 'auditd', + description: 'kind of file operation being referenced', + name: 'auditd.paths.nametype', type: 'keyword', }, - 'elasticsearch.audit.user.roles': { - category: 'elasticsearch', - description: 'Roles to which the principal belongs', - example: '["kibana_admin","beats_admin"]', - name: 'elasticsearch.audit.user.roles', + 'auditd.paths.ogid': { + category: 'auditd', + description: 'file owner group ID', + name: 'auditd.paths.ogid', type: 'keyword', }, - 'elasticsearch.audit.action': { - category: 'elasticsearch', - description: 'The name of the action that was executed', - example: 'cluster:monitor/main', - name: 'elasticsearch.audit.action', + 'auditd.paths.item': { + category: 'auditd', + description: 'which item is being recorded', + name: 'auditd.paths.item', type: 'keyword', }, - 'elasticsearch.audit.url.params': { - category: 'elasticsearch', - description: 'REST URI parameters', - example: '{username=jacknich2}', - name: 'elasticsearch.audit.url.params', + 'auditd.paths.mode': { + category: 'auditd', + description: 'mode flags on a file', + name: 'auditd.paths.mode', + type: 'keyword', }, - 'elasticsearch.audit.indices': { - category: 'elasticsearch', - description: 'Indices accessed by action', - example: '["foo-2019.01.04","foo-2019.01.03","foo-2019.01.06"]', - name: 'elasticsearch.audit.indices', + 'auditd.paths.name': { + category: 'auditd', + description: 'file name in avcs', + name: 'auditd.paths.name', type: 'keyword', }, - 'elasticsearch.audit.request.id': { - category: 'elasticsearch', - description: 'Unique ID of request', - example: 'WzL_kb6VSvOhAq0twPvHOQ', - name: 'elasticsearch.audit.request.id', + 'auditd.data.action': { + category: 'auditd', + description: 'netfilter packet disposition', + name: 'auditd.data.action', type: 'keyword', }, - 'elasticsearch.audit.request.name': { - category: 'elasticsearch', - description: 'The type of request that was executed', - example: 'ClearScrollRequest', - name: 'elasticsearch.audit.request.name', + 'auditd.data.minor': { + category: 'auditd', + description: 'device minor number', + name: 'auditd.data.minor', type: 'keyword', }, - 'elasticsearch.audit.request_body': { - category: 'elasticsearch', - name: 'elasticsearch.audit.request_body', - type: 'alias', + 'auditd.data.acct': { + category: 'auditd', + description: "a user's account name", + name: 'auditd.data.acct', + type: 'keyword', }, - 'elasticsearch.audit.origin_address': { - category: 'elasticsearch', - name: 'elasticsearch.audit.origin_address', - type: 'alias', + 'auditd.data.addr': { + category: 'auditd', + description: 'the remote address that the user is connecting from', + name: 'auditd.data.addr', + type: 'keyword', }, - 'elasticsearch.audit.uri': { - category: 'elasticsearch', - name: 'elasticsearch.audit.uri', - type: 'alias', + 'auditd.data.cipher': { + category: 'auditd', + description: 'name of crypto cipher selected', + name: 'auditd.data.cipher', + type: 'keyword', }, - 'elasticsearch.audit.principal': { - category: 'elasticsearch', - name: 'elasticsearch.audit.principal', - type: 'alias', + 'auditd.data.id': { + category: 'auditd', + description: 'during account changes', + name: 'auditd.data.id', + type: 'keyword', }, - 'elasticsearch.audit.message': { - category: 'elasticsearch', - name: 'elasticsearch.audit.message', - type: 'text', + 'auditd.data.entries': { + category: 'auditd', + description: 'number of entries in the netfilter table', + name: 'auditd.data.entries', + type: 'keyword', }, - 'elasticsearch.deprecation': { - category: 'elasticsearch', - description: '', - name: 'elasticsearch.deprecation', - type: 'group', + 'auditd.data.kind': { + category: 'auditd', + description: 'server or client in crypto operation', + name: 'auditd.data.kind', + type: 'keyword', }, - 'elasticsearch.gc.phase.name': { - category: 'elasticsearch', - description: 'Name of the GC collection phase. ', - name: 'elasticsearch.gc.phase.name', + 'auditd.data.ksize': { + category: 'auditd', + description: 'key size for crypto operation', + name: 'auditd.data.ksize', type: 'keyword', }, - 'elasticsearch.gc.phase.duration_sec': { - category: 'elasticsearch', - description: 'Collection phase duration according to the Java virtual machine. ', - name: 'elasticsearch.gc.phase.duration_sec', - type: 'float', + 'auditd.data.spid': { + category: 'auditd', + description: 'sent process ID', + name: 'auditd.data.spid', + type: 'keyword', }, - 'elasticsearch.gc.phase.scrub_symbol_table_time_sec': { - category: 'elasticsearch', - description: 'Pause time in seconds cleaning up symbol tables. ', - name: 'elasticsearch.gc.phase.scrub_symbol_table_time_sec', - type: 'float', + 'auditd.data.arch': { + category: 'auditd', + description: 'the elf architecture flags', + name: 'auditd.data.arch', + type: 'keyword', }, - 'elasticsearch.gc.phase.scrub_string_table_time_sec': { - category: 'elasticsearch', - description: 'Pause time in seconds cleaning up string tables. ', - name: 'elasticsearch.gc.phase.scrub_string_table_time_sec', - type: 'float', + 'auditd.data.argc': { + category: 'auditd', + description: 'the number of arguments to an execve syscall', + name: 'auditd.data.argc', + type: 'keyword', }, - 'elasticsearch.gc.phase.weak_refs_processing_time_sec': { - category: 'elasticsearch', - description: 'Time spent processing weak references in seconds. ', - name: 'elasticsearch.gc.phase.weak_refs_processing_time_sec', - type: 'float', + 'auditd.data.major': { + category: 'auditd', + description: 'device major number', + name: 'auditd.data.major', + type: 'keyword', }, - 'elasticsearch.gc.phase.parallel_rescan_time_sec': { - category: 'elasticsearch', - description: 'Time spent in seconds marking live objects while application is stopped. ', - name: 'elasticsearch.gc.phase.parallel_rescan_time_sec', - type: 'float', + 'auditd.data.unit': { + category: 'auditd', + description: 'systemd unit', + name: 'auditd.data.unit', + type: 'keyword', }, - 'elasticsearch.gc.phase.class_unload_time_sec': { - category: 'elasticsearch', - description: 'Time spent unloading unused classes in seconds. ', - name: 'elasticsearch.gc.phase.class_unload_time_sec', - type: 'float', + 'auditd.data.table': { + category: 'auditd', + description: 'netfilter table name', + name: 'auditd.data.table', + type: 'keyword', }, - 'elasticsearch.gc.phase.cpu_time.user_sec': { - category: 'elasticsearch', - description: 'CPU time spent outside the kernel. ', - name: 'elasticsearch.gc.phase.cpu_time.user_sec', - type: 'float', + 'auditd.data.terminal': { + category: 'auditd', + description: 'terminal name the user is running programs on', + name: 'auditd.data.terminal', + type: 'keyword', }, - 'elasticsearch.gc.phase.cpu_time.sys_sec': { - category: 'elasticsearch', - description: 'CPU time spent inside the kernel. ', - name: 'elasticsearch.gc.phase.cpu_time.sys_sec', - type: 'float', + 'auditd.data.grantors': { + category: 'auditd', + description: 'pam modules approving the action', + name: 'auditd.data.grantors', + type: 'keyword', }, - 'elasticsearch.gc.phase.cpu_time.real_sec': { - category: 'elasticsearch', - description: 'Total elapsed CPU time spent to complete the collection from start to finish. ', - name: 'elasticsearch.gc.phase.cpu_time.real_sec', - type: 'float', + 'auditd.data.direction': { + category: 'auditd', + description: 'direction of crypto operation', + name: 'auditd.data.direction', + type: 'keyword', }, - 'elasticsearch.gc.jvm_runtime_sec': { - category: 'elasticsearch', - description: 'The time from JVM start up in seconds, as a floating point number. ', - name: 'elasticsearch.gc.jvm_runtime_sec', - type: 'float', + 'auditd.data.op': { + category: 'auditd', + description: 'the operation being performed that is audited', + name: 'auditd.data.op', + type: 'keyword', }, - 'elasticsearch.gc.threads_total_stop_time_sec': { - category: 'elasticsearch', - description: 'Garbage collection threads total stop time seconds. ', - name: 'elasticsearch.gc.threads_total_stop_time_sec', - type: 'float', + 'auditd.data.tty': { + category: 'auditd', + description: 'tty udevice the user is running programs on', + name: 'auditd.data.tty', + type: 'keyword', }, - 'elasticsearch.gc.stopping_threads_time_sec': { - category: 'elasticsearch', - description: 'Time took to stop threads seconds. ', - name: 'elasticsearch.gc.stopping_threads_time_sec', - type: 'float', + 'auditd.data.syscall': { + category: 'auditd', + description: 'syscall number in effect when the event occurred', + name: 'auditd.data.syscall', + type: 'keyword', }, - 'elasticsearch.gc.tags': { - category: 'elasticsearch', - description: 'GC logging tags. ', - name: 'elasticsearch.gc.tags', + 'auditd.data.data': { + category: 'auditd', + description: 'TTY text', + name: 'auditd.data.data', type: 'keyword', }, - 'elasticsearch.gc.heap.size_kb': { - category: 'elasticsearch', - description: 'Total heap size in kilobytes. ', - name: 'elasticsearch.gc.heap.size_kb', - type: 'integer', + 'auditd.data.family': { + category: 'auditd', + description: 'netfilter protocol', + name: 'auditd.data.family', + type: 'keyword', }, - 'elasticsearch.gc.heap.used_kb': { - category: 'elasticsearch', - description: 'Used heap in kilobytes. ', - name: 'elasticsearch.gc.heap.used_kb', - type: 'integer', + 'auditd.data.mac': { + category: 'auditd', + description: 'crypto MAC algorithm selected', + name: 'auditd.data.mac', + type: 'keyword', }, - 'elasticsearch.gc.old_gen.size_kb': { - category: 'elasticsearch', - description: 'Total size of old generation in kilobytes. ', - name: 'elasticsearch.gc.old_gen.size_kb', - type: 'integer', + 'auditd.data.pfs': { + category: 'auditd', + description: 'perfect forward secrecy method', + name: 'auditd.data.pfs', + type: 'keyword', }, - 'elasticsearch.gc.old_gen.used_kb': { - category: 'elasticsearch', - description: 'Old generation occupancy in kilobytes. ', - name: 'elasticsearch.gc.old_gen.used_kb', - type: 'integer', - }, - 'elasticsearch.gc.young_gen.size_kb': { - category: 'elasticsearch', - description: 'Total size of young generation in kilobytes. ', - name: 'elasticsearch.gc.young_gen.size_kb', - type: 'integer', + 'auditd.data.items': { + category: 'auditd', + description: 'the number of path records in the event', + name: 'auditd.data.items', + type: 'keyword', }, - 'elasticsearch.gc.young_gen.used_kb': { - category: 'elasticsearch', - description: 'Young generation occupancy in kilobytes. ', - name: 'elasticsearch.gc.young_gen.used_kb', - type: 'integer', + 'auditd.data.a0': { + category: 'auditd', + description: '', + name: 'auditd.data.a0', + type: 'keyword', }, - 'elasticsearch.server.stacktrace': { - category: 'elasticsearch', - name: 'elasticsearch.server.stacktrace', + 'auditd.data.a1': { + category: 'auditd', + description: '', + name: 'auditd.data.a1', + type: 'keyword', }, - 'elasticsearch.server.gc.young.one': { - category: 'elasticsearch', + 'auditd.data.a2': { + category: 'auditd', description: '', - example: '', - name: 'elasticsearch.server.gc.young.one', - type: 'long', + name: 'auditd.data.a2', + type: 'keyword', }, - 'elasticsearch.server.gc.young.two': { - category: 'elasticsearch', + 'auditd.data.a3': { + category: 'auditd', description: '', - example: '', - name: 'elasticsearch.server.gc.young.two', - type: 'long', + name: 'auditd.data.a3', + type: 'keyword', }, - 'elasticsearch.server.gc.overhead_seq': { - category: 'elasticsearch', - description: 'Sequence number', - example: 3449992, - name: 'elasticsearch.server.gc.overhead_seq', - type: 'long', + 'auditd.data.hostname': { + category: 'auditd', + description: 'the hostname that the user is connecting from', + name: 'auditd.data.hostname', + type: 'keyword', }, - 'elasticsearch.server.gc.collection_duration.ms': { - category: 'elasticsearch', - description: 'Time spent in GC, in milliseconds', - example: 1600, - name: 'elasticsearch.server.gc.collection_duration.ms', - type: 'float', + 'auditd.data.lport': { + category: 'auditd', + description: 'local network port', + name: 'auditd.data.lport', + type: 'keyword', }, - 'elasticsearch.server.gc.observation_duration.ms': { - category: 'elasticsearch', - description: 'Total time over which collection was observed, in milliseconds', - example: 1800, - name: 'elasticsearch.server.gc.observation_duration.ms', - type: 'float', + 'auditd.data.rport': { + category: 'auditd', + description: 'remote port number', + name: 'auditd.data.rport', + type: 'keyword', }, - 'elasticsearch.slowlog.logger': { - category: 'elasticsearch', - description: 'Logger name', - example: 'index.search.slowlog.fetch', - name: 'elasticsearch.slowlog.logger', + 'auditd.data.exit': { + category: 'auditd', + description: 'syscall exit code', + name: 'auditd.data.exit', type: 'keyword', }, - 'elasticsearch.slowlog.took': { - category: 'elasticsearch', - description: 'Time it took to execute the query', - example: '300ms', - name: 'elasticsearch.slowlog.took', + 'auditd.data.fp': { + category: 'auditd', + description: 'crypto key finger print', + name: 'auditd.data.fp', type: 'keyword', }, - 'elasticsearch.slowlog.types': { - category: 'elasticsearch', - description: 'Types', - example: '', - name: 'elasticsearch.slowlog.types', + 'auditd.data.laddr': { + category: 'auditd', + description: 'local network address', + name: 'auditd.data.laddr', type: 'keyword', }, - 'elasticsearch.slowlog.stats': { - category: 'elasticsearch', - description: 'Stats groups', - example: 'group1', - name: 'elasticsearch.slowlog.stats', + 'auditd.data.sport': { + category: 'auditd', + description: 'local port number', + name: 'auditd.data.sport', type: 'keyword', }, - 'elasticsearch.slowlog.search_type': { - category: 'elasticsearch', - description: 'Search type', - example: 'QUERY_THEN_FETCH', - name: 'elasticsearch.slowlog.search_type', + 'auditd.data.capability': { + category: 'auditd', + description: 'posix capabilities', + name: 'auditd.data.capability', type: 'keyword', }, - 'elasticsearch.slowlog.source_query': { - category: 'elasticsearch', - description: 'Slow query', - example: '{"query":{"match_all":{"boost":1.0}}}', - name: 'elasticsearch.slowlog.source_query', + 'auditd.data.nargs': { + category: 'auditd', + description: 'the number of arguments to a socket call', + name: 'auditd.data.nargs', type: 'keyword', }, - 'elasticsearch.slowlog.extra_source': { - category: 'elasticsearch', - description: 'Extra source information', - example: '', - name: 'elasticsearch.slowlog.extra_source', + 'auditd.data.new-enabled': { + category: 'auditd', + description: 'new TTY audit enabled setting', + name: 'auditd.data.new-enabled', type: 'keyword', }, - 'elasticsearch.slowlog.total_hits': { - category: 'elasticsearch', - description: 'Total hits', - example: 42, - name: 'elasticsearch.slowlog.total_hits', + 'auditd.data.audit_backlog_limit': { + category: 'auditd', + description: "audit system's backlog queue size", + name: 'auditd.data.audit_backlog_limit', type: 'keyword', }, - 'elasticsearch.slowlog.total_shards': { - category: 'elasticsearch', - description: 'Total queried shards', - example: 22, - name: 'elasticsearch.slowlog.total_shards', + 'auditd.data.dir': { + category: 'auditd', + description: 'directory name', + name: 'auditd.data.dir', type: 'keyword', }, - 'elasticsearch.slowlog.routing': { - category: 'elasticsearch', - description: 'Routing', - example: 's01HZ2QBk9jw4gtgaFtn', - name: 'elasticsearch.slowlog.routing', + 'auditd.data.cap_pe': { + category: 'auditd', + description: 'process effective capability map', + name: 'auditd.data.cap_pe', type: 'keyword', }, - 'elasticsearch.slowlog.id': { - category: 'elasticsearch', - description: 'Id', - example: '', - name: 'elasticsearch.slowlog.id', + 'auditd.data.model': { + category: 'auditd', + description: 'security model being used for virt', + name: 'auditd.data.model', type: 'keyword', }, - 'elasticsearch.slowlog.type': { - category: 'elasticsearch', - description: 'Type', - example: 'doc', - name: 'elasticsearch.slowlog.type', + 'auditd.data.new_pp': { + category: 'auditd', + description: 'new process permitted capability map', + name: 'auditd.data.new_pp', type: 'keyword', }, - 'elasticsearch.slowlog.source': { - category: 'elasticsearch', - description: 'Source of document that was indexed', - name: 'elasticsearch.slowlog.source', + 'auditd.data.old-enabled': { + category: 'auditd', + description: 'present TTY audit enabled setting', + name: 'auditd.data.old-enabled', type: 'keyword', }, - 'haproxy.frontend_name': { - category: 'haproxy', - description: 'Name of the frontend (or listener) which received and processed the connection.', - name: 'haproxy.frontend_name', + 'auditd.data.oauid': { + category: 'auditd', + description: "object's login user ID", + name: 'auditd.data.oauid', + type: 'keyword', }, - 'haproxy.backend_name': { - category: 'haproxy', - description: - 'Name of the backend (or listener) which was selected to manage the connection to the server.', - name: 'haproxy.backend_name', + 'auditd.data.old': { + category: 'auditd', + description: 'old value', + name: 'auditd.data.old', + type: 'keyword', }, - 'haproxy.server_name': { - category: 'haproxy', - description: 'Name of the last server to which the connection was sent.', - name: 'haproxy.server_name', + 'auditd.data.banners': { + category: 'auditd', + description: 'banners used on printed page', + name: 'auditd.data.banners', + type: 'keyword', }, - 'haproxy.total_waiting_time_ms': { - category: 'haproxy', - description: 'Total time in milliseconds spent waiting in the various queues', - name: 'haproxy.total_waiting_time_ms', - type: 'long', + 'auditd.data.feature': { + category: 'auditd', + description: 'kernel feature being changed', + name: 'auditd.data.feature', + type: 'keyword', }, - 'haproxy.connection_wait_time_ms': { - category: 'haproxy', - description: - 'Total time in milliseconds spent waiting for the connection to establish to the final server', - name: 'haproxy.connection_wait_time_ms', - type: 'long', + 'auditd.data.vm-ctx': { + category: 'auditd', + description: "the vm's context string", + name: 'auditd.data.vm-ctx', + type: 'keyword', }, - 'haproxy.bytes_read': { - category: 'haproxy', - description: 'Total number of bytes transmitted to the client when the log is emitted.', - name: 'haproxy.bytes_read', - type: 'long', + 'auditd.data.opid': { + category: 'auditd', + description: "object's process ID", + name: 'auditd.data.opid', + type: 'keyword', }, - 'haproxy.time_queue': { - category: 'haproxy', - description: 'Total time in milliseconds spent waiting in the various queues.', - name: 'haproxy.time_queue', - type: 'long', + 'auditd.data.seperms': { + category: 'auditd', + description: 'SELinux permissions being used', + name: 'auditd.data.seperms', + type: 'keyword', }, - 'haproxy.time_backend_connect': { - category: 'haproxy', - description: - 'Total time in milliseconds spent waiting for the connection to establish to the final server, including retries.', - name: 'haproxy.time_backend_connect', - type: 'long', + 'auditd.data.seresult': { + category: 'auditd', + description: 'SELinux AVC decision granted/denied', + name: 'auditd.data.seresult', + type: 'keyword', }, - 'haproxy.server_queue': { - category: 'haproxy', - description: - 'Total number of requests which were processed before this one in the server queue.', - name: 'haproxy.server_queue', - type: 'long', + 'auditd.data.new-rng': { + category: 'auditd', + description: 'device name of rng being added from a vm', + name: 'auditd.data.new-rng', + type: 'keyword', }, - 'haproxy.backend_queue': { - category: 'haproxy', - description: - "Total number of requests which were processed before this one in the backend's global queue.", - name: 'haproxy.backend_queue', - type: 'long', + 'auditd.data.old-net': { + category: 'auditd', + description: 'present MAC address assigned to vm', + name: 'auditd.data.old-net', + type: 'keyword', }, - 'haproxy.bind_name': { - category: 'haproxy', - description: 'Name of the listening address which received the connection.', - name: 'haproxy.bind_name', + 'auditd.data.sigev_signo': { + category: 'auditd', + description: 'signal number', + name: 'auditd.data.sigev_signo', + type: 'keyword', }, - 'haproxy.error_message': { - category: 'haproxy', - description: 'Error message logged by HAProxy in case of error.', - name: 'haproxy.error_message', - type: 'text', + 'auditd.data.ino': { + category: 'auditd', + description: 'inode number', + name: 'auditd.data.ino', + type: 'keyword', }, - 'haproxy.source': { - category: 'haproxy', - description: 'The HAProxy source of the log', - name: 'haproxy.source', + 'auditd.data.old_enforcing': { + category: 'auditd', + description: 'old MAC enforcement status', + name: 'auditd.data.old_enforcing', type: 'keyword', }, - 'haproxy.termination_state': { - category: 'haproxy', - description: 'Condition the session was in when the session ended.', - name: 'haproxy.termination_state', + 'auditd.data.old-vcpu': { + category: 'auditd', + description: 'present number of CPU cores', + name: 'auditd.data.old-vcpu', + type: 'keyword', }, - 'haproxy.mode': { - category: 'haproxy', - description: 'mode that the frontend is operating (TCP or HTTP)', - name: 'haproxy.mode', + 'auditd.data.range': { + category: 'auditd', + description: "user's SE Linux range", + name: 'auditd.data.range', type: 'keyword', }, - 'haproxy.connections.active': { - category: 'haproxy', - description: - 'Total number of concurrent connections on the process when the session was logged.', - name: 'haproxy.connections.active', - type: 'long', + 'auditd.data.res': { + category: 'auditd', + description: 'result of the audited operation(success/fail)', + name: 'auditd.data.res', + type: 'keyword', }, - 'haproxy.connections.frontend': { - category: 'haproxy', - description: - 'Total number of concurrent connections on the frontend when the session was logged.', - name: 'haproxy.connections.frontend', - type: 'long', + 'auditd.data.added': { + category: 'auditd', + description: 'number of new files detected', + name: 'auditd.data.added', + type: 'keyword', }, - 'haproxy.connections.backend': { - category: 'haproxy', - description: - 'Total number of concurrent connections handled by the backend when the session was logged.', - name: 'haproxy.connections.backend', - type: 'long', + 'auditd.data.fam': { + category: 'auditd', + description: 'socket address family', + name: 'auditd.data.fam', + type: 'keyword', }, - 'haproxy.connections.server': { - category: 'haproxy', - description: - 'Total number of concurrent connections still active on the server when the session was logged.', - name: 'haproxy.connections.server', - type: 'long', + 'auditd.data.nlnk-pid': { + category: 'auditd', + description: 'pid of netlink packet sender', + name: 'auditd.data.nlnk-pid', + type: 'keyword', }, - 'haproxy.connections.retries': { - category: 'haproxy', - description: - 'Number of connection retries experienced by this session when trying to connect to the server.', - name: 'haproxy.connections.retries', - type: 'long', + 'auditd.data.subj': { + category: 'auditd', + description: "lspp subject's context string", + name: 'auditd.data.subj', + type: 'keyword', }, - 'haproxy.client.ip': { - category: 'haproxy', - name: 'haproxy.client.ip', - type: 'alias', + 'auditd.data.a[0-3]': { + category: 'auditd', + description: 'the arguments to a syscall', + name: 'auditd.data.a[0-3]', + type: 'keyword', }, - 'haproxy.client.port': { - category: 'haproxy', - name: 'haproxy.client.port', - type: 'alias', + 'auditd.data.cgroup': { + category: 'auditd', + description: 'path to cgroup in sysfs', + name: 'auditd.data.cgroup', + type: 'keyword', }, - 'haproxy.process_name': { - category: 'haproxy', - name: 'haproxy.process_name', - type: 'alias', + 'auditd.data.kernel': { + category: 'auditd', + description: "kernel's version number", + name: 'auditd.data.kernel', + type: 'keyword', }, - 'haproxy.pid': { - category: 'haproxy', - name: 'haproxy.pid', - type: 'alias', + 'auditd.data.ocomm': { + category: 'auditd', + description: "object's command line name", + name: 'auditd.data.ocomm', + type: 'keyword', }, - 'haproxy.destination.port': { - category: 'haproxy', - name: 'haproxy.destination.port', - type: 'alias', + 'auditd.data.new-net': { + category: 'auditd', + description: 'MAC address being assigned to vm', + name: 'auditd.data.new-net', + type: 'keyword', }, - 'haproxy.destination.ip': { - category: 'haproxy', - name: 'haproxy.destination.ip', - type: 'alias', + 'auditd.data.permissive': { + category: 'auditd', + description: 'SELinux is in permissive mode', + name: 'auditd.data.permissive', + type: 'keyword', }, - 'haproxy.geoip.continent_name': { - category: 'haproxy', - name: 'haproxy.geoip.continent_name', - type: 'alias', + 'auditd.data.class': { + category: 'auditd', + description: 'resource class assigned to vm', + name: 'auditd.data.class', + type: 'keyword', }, - 'haproxy.geoip.country_iso_code': { - category: 'haproxy', - name: 'haproxy.geoip.country_iso_code', - type: 'alias', + 'auditd.data.compat': { + category: 'auditd', + description: 'is_compat_task result', + name: 'auditd.data.compat', + type: 'keyword', }, - 'haproxy.geoip.location': { - category: 'haproxy', - name: 'haproxy.geoip.location', - type: 'alias', + 'auditd.data.fi': { + category: 'auditd', + description: 'file assigned inherited capability map', + name: 'auditd.data.fi', + type: 'keyword', }, - 'haproxy.geoip.region_name': { - category: 'haproxy', - name: 'haproxy.geoip.region_name', - type: 'alias', + 'auditd.data.changed': { + category: 'auditd', + description: 'number of changed files', + name: 'auditd.data.changed', + type: 'keyword', }, - 'haproxy.geoip.city_name': { - category: 'haproxy', - name: 'haproxy.geoip.city_name', - type: 'alias', + 'auditd.data.msg': { + category: 'auditd', + description: 'the payload of the audit record', + name: 'auditd.data.msg', + type: 'keyword', }, - 'haproxy.geoip.region_iso_code': { - category: 'haproxy', - name: 'haproxy.geoip.region_iso_code', - type: 'alias', + 'auditd.data.dport': { + category: 'auditd', + description: 'remote port number', + name: 'auditd.data.dport', + type: 'keyword', }, - 'haproxy.http.response.captured_cookie': { - category: 'haproxy', - description: - 'Optional "name=value" entry indicating that the client had this cookie in the response. ', - name: 'haproxy.http.response.captured_cookie', + 'auditd.data.new-seuser': { + category: 'auditd', + description: 'new SELinux user', + name: 'auditd.data.new-seuser', + type: 'keyword', }, - 'haproxy.http.response.captured_headers': { - category: 'haproxy', - description: - 'List of headers captured in the response due to the presence of the "capture response header" statement in the frontend. ', - name: 'haproxy.http.response.captured_headers', + 'auditd.data.invalid_context': { + category: 'auditd', + description: 'SELinux context', + name: 'auditd.data.invalid_context', type: 'keyword', }, - 'haproxy.http.response.status_code': { - category: 'haproxy', - name: 'haproxy.http.response.status_code', - type: 'alias', + 'auditd.data.dmac': { + category: 'auditd', + description: 'remote MAC address', + name: 'auditd.data.dmac', + type: 'keyword', }, - 'haproxy.http.request.captured_cookie': { - category: 'haproxy', - description: - 'Optional "name=value" entry indicating that the server has returned a cookie with its request. ', - name: 'haproxy.http.request.captured_cookie', + 'auditd.data.ipx-net': { + category: 'auditd', + description: 'IPX network number', + name: 'auditd.data.ipx-net', + type: 'keyword', }, - 'haproxy.http.request.captured_headers': { - category: 'haproxy', - description: - 'List of headers captured in the request due to the presence of the "capture request header" statement in the frontend. ', - name: 'haproxy.http.request.captured_headers', + 'auditd.data.iuid': { + category: 'auditd', + description: "ipc object's user ID", + name: 'auditd.data.iuid', type: 'keyword', }, - 'haproxy.http.request.raw_request_line': { - category: 'haproxy', - description: - 'Complete HTTP request line, including the method, request and HTTP version string.', - name: 'haproxy.http.request.raw_request_line', + 'auditd.data.macproto': { + category: 'auditd', + description: 'ethernet packet type ID field', + name: 'auditd.data.macproto', type: 'keyword', }, - 'haproxy.http.request.time_wait_without_data_ms': { - category: 'haproxy', - description: - 'Total time in milliseconds spent waiting for the server to send a full HTTP response, not counting data.', - name: 'haproxy.http.request.time_wait_without_data_ms', - type: 'long', + 'auditd.data.obj': { + category: 'auditd', + description: 'lspp object context string', + name: 'auditd.data.obj', + type: 'keyword', }, - 'haproxy.http.request.time_wait_ms': { - category: 'haproxy', - description: - 'Total time in milliseconds spent waiting for a full HTTP request from the client (not counting body) after the first byte was received.', - name: 'haproxy.http.request.time_wait_ms', - type: 'long', + 'auditd.data.ipid': { + category: 'auditd', + description: 'IP datagram fragment identifier', + name: 'auditd.data.ipid', + type: 'keyword', }, - 'haproxy.tcp.connection_waiting_time_ms': { - category: 'haproxy', - description: 'Total time in milliseconds elapsed between the accept and the last close', - name: 'haproxy.tcp.connection_waiting_time_ms', - type: 'long', + 'auditd.data.new-fs': { + category: 'auditd', + description: 'file system being added to vm', + name: 'auditd.data.new-fs', + type: 'keyword', }, - 'icinga.debug.facility': { - category: 'icinga', - description: 'Specifies what component of Icinga logged the message. ', - name: 'icinga.debug.facility', + 'auditd.data.vm-pid': { + category: 'auditd', + description: "vm's process ID", + name: 'auditd.data.vm-pid', type: 'keyword', }, - 'icinga.debug.severity': { - category: 'icinga', - name: 'icinga.debug.severity', - type: 'alias', + 'auditd.data.cap_pi': { + category: 'auditd', + description: 'process inherited capability map', + name: 'auditd.data.cap_pi', + type: 'keyword', }, - 'icinga.debug.message': { - category: 'icinga', - name: 'icinga.debug.message', - type: 'alias', + 'auditd.data.old-auid': { + category: 'auditd', + description: 'previous auid value', + name: 'auditd.data.old-auid', + type: 'keyword', }, - 'icinga.main.facility': { - category: 'icinga', - description: 'Specifies what component of Icinga logged the message. ', - name: 'icinga.main.facility', + 'auditd.data.oses': { + category: 'auditd', + description: "object's session ID", + name: 'auditd.data.oses', type: 'keyword', }, - 'icinga.main.severity': { - category: 'icinga', - name: 'icinga.main.severity', - type: 'alias', + 'auditd.data.fd': { + category: 'auditd', + description: 'file descriptor number', + name: 'auditd.data.fd', + type: 'keyword', }, - 'icinga.main.message': { - category: 'icinga', - name: 'icinga.main.message', - type: 'alias', + 'auditd.data.igid': { + category: 'auditd', + description: "ipc object's group ID", + name: 'auditd.data.igid', + type: 'keyword', }, - 'icinga.startup.facility': { - category: 'icinga', - description: 'Specifies what component of Icinga logged the message. ', - name: 'icinga.startup.facility', + 'auditd.data.new-disk': { + category: 'auditd', + description: 'disk being added to vm', + name: 'auditd.data.new-disk', type: 'keyword', }, - 'icinga.startup.severity': { - category: 'icinga', - name: 'icinga.startup.severity', - type: 'alias', + 'auditd.data.parent': { + category: 'auditd', + description: 'the inode number of the parent file', + name: 'auditd.data.parent', + type: 'keyword', }, - 'icinga.startup.message': { - category: 'icinga', - name: 'icinga.startup.message', - type: 'alias', + 'auditd.data.len': { + category: 'auditd', + description: 'length', + name: 'auditd.data.len', + type: 'keyword', }, - 'iis.access.sub_status': { - category: 'iis', - description: 'The HTTP substatus code. ', - name: 'iis.access.sub_status', - type: 'long', + 'auditd.data.oflag': { + category: 'auditd', + description: 'open syscall flags', + name: 'auditd.data.oflag', + type: 'keyword', }, - 'iis.access.win32_status': { - category: 'iis', - description: 'The Windows status code. ', - name: 'iis.access.win32_status', - type: 'long', + 'auditd.data.uuid': { + category: 'auditd', + description: 'a UUID', + name: 'auditd.data.uuid', + type: 'keyword', }, - 'iis.access.site_name': { - category: 'iis', - description: 'The site name and instance number. ', - name: 'iis.access.site_name', + 'auditd.data.code': { + category: 'auditd', + description: 'seccomp action code', + name: 'auditd.data.code', type: 'keyword', }, - 'iis.access.server_name': { - category: 'iis', - description: 'The name of the server on which the log file entry was generated. ', - name: 'iis.access.server_name', + 'auditd.data.nlnk-grp': { + category: 'auditd', + description: 'netlink group number', + name: 'auditd.data.nlnk-grp', type: 'keyword', }, - 'iis.access.cookie': { - category: 'iis', - description: 'The content of the cookie sent or received, if any. ', - name: 'iis.access.cookie', + 'auditd.data.cap_fp': { + category: 'auditd', + description: 'file permitted capability map', + name: 'auditd.data.cap_fp', type: 'keyword', }, - 'iis.access.body_received.bytes': { - category: 'iis', - name: 'iis.access.body_received.bytes', - type: 'alias', + 'auditd.data.new-mem': { + category: 'auditd', + description: 'new amount of memory in KB', + name: 'auditd.data.new-mem', + type: 'keyword', }, - 'iis.access.body_sent.bytes': { - category: 'iis', - name: 'iis.access.body_sent.bytes', - type: 'alias', + 'auditd.data.seperm': { + category: 'auditd', + description: 'SELinux permission being decided on', + name: 'auditd.data.seperm', + type: 'keyword', }, - 'iis.access.server_ip': { - category: 'iis', - name: 'iis.access.server_ip', - type: 'alias', + 'auditd.data.enforcing': { + category: 'auditd', + description: 'new MAC enforcement status', + name: 'auditd.data.enforcing', + type: 'keyword', }, - 'iis.access.method': { - category: 'iis', - name: 'iis.access.method', - type: 'alias', + 'auditd.data.new-chardev': { + category: 'auditd', + description: 'new character device being assigned to vm', + name: 'auditd.data.new-chardev', + type: 'keyword', }, - 'iis.access.url': { - category: 'iis', - name: 'iis.access.url', - type: 'alias', + 'auditd.data.old-rng': { + category: 'auditd', + description: 'device name of rng being removed from a vm', + name: 'auditd.data.old-rng', + type: 'keyword', }, - 'iis.access.query_string': { - category: 'iis', - name: 'iis.access.query_string', - type: 'alias', + 'auditd.data.outif': { + category: 'auditd', + description: 'out interface number', + name: 'auditd.data.outif', + type: 'keyword', }, - 'iis.access.port': { - category: 'iis', - name: 'iis.access.port', - type: 'alias', + 'auditd.data.cmd': { + category: 'auditd', + description: 'command being executed', + name: 'auditd.data.cmd', + type: 'keyword', }, - 'iis.access.user_name': { - category: 'iis', - name: 'iis.access.user_name', - type: 'alias', + 'auditd.data.hook': { + category: 'auditd', + description: 'netfilter hook that packet came from', + name: 'auditd.data.hook', + type: 'keyword', }, - 'iis.access.remote_ip': { - category: 'iis', - name: 'iis.access.remote_ip', - type: 'alias', + 'auditd.data.new-level': { + category: 'auditd', + description: 'new run level', + name: 'auditd.data.new-level', + type: 'keyword', }, - 'iis.access.referrer': { - category: 'iis', - name: 'iis.access.referrer', - type: 'alias', + 'auditd.data.sauid': { + category: 'auditd', + description: 'sent login user ID', + name: 'auditd.data.sauid', + type: 'keyword', }, - 'iis.access.response_code': { - category: 'iis', - name: 'iis.access.response_code', - type: 'alias', + 'auditd.data.sig': { + category: 'auditd', + description: 'signal number', + name: 'auditd.data.sig', + type: 'keyword', }, - 'iis.access.http_version': { - category: 'iis', - name: 'iis.access.http_version', - type: 'alias', + 'auditd.data.audit_backlog_wait_time': { + category: 'auditd', + description: "audit system's backlog wait time", + name: 'auditd.data.audit_backlog_wait_time', + type: 'keyword', }, - 'iis.access.hostname': { - category: 'iis', - name: 'iis.access.hostname', - type: 'alias', + 'auditd.data.printer': { + category: 'auditd', + description: 'printer name', + name: 'auditd.data.printer', + type: 'keyword', }, - 'iis.access.user_agent.device': { - category: 'iis', - name: 'iis.access.user_agent.device', - type: 'alias', + 'auditd.data.old-mem': { + category: 'auditd', + description: 'present amount of memory in KB', + name: 'auditd.data.old-mem', + type: 'keyword', }, - 'iis.access.user_agent.name': { - category: 'iis', - name: 'iis.access.user_agent.name', - type: 'alias', + 'auditd.data.perm': { + category: 'auditd', + description: 'the file permission being used', + name: 'auditd.data.perm', + type: 'keyword', }, - 'iis.access.user_agent.os': { - category: 'iis', - name: 'iis.access.user_agent.os', - type: 'alias', + 'auditd.data.old_pi': { + category: 'auditd', + description: 'old process inherited capability map', + name: 'auditd.data.old_pi', + type: 'keyword', }, - 'iis.access.user_agent.os_name': { - category: 'iis', - name: 'iis.access.user_agent.os_name', - type: 'alias', + 'auditd.data.state': { + category: 'auditd', + description: 'audit daemon configuration resulting state', + name: 'auditd.data.state', + type: 'keyword', }, - 'iis.access.user_agent.original': { - category: 'iis', - name: 'iis.access.user_agent.original', - type: 'alias', + 'auditd.data.format': { + category: 'auditd', + description: "audit log's format", + name: 'auditd.data.format', + type: 'keyword', }, - 'iis.access.geoip.continent_name': { - category: 'iis', - name: 'iis.access.geoip.continent_name', - type: 'alias', + 'auditd.data.new_gid': { + category: 'auditd', + description: 'new group ID being assigned', + name: 'auditd.data.new_gid', + type: 'keyword', }, - 'iis.access.geoip.country_iso_code': { - category: 'iis', - name: 'iis.access.geoip.country_iso_code', - type: 'alias', + 'auditd.data.tcontext': { + category: 'auditd', + description: "the target's or object's context string", + name: 'auditd.data.tcontext', + type: 'keyword', }, - 'iis.access.geoip.location': { - category: 'iis', - name: 'iis.access.geoip.location', - type: 'alias', + 'auditd.data.maj': { + category: 'auditd', + description: 'device major number', + name: 'auditd.data.maj', + type: 'keyword', }, - 'iis.access.geoip.region_name': { - category: 'iis', - name: 'iis.access.geoip.region_name', - type: 'alias', + 'auditd.data.watch': { + category: 'auditd', + description: 'file name in a watch record', + name: 'auditd.data.watch', + type: 'keyword', }, - 'iis.access.geoip.city_name': { - category: 'iis', - name: 'iis.access.geoip.city_name', - type: 'alias', + 'auditd.data.device': { + category: 'auditd', + description: 'device name', + name: 'auditd.data.device', + type: 'keyword', }, - 'iis.access.geoip.region_iso_code': { - category: 'iis', - name: 'iis.access.geoip.region_iso_code', - type: 'alias', + 'auditd.data.grp': { + category: 'auditd', + description: 'group name', + name: 'auditd.data.grp', + type: 'keyword', }, - 'iis.error.reason_phrase': { - category: 'iis', - description: 'The HTTP reason phrase. ', - name: 'iis.error.reason_phrase', + 'auditd.data.bool': { + category: 'auditd', + description: 'name of SELinux boolean', + name: 'auditd.data.bool', type: 'keyword', }, - 'iis.error.queue_name': { - category: 'iis', - description: 'The IIS application pool name. ', - name: 'iis.error.queue_name', + 'auditd.data.icmp_type': { + category: 'auditd', + description: 'type of icmp message', + name: 'auditd.data.icmp_type', type: 'keyword', }, - 'iis.error.remote_ip': { - category: 'iis', - name: 'iis.error.remote_ip', - type: 'alias', + 'auditd.data.new_lock': { + category: 'auditd', + description: 'new value of feature lock', + name: 'auditd.data.new_lock', + type: 'keyword', }, - 'iis.error.remote_port': { - category: 'iis', - name: 'iis.error.remote_port', - type: 'alias', + 'auditd.data.old_prom': { + category: 'auditd', + description: 'network promiscuity flag', + name: 'auditd.data.old_prom', + type: 'keyword', }, - 'iis.error.server_ip': { - category: 'iis', - name: 'iis.error.server_ip', - type: 'alias', + 'auditd.data.acl': { + category: 'auditd', + description: 'access mode of resource assigned to vm', + name: 'auditd.data.acl', + type: 'keyword', }, - 'iis.error.server_port': { - category: 'iis', - name: 'iis.error.server_port', - type: 'alias', + 'auditd.data.ip': { + category: 'auditd', + description: 'network address of a printer', + name: 'auditd.data.ip', + type: 'keyword', }, - 'iis.error.http_version': { - category: 'iis', - name: 'iis.error.http_version', - type: 'alias', + 'auditd.data.new_pi': { + category: 'auditd', + description: 'new process inherited capability map', + name: 'auditd.data.new_pi', + type: 'keyword', }, - 'iis.error.method': { - category: 'iis', - name: 'iis.error.method', - type: 'alias', + 'auditd.data.default-context': { + category: 'auditd', + description: 'default MAC context', + name: 'auditd.data.default-context', + type: 'keyword', }, - 'iis.error.url': { - category: 'iis', - name: 'iis.error.url', - type: 'alias', + 'auditd.data.inode_gid': { + category: 'auditd', + description: "group ID of the inode's owner", + name: 'auditd.data.inode_gid', + type: 'keyword', }, - 'iis.error.response_code': { - category: 'iis', - name: 'iis.error.response_code', - type: 'alias', + 'auditd.data.new-log_passwd': { + category: 'auditd', + description: 'new value for TTY password logging', + name: 'auditd.data.new-log_passwd', + type: 'keyword', }, - 'iis.error.geoip.continent_name': { - category: 'iis', - name: 'iis.error.geoip.continent_name', - type: 'alias', - }, - 'iis.error.geoip.country_iso_code': { - category: 'iis', - name: 'iis.error.geoip.country_iso_code', - type: 'alias', - }, - 'iis.error.geoip.location': { - category: 'iis', - name: 'iis.error.geoip.location', - type: 'alias', - }, - 'iis.error.geoip.region_name': { - category: 'iis', - name: 'iis.error.geoip.region_name', - type: 'alias', + 'auditd.data.new_pe': { + category: 'auditd', + description: 'new process effective capability map', + name: 'auditd.data.new_pe', + type: 'keyword', }, - 'iis.error.geoip.city_name': { - category: 'iis', - name: 'iis.error.geoip.city_name', - type: 'alias', + 'auditd.data.selected-context': { + category: 'auditd', + description: 'new MAC context assigned to session', + name: 'auditd.data.selected-context', + type: 'keyword', }, - 'iis.error.geoip.region_iso_code': { - category: 'iis', - name: 'iis.error.geoip.region_iso_code', - type: 'alias', + 'auditd.data.cap_fver': { + category: 'auditd', + description: 'file system capabilities version number', + name: 'auditd.data.cap_fver', + type: 'keyword', }, - 'kafka.log.level': { - category: 'kafka', - name: 'kafka.log.level', - type: 'alias', + 'auditd.data.file': { + category: 'auditd', + description: 'file name', + name: 'auditd.data.file', + type: 'keyword', }, - 'kafka.log.message': { - category: 'kafka', - name: 'kafka.log.message', - type: 'alias', + 'auditd.data.net': { + category: 'auditd', + description: 'network MAC address', + name: 'auditd.data.net', + type: 'keyword', }, - 'kafka.log.component': { - category: 'kafka', - description: 'Component the log is coming from. ', - name: 'kafka.log.component', + 'auditd.data.virt': { + category: 'auditd', + description: 'kind of virtualization being referenced', + name: 'auditd.data.virt', type: 'keyword', }, - 'kafka.log.class': { - category: 'kafka', - description: 'Java class the log is coming from. ', - name: 'kafka.log.class', + 'auditd.data.cap_pp': { + category: 'auditd', + description: 'process permitted capability map', + name: 'auditd.data.cap_pp', type: 'keyword', }, - 'kafka.log.thread': { - category: 'kafka', - description: 'Thread name the log is coming from. ', - name: 'kafka.log.thread', + 'auditd.data.old-range': { + category: 'auditd', + description: 'present SELinux range', + name: 'auditd.data.old-range', type: 'keyword', }, - 'kafka.log.trace.class': { - category: 'kafka', - description: 'Java class the trace is coming from. ', - name: 'kafka.log.trace.class', + 'auditd.data.resrc': { + category: 'auditd', + description: 'resource being assigned', + name: 'auditd.data.resrc', type: 'keyword', }, - 'kafka.log.trace.message': { - category: 'kafka', - description: 'Message part of the trace. ', - name: 'kafka.log.trace.message', - type: 'text', + 'auditd.data.new-range': { + category: 'auditd', + description: 'new SELinux range', + name: 'auditd.data.new-range', + type: 'keyword', }, - 'kibana.log.tags': { - category: 'kibana', - description: 'Kibana logging tags. ', - name: 'kibana.log.tags', + 'auditd.data.obj_gid': { + category: 'auditd', + description: 'group ID of object', + name: 'auditd.data.obj_gid', type: 'keyword', }, - 'kibana.log.state': { - category: 'kibana', - description: 'Current state of Kibana. ', - name: 'kibana.log.state', + 'auditd.data.proto': { + category: 'auditd', + description: 'network protocol', + name: 'auditd.data.proto', type: 'keyword', }, - 'kibana.log.meta': { - category: 'kibana', - name: 'kibana.log.meta', - type: 'object', + 'auditd.data.old-disk': { + category: 'auditd', + description: 'disk being removed from vm', + name: 'auditd.data.old-disk', + type: 'keyword', }, - 'kibana.log.kibana.log.meta.req.headers.referer': { - category: 'kibana', - name: 'kibana.log.kibana.log.meta.req.headers.referer', - type: 'alias', + 'auditd.data.audit_failure': { + category: 'auditd', + description: "audit system's failure mode", + name: 'auditd.data.audit_failure', + type: 'keyword', }, - 'kibana.log.kibana.log.meta.req.referer': { - category: 'kibana', - name: 'kibana.log.kibana.log.meta.req.referer', - type: 'alias', + 'auditd.data.inif': { + category: 'auditd', + description: 'in interface number', + name: 'auditd.data.inif', + type: 'keyword', }, - 'kibana.log.kibana.log.meta.req.headers.user-agent': { - category: 'kibana', - name: 'kibana.log.kibana.log.meta.req.headers.user-agent', - type: 'alias', + 'auditd.data.vm': { + category: 'auditd', + description: 'virtual machine name', + name: 'auditd.data.vm', + type: 'keyword', }, - 'kibana.log.kibana.log.meta.req.remoteAddress': { - category: 'kibana', - name: 'kibana.log.kibana.log.meta.req.remoteAddress', - type: 'alias', + 'auditd.data.flags': { + category: 'auditd', + description: 'mmap syscall flags', + name: 'auditd.data.flags', + type: 'keyword', }, - 'kibana.log.kibana.log.meta.req.url': { - category: 'kibana', - name: 'kibana.log.kibana.log.meta.req.url', - type: 'alias', + 'auditd.data.nlnk-fam': { + category: 'auditd', + description: 'netlink protocol number', + name: 'auditd.data.nlnk-fam', + type: 'keyword', }, - 'kibana.log.kibana.log.meta.statusCode': { - category: 'kibana', - name: 'kibana.log.kibana.log.meta.statusCode', - type: 'alias', + 'auditd.data.old-fs': { + category: 'auditd', + description: 'file system being removed from vm', + name: 'auditd.data.old-fs', + type: 'keyword', }, - 'kibana.log.kibana.log.meta.method': { - category: 'kibana', - name: 'kibana.log.kibana.log.meta.method', - type: 'alias', + 'auditd.data.old-ses': { + category: 'auditd', + description: 'previous ses value', + name: 'auditd.data.old-ses', + type: 'keyword', }, - 'logstash.log.module': { - category: 'logstash', - description: 'The module or class where the event originate. ', - name: 'logstash.log.module', + 'auditd.data.seqno': { + category: 'auditd', + description: 'sequence number', + name: 'auditd.data.seqno', type: 'keyword', }, - 'logstash.log.thread': { - category: 'logstash', - description: 'Information about the running thread where the log originate. ', - name: 'logstash.log.thread', + 'auditd.data.fver': { + category: 'auditd', + description: 'file system capabilities version number', + name: 'auditd.data.fver', type: 'keyword', }, - 'logstash.log.log_event': { - category: 'logstash', - description: 'key and value debugging information. ', - name: 'logstash.log.log_event', - type: 'object', + 'auditd.data.qbytes': { + category: 'auditd', + description: 'ipc objects quantity of bytes', + name: 'auditd.data.qbytes', + type: 'keyword', }, - 'logstash.log.pipeline_id': { - category: 'logstash', - description: 'The ID of the pipeline. ', - example: 'main', - name: 'logstash.log.pipeline_id', + 'auditd.data.seuser': { + category: 'auditd', + description: "user's SE Linux user acct", + name: 'auditd.data.seuser', type: 'keyword', }, - 'logstash.log.message': { - category: 'logstash', - name: 'logstash.log.message', - type: 'alias', + 'auditd.data.cap_fe': { + category: 'auditd', + description: 'file assigned effective capability map', + name: 'auditd.data.cap_fe', + type: 'keyword', }, - 'logstash.log.level': { - category: 'logstash', - name: 'logstash.log.level', - type: 'alias', + 'auditd.data.new-vcpu': { + category: 'auditd', + description: 'new number of CPU cores', + name: 'auditd.data.new-vcpu', + type: 'keyword', }, - 'logstash.slowlog.module': { - category: 'logstash', - description: 'The module or class where the event originate. ', - name: 'logstash.slowlog.module', + 'auditd.data.old-level': { + category: 'auditd', + description: 'old run level', + name: 'auditd.data.old-level', type: 'keyword', }, - 'logstash.slowlog.thread': { - category: 'logstash', - description: 'Information about the running thread where the log originate. ', - name: 'logstash.slowlog.thread', + 'auditd.data.old_pp': { + category: 'auditd', + description: 'old process permitted capability map', + name: 'auditd.data.old_pp', type: 'keyword', }, - 'logstash.slowlog.event': { - category: 'logstash', - description: 'Raw dump of the original event ', - name: 'logstash.slowlog.event', + 'auditd.data.daddr': { + category: 'auditd', + description: 'remote IP address', + name: 'auditd.data.daddr', type: 'keyword', }, - 'logstash.slowlog.plugin_name': { - category: 'logstash', - description: 'Name of the plugin ', - name: 'logstash.slowlog.plugin_name', + 'auditd.data.old-role': { + category: 'auditd', + description: 'present SELinux role', + name: 'auditd.data.old-role', type: 'keyword', }, - 'logstash.slowlog.plugin_type': { - category: 'logstash', - description: 'Type of the plugin: Inputs, Filters, Outputs or Codecs. ', - name: 'logstash.slowlog.plugin_type', + 'auditd.data.ioctlcmd': { + category: 'auditd', + description: 'The request argument to the ioctl syscall', + name: 'auditd.data.ioctlcmd', type: 'keyword', }, - 'logstash.slowlog.took_in_millis': { - category: 'logstash', - description: 'Execution time for the plugin in milliseconds. ', - name: 'logstash.slowlog.took_in_millis', - type: 'long', + 'auditd.data.smac': { + category: 'auditd', + description: 'local MAC address', + name: 'auditd.data.smac', + type: 'keyword', }, - 'logstash.slowlog.plugin_params': { - category: 'logstash', - description: 'String value of the plugin configuration ', - name: 'logstash.slowlog.plugin_params', + 'auditd.data.apparmor': { + category: 'auditd', + description: 'apparmor event information', + name: 'auditd.data.apparmor', type: 'keyword', }, - 'logstash.slowlog.plugin_params_object': { - category: 'logstash', - description: 'key -> value of the configuration used by the plugin. ', - name: 'logstash.slowlog.plugin_params_object', - type: 'object', + 'auditd.data.fe': { + category: 'auditd', + description: 'file assigned effective capability map', + name: 'auditd.data.fe', + type: 'keyword', }, - 'logstash.slowlog.level': { - category: 'logstash', - name: 'logstash.slowlog.level', - type: 'alias', + 'auditd.data.perm_mask': { + category: 'auditd', + description: 'file permission mask that triggered a watch event', + name: 'auditd.data.perm_mask', + type: 'keyword', }, - 'logstash.slowlog.took_in_nanos': { - category: 'logstash', - name: 'logstash.slowlog.took_in_nanos', - type: 'alias', + 'auditd.data.ses': { + category: 'auditd', + description: 'login session ID', + name: 'auditd.data.ses', + type: 'keyword', }, - 'mongodb.log.component': { - category: 'mongodb', - description: 'Functional categorization of message ', - example: 'COMMAND', - name: 'mongodb.log.component', + 'auditd.data.cap_fi': { + category: 'auditd', + description: 'file inherited capability map', + name: 'auditd.data.cap_fi', type: 'keyword', }, - 'mongodb.log.context': { - category: 'mongodb', - description: 'Context of message ', - example: 'initandlisten', - name: 'mongodb.log.context', + 'auditd.data.obj_uid': { + category: 'auditd', + description: 'user ID of object', + name: 'auditd.data.obj_uid', type: 'keyword', }, - 'mongodb.log.severity': { - category: 'mongodb', - name: 'mongodb.log.severity', - type: 'alias', + 'auditd.data.reason': { + category: 'auditd', + description: 'text string denoting a reason for the action', + name: 'auditd.data.reason', + type: 'keyword', }, - 'mongodb.log.message': { - category: 'mongodb', - name: 'mongodb.log.message', - type: 'alias', + 'auditd.data.list': { + category: 'auditd', + description: "the audit system's filter list number", + name: 'auditd.data.list', + type: 'keyword', }, - 'mysql.thread_id': { - category: 'mysql', - description: 'The connection or thread ID for the query. ', - name: 'mysql.thread_id', - type: 'long', + 'auditd.data.old_lock': { + category: 'auditd', + description: 'present value of feature lock', + name: 'auditd.data.old_lock', + type: 'keyword', }, - 'mysql.error.thread_id': { - category: 'mysql', - name: 'mysql.error.thread_id', - type: 'alias', + 'auditd.data.bus': { + category: 'auditd', + description: 'name of subsystem bus a vm resource belongs to', + name: 'auditd.data.bus', + type: 'keyword', }, - 'mysql.error.level': { - category: 'mysql', - name: 'mysql.error.level', - type: 'alias', + 'auditd.data.old_pe': { + category: 'auditd', + description: 'old process effective capability map', + name: 'auditd.data.old_pe', + type: 'keyword', }, - 'mysql.error.message': { - category: 'mysql', - name: 'mysql.error.message', - type: 'alias', + 'auditd.data.new-role': { + category: 'auditd', + description: 'new SELinux role', + name: 'auditd.data.new-role', + type: 'keyword', }, - 'mysql.slowlog.lock_time.sec': { - category: 'mysql', - description: - 'The amount of time the query waited for the lock to be available. The value is in seconds, as a floating point number. ', - name: 'mysql.slowlog.lock_time.sec', - type: 'float', + 'auditd.data.prom': { + category: 'auditd', + description: 'network promiscuity flag', + name: 'auditd.data.prom', + type: 'keyword', }, - 'mysql.slowlog.rows_sent': { - category: 'mysql', - description: 'The number of rows returned by the query. ', - name: 'mysql.slowlog.rows_sent', - type: 'long', + 'auditd.data.uri': { + category: 'auditd', + description: 'URI pointing to a printer', + name: 'auditd.data.uri', + type: 'keyword', }, - 'mysql.slowlog.rows_examined': { - category: 'mysql', - description: 'The number of rows scanned by the query. ', - name: 'mysql.slowlog.rows_examined', - type: 'long', + 'auditd.data.audit_enabled': { + category: 'auditd', + description: "audit systems's enable/disable status", + name: 'auditd.data.audit_enabled', + type: 'keyword', }, - 'mysql.slowlog.rows_affected': { - category: 'mysql', - description: 'The number of rows modified by the query. ', - name: 'mysql.slowlog.rows_affected', - type: 'long', + 'auditd.data.old-log_passwd': { + category: 'auditd', + description: 'present value for TTY password logging', + name: 'auditd.data.old-log_passwd', + type: 'keyword', }, - 'mysql.slowlog.bytes_sent': { - category: 'mysql', - description: 'The number of bytes sent to client. ', - name: 'mysql.slowlog.bytes_sent', - type: 'long', - format: 'bytes', + 'auditd.data.old-seuser': { + category: 'auditd', + description: 'present SELinux user', + name: 'auditd.data.old-seuser', + type: 'keyword', }, - 'mysql.slowlog.bytes_received': { - category: 'mysql', - description: 'The number of bytes received from client. ', - name: 'mysql.slowlog.bytes_received', - type: 'long', - format: 'bytes', + 'auditd.data.per': { + category: 'auditd', + description: 'linux personality', + name: 'auditd.data.per', + type: 'keyword', }, - 'mysql.slowlog.query': { - category: 'mysql', - description: 'The slow query. ', - name: 'mysql.slowlog.query', + 'auditd.data.scontext': { + category: 'auditd', + description: "the subject's context string", + name: 'auditd.data.scontext', + type: 'keyword', }, - 'mysql.slowlog.id': { - category: 'mysql', - name: 'mysql.slowlog.id', - type: 'alias', + 'auditd.data.tclass': { + category: 'auditd', + description: "target's object classification", + name: 'auditd.data.tclass', + type: 'keyword', }, - 'mysql.slowlog.schema': { - category: 'mysql', - description: 'The schema where the slow query was executed. ', - name: 'mysql.slowlog.schema', + 'auditd.data.ver': { + category: 'auditd', + description: "audit daemon's version number", + name: 'auditd.data.ver', type: 'keyword', }, - 'mysql.slowlog.current_user': { - category: 'mysql', - description: - 'Current authenticated user, used to determine access privileges. Can differ from the value for user. ', - name: 'mysql.slowlog.current_user', + 'auditd.data.new': { + category: 'auditd', + description: 'value being set in feature', + name: 'auditd.data.new', type: 'keyword', }, - 'mysql.slowlog.last_errno': { - category: 'mysql', - description: 'Last SQL error seen. ', - name: 'mysql.slowlog.last_errno', + 'auditd.data.val': { + category: 'auditd', + description: 'generic value associated with the operation', + name: 'auditd.data.val', type: 'keyword', }, - 'mysql.slowlog.killed': { - category: 'mysql', - description: 'Code of the reason if the query was killed. ', - name: 'mysql.slowlog.killed', + 'auditd.data.img-ctx': { + category: 'auditd', + description: "the vm's disk image context string", + name: 'auditd.data.img-ctx', type: 'keyword', }, - 'mysql.slowlog.query_cache_hit': { - category: 'mysql', - description: 'Whether the query cache was hit. ', - name: 'mysql.slowlog.query_cache_hit', - type: 'boolean', + 'auditd.data.old-chardev': { + category: 'auditd', + description: 'present character device assigned to vm', + name: 'auditd.data.old-chardev', + type: 'keyword', }, - 'mysql.slowlog.tmp_table': { - category: 'mysql', - description: 'Whether a temporary table was used to resolve the query. ', - name: 'mysql.slowlog.tmp_table', - type: 'boolean', + 'auditd.data.old_val': { + category: 'auditd', + description: 'current value of SELinux boolean', + name: 'auditd.data.old_val', + type: 'keyword', }, - 'mysql.slowlog.tmp_table_on_disk': { - category: 'mysql', - description: 'Whether the query needed temporary tables on disk. ', - name: 'mysql.slowlog.tmp_table_on_disk', - type: 'boolean', + 'auditd.data.success': { + category: 'auditd', + description: 'whether the syscall was successful or not', + name: 'auditd.data.success', + type: 'keyword', }, - 'mysql.slowlog.tmp_tables': { - category: 'mysql', - description: 'Number of temporary tables created for this query ', - name: 'mysql.slowlog.tmp_tables', - type: 'long', + 'auditd.data.inode_uid': { + category: 'auditd', + description: "user ID of the inode's owner", + name: 'auditd.data.inode_uid', + type: 'keyword', }, - 'mysql.slowlog.tmp_disk_tables': { - category: 'mysql', - description: 'Number of temporary tables created on disk for this query. ', - name: 'mysql.slowlog.tmp_disk_tables', - type: 'long', + 'auditd.data.removed': { + category: 'auditd', + description: 'number of deleted files', + name: 'auditd.data.removed', + type: 'keyword', }, - 'mysql.slowlog.tmp_table_sizes': { - category: 'mysql', - description: 'Size of temporary tables created for this query.', - name: 'mysql.slowlog.tmp_table_sizes', - type: 'long', - format: 'bytes', + 'auditd.data.socket.port': { + category: 'auditd', + description: 'The port number.', + name: 'auditd.data.socket.port', + type: 'keyword', }, - 'mysql.slowlog.filesort': { - category: 'mysql', - description: 'Whether filesort optimization was used. ', - name: 'mysql.slowlog.filesort', - type: 'boolean', + 'auditd.data.socket.saddr': { + category: 'auditd', + description: 'The raw socket address structure.', + name: 'auditd.data.socket.saddr', + type: 'keyword', }, - 'mysql.slowlog.filesort_on_disk': { - category: 'mysql', - description: 'Whether filesort optimization was used and it needed temporary tables on disk. ', - name: 'mysql.slowlog.filesort_on_disk', - type: 'boolean', + 'auditd.data.socket.addr': { + category: 'auditd', + description: 'The remote address.', + name: 'auditd.data.socket.addr', + type: 'keyword', }, - 'mysql.slowlog.priority_queue': { - category: 'mysql', - description: 'Whether a priority queue was used for filesort. ', - name: 'mysql.slowlog.priority_queue', - type: 'boolean', + 'auditd.data.socket.family': { + category: 'auditd', + description: 'The socket family (unix, ipv4, ipv6, netlink).', + example: 'unix', + name: 'auditd.data.socket.family', + type: 'keyword', }, - 'mysql.slowlog.full_scan': { - category: 'mysql', - description: 'Whether a full table scan was needed for the slow query. ', - name: 'mysql.slowlog.full_scan', - type: 'boolean', + 'auditd.data.socket.path': { + category: 'auditd', + description: 'This is the path associated with a unix socket.', + name: 'auditd.data.socket.path', + type: 'keyword', }, - 'mysql.slowlog.full_join': { - category: 'mysql', + 'auditd.messages': { + category: 'auditd', description: - 'Whether a full join was needed for the slow query (no indexes were used for joins). ', - name: 'mysql.slowlog.full_join', + 'An ordered list of the raw messages received from the kernel that were used to construct this document. This field is present if an error occurred processing the data or if `include_raw_message` is set in the config. ', + name: 'auditd.messages', + type: 'alias', + }, + 'auditd.warnings': { + category: 'auditd', + description: + 'The warnings generated by the Beat during the construction of the event. These are disabled by default and are used for development and debug purposes only. ', + name: 'auditd.warnings', + type: 'alias', + }, + 'geoip.continent_name': { + category: 'geoip', + description: 'The name of the continent. ', + name: 'geoip.continent_name', + type: 'keyword', + }, + 'geoip.city_name': { + category: 'geoip', + description: 'The name of the city. ', + name: 'geoip.city_name', + type: 'keyword', + }, + 'geoip.region_name': { + category: 'geoip', + description: 'The name of the region. ', + name: 'geoip.region_name', + type: 'keyword', + }, + 'geoip.country_iso_code': { + category: 'geoip', + description: 'Country ISO code. ', + name: 'geoip.country_iso_code', + type: 'keyword', + }, + 'geoip.location': { + category: 'geoip', + description: 'The longitude and latitude. ', + name: 'geoip.location', + type: 'geo_point', + }, + 'hash.blake2b_256': { + category: 'hash', + description: 'BLAKE2b-256 hash of the file.', + name: 'hash.blake2b_256', + type: 'keyword', + }, + 'hash.blake2b_384': { + category: 'hash', + description: 'BLAKE2b-384 hash of the file.', + name: 'hash.blake2b_384', + type: 'keyword', + }, + 'hash.blake2b_512': { + category: 'hash', + description: 'BLAKE2b-512 hash of the file.', + name: 'hash.blake2b_512', + type: 'keyword', + }, + 'hash.sha224': { + category: 'hash', + description: 'SHA224 hash of the file.', + name: 'hash.sha224', + type: 'keyword', + }, + 'hash.sha384': { + category: 'hash', + description: 'SHA384 hash of the file.', + name: 'hash.sha384', + type: 'keyword', + }, + 'hash.sha3_224': { + category: 'hash', + description: 'SHA3_224 hash of the file.', + name: 'hash.sha3_224', + type: 'keyword', + }, + 'hash.sha3_256': { + category: 'hash', + description: 'SHA3_256 hash of the file.', + name: 'hash.sha3_256', + type: 'keyword', + }, + 'hash.sha3_384': { + category: 'hash', + description: 'SHA3_384 hash of the file.', + name: 'hash.sha3_384', + type: 'keyword', + }, + 'hash.sha3_512': { + category: 'hash', + description: 'SHA3_512 hash of the file.', + name: 'hash.sha3_512', + type: 'keyword', + }, + 'hash.sha512_224': { + category: 'hash', + description: 'SHA512/224 hash of the file.', + name: 'hash.sha512_224', + type: 'keyword', + }, + 'hash.sha512_256': { + category: 'hash', + description: 'SHA512/256 hash of the file.', + name: 'hash.sha512_256', + type: 'keyword', + }, + 'hash.xxh64': { + category: 'hash', + description: 'XX64 hash of the file.', + name: 'hash.xxh64', + type: 'keyword', + }, + 'event.origin': { + category: 'event', + description: + 'Origin of the event. This can be a file path (e.g. `/var/log/log.1`), or the name of the system component that supplied the data (e.g. `netlink`). ', + name: 'event.origin', + type: 'keyword', + }, + 'user.entity_id': { + category: 'user', + description: + 'ID uniquely identifying the user on a host. It is computed as a SHA-256 hash of the host ID, user ID, and user name. ', + name: 'user.entity_id', + type: 'keyword', + }, + 'user.terminal': { + category: 'user', + description: 'Terminal of the user. ', + name: 'user.terminal', + type: 'keyword', + }, + 'process.hash.blake2b_256': { + category: 'process', + description: 'BLAKE2b-256 hash of the executable.', + name: 'process.hash.blake2b_256', + type: 'keyword', + }, + 'process.hash.blake2b_384': { + category: 'process', + description: 'BLAKE2b-384 hash of the executable.', + name: 'process.hash.blake2b_384', + type: 'keyword', + }, + 'process.hash.blake2b_512': { + category: 'process', + description: 'BLAKE2b-512 hash of the executable.', + name: 'process.hash.blake2b_512', + type: 'keyword', + }, + 'process.hash.sha224': { + category: 'process', + description: 'SHA224 hash of the executable.', + name: 'process.hash.sha224', + type: 'keyword', + }, + 'process.hash.sha384': { + category: 'process', + description: 'SHA384 hash of the executable.', + name: 'process.hash.sha384', + type: 'keyword', + }, + 'process.hash.sha3_224': { + category: 'process', + description: 'SHA3_224 hash of the executable.', + name: 'process.hash.sha3_224', + type: 'keyword', + }, + 'process.hash.sha3_256': { + category: 'process', + description: 'SHA3_256 hash of the executable.', + name: 'process.hash.sha3_256', + type: 'keyword', + }, + 'process.hash.sha3_384': { + category: 'process', + description: 'SHA3_384 hash of the executable.', + name: 'process.hash.sha3_384', + type: 'keyword', + }, + 'process.hash.sha3_512': { + category: 'process', + description: 'SHA3_512 hash of the executable.', + name: 'process.hash.sha3_512', + type: 'keyword', + }, + 'process.hash.sha512_224': { + category: 'process', + description: 'SHA512/224 hash of the executable.', + name: 'process.hash.sha512_224', + type: 'keyword', + }, + 'process.hash.sha512_256': { + category: 'process', + description: 'SHA512/256 hash of the executable.', + name: 'process.hash.sha512_256', + type: 'keyword', + }, + 'process.hash.xxh64': { + category: 'process', + description: 'XX64 hash of the executable.', + name: 'process.hash.xxh64', + type: 'keyword', + }, + 'socket.entity_id': { + category: 'socket', + description: + 'ID uniquely identifying the socket. It is computed as a SHA-256 hash of the host ID, socket inode, local IP, local port, remote IP, and remote port. ', + name: 'socket.entity_id', + type: 'keyword', + }, + 'system.audit.host.uptime': { + category: 'system', + description: 'Uptime in nanoseconds. ', + name: 'system.audit.host.uptime', + type: 'long', + format: 'duration', + }, + 'system.audit.host.boottime': { + category: 'system', + description: 'Boot time. ', + name: 'system.audit.host.boottime', + type: 'date', + }, + 'system.audit.host.containerized': { + category: 'system', + description: 'Set if host is a container. ', + name: 'system.audit.host.containerized', type: 'boolean', }, - 'mysql.slowlog.merge_passes': { - category: 'mysql', - description: 'Number of merge passes executed for the query. ', - name: 'mysql.slowlog.merge_passes', + 'system.audit.host.timezone.name': { + category: 'system', + description: 'Name of the timezone of the host, e.g. BST. ', + name: 'system.audit.host.timezone.name', + type: 'keyword', + }, + 'system.audit.host.timezone.offset.sec': { + category: 'system', + description: 'Timezone offset in seconds. ', + name: 'system.audit.host.timezone.offset.sec', type: 'long', }, - 'mysql.slowlog.sort_merge_passes': { - category: 'mysql', - description: 'Number of merge passes that the sort algorithm has had to do. ', - name: 'mysql.slowlog.sort_merge_passes', + 'system.audit.host.hostname': { + category: 'system', + description: 'Hostname. ', + name: 'system.audit.host.hostname', + type: 'keyword', + }, + 'system.audit.host.id': { + category: 'system', + description: 'Host ID. ', + name: 'system.audit.host.id', + type: 'keyword', + }, + 'system.audit.host.architecture': { + category: 'system', + description: 'Host architecture (e.g. x86_64). ', + name: 'system.audit.host.architecture', + type: 'keyword', + }, + 'system.audit.host.mac': { + category: 'system', + description: 'MAC addresses. ', + name: 'system.audit.host.mac', + type: 'keyword', + }, + 'system.audit.host.ip': { + category: 'system', + description: 'IP addresses. ', + name: 'system.audit.host.ip', + type: 'ip', + }, + 'system.audit.host.os.codename': { + category: 'system', + description: 'OS codename, if any (e.g. stretch). ', + name: 'system.audit.host.os.codename', + type: 'keyword', + }, + 'system.audit.host.os.platform': { + category: 'system', + description: 'OS platform (e.g. centos, ubuntu, windows). ', + name: 'system.audit.host.os.platform', + type: 'keyword', + }, + 'system.audit.host.os.name': { + category: 'system', + description: 'OS name (e.g. Mac OS X). ', + name: 'system.audit.host.os.name', + type: 'keyword', + }, + 'system.audit.host.os.family': { + category: 'system', + description: 'OS family (e.g. redhat, debian, freebsd, windows). ', + name: 'system.audit.host.os.family', + type: 'keyword', + }, + 'system.audit.host.os.version': { + category: 'system', + description: 'OS version. ', + name: 'system.audit.host.os.version', + type: 'keyword', + }, + 'system.audit.host.os.kernel': { + category: 'system', + description: "The operating system's kernel version. ", + name: 'system.audit.host.os.kernel', + type: 'keyword', + }, + 'system.audit.host.os.type': { + category: 'system', + description: 'OS type (see ECS os.type). ', + name: 'system.audit.host.os.type', + type: 'keyword', + }, + 'system.audit.package.entity_id': { + category: 'system', + description: + 'ID uniquely identifying the package. It is computed as a SHA-256 hash of the host ID, package name, and package version. ', + name: 'system.audit.package.entity_id', + type: 'keyword', + }, + 'system.audit.package.name': { + category: 'system', + description: 'Package name. ', + name: 'system.audit.package.name', + type: 'keyword', + }, + 'system.audit.package.version': { + category: 'system', + description: 'Package version. ', + name: 'system.audit.package.version', + type: 'keyword', + }, + 'system.audit.package.release': { + category: 'system', + description: 'Package release. ', + name: 'system.audit.package.release', + type: 'keyword', + }, + 'system.audit.package.arch': { + category: 'system', + description: 'Package architecture. ', + name: 'system.audit.package.arch', + type: 'keyword', + }, + 'system.audit.package.license': { + category: 'system', + description: 'Package license. ', + name: 'system.audit.package.license', + type: 'keyword', + }, + 'system.audit.package.installtime': { + category: 'system', + description: 'Package install time. ', + name: 'system.audit.package.installtime', + type: 'date', + }, + 'system.audit.package.size': { + category: 'system', + description: 'Package size. ', + name: 'system.audit.package.size', type: 'long', }, - 'mysql.slowlog.sort_range_count': { - category: 'mysql', - description: 'Number of sorts that were done using ranges. ', - name: 'mysql.slowlog.sort_range_count', - type: 'long', + 'system.audit.package.summary': { + category: 'system', + description: 'Package summary. ', + name: 'system.audit.package.summary', + }, + 'system.audit.package.url': { + category: 'system', + description: 'Package URL. ', + name: 'system.audit.package.url', + type: 'keyword', + }, + 'system.audit.user.name': { + category: 'system', + description: 'User name. ', + name: 'system.audit.user.name', + type: 'keyword', + }, + 'system.audit.user.uid': { + category: 'system', + description: 'User ID. ', + name: 'system.audit.user.uid', + type: 'keyword', + }, + 'system.audit.user.gid': { + category: 'system', + description: 'Group ID. ', + name: 'system.audit.user.gid', + type: 'keyword', + }, + 'system.audit.user.dir': { + category: 'system', + description: "User's home directory. ", + name: 'system.audit.user.dir', + type: 'keyword', + }, + 'system.audit.user.shell': { + category: 'system', + description: 'Program to run at login. ', + name: 'system.audit.user.shell', + type: 'keyword', + }, + 'system.audit.user.user_information': { + category: 'system', + description: 'General user information. On Linux, this is the gecos field. ', + name: 'system.audit.user.user_information', + type: 'keyword', + }, + 'system.audit.user.group.name': { + category: 'system', + description: 'Group name. ', + name: 'system.audit.user.group.name', + type: 'keyword', + }, + 'system.audit.user.group.gid': { + category: 'system', + description: 'Group ID. ', + name: 'system.audit.user.group.gid', + type: 'integer', + }, + 'system.audit.user.password.type': { + category: 'system', + description: + "A user's password type. Possible values are `shadow_password` (the password hash is in the shadow file), `password_disabled`, `no_password` (this is dangerous as anyone can log in), and `crypt_password` (when the password field in /etc/passwd seems to contain an encrypted password). ", + name: 'system.audit.user.password.type', + type: 'keyword', + }, + 'system.audit.user.password.last_changed': { + category: 'system', + description: "The day the user's password was last changed. ", + name: 'system.audit.user.password.last_changed', + type: 'date', + }, + 'log.source.address': { + category: 'log', + description: 'Source address from which the log event was read / sent from. ', + name: 'log.source.address', + type: 'keyword', + }, + 'log.offset': { + category: 'log', + description: 'The file offset the reported line starts at. ', + name: 'log.offset', + type: 'long', + }, + stream: { + category: 'base', + description: "Log stream when reading container logs, can be 'stdout' or 'stderr' ", + name: 'stream', + type: 'keyword', + }, + 'input.type': { + category: 'input', + description: + 'The input type from which the event was generated. This field is set to the value specified for the `type` option in the input section of the Filebeat config file. ', + name: 'input.type', + }, + 'syslog.facility': { + category: 'syslog', + description: 'The facility extracted from the priority. ', + name: 'syslog.facility', + type: 'long', + }, + 'syslog.priority': { + category: 'syslog', + description: 'The priority of the syslog event. ', + name: 'syslog.priority', + type: 'long', + }, + 'syslog.severity_label': { + category: 'syslog', + description: 'The human readable severity. ', + name: 'syslog.severity_label', + type: 'keyword', + }, + 'syslog.facility_label': { + category: 'syslog', + description: 'The human readable facility. ', + name: 'syslog.facility_label', + type: 'keyword', + }, + 'process.program': { + category: 'process', + description: 'The name of the program. ', + name: 'process.program', + type: 'keyword', + }, + 'log.flags': { + category: 'log', + description: 'This field contains the flags of the event. ', + name: 'log.flags', + }, + 'http.response.content_length': { + category: 'http', + name: 'http.response.content_length', + type: 'alias', + }, + 'user_agent.os.full_name': { + category: 'user_agent', + name: 'user_agent.os.full_name', + type: 'keyword', + }, + 'fileset.name': { + category: 'fileset', + description: 'The Filebeat fileset that generated this event. ', + name: 'fileset.name', + type: 'keyword', + }, + 'fileset.module': { + category: 'fileset', + name: 'fileset.module', + type: 'alias', + }, + read_timestamp: { + category: 'base', + name: 'read_timestamp', + type: 'alias', + }, + 'docker.attrs': { + category: 'docker', + description: + "docker.attrs contains labels and environment variables written by docker's JSON File logging driver. These fields are only available when they are configured in the logging driver options. ", + name: 'docker.attrs', + type: 'object', + }, + 'icmp.code': { + category: 'icmp', + description: 'ICMP code. ', + name: 'icmp.code', + type: 'keyword', + }, + 'icmp.type': { + category: 'icmp', + description: 'ICMP type. ', + name: 'icmp.type', + type: 'keyword', + }, + 'igmp.type': { + category: 'igmp', + description: 'IGMP type. ', + name: 'igmp.type', + type: 'keyword', + }, + 'azure.eventhub': { + category: 'azure', + description: 'Name of the eventhub. ', + name: 'azure.eventhub', + type: 'keyword', + }, + 'azure.offset': { + category: 'azure', + description: 'The offset. ', + name: 'azure.offset', + type: 'long', + }, + 'azure.enqueued_time': { + category: 'azure', + description: 'The enqueued time. ', + name: 'azure.enqueued_time', + type: 'date', + }, + 'azure.partition_id': { + category: 'azure', + description: 'The partition id. ', + name: 'azure.partition_id', + type: 'long', + }, + 'azure.consumer_group': { + category: 'azure', + description: 'The consumer group. ', + name: 'azure.consumer_group', + type: 'keyword', + }, + 'azure.sequence_number': { + category: 'azure', + description: 'The sequence number. ', + name: 'azure.sequence_number', + type: 'long', + }, + 'kafka.topic': { + category: 'kafka', + description: 'Kafka topic ', + name: 'kafka.topic', + type: 'keyword', + }, + 'kafka.partition': { + category: 'kafka', + description: 'Kafka partition number ', + name: 'kafka.partition', + type: 'long', + }, + 'kafka.offset': { + category: 'kafka', + description: 'Kafka offset of this message ', + name: 'kafka.offset', + type: 'long', + }, + 'kafka.key': { + category: 'kafka', + description: 'Kafka key, corresponding to the Kafka value stored in the message ', + name: 'kafka.key', + type: 'keyword', + }, + 'kafka.block_timestamp': { + category: 'kafka', + description: 'Kafka outer (compressed) block timestamp ', + name: 'kafka.block_timestamp', + type: 'date', + }, + 'kafka.headers': { + category: 'kafka', + description: + 'An array of Kafka header strings for this message, in the form ": ". ', + name: 'kafka.headers', + type: 'array', + }, + 'apache.access.ssl.protocol': { + category: 'apache', + description: 'SSL protocol version. ', + name: 'apache.access.ssl.protocol', + type: 'keyword', + }, + 'apache.access.ssl.cipher': { + category: 'apache', + description: 'SSL cipher name. ', + name: 'apache.access.ssl.cipher', + type: 'keyword', + }, + 'apache.error.module': { + category: 'apache', + description: 'The module producing the logged message. ', + name: 'apache.error.module', + type: 'keyword', + }, + 'user.audit.group.id': { + category: 'user', + description: 'Unique identifier for the group on the system/platform. ', + name: 'user.audit.group.id', + type: 'keyword', + }, + 'user.audit.group.name': { + category: 'user', + description: 'Name of the group. ', + name: 'user.audit.group.name', + type: 'keyword', + }, + 'user.owner.id': { + category: 'user', + description: 'One or multiple unique identifiers of the user. ', + name: 'user.owner.id', + type: 'keyword', + }, + 'user.owner.name': { + category: 'user', + description: 'Short name or login of the user. ', + example: 'albert', + name: 'user.owner.name', + type: 'keyword', + }, + 'user.owner.group.id': { + category: 'user', + description: 'Unique identifier for the group on the system/platform. ', + name: 'user.owner.group.id', + type: 'keyword', + }, + 'user.owner.group.name': { + category: 'user', + description: 'Name of the group. ', + name: 'user.owner.group.name', + type: 'keyword', + }, + 'auditd.log.old_auid': { + category: 'auditd', + description: + 'For login events this is the old audit ID used for the user prior to this login. ', + name: 'auditd.log.old_auid', + }, + 'auditd.log.new_auid': { + category: 'auditd', + description: + 'For login events this is the new audit ID. The audit ID can be used to trace future events to the user even if their identity changes (like becoming root). ', + name: 'auditd.log.new_auid', + }, + 'auditd.log.old_ses': { + category: 'auditd', + description: + 'For login events this is the old session ID used for the user prior to this login. ', + name: 'auditd.log.old_ses', + }, + 'auditd.log.new_ses': { + category: 'auditd', + description: + 'For login events this is the new session ID. It can be used to tie a user to future events by session ID. ', + name: 'auditd.log.new_ses', + }, + 'auditd.log.sequence': { + category: 'auditd', + description: 'The audit event sequence number. ', + name: 'auditd.log.sequence', + type: 'long', + }, + 'auditd.log.items': { + category: 'auditd', + description: 'The number of items in an event. ', + name: 'auditd.log.items', + }, + 'auditd.log.item': { + category: 'auditd', + description: + 'The item field indicates which item out of the total number of items. This number is zero-based; a value of 0 means it is the first item. ', + name: 'auditd.log.item', + }, + 'auditd.log.tty': { + category: 'auditd', + name: 'auditd.log.tty', + type: 'keyword', + }, + 'auditd.log.a0': { + category: 'auditd', + description: 'The first argument to the system call. ', + name: 'auditd.log.a0', + }, + 'auditd.log.addr': { + category: 'auditd', + name: 'auditd.log.addr', + type: 'ip', + }, + 'auditd.log.rport': { + category: 'auditd', + name: 'auditd.log.rport', + type: 'long', + }, + 'auditd.log.laddr': { + category: 'auditd', + name: 'auditd.log.laddr', + type: 'ip', + }, + 'auditd.log.lport': { + category: 'auditd', + name: 'auditd.log.lport', + type: 'long', + }, + 'auditd.log.acct': { + category: 'auditd', + name: 'auditd.log.acct', + type: 'alias', + }, + 'auditd.log.pid': { + category: 'auditd', + name: 'auditd.log.pid', + type: 'alias', + }, + 'auditd.log.ppid': { + category: 'auditd', + name: 'auditd.log.ppid', + type: 'alias', + }, + 'auditd.log.res': { + category: 'auditd', + name: 'auditd.log.res', + type: 'alias', + }, + 'auditd.log.record_type': { + category: 'auditd', + name: 'auditd.log.record_type', + type: 'alias', + }, + 'auditd.log.geoip.continent_name': { + category: 'auditd', + name: 'auditd.log.geoip.continent_name', + type: 'alias', + }, + 'auditd.log.geoip.country_iso_code': { + category: 'auditd', + name: 'auditd.log.geoip.country_iso_code', + type: 'alias', + }, + 'auditd.log.geoip.location': { + category: 'auditd', + name: 'auditd.log.geoip.location', + type: 'alias', + }, + 'auditd.log.geoip.region_name': { + category: 'auditd', + name: 'auditd.log.geoip.region_name', + type: 'alias', + }, + 'auditd.log.geoip.city_name': { + category: 'auditd', + name: 'auditd.log.geoip.city_name', + type: 'alias', + }, + 'auditd.log.geoip.region_iso_code': { + category: 'auditd', + name: 'auditd.log.geoip.region_iso_code', + type: 'alias', + }, + 'auditd.log.arch': { + category: 'auditd', + name: 'auditd.log.arch', + type: 'alias', + }, + 'auditd.log.gid': { + category: 'auditd', + name: 'auditd.log.gid', + type: 'alias', + }, + 'auditd.log.uid': { + category: 'auditd', + name: 'auditd.log.uid', + type: 'alias', + }, + 'auditd.log.agid': { + category: 'auditd', + name: 'auditd.log.agid', + type: 'alias', + }, + 'auditd.log.auid': { + category: 'auditd', + name: 'auditd.log.auid', + type: 'alias', + }, + 'auditd.log.fsgid': { + category: 'auditd', + name: 'auditd.log.fsgid', + type: 'alias', + }, + 'auditd.log.fsuid': { + category: 'auditd', + name: 'auditd.log.fsuid', + type: 'alias', + }, + 'auditd.log.egid': { + category: 'auditd', + name: 'auditd.log.egid', + type: 'alias', + }, + 'auditd.log.euid': { + category: 'auditd', + name: 'auditd.log.euid', + type: 'alias', + }, + 'auditd.log.sgid': { + category: 'auditd', + name: 'auditd.log.sgid', + type: 'alias', + }, + 'auditd.log.suid': { + category: 'auditd', + name: 'auditd.log.suid', + type: 'alias', + }, + 'auditd.log.ogid': { + category: 'auditd', + name: 'auditd.log.ogid', + type: 'alias', + }, + 'auditd.log.ouid': { + category: 'auditd', + name: 'auditd.log.ouid', + type: 'alias', + }, + 'auditd.log.comm': { + category: 'auditd', + name: 'auditd.log.comm', + type: 'alias', + }, + 'auditd.log.exe': { + category: 'auditd', + name: 'auditd.log.exe', + type: 'alias', + }, + 'auditd.log.terminal': { + category: 'auditd', + name: 'auditd.log.terminal', + type: 'alias', + }, + 'auditd.log.msg': { + category: 'auditd', + name: 'auditd.log.msg', + type: 'alias', + }, + 'auditd.log.src': { + category: 'auditd', + name: 'auditd.log.src', + type: 'alias', + }, + 'auditd.log.dst': { + category: 'auditd', + name: 'auditd.log.dst', + type: 'alias', + }, + 'elasticsearch.component': { + category: 'elasticsearch', + description: 'Elasticsearch component from where the log event originated', + example: 'o.e.c.m.MetaDataCreateIndexService', + name: 'elasticsearch.component', + type: 'keyword', + }, + 'elasticsearch.cluster.uuid': { + category: 'elasticsearch', + description: 'UUID of the cluster', + example: 'GmvrbHlNTiSVYiPf8kxg9g', + name: 'elasticsearch.cluster.uuid', + type: 'keyword', + }, + 'elasticsearch.cluster.name': { + category: 'elasticsearch', + description: 'Name of the cluster', + example: 'docker-cluster', + name: 'elasticsearch.cluster.name', + type: 'keyword', + }, + 'elasticsearch.node.id': { + category: 'elasticsearch', + description: 'ID of the node', + example: 'DSiWcTyeThWtUXLB9J0BMw', + name: 'elasticsearch.node.id', + type: 'keyword', + }, + 'elasticsearch.node.name': { + category: 'elasticsearch', + description: 'Name of the node', + example: 'vWNJsZ3', + name: 'elasticsearch.node.name', + type: 'keyword', + }, + 'elasticsearch.index.name': { + category: 'elasticsearch', + description: 'Index name', + example: 'filebeat-test-input', + name: 'elasticsearch.index.name', + type: 'keyword', + }, + 'elasticsearch.index.id': { + category: 'elasticsearch', + description: 'Index id', + example: 'aOGgDwbURfCV57AScqbCgw', + name: 'elasticsearch.index.id', + type: 'keyword', + }, + 'elasticsearch.shard.id': { + category: 'elasticsearch', + description: 'Id of the shard', + example: '0', + name: 'elasticsearch.shard.id', + type: 'keyword', + }, + 'elasticsearch.audit.layer': { + category: 'elasticsearch', + description: 'The layer from which this event originated: rest, transport or ip_filter', + example: 'rest', + name: 'elasticsearch.audit.layer', + type: 'keyword', + }, + 'elasticsearch.audit.event_type': { + category: 'elasticsearch', + description: + 'The type of event that occurred: anonymous_access_denied, authentication_failed, access_denied, access_granted, connection_granted, connection_denied, tampered_request, run_as_granted, run_as_denied', + example: 'access_granted', + name: 'elasticsearch.audit.event_type', + type: 'keyword', + }, + 'elasticsearch.audit.origin.type': { + category: 'elasticsearch', + description: + 'Where the request originated: rest (request originated from a REST API request), transport (request was received on the transport channel), local_node (the local node issued the request)', + example: 'local_node', + name: 'elasticsearch.audit.origin.type', + type: 'keyword', + }, + 'elasticsearch.audit.realm': { + category: 'elasticsearch', + description: 'The authentication realm the authentication was validated against', + name: 'elasticsearch.audit.realm', + type: 'keyword', + }, + 'elasticsearch.audit.user.realm': { + category: 'elasticsearch', + description: "The user's authentication realm, if authenticated", + name: 'elasticsearch.audit.user.realm', + type: 'keyword', + }, + 'elasticsearch.audit.user.roles': { + category: 'elasticsearch', + description: 'Roles to which the principal belongs', + example: '["kibana_admin","beats_admin"]', + name: 'elasticsearch.audit.user.roles', + type: 'keyword', + }, + 'elasticsearch.audit.user.run_as.name': { + category: 'elasticsearch', + name: 'elasticsearch.audit.user.run_as.name', + type: 'keyword', + }, + 'elasticsearch.audit.user.run_as.realm': { + category: 'elasticsearch', + name: 'elasticsearch.audit.user.run_as.realm', + type: 'keyword', + }, + 'elasticsearch.audit.component': { + category: 'elasticsearch', + name: 'elasticsearch.audit.component', + type: 'keyword', + }, + 'elasticsearch.audit.action': { + category: 'elasticsearch', + description: 'The name of the action that was executed', + example: 'cluster:monitor/main', + name: 'elasticsearch.audit.action', + type: 'keyword', + }, + 'elasticsearch.audit.url.params': { + category: 'elasticsearch', + description: 'REST URI parameters', + example: '{username=jacknich2}', + name: 'elasticsearch.audit.url.params', + }, + 'elasticsearch.audit.indices': { + category: 'elasticsearch', + description: 'Indices accessed by action', + example: '["foo-2019.01.04","foo-2019.01.03","foo-2019.01.06"]', + name: 'elasticsearch.audit.indices', + type: 'keyword', + }, + 'elasticsearch.audit.request.id': { + category: 'elasticsearch', + description: 'Unique ID of request', + example: 'WzL_kb6VSvOhAq0twPvHOQ', + name: 'elasticsearch.audit.request.id', + type: 'keyword', + }, + 'elasticsearch.audit.request.name': { + category: 'elasticsearch', + description: 'The type of request that was executed', + example: 'ClearScrollRequest', + name: 'elasticsearch.audit.request.name', + type: 'keyword', + }, + 'elasticsearch.audit.request_body': { + category: 'elasticsearch', + name: 'elasticsearch.audit.request_body', + type: 'alias', + }, + 'elasticsearch.audit.origin_address': { + category: 'elasticsearch', + name: 'elasticsearch.audit.origin_address', + type: 'alias', + }, + 'elasticsearch.audit.uri': { + category: 'elasticsearch', + name: 'elasticsearch.audit.uri', + type: 'alias', + }, + 'elasticsearch.audit.principal': { + category: 'elasticsearch', + name: 'elasticsearch.audit.principal', + type: 'alias', + }, + 'elasticsearch.audit.message': { + category: 'elasticsearch', + name: 'elasticsearch.audit.message', + type: 'text', + }, + 'elasticsearch.audit.invalidate.apikeys.owned_by_authenticated_user': { + category: 'elasticsearch', + name: 'elasticsearch.audit.invalidate.apikeys.owned_by_authenticated_user', + type: 'boolean', + }, + 'elasticsearch.deprecation': { + category: 'elasticsearch', + description: '', + name: 'elasticsearch.deprecation', + type: 'group', + }, + 'elasticsearch.gc.phase.name': { + category: 'elasticsearch', + description: 'Name of the GC collection phase. ', + name: 'elasticsearch.gc.phase.name', + type: 'keyword', + }, + 'elasticsearch.gc.phase.duration_sec': { + category: 'elasticsearch', + description: 'Collection phase duration according to the Java virtual machine. ', + name: 'elasticsearch.gc.phase.duration_sec', + type: 'float', + }, + 'elasticsearch.gc.phase.scrub_symbol_table_time_sec': { + category: 'elasticsearch', + description: 'Pause time in seconds cleaning up symbol tables. ', + name: 'elasticsearch.gc.phase.scrub_symbol_table_time_sec', + type: 'float', + }, + 'elasticsearch.gc.phase.scrub_string_table_time_sec': { + category: 'elasticsearch', + description: 'Pause time in seconds cleaning up string tables. ', + name: 'elasticsearch.gc.phase.scrub_string_table_time_sec', + type: 'float', + }, + 'elasticsearch.gc.phase.weak_refs_processing_time_sec': { + category: 'elasticsearch', + description: 'Time spent processing weak references in seconds. ', + name: 'elasticsearch.gc.phase.weak_refs_processing_time_sec', + type: 'float', + }, + 'elasticsearch.gc.phase.parallel_rescan_time_sec': { + category: 'elasticsearch', + description: 'Time spent in seconds marking live objects while application is stopped. ', + name: 'elasticsearch.gc.phase.parallel_rescan_time_sec', + type: 'float', + }, + 'elasticsearch.gc.phase.class_unload_time_sec': { + category: 'elasticsearch', + description: 'Time spent unloading unused classes in seconds. ', + name: 'elasticsearch.gc.phase.class_unload_time_sec', + type: 'float', + }, + 'elasticsearch.gc.phase.cpu_time.user_sec': { + category: 'elasticsearch', + description: 'CPU time spent outside the kernel. ', + name: 'elasticsearch.gc.phase.cpu_time.user_sec', + type: 'float', + }, + 'elasticsearch.gc.phase.cpu_time.sys_sec': { + category: 'elasticsearch', + description: 'CPU time spent inside the kernel. ', + name: 'elasticsearch.gc.phase.cpu_time.sys_sec', + type: 'float', + }, + 'elasticsearch.gc.phase.cpu_time.real_sec': { + category: 'elasticsearch', + description: 'Total elapsed CPU time spent to complete the collection from start to finish. ', + name: 'elasticsearch.gc.phase.cpu_time.real_sec', + type: 'float', + }, + 'elasticsearch.gc.jvm_runtime_sec': { + category: 'elasticsearch', + description: 'The time from JVM start up in seconds, as a floating point number. ', + name: 'elasticsearch.gc.jvm_runtime_sec', + type: 'float', + }, + 'elasticsearch.gc.threads_total_stop_time_sec': { + category: 'elasticsearch', + description: 'Garbage collection threads total stop time seconds. ', + name: 'elasticsearch.gc.threads_total_stop_time_sec', + type: 'float', + }, + 'elasticsearch.gc.stopping_threads_time_sec': { + category: 'elasticsearch', + description: 'Time took to stop threads seconds. ', + name: 'elasticsearch.gc.stopping_threads_time_sec', + type: 'float', + }, + 'elasticsearch.gc.tags': { + category: 'elasticsearch', + description: 'GC logging tags. ', + name: 'elasticsearch.gc.tags', + type: 'keyword', + }, + 'elasticsearch.gc.heap.size_kb': { + category: 'elasticsearch', + description: 'Total heap size in kilobytes. ', + name: 'elasticsearch.gc.heap.size_kb', + type: 'integer', + }, + 'elasticsearch.gc.heap.used_kb': { + category: 'elasticsearch', + description: 'Used heap in kilobytes. ', + name: 'elasticsearch.gc.heap.used_kb', + type: 'integer', + }, + 'elasticsearch.gc.old_gen.size_kb': { + category: 'elasticsearch', + description: 'Total size of old generation in kilobytes. ', + name: 'elasticsearch.gc.old_gen.size_kb', + type: 'integer', + }, + 'elasticsearch.gc.old_gen.used_kb': { + category: 'elasticsearch', + description: 'Old generation occupancy in kilobytes. ', + name: 'elasticsearch.gc.old_gen.used_kb', + type: 'integer', + }, + 'elasticsearch.gc.young_gen.size_kb': { + category: 'elasticsearch', + description: 'Total size of young generation in kilobytes. ', + name: 'elasticsearch.gc.young_gen.size_kb', + type: 'integer', + }, + 'elasticsearch.gc.young_gen.used_kb': { + category: 'elasticsearch', + description: 'Young generation occupancy in kilobytes. ', + name: 'elasticsearch.gc.young_gen.used_kb', + type: 'integer', + }, + 'elasticsearch.server.stacktrace': { + category: 'elasticsearch', + name: 'elasticsearch.server.stacktrace', + }, + 'elasticsearch.server.gc.young.one': { + category: 'elasticsearch', + description: '', + example: '', + name: 'elasticsearch.server.gc.young.one', + type: 'long', + }, + 'elasticsearch.server.gc.young.two': { + category: 'elasticsearch', + description: '', + example: '', + name: 'elasticsearch.server.gc.young.two', + type: 'long', + }, + 'elasticsearch.server.gc.overhead_seq': { + category: 'elasticsearch', + description: 'Sequence number', + example: 3449992, + name: 'elasticsearch.server.gc.overhead_seq', + type: 'long', + }, + 'elasticsearch.server.gc.collection_duration.ms': { + category: 'elasticsearch', + description: 'Time spent in GC, in milliseconds', + example: 1600, + name: 'elasticsearch.server.gc.collection_duration.ms', + type: 'float', + }, + 'elasticsearch.server.gc.observation_duration.ms': { + category: 'elasticsearch', + description: 'Total time over which collection was observed, in milliseconds', + example: 1800, + name: 'elasticsearch.server.gc.observation_duration.ms', + type: 'float', + }, + 'elasticsearch.slowlog.logger': { + category: 'elasticsearch', + description: 'Logger name', + example: 'index.search.slowlog.fetch', + name: 'elasticsearch.slowlog.logger', + type: 'keyword', + }, + 'elasticsearch.slowlog.took': { + category: 'elasticsearch', + description: 'Time it took to execute the query', + example: '300ms', + name: 'elasticsearch.slowlog.took', + type: 'keyword', + }, + 'elasticsearch.slowlog.types': { + category: 'elasticsearch', + description: 'Types', + example: '', + name: 'elasticsearch.slowlog.types', + type: 'keyword', + }, + 'elasticsearch.slowlog.stats': { + category: 'elasticsearch', + description: 'Stats groups', + example: 'group1', + name: 'elasticsearch.slowlog.stats', + type: 'keyword', + }, + 'elasticsearch.slowlog.search_type': { + category: 'elasticsearch', + description: 'Search type', + example: 'QUERY_THEN_FETCH', + name: 'elasticsearch.slowlog.search_type', + type: 'keyword', + }, + 'elasticsearch.slowlog.source_query': { + category: 'elasticsearch', + description: 'Slow query', + example: '{"query":{"match_all":{"boost":1.0}}}', + name: 'elasticsearch.slowlog.source_query', + type: 'keyword', + }, + 'elasticsearch.slowlog.extra_source': { + category: 'elasticsearch', + description: 'Extra source information', + example: '', + name: 'elasticsearch.slowlog.extra_source', + type: 'keyword', + }, + 'elasticsearch.slowlog.total_hits': { + category: 'elasticsearch', + description: 'Total hits', + example: 42, + name: 'elasticsearch.slowlog.total_hits', + type: 'keyword', + }, + 'elasticsearch.slowlog.total_shards': { + category: 'elasticsearch', + description: 'Total queried shards', + example: 22, + name: 'elasticsearch.slowlog.total_shards', + type: 'keyword', + }, + 'elasticsearch.slowlog.routing': { + category: 'elasticsearch', + description: 'Routing', + example: 's01HZ2QBk9jw4gtgaFtn', + name: 'elasticsearch.slowlog.routing', + type: 'keyword', + }, + 'elasticsearch.slowlog.id': { + category: 'elasticsearch', + description: 'Id', + example: '', + name: 'elasticsearch.slowlog.id', + type: 'keyword', + }, + 'elasticsearch.slowlog.type': { + category: 'elasticsearch', + description: 'Type', + example: 'doc', + name: 'elasticsearch.slowlog.type', + type: 'keyword', + }, + 'elasticsearch.slowlog.source': { + category: 'elasticsearch', + description: 'Source of document that was indexed', + name: 'elasticsearch.slowlog.source', + type: 'keyword', + }, + 'haproxy.frontend_name': { + category: 'haproxy', + description: 'Name of the frontend (or listener) which received and processed the connection.', + name: 'haproxy.frontend_name', + }, + 'haproxy.backend_name': { + category: 'haproxy', + description: + 'Name of the backend (or listener) which was selected to manage the connection to the server.', + name: 'haproxy.backend_name', + }, + 'haproxy.server_name': { + category: 'haproxy', + description: 'Name of the last server to which the connection was sent.', + name: 'haproxy.server_name', + }, + 'haproxy.total_waiting_time_ms': { + category: 'haproxy', + description: 'Total time in milliseconds spent waiting in the various queues', + name: 'haproxy.total_waiting_time_ms', + type: 'long', + }, + 'haproxy.connection_wait_time_ms': { + category: 'haproxy', + description: + 'Total time in milliseconds spent waiting for the connection to establish to the final server', + name: 'haproxy.connection_wait_time_ms', + type: 'long', + }, + 'haproxy.bytes_read': { + category: 'haproxy', + description: 'Total number of bytes transmitted to the client when the log is emitted.', + name: 'haproxy.bytes_read', + type: 'long', + }, + 'haproxy.time_queue': { + category: 'haproxy', + description: 'Total time in milliseconds spent waiting in the various queues.', + name: 'haproxy.time_queue', + type: 'long', + }, + 'haproxy.time_backend_connect': { + category: 'haproxy', + description: + 'Total time in milliseconds spent waiting for the connection to establish to the final server, including retries.', + name: 'haproxy.time_backend_connect', + type: 'long', + }, + 'haproxy.server_queue': { + category: 'haproxy', + description: + 'Total number of requests which were processed before this one in the server queue.', + name: 'haproxy.server_queue', + type: 'long', + }, + 'haproxy.backend_queue': { + category: 'haproxy', + description: + "Total number of requests which were processed before this one in the backend's global queue.", + name: 'haproxy.backend_queue', + type: 'long', + }, + 'haproxy.bind_name': { + category: 'haproxy', + description: 'Name of the listening address which received the connection.', + name: 'haproxy.bind_name', + }, + 'haproxy.error_message': { + category: 'haproxy', + description: 'Error message logged by HAProxy in case of error.', + name: 'haproxy.error_message', + type: 'text', + }, + 'haproxy.source': { + category: 'haproxy', + description: 'The HAProxy source of the log', + name: 'haproxy.source', + type: 'keyword', + }, + 'haproxy.termination_state': { + category: 'haproxy', + description: 'Condition the session was in when the session ended.', + name: 'haproxy.termination_state', + }, + 'haproxy.mode': { + category: 'haproxy', + description: 'mode that the frontend is operating (TCP or HTTP)', + name: 'haproxy.mode', + type: 'keyword', + }, + 'haproxy.connections.active': { + category: 'haproxy', + description: + 'Total number of concurrent connections on the process when the session was logged.', + name: 'haproxy.connections.active', + type: 'long', + }, + 'haproxy.connections.frontend': { + category: 'haproxy', + description: + 'Total number of concurrent connections on the frontend when the session was logged.', + name: 'haproxy.connections.frontend', + type: 'long', + }, + 'haproxy.connections.backend': { + category: 'haproxy', + description: + 'Total number of concurrent connections handled by the backend when the session was logged.', + name: 'haproxy.connections.backend', + type: 'long', + }, + 'haproxy.connections.server': { + category: 'haproxy', + description: + 'Total number of concurrent connections still active on the server when the session was logged.', + name: 'haproxy.connections.server', + type: 'long', + }, + 'haproxy.connections.retries': { + category: 'haproxy', + description: + 'Number of connection retries experienced by this session when trying to connect to the server.', + name: 'haproxy.connections.retries', + type: 'long', + }, + 'haproxy.client.ip': { + category: 'haproxy', + name: 'haproxy.client.ip', + type: 'alias', + }, + 'haproxy.client.port': { + category: 'haproxy', + name: 'haproxy.client.port', + type: 'alias', + }, + 'haproxy.process_name': { + category: 'haproxy', + name: 'haproxy.process_name', + type: 'alias', + }, + 'haproxy.pid': { + category: 'haproxy', + name: 'haproxy.pid', + type: 'alias', + }, + 'haproxy.destination.port': { + category: 'haproxy', + name: 'haproxy.destination.port', + type: 'alias', + }, + 'haproxy.destination.ip': { + category: 'haproxy', + name: 'haproxy.destination.ip', + type: 'alias', + }, + 'haproxy.geoip.continent_name': { + category: 'haproxy', + name: 'haproxy.geoip.continent_name', + type: 'alias', + }, + 'haproxy.geoip.country_iso_code': { + category: 'haproxy', + name: 'haproxy.geoip.country_iso_code', + type: 'alias', + }, + 'haproxy.geoip.location': { + category: 'haproxy', + name: 'haproxy.geoip.location', + type: 'alias', + }, + 'haproxy.geoip.region_name': { + category: 'haproxy', + name: 'haproxy.geoip.region_name', + type: 'alias', + }, + 'haproxy.geoip.city_name': { + category: 'haproxy', + name: 'haproxy.geoip.city_name', + type: 'alias', + }, + 'haproxy.geoip.region_iso_code': { + category: 'haproxy', + name: 'haproxy.geoip.region_iso_code', + type: 'alias', + }, + 'haproxy.http.response.captured_cookie': { + category: 'haproxy', + description: + 'Optional "name=value" entry indicating that the client had this cookie in the response. ', + name: 'haproxy.http.response.captured_cookie', + }, + 'haproxy.http.response.captured_headers': { + category: 'haproxy', + description: + 'List of headers captured in the response due to the presence of the "capture response header" statement in the frontend. ', + name: 'haproxy.http.response.captured_headers', + type: 'keyword', + }, + 'haproxy.http.response.status_code': { + category: 'haproxy', + name: 'haproxy.http.response.status_code', + type: 'alias', + }, + 'haproxy.http.request.captured_cookie': { + category: 'haproxy', + description: + 'Optional "name=value" entry indicating that the server has returned a cookie with its request. ', + name: 'haproxy.http.request.captured_cookie', + }, + 'haproxy.http.request.captured_headers': { + category: 'haproxy', + description: + 'List of headers captured in the request due to the presence of the "capture request header" statement in the frontend. ', + name: 'haproxy.http.request.captured_headers', + type: 'keyword', + }, + 'haproxy.http.request.raw_request_line': { + category: 'haproxy', + description: + 'Complete HTTP request line, including the method, request and HTTP version string.', + name: 'haproxy.http.request.raw_request_line', + type: 'keyword', + }, + 'haproxy.http.request.time_wait_without_data_ms': { + category: 'haproxy', + description: + 'Total time in milliseconds spent waiting for the server to send a full HTTP response, not counting data.', + name: 'haproxy.http.request.time_wait_without_data_ms', + type: 'long', + }, + 'haproxy.http.request.time_wait_ms': { + category: 'haproxy', + description: + 'Total time in milliseconds spent waiting for a full HTTP request from the client (not counting body) after the first byte was received.', + name: 'haproxy.http.request.time_wait_ms', + type: 'long', + }, + 'haproxy.tcp.connection_waiting_time_ms': { + category: 'haproxy', + description: 'Total time in milliseconds elapsed between the accept and the last close', + name: 'haproxy.tcp.connection_waiting_time_ms', + type: 'long', + }, + 'icinga.debug.facility': { + category: 'icinga', + description: 'Specifies what component of Icinga logged the message. ', + name: 'icinga.debug.facility', + type: 'keyword', + }, + 'icinga.debug.severity': { + category: 'icinga', + name: 'icinga.debug.severity', + type: 'alias', + }, + 'icinga.debug.message': { + category: 'icinga', + name: 'icinga.debug.message', + type: 'alias', + }, + 'icinga.main.facility': { + category: 'icinga', + description: 'Specifies what component of Icinga logged the message. ', + name: 'icinga.main.facility', + type: 'keyword', + }, + 'icinga.main.severity': { + category: 'icinga', + name: 'icinga.main.severity', + type: 'alias', + }, + 'icinga.main.message': { + category: 'icinga', + name: 'icinga.main.message', + type: 'alias', + }, + 'icinga.startup.facility': { + category: 'icinga', + description: 'Specifies what component of Icinga logged the message. ', + name: 'icinga.startup.facility', + type: 'keyword', + }, + 'icinga.startup.severity': { + category: 'icinga', + name: 'icinga.startup.severity', + type: 'alias', + }, + 'icinga.startup.message': { + category: 'icinga', + name: 'icinga.startup.message', + type: 'alias', + }, + 'iis.access.sub_status': { + category: 'iis', + description: 'The HTTP substatus code. ', + name: 'iis.access.sub_status', + type: 'long', + }, + 'iis.access.win32_status': { + category: 'iis', + description: 'The Windows status code. ', + name: 'iis.access.win32_status', + type: 'long', + }, + 'iis.access.site_name': { + category: 'iis', + description: 'The site name and instance number. ', + name: 'iis.access.site_name', + type: 'keyword', + }, + 'iis.access.server_name': { + category: 'iis', + description: 'The name of the server on which the log file entry was generated. ', + name: 'iis.access.server_name', + type: 'keyword', + }, + 'iis.access.cookie': { + category: 'iis', + description: 'The content of the cookie sent or received, if any. ', + name: 'iis.access.cookie', + type: 'keyword', + }, + 'iis.access.body_received.bytes': { + category: 'iis', + name: 'iis.access.body_received.bytes', + type: 'alias', + }, + 'iis.access.body_sent.bytes': { + category: 'iis', + name: 'iis.access.body_sent.bytes', + type: 'alias', + }, + 'iis.access.server_ip': { + category: 'iis', + name: 'iis.access.server_ip', + type: 'alias', + }, + 'iis.access.method': { + category: 'iis', + name: 'iis.access.method', + type: 'alias', + }, + 'iis.access.url': { + category: 'iis', + name: 'iis.access.url', + type: 'alias', + }, + 'iis.access.query_string': { + category: 'iis', + name: 'iis.access.query_string', + type: 'alias', + }, + 'iis.access.port': { + category: 'iis', + name: 'iis.access.port', + type: 'alias', + }, + 'iis.access.user_name': { + category: 'iis', + name: 'iis.access.user_name', + type: 'alias', + }, + 'iis.access.remote_ip': { + category: 'iis', + name: 'iis.access.remote_ip', + type: 'alias', + }, + 'iis.access.referrer': { + category: 'iis', + name: 'iis.access.referrer', + type: 'alias', + }, + 'iis.access.response_code': { + category: 'iis', + name: 'iis.access.response_code', + type: 'alias', + }, + 'iis.access.http_version': { + category: 'iis', + name: 'iis.access.http_version', + type: 'alias', + }, + 'iis.access.hostname': { + category: 'iis', + name: 'iis.access.hostname', + type: 'alias', + }, + 'iis.access.user_agent.device': { + category: 'iis', + name: 'iis.access.user_agent.device', + type: 'alias', + }, + 'iis.access.user_agent.name': { + category: 'iis', + name: 'iis.access.user_agent.name', + type: 'alias', + }, + 'iis.access.user_agent.os': { + category: 'iis', + name: 'iis.access.user_agent.os', + type: 'alias', + }, + 'iis.access.user_agent.os_name': { + category: 'iis', + name: 'iis.access.user_agent.os_name', + type: 'alias', + }, + 'iis.access.user_agent.original': { + category: 'iis', + name: 'iis.access.user_agent.original', + type: 'alias', + }, + 'iis.access.geoip.continent_name': { + category: 'iis', + name: 'iis.access.geoip.continent_name', + type: 'alias', + }, + 'iis.access.geoip.country_iso_code': { + category: 'iis', + name: 'iis.access.geoip.country_iso_code', + type: 'alias', + }, + 'iis.access.geoip.location': { + category: 'iis', + name: 'iis.access.geoip.location', + type: 'alias', + }, + 'iis.access.geoip.region_name': { + category: 'iis', + name: 'iis.access.geoip.region_name', + type: 'alias', + }, + 'iis.access.geoip.city_name': { + category: 'iis', + name: 'iis.access.geoip.city_name', + type: 'alias', + }, + 'iis.access.geoip.region_iso_code': { + category: 'iis', + name: 'iis.access.geoip.region_iso_code', + type: 'alias', + }, + 'iis.error.reason_phrase': { + category: 'iis', + description: 'The HTTP reason phrase. ', + name: 'iis.error.reason_phrase', + type: 'keyword', + }, + 'iis.error.queue_name': { + category: 'iis', + description: 'The IIS application pool name. ', + name: 'iis.error.queue_name', + type: 'keyword', + }, + 'iis.error.remote_ip': { + category: 'iis', + name: 'iis.error.remote_ip', + type: 'alias', + }, + 'iis.error.remote_port': { + category: 'iis', + name: 'iis.error.remote_port', + type: 'alias', + }, + 'iis.error.server_ip': { + category: 'iis', + name: 'iis.error.server_ip', + type: 'alias', + }, + 'iis.error.server_port': { + category: 'iis', + name: 'iis.error.server_port', + type: 'alias', + }, + 'iis.error.http_version': { + category: 'iis', + name: 'iis.error.http_version', + type: 'alias', + }, + 'iis.error.method': { + category: 'iis', + name: 'iis.error.method', + type: 'alias', + }, + 'iis.error.url': { + category: 'iis', + name: 'iis.error.url', + type: 'alias', + }, + 'iis.error.response_code': { + category: 'iis', + name: 'iis.error.response_code', + type: 'alias', + }, + 'iis.error.geoip.continent_name': { + category: 'iis', + name: 'iis.error.geoip.continent_name', + type: 'alias', + }, + 'iis.error.geoip.country_iso_code': { + category: 'iis', + name: 'iis.error.geoip.country_iso_code', + type: 'alias', + }, + 'iis.error.geoip.location': { + category: 'iis', + name: 'iis.error.geoip.location', + type: 'alias', + }, + 'iis.error.geoip.region_name': { + category: 'iis', + name: 'iis.error.geoip.region_name', + type: 'alias', + }, + 'iis.error.geoip.city_name': { + category: 'iis', + name: 'iis.error.geoip.city_name', + type: 'alias', + }, + 'iis.error.geoip.region_iso_code': { + category: 'iis', + name: 'iis.error.geoip.region_iso_code', + type: 'alias', + }, + 'kafka.log.component': { + category: 'kafka', + description: 'Component the log is coming from. ', + name: 'kafka.log.component', + type: 'keyword', + }, + 'kafka.log.class': { + category: 'kafka', + description: 'Java class the log is coming from. ', + name: 'kafka.log.class', + type: 'keyword', + }, + 'kafka.log.thread': { + category: 'kafka', + description: 'Thread name the log is coming from. ', + name: 'kafka.log.thread', + type: 'keyword', + }, + 'kafka.log.trace.class': { + category: 'kafka', + description: 'Java class the trace is coming from. ', + name: 'kafka.log.trace.class', + type: 'keyword', + }, + 'kafka.log.trace.message': { + category: 'kafka', + description: 'Message part of the trace. ', + name: 'kafka.log.trace.message', + type: 'text', + }, + 'kibana.session_id': { + category: 'kibana', + description: + 'The ID of the user session associated with this event. Each login attempt results in a unique session id.', + example: '123e4567-e89b-12d3-a456-426614174000', + name: 'kibana.session_id', + type: 'keyword', + }, + 'kibana.space_id': { + category: 'kibana', + description: 'The id of the space associated with this event.', + example: 'default', + name: 'kibana.space_id', + type: 'keyword', + }, + 'kibana.saved_object.type': { + category: 'kibana', + description: 'The type of the saved object associated with this event.', + example: 'dashboard', + name: 'kibana.saved_object.type', + type: 'keyword', + }, + 'kibana.saved_object.id': { + category: 'kibana', + description: 'The id of the saved object associated with this event.', + example: '6295bdd0-0a0e-11e7-825f-6748cda7d858', + name: 'kibana.saved_object.id', + type: 'keyword', + }, + 'kibana.add_to_spaces': { + category: 'kibana', + description: 'The set of space ids that a saved object was shared to.', + example: "['default', 'marketing']", + name: 'kibana.add_to_spaces', + type: 'keyword', + }, + 'kibana.delete_from_spaces': { + category: 'kibana', + description: 'The set of space ids that a saved object was removed from.', + example: "['default', 'marketing']", + name: 'kibana.delete_from_spaces', + type: 'keyword', + }, + 'kibana.authentication_provider': { + category: 'kibana', + description: 'The authentication provider associated with a login event.', + example: 'basic1', + name: 'kibana.authentication_provider', + type: 'keyword', + }, + 'kibana.authentication_type': { + category: 'kibana', + description: 'The authentication provider type associated with a login event.', + example: 'basic', + name: 'kibana.authentication_type', + type: 'keyword', + }, + 'kibana.authentication_realm': { + category: 'kibana', + description: 'The Elasticsearch authentication realm name which fulfilled a login event.', + example: 'native', + name: 'kibana.authentication_realm', + type: 'keyword', + }, + 'kibana.lookup_realm': { + category: 'kibana', + description: 'The Elasticsearch lookup realm which fulfilled a login event.', + example: 'native', + name: 'kibana.lookup_realm', + type: 'keyword', + }, + 'kibana.log.tags': { + category: 'kibana', + description: 'Kibana logging tags. ', + name: 'kibana.log.tags', + type: 'keyword', + }, + 'kibana.log.state': { + category: 'kibana', + description: 'Current state of Kibana. ', + name: 'kibana.log.state', + type: 'keyword', + }, + 'kibana.log.meta': { + category: 'kibana', + name: 'kibana.log.meta', + type: 'object', + }, + 'kibana.log.kibana.log.meta.req.headers.referer': { + category: 'kibana', + name: 'kibana.log.kibana.log.meta.req.headers.referer', + type: 'alias', + }, + 'kibana.log.kibana.log.meta.req.referer': { + category: 'kibana', + name: 'kibana.log.kibana.log.meta.req.referer', + type: 'alias', + }, + 'kibana.log.kibana.log.meta.req.headers.user-agent': { + category: 'kibana', + name: 'kibana.log.kibana.log.meta.req.headers.user-agent', + type: 'alias', + }, + 'kibana.log.kibana.log.meta.req.remoteAddress': { + category: 'kibana', + name: 'kibana.log.kibana.log.meta.req.remoteAddress', + type: 'alias', + }, + 'kibana.log.kibana.log.meta.req.url': { + category: 'kibana', + name: 'kibana.log.kibana.log.meta.req.url', + type: 'alias', + }, + 'kibana.log.kibana.log.meta.statusCode': { + category: 'kibana', + name: 'kibana.log.kibana.log.meta.statusCode', + type: 'alias', + }, + 'kibana.log.kibana.log.meta.method': { + category: 'kibana', + name: 'kibana.log.kibana.log.meta.method', + type: 'alias', + }, + 'logstash.log.module': { + category: 'logstash', + description: 'The module or class where the event originate. ', + name: 'logstash.log.module', + type: 'keyword', + }, + 'logstash.log.thread': { + category: 'logstash', + description: 'Information about the running thread where the log originate. ', + name: 'logstash.log.thread', + type: 'keyword', + }, + 'logstash.log.log_event': { + category: 'logstash', + description: 'key and value debugging information. ', + name: 'logstash.log.log_event', + type: 'object', + }, + 'logstash.log.log_event.action': { + category: 'logstash', + name: 'logstash.log.log_event.action', + type: 'keyword', + }, + 'logstash.log.pipeline_id': { + category: 'logstash', + description: 'The ID of the pipeline. ', + example: 'main', + name: 'logstash.log.pipeline_id', + type: 'keyword', + }, + 'logstash.log.message': { + category: 'logstash', + name: 'logstash.log.message', + type: 'alias', + }, + 'logstash.log.level': { + category: 'logstash', + name: 'logstash.log.level', + type: 'alias', + }, + 'logstash.slowlog.module': { + category: 'logstash', + description: 'The module or class where the event originate. ', + name: 'logstash.slowlog.module', + type: 'keyword', + }, + 'logstash.slowlog.thread': { + category: 'logstash', + description: 'Information about the running thread where the log originate. ', + name: 'logstash.slowlog.thread', + type: 'keyword', + }, + 'logstash.slowlog.event': { + category: 'logstash', + description: 'Raw dump of the original event ', + name: 'logstash.slowlog.event', + type: 'keyword', + }, + 'logstash.slowlog.plugin_name': { + category: 'logstash', + description: 'Name of the plugin ', + name: 'logstash.slowlog.plugin_name', + type: 'keyword', + }, + 'logstash.slowlog.plugin_type': { + category: 'logstash', + description: 'Type of the plugin: Inputs, Filters, Outputs or Codecs. ', + name: 'logstash.slowlog.plugin_type', + type: 'keyword', + }, + 'logstash.slowlog.took_in_millis': { + category: 'logstash', + description: 'Execution time for the plugin in milliseconds. ', + name: 'logstash.slowlog.took_in_millis', + type: 'long', + }, + 'logstash.slowlog.plugin_params': { + category: 'logstash', + description: 'String value of the plugin configuration ', + name: 'logstash.slowlog.plugin_params', + type: 'keyword', + }, + 'logstash.slowlog.plugin_params_object': { + category: 'logstash', + description: 'key -> value of the configuration used by the plugin. ', + name: 'logstash.slowlog.plugin_params_object', + type: 'object', + }, + 'logstash.slowlog.level': { + category: 'logstash', + name: 'logstash.slowlog.level', + type: 'alias', + }, + 'logstash.slowlog.took_in_nanos': { + category: 'logstash', + name: 'logstash.slowlog.took_in_nanos', + type: 'alias', + }, + 'mongodb.log.component': { + category: 'mongodb', + description: 'Functional categorization of message ', + example: 'COMMAND', + name: 'mongodb.log.component', + type: 'keyword', + }, + 'mongodb.log.context': { + category: 'mongodb', + description: 'Context of message ', + example: 'initandlisten', + name: 'mongodb.log.context', + type: 'keyword', + }, + 'mongodb.log.severity': { + category: 'mongodb', + name: 'mongodb.log.severity', + type: 'alias', + }, + 'mongodb.log.message': { + category: 'mongodb', + name: 'mongodb.log.message', + type: 'alias', + }, + 'mongodb.log.id': { + category: 'mongodb', + description: 'Integer representing the unique identifier of the log statement ', + example: 4615611, + name: 'mongodb.log.id', + type: 'long', + }, + 'mysql.thread_id': { + category: 'mysql', + description: 'The connection or thread ID for the query. ', + name: 'mysql.thread_id', + type: 'long', + }, + 'mysql.error.thread_id': { + category: 'mysql', + name: 'mysql.error.thread_id', + type: 'alias', + }, + 'mysql.error.level': { + category: 'mysql', + name: 'mysql.error.level', + type: 'alias', + }, + 'mysql.error.message': { + category: 'mysql', + name: 'mysql.error.message', + type: 'alias', + }, + 'mysql.slowlog.lock_time.sec': { + category: 'mysql', + description: + 'The amount of time the query waited for the lock to be available. The value is in seconds, as a floating point number. ', + name: 'mysql.slowlog.lock_time.sec', + type: 'float', + }, + 'mysql.slowlog.rows_sent': { + category: 'mysql', + description: 'The number of rows returned by the query. ', + name: 'mysql.slowlog.rows_sent', + type: 'long', + }, + 'mysql.slowlog.rows_examined': { + category: 'mysql', + description: 'The number of rows scanned by the query. ', + name: 'mysql.slowlog.rows_examined', + type: 'long', + }, + 'mysql.slowlog.rows_affected': { + category: 'mysql', + description: 'The number of rows modified by the query. ', + name: 'mysql.slowlog.rows_affected', + type: 'long', + }, + 'mysql.slowlog.bytes_sent': { + category: 'mysql', + description: 'The number of bytes sent to client. ', + name: 'mysql.slowlog.bytes_sent', + type: 'long', + format: 'bytes', + }, + 'mysql.slowlog.bytes_received': { + category: 'mysql', + description: 'The number of bytes received from client. ', + name: 'mysql.slowlog.bytes_received', + type: 'long', + format: 'bytes', + }, + 'mysql.slowlog.query': { + category: 'mysql', + description: 'The slow query. ', + name: 'mysql.slowlog.query', + }, + 'mysql.slowlog.id': { + category: 'mysql', + name: 'mysql.slowlog.id', + type: 'alias', + }, + 'mysql.slowlog.schema': { + category: 'mysql', + description: 'The schema where the slow query was executed. ', + name: 'mysql.slowlog.schema', + type: 'keyword', + }, + 'mysql.slowlog.current_user': { + category: 'mysql', + description: + 'Current authenticated user, used to determine access privileges. Can differ from the value for user. ', + name: 'mysql.slowlog.current_user', + type: 'keyword', + }, + 'mysql.slowlog.last_errno': { + category: 'mysql', + description: 'Last SQL error seen. ', + name: 'mysql.slowlog.last_errno', + type: 'keyword', + }, + 'mysql.slowlog.killed': { + category: 'mysql', + description: 'Code of the reason if the query was killed. ', + name: 'mysql.slowlog.killed', + type: 'keyword', + }, + 'mysql.slowlog.query_cache_hit': { + category: 'mysql', + description: 'Whether the query cache was hit. ', + name: 'mysql.slowlog.query_cache_hit', + type: 'boolean', + }, + 'mysql.slowlog.tmp_table': { + category: 'mysql', + description: 'Whether a temporary table was used to resolve the query. ', + name: 'mysql.slowlog.tmp_table', + type: 'boolean', + }, + 'mysql.slowlog.tmp_table_on_disk': { + category: 'mysql', + description: 'Whether the query needed temporary tables on disk. ', + name: 'mysql.slowlog.tmp_table_on_disk', + type: 'boolean', + }, + 'mysql.slowlog.tmp_tables': { + category: 'mysql', + description: 'Number of temporary tables created for this query ', + name: 'mysql.slowlog.tmp_tables', + type: 'long', + }, + 'mysql.slowlog.tmp_disk_tables': { + category: 'mysql', + description: 'Number of temporary tables created on disk for this query. ', + name: 'mysql.slowlog.tmp_disk_tables', + type: 'long', + }, + 'mysql.slowlog.tmp_table_sizes': { + category: 'mysql', + description: 'Size of temporary tables created for this query.', + name: 'mysql.slowlog.tmp_table_sizes', + type: 'long', + format: 'bytes', + }, + 'mysql.slowlog.filesort': { + category: 'mysql', + description: 'Whether filesort optimization was used. ', + name: 'mysql.slowlog.filesort', + type: 'boolean', + }, + 'mysql.slowlog.filesort_on_disk': { + category: 'mysql', + description: 'Whether filesort optimization was used and it needed temporary tables on disk. ', + name: 'mysql.slowlog.filesort_on_disk', + type: 'boolean', + }, + 'mysql.slowlog.priority_queue': { + category: 'mysql', + description: 'Whether a priority queue was used for filesort. ', + name: 'mysql.slowlog.priority_queue', + type: 'boolean', + }, + 'mysql.slowlog.full_scan': { + category: 'mysql', + description: 'Whether a full table scan was needed for the slow query. ', + name: 'mysql.slowlog.full_scan', + type: 'boolean', + }, + 'mysql.slowlog.full_join': { + category: 'mysql', + description: + 'Whether a full join was needed for the slow query (no indexes were used for joins). ', + name: 'mysql.slowlog.full_join', + type: 'boolean', + }, + 'mysql.slowlog.merge_passes': { + category: 'mysql', + description: 'Number of merge passes executed for the query. ', + name: 'mysql.slowlog.merge_passes', + type: 'long', + }, + 'mysql.slowlog.sort_merge_passes': { + category: 'mysql', + description: 'Number of merge passes that the sort algorithm has had to do. ', + name: 'mysql.slowlog.sort_merge_passes', + type: 'long', + }, + 'mysql.slowlog.sort_range_count': { + category: 'mysql', + description: 'Number of sorts that were done using ranges. ', + name: 'mysql.slowlog.sort_range_count', + type: 'long', + }, + 'mysql.slowlog.sort_rows': { + category: 'mysql', + description: 'Number of sorted rows. ', + name: 'mysql.slowlog.sort_rows', + type: 'long', + }, + 'mysql.slowlog.sort_scan_count': { + category: 'mysql', + description: 'Number of sorts that were done by scanning the table. ', + name: 'mysql.slowlog.sort_scan_count', + type: 'long', + }, + 'mysql.slowlog.log_slow_rate_type': { + category: 'mysql', + description: + 'Type of slow log rate limit, it can be `session` if the rate limit is applied per session, or `query` if it applies per query. ', + name: 'mysql.slowlog.log_slow_rate_type', + type: 'keyword', + }, + 'mysql.slowlog.log_slow_rate_limit': { + category: 'mysql', + description: + 'Slow log rate limit, a value of 100 means that one in a hundred queries or sessions are being logged. ', + name: 'mysql.slowlog.log_slow_rate_limit', + type: 'keyword', + }, + 'mysql.slowlog.read_first': { + category: 'mysql', + description: 'The number of times the first entry in an index was read. ', + name: 'mysql.slowlog.read_first', + type: 'long', + }, + 'mysql.slowlog.read_last': { + category: 'mysql', + description: 'The number of times the last key in an index was read. ', + name: 'mysql.slowlog.read_last', + type: 'long', + }, + 'mysql.slowlog.read_key': { + category: 'mysql', + description: 'The number of requests to read a row based on a key. ', + name: 'mysql.slowlog.read_key', + type: 'long', + }, + 'mysql.slowlog.read_next': { + category: 'mysql', + description: 'The number of requests to read the next row in key order. ', + name: 'mysql.slowlog.read_next', + type: 'long', + }, + 'mysql.slowlog.read_prev': { + category: 'mysql', + description: 'The number of requests to read the previous row in key order. ', + name: 'mysql.slowlog.read_prev', + type: 'long', + }, + 'mysql.slowlog.read_rnd': { + category: 'mysql', + description: 'The number of requests to read a row based on a fixed position. ', + name: 'mysql.slowlog.read_rnd', + type: 'long', + }, + 'mysql.slowlog.read_rnd_next': { + category: 'mysql', + description: 'The number of requests to read the next row in the data file. ', + name: 'mysql.slowlog.read_rnd_next', + type: 'long', + }, + 'mysql.slowlog.innodb.trx_id': { + category: 'mysql', + description: 'Transaction ID ', + name: 'mysql.slowlog.innodb.trx_id', + type: 'keyword', + }, + 'mysql.slowlog.innodb.io_r_ops': { + category: 'mysql', + description: 'Number of page read operations. ', + name: 'mysql.slowlog.innodb.io_r_ops', + type: 'long', + }, + 'mysql.slowlog.innodb.io_r_bytes': { + category: 'mysql', + description: 'Bytes read during page read operations. ', + name: 'mysql.slowlog.innodb.io_r_bytes', + type: 'long', + format: 'bytes', + }, + 'mysql.slowlog.innodb.io_r_wait.sec': { + category: 'mysql', + description: 'How long it took to read all needed data from storage. ', + name: 'mysql.slowlog.innodb.io_r_wait.sec', + type: 'long', + }, + 'mysql.slowlog.innodb.rec_lock_wait.sec': { + category: 'mysql', + description: 'How long the query waited for locks. ', + name: 'mysql.slowlog.innodb.rec_lock_wait.sec', + type: 'long', + }, + 'mysql.slowlog.innodb.queue_wait.sec': { + category: 'mysql', + description: + 'How long the query waited to enter the InnoDB queue and to be executed once in the queue. ', + name: 'mysql.slowlog.innodb.queue_wait.sec', + type: 'long', + }, + 'mysql.slowlog.innodb.pages_distinct': { + category: 'mysql', + description: 'Approximated count of pages accessed to execute the query. ', + name: 'mysql.slowlog.innodb.pages_distinct', + type: 'long', + }, + 'mysql.slowlog.user': { + category: 'mysql', + name: 'mysql.slowlog.user', + type: 'alias', + }, + 'mysql.slowlog.host': { + category: 'mysql', + name: 'mysql.slowlog.host', + type: 'alias', + }, + 'mysql.slowlog.ip': { + category: 'mysql', + name: 'mysql.slowlog.ip', + type: 'alias', + }, + 'nats.log.client.id': { + category: 'nats', + description: 'The id of the client ', + name: 'nats.log.client.id', + type: 'integer', + }, + 'nats.log.msg.bytes': { + category: 'nats', + description: 'Size of the payload in bytes ', + name: 'nats.log.msg.bytes', + type: 'long', + format: 'bytes', + }, + 'nats.log.msg.type': { + category: 'nats', + description: 'The protocol message type ', + name: 'nats.log.msg.type', + type: 'keyword', + }, + 'nats.log.msg.subject': { + category: 'nats', + description: 'Subject name this message was received on ', + name: 'nats.log.msg.subject', + type: 'keyword', + }, + 'nats.log.msg.sid': { + category: 'nats', + description: 'The unique alphanumeric subscription ID of the subject ', + name: 'nats.log.msg.sid', + type: 'integer', + }, + 'nats.log.msg.reply_to': { + category: 'nats', + description: 'The inbox subject on which the publisher is listening for responses ', + name: 'nats.log.msg.reply_to', + type: 'keyword', + }, + 'nats.log.msg.max_messages': { + category: 'nats', + description: 'An optional number of messages to wait for before automatically unsubscribing ', + name: 'nats.log.msg.max_messages', + type: 'integer', + }, + 'nats.log.msg.error.message': { + category: 'nats', + description: 'Details about the error occurred ', + name: 'nats.log.msg.error.message', + type: 'text', + }, + 'nats.log.msg.queue_group': { + category: 'nats', + description: 'The queue group which subscriber will join ', + name: 'nats.log.msg.queue_group', + type: 'text', + }, + 'nginx.access.remote_ip_list': { + category: 'nginx', + description: + 'An array of remote IP addresses. It is a list because it is common to include, besides the client IP address, IP addresses from headers like `X-Forwarded-For`. Real source IP is restored to `source.ip`. ', + name: 'nginx.access.remote_ip_list', + type: 'array', + }, + 'nginx.access.body_sent.bytes': { + category: 'nginx', + name: 'nginx.access.body_sent.bytes', + type: 'alias', + }, + 'nginx.access.user_name': { + category: 'nginx', + name: 'nginx.access.user_name', + type: 'alias', + }, + 'nginx.access.method': { + category: 'nginx', + name: 'nginx.access.method', + type: 'alias', + }, + 'nginx.access.url': { + category: 'nginx', + name: 'nginx.access.url', + type: 'alias', + }, + 'nginx.access.http_version': { + category: 'nginx', + name: 'nginx.access.http_version', + type: 'alias', + }, + 'nginx.access.response_code': { + category: 'nginx', + name: 'nginx.access.response_code', + type: 'alias', + }, + 'nginx.access.referrer': { + category: 'nginx', + name: 'nginx.access.referrer', + type: 'alias', + }, + 'nginx.access.agent': { + category: 'nginx', + name: 'nginx.access.agent', + type: 'alias', + }, + 'nginx.access.user_agent.device': { + category: 'nginx', + name: 'nginx.access.user_agent.device', + type: 'alias', + }, + 'nginx.access.user_agent.name': { + category: 'nginx', + name: 'nginx.access.user_agent.name', + type: 'alias', + }, + 'nginx.access.user_agent.os': { + category: 'nginx', + name: 'nginx.access.user_agent.os', + type: 'alias', + }, + 'nginx.access.user_agent.os_name': { + category: 'nginx', + name: 'nginx.access.user_agent.os_name', + type: 'alias', + }, + 'nginx.access.user_agent.original': { + category: 'nginx', + name: 'nginx.access.user_agent.original', + type: 'alias', + }, + 'nginx.access.geoip.continent_name': { + category: 'nginx', + name: 'nginx.access.geoip.continent_name', + type: 'alias', + }, + 'nginx.access.geoip.country_iso_code': { + category: 'nginx', + name: 'nginx.access.geoip.country_iso_code', + type: 'alias', + }, + 'nginx.access.geoip.location': { + category: 'nginx', + name: 'nginx.access.geoip.location', + type: 'alias', + }, + 'nginx.access.geoip.region_name': { + category: 'nginx', + name: 'nginx.access.geoip.region_name', + type: 'alias', + }, + 'nginx.access.geoip.city_name': { + category: 'nginx', + name: 'nginx.access.geoip.city_name', + type: 'alias', + }, + 'nginx.access.geoip.region_iso_code': { + category: 'nginx', + name: 'nginx.access.geoip.region_iso_code', + type: 'alias', + }, + 'nginx.error.connection_id': { + category: 'nginx', + description: 'Connection identifier. ', + name: 'nginx.error.connection_id', + type: 'long', + }, + 'nginx.error.level': { + category: 'nginx', + name: 'nginx.error.level', + type: 'alias', + }, + 'nginx.error.pid': { + category: 'nginx', + name: 'nginx.error.pid', + type: 'alias', + }, + 'nginx.error.tid': { + category: 'nginx', + name: 'nginx.error.tid', + type: 'alias', + }, + 'nginx.error.message': { + category: 'nginx', + name: 'nginx.error.message', + type: 'alias', + }, + 'nginx.ingress_controller.remote_ip_list': { + category: 'nginx', + description: + 'An array of remote IP addresses. It is a list because it is common to include, besides the client IP address, IP addresses from headers like `X-Forwarded-For`. Real source IP is restored to `source.ip`. ', + name: 'nginx.ingress_controller.remote_ip_list', + type: 'array', + }, + 'nginx.ingress_controller.upstream_address_list': { + category: 'nginx', + description: + 'An array of the upstream addresses. It is a list because it is common that several upstream servers were contacted during request processing. ', + name: 'nginx.ingress_controller.upstream_address_list', + type: 'keyword', + }, + 'nginx.ingress_controller.upstream.response.length_list': { + category: 'nginx', + description: + 'An array of upstream response lengths. It is a list because it is common that several upstream servers were contacted during request processing. ', + name: 'nginx.ingress_controller.upstream.response.length_list', + type: 'keyword', + }, + 'nginx.ingress_controller.upstream.response.time_list': { + category: 'nginx', + description: + 'An array of upstream response durations. It is a list because it is common that several upstream servers were contacted during request processing. ', + name: 'nginx.ingress_controller.upstream.response.time_list', + type: 'keyword', + }, + 'nginx.ingress_controller.upstream.response.status_code_list': { + category: 'nginx', + description: + 'An array of upstream response status codes. It is a list because it is common that several upstream servers were contacted during request processing. ', + name: 'nginx.ingress_controller.upstream.response.status_code_list', + type: 'keyword', + }, + 'nginx.ingress_controller.http.request.length': { + category: 'nginx', + description: 'The request length (including request line, header, and request body) ', + name: 'nginx.ingress_controller.http.request.length', + type: 'long', + format: 'bytes', + }, + 'nginx.ingress_controller.http.request.time': { + category: 'nginx', + description: 'Time elapsed since the first bytes were read from the client ', + name: 'nginx.ingress_controller.http.request.time', + type: 'double', + format: 'duration', + }, + 'nginx.ingress_controller.upstream.name': { + category: 'nginx', + description: 'The name of the upstream. ', + name: 'nginx.ingress_controller.upstream.name', + type: 'keyword', + }, + 'nginx.ingress_controller.upstream.alternative_name': { + category: 'nginx', + description: 'The name of the alternative upstream. ', + name: 'nginx.ingress_controller.upstream.alternative_name', + type: 'keyword', + }, + 'nginx.ingress_controller.upstream.response.length': { + category: 'nginx', + description: + 'The length of the response obtained from the upstream server. If several servers were contacted during request process, the summary of the multiple response lengths is stored. ', + name: 'nginx.ingress_controller.upstream.response.length', + type: 'long', + format: 'bytes', + }, + 'nginx.ingress_controller.upstream.response.time': { + category: 'nginx', + description: + 'The time spent on receiving the response from the upstream as seconds with millisecond resolution. If several servers were contacted during request process, the summary of the multiple response times is stored. ', + name: 'nginx.ingress_controller.upstream.response.time', + type: 'double', + format: 'duration', + }, + 'nginx.ingress_controller.upstream.response.status_code': { + category: 'nginx', + description: + 'The status code of the response obtained from the upstream server. If several servers were contacted during request process, only the status code of the response from the last one is stored in this field. ', + name: 'nginx.ingress_controller.upstream.response.status_code', + type: 'long', + }, + 'nginx.ingress_controller.upstream.ip': { + category: 'nginx', + description: + 'The IP address of the upstream server. If several servers were contacted during request process, only the last one is stored in this field. ', + name: 'nginx.ingress_controller.upstream.ip', + type: 'ip', + }, + 'nginx.ingress_controller.upstream.port': { + category: 'nginx', + description: + 'The port of the upstream server. If several servers were contacted during request process, only the last one is stored in this field. ', + name: 'nginx.ingress_controller.upstream.port', + type: 'long', + }, + 'nginx.ingress_controller.http.request.id': { + category: 'nginx', + description: 'The randomly generated ID of the request ', + name: 'nginx.ingress_controller.http.request.id', + type: 'keyword', + }, + 'nginx.ingress_controller.body_sent.bytes': { + category: 'nginx', + name: 'nginx.ingress_controller.body_sent.bytes', + type: 'alias', + }, + 'nginx.ingress_controller.user_name': { + category: 'nginx', + name: 'nginx.ingress_controller.user_name', + type: 'alias', + }, + 'nginx.ingress_controller.method': { + category: 'nginx', + name: 'nginx.ingress_controller.method', + type: 'alias', + }, + 'nginx.ingress_controller.url': { + category: 'nginx', + name: 'nginx.ingress_controller.url', + type: 'alias', + }, + 'nginx.ingress_controller.http_version': { + category: 'nginx', + name: 'nginx.ingress_controller.http_version', + type: 'alias', + }, + 'nginx.ingress_controller.response_code': { + category: 'nginx', + name: 'nginx.ingress_controller.response_code', + type: 'alias', + }, + 'nginx.ingress_controller.referrer': { + category: 'nginx', + name: 'nginx.ingress_controller.referrer', + type: 'alias', + }, + 'nginx.ingress_controller.agent': { + category: 'nginx', + name: 'nginx.ingress_controller.agent', + type: 'alias', + }, + 'nginx.ingress_controller.user_agent.device': { + category: 'nginx', + name: 'nginx.ingress_controller.user_agent.device', + type: 'alias', + }, + 'nginx.ingress_controller.user_agent.name': { + category: 'nginx', + name: 'nginx.ingress_controller.user_agent.name', + type: 'alias', + }, + 'nginx.ingress_controller.user_agent.os': { + category: 'nginx', + name: 'nginx.ingress_controller.user_agent.os', + type: 'alias', + }, + 'nginx.ingress_controller.user_agent.os_name': { + category: 'nginx', + name: 'nginx.ingress_controller.user_agent.os_name', + type: 'alias', + }, + 'nginx.ingress_controller.user_agent.original': { + category: 'nginx', + name: 'nginx.ingress_controller.user_agent.original', + type: 'alias', + }, + 'nginx.ingress_controller.geoip.continent_name': { + category: 'nginx', + name: 'nginx.ingress_controller.geoip.continent_name', + type: 'alias', + }, + 'nginx.ingress_controller.geoip.country_iso_code': { + category: 'nginx', + name: 'nginx.ingress_controller.geoip.country_iso_code', + type: 'alias', + }, + 'nginx.ingress_controller.geoip.location': { + category: 'nginx', + name: 'nginx.ingress_controller.geoip.location', + type: 'alias', + }, + 'nginx.ingress_controller.geoip.region_name': { + category: 'nginx', + name: 'nginx.ingress_controller.geoip.region_name', + type: 'alias', + }, + 'nginx.ingress_controller.geoip.city_name': { + category: 'nginx', + name: 'nginx.ingress_controller.geoip.city_name', + type: 'alias', + }, + 'nginx.ingress_controller.geoip.region_iso_code': { + category: 'nginx', + name: 'nginx.ingress_controller.geoip.region_iso_code', + type: 'alias', + }, + 'osquery.result.name': { + category: 'osquery', + description: 'The name of the query that generated this event. ', + name: 'osquery.result.name', + type: 'keyword', + }, + 'osquery.result.action': { + category: 'osquery', + description: + 'For incremental data, marks whether the entry was added or removed. It can be one of "added", "removed", or "snapshot". ', + name: 'osquery.result.action', + type: 'keyword', + }, + 'osquery.result.host_identifier': { + category: 'osquery', + description: + 'The identifier for the host on which the osquery agent is running. Normally the hostname. ', + name: 'osquery.result.host_identifier', + type: 'keyword', + }, + 'osquery.result.unix_time': { + category: 'osquery', + description: + 'Unix timestamp of the event, in seconds since the epoch. Used for computing the `@timestamp` column. ', + name: 'osquery.result.unix_time', + type: 'long', + }, + 'osquery.result.calendar_time': { + category: 'osquery', + description: 'String representation of the collection time, as formatted by osquery. ', + name: 'osquery.result.calendar_time', + type: 'keyword', + }, + 'pensando.dfw.action': { + category: 'pensando', + description: 'Action on the flow. ', + name: 'pensando.dfw.action', + type: 'keyword', + }, + 'pensando.dfw.app_id': { + category: 'pensando', + description: 'Application ID ', + name: 'pensando.dfw.app_id', + type: 'integer', + }, + 'pensando.dfw.destination_address': { + category: 'pensando', + description: 'Address of destination. ', + name: 'pensando.dfw.destination_address', + type: 'keyword', + }, + 'pensando.dfw.destination_port': { + category: 'pensando', + description: 'Port of destination. ', + name: 'pensando.dfw.destination_port', + type: 'integer', + }, + 'pensando.dfw.direction': { + category: 'pensando', + description: 'Direction of the flow ', + name: 'pensando.dfw.direction', + type: 'keyword', + }, + 'pensando.dfw.protocol': { + category: 'pensando', + description: 'Protocol of the flow ', + name: 'pensando.dfw.protocol', + type: 'keyword', + }, + 'pensando.dfw.rule_id': { + category: 'pensando', + description: 'Rule ID that was matched. ', + name: 'pensando.dfw.rule_id', + type: 'keyword', + }, + 'pensando.dfw.session_id': { + category: 'pensando', + description: 'Session ID of the flow ', + name: 'pensando.dfw.session_id', + type: 'integer', + }, + 'pensando.dfw.session_state': { + category: 'pensando', + description: 'Session state of the flow. ', + name: 'pensando.dfw.session_state', + type: 'keyword', + }, + 'pensando.dfw.source_address': { + category: 'pensando', + description: 'Source address of the flow. ', + name: 'pensando.dfw.source_address', + type: 'keyword', + }, + 'pensando.dfw.source_port': { + category: 'pensando', + description: 'Source port of the flow. ', + name: 'pensando.dfw.source_port', + type: 'integer', + }, + 'pensando.dfw.timestamp': { + category: 'pensando', + description: 'Timestamp of the log. ', + name: 'pensando.dfw.timestamp', + type: 'date', + }, + 'postgresql.log.timestamp': { + category: 'postgresql', + description: 'The timestamp from the log line. ', + name: 'postgresql.log.timestamp', + }, + 'postgresql.log.core_id': { + category: 'postgresql', + description: + 'Core id. (deprecated, there is no core_id in PostgreSQL logs, this is actually session_line_number). ', + name: 'postgresql.log.core_id', + type: 'alias', + }, + 'postgresql.log.client_addr': { + category: 'postgresql', + description: 'Host where the connection originated from. ', + example: '127.0.0.1', + name: 'postgresql.log.client_addr', + }, + 'postgresql.log.client_port': { + category: 'postgresql', + description: 'Port where the connection originated from. ', + example: '59700', + name: 'postgresql.log.client_port', + }, + 'postgresql.log.session_id': { + category: 'postgresql', + description: 'PostgreSQL session. ', + example: '5ff1dd98.22', + name: 'postgresql.log.session_id', + }, + 'postgresql.log.session_line_number': { + category: 'postgresql', + description: 'Line number inside a session. (%l in `log_line_prefix`). ', + name: 'postgresql.log.session_line_number', + type: 'long', + }, + 'postgresql.log.database': { + category: 'postgresql', + description: 'Name of database. ', + example: 'postgres', + name: 'postgresql.log.database', + }, + 'postgresql.log.query': { + category: 'postgresql', + description: + 'Query statement. In the case of CSV parse, look at command_tag to get more context. ', + example: 'SELECT * FROM users;', + name: 'postgresql.log.query', + }, + 'postgresql.log.query_step': { + category: 'postgresql', + description: + 'Statement step when using extended query protocol (one of statement, parse, bind or execute). ', + example: 'parse', + name: 'postgresql.log.query_step', + }, + 'postgresql.log.query_name': { + category: 'postgresql', + description: + 'Name given to a query when using extended query protocol. If it is "", or not present, this field is ignored. ', + example: 'pdo_stmt_00000001', + name: 'postgresql.log.query_name', + }, + 'postgresql.log.command_tag': { + category: 'postgresql', + description: + "Type of session's current command. The complete list can be found at: src/include/tcop/cmdtaglist.h ", + example: 'SELECT', + name: 'postgresql.log.command_tag', + }, + 'postgresql.log.session_start_time': { + category: 'postgresql', + description: 'Time when this session started. ', + name: 'postgresql.log.session_start_time', + type: 'date', + }, + 'postgresql.log.virtual_transaction_id': { + category: 'postgresql', + description: 'Backend local transaction id. ', + name: 'postgresql.log.virtual_transaction_id', + }, + 'postgresql.log.transaction_id': { + category: 'postgresql', + description: 'The id of current transaction. ', + name: 'postgresql.log.transaction_id', + type: 'long', + }, + 'postgresql.log.sql_state_code': { + category: 'postgresql', + description: + 'State code returned by Postgres (if any). See also https://www.postgresql.org/docs/current/errcodes-appendix.html ', + name: 'postgresql.log.sql_state_code', + type: 'keyword', + }, + 'postgresql.log.detail': { + category: 'postgresql', + description: + "More information about the message, parameters in case of a parametrized query. e.g. 'Role \\\"user\\\" does not exist.', 'parameters: $1 = 42', etc. ", + name: 'postgresql.log.detail', + }, + 'postgresql.log.hint': { + category: 'postgresql', + description: 'A possible solution to solve an error. ', + name: 'postgresql.log.hint', + }, + 'postgresql.log.internal_query': { + category: 'postgresql', + description: 'Internal query that led to the error (if any). ', + name: 'postgresql.log.internal_query', + }, + 'postgresql.log.internal_query_pos': { + category: 'postgresql', + description: 'Character count of the internal query (if any). ', + name: 'postgresql.log.internal_query_pos', + type: 'long', + }, + 'postgresql.log.context': { + category: 'postgresql', + description: 'Error context. ', + name: 'postgresql.log.context', + }, + 'postgresql.log.query_pos': { + category: 'postgresql', + description: 'Character count of the error position (if any). ', + name: 'postgresql.log.query_pos', + type: 'long', + }, + 'postgresql.log.location': { + category: 'postgresql', + description: + 'Location of the error in the PostgreSQL source code (if log_error_verbosity is set to verbose). ', + name: 'postgresql.log.location', + }, + 'postgresql.log.application_name': { + category: 'postgresql', + description: 'Name of the application of this event. It is defined by the client. ', + name: 'postgresql.log.application_name', + }, + 'postgresql.log.backend_type': { + category: 'postgresql', + description: + 'Type of backend of this event. Possible types are autovacuum launcher, autovacuum worker, logical replication launcher, logical replication worker, parallel worker, background writer, client backend, checkpointer, startup, walreceiver, walsender and walwriter. In addition, background workers registered by extensions may have additional types. ', + example: 'client backend', + name: 'postgresql.log.backend_type', + }, + 'postgresql.log.error.code': { + category: 'postgresql', + description: + 'Error code returned by Postgres (if any). Deprecated: errors can have letters. Use sql_state_code instead. ', + name: 'postgresql.log.error.code', + type: 'alias', + }, + 'postgresql.log.timezone': { + category: 'postgresql', + name: 'postgresql.log.timezone', + type: 'alias', + }, + 'postgresql.log.user': { + category: 'postgresql', + name: 'postgresql.log.user', + type: 'alias', + }, + 'postgresql.log.level': { + category: 'postgresql', + description: + 'Valid values are DEBUG5, DEBUG4, DEBUG3, DEBUG2, DEBUG1, INFO, NOTICE, WARNING, ERROR, LOG, FATAL, and PANIC. ', + example: 'LOG', + name: 'postgresql.log.level', + type: 'alias', + }, + 'postgresql.log.message': { + category: 'postgresql', + name: 'postgresql.log.message', + type: 'alias', + }, + 'redis.log.role': { + category: 'redis', + description: + 'The role of the Redis instance. Can be one of `master`, `slave`, `child` (for RDF/AOF writing child), or `sentinel`. ', + name: 'redis.log.role', + type: 'keyword', + }, + 'redis.log.pid': { + category: 'redis', + name: 'redis.log.pid', + type: 'alias', + }, + 'redis.log.level': { + category: 'redis', + name: 'redis.log.level', + type: 'alias', + }, + 'redis.log.message': { + category: 'redis', + name: 'redis.log.message', + type: 'alias', + }, + 'redis.slowlog.cmd': { + category: 'redis', + description: 'The command executed. ', + name: 'redis.slowlog.cmd', + type: 'keyword', + }, + 'redis.slowlog.duration.us': { + category: 'redis', + description: 'How long it took to execute the command in microseconds. ', + name: 'redis.slowlog.duration.us', + type: 'long', + }, + 'redis.slowlog.id': { + category: 'redis', + description: 'The ID of the query. ', + name: 'redis.slowlog.id', + type: 'long', + }, + 'redis.slowlog.key': { + category: 'redis', + description: 'The key on which the command was executed. ', + name: 'redis.slowlog.key', + type: 'keyword', + }, + 'redis.slowlog.args': { + category: 'redis', + description: 'The arguments with which the command was called. ', + name: 'redis.slowlog.args', + type: 'keyword', + }, + 'santa.action': { + category: 'santa', + description: 'Action', + example: 'EXEC', + name: 'santa.action', + type: 'keyword', + }, + 'santa.decision': { + category: 'santa', + description: 'Decision that santad took.', + example: 'ALLOW', + name: 'santa.decision', + type: 'keyword', + }, + 'santa.reason': { + category: 'santa', + description: 'Reason for the decsision.', + example: 'CERT', + name: 'santa.reason', + type: 'keyword', + }, + 'santa.mode': { + category: 'santa', + description: 'Operating mode of Santa.', + example: 'M', + name: 'santa.mode', + type: 'keyword', + }, + 'santa.disk.volume': { + category: 'santa', + description: 'The volume name.', + name: 'santa.disk.volume', + }, + 'santa.disk.bus': { + category: 'santa', + description: 'The disk bus protocol.', + name: 'santa.disk.bus', + }, + 'santa.disk.serial': { + category: 'santa', + description: 'The disk serial number.', + name: 'santa.disk.serial', + }, + 'santa.disk.bsdname': { + category: 'santa', + description: 'The disk BSD name.', + example: 'disk1s3', + name: 'santa.disk.bsdname', + }, + 'santa.disk.model': { + category: 'santa', + description: 'The disk model.', + example: 'APPLE SSD SM0512L', + name: 'santa.disk.model', + }, + 'santa.disk.fs': { + category: 'santa', + description: 'The disk volume kind (filesystem type).', + example: 'apfs', + name: 'santa.disk.fs', + }, + 'santa.disk.mount': { + category: 'santa', + description: 'The disk volume path.', + name: 'santa.disk.mount', + }, + 'santa.certificate.common_name': { + category: 'santa', + description: 'Common name from code signing certificate.', + name: 'santa.certificate.common_name', + type: 'keyword', + }, + 'santa.certificate.sha256': { + category: 'santa', + description: 'SHA256 hash of code signing certificate.', + name: 'santa.certificate.sha256', + type: 'keyword', + }, + 'system.auth.timestamp': { + category: 'system', + name: 'system.auth.timestamp', + type: 'alias', + }, + 'system.auth.hostname': { + category: 'system', + name: 'system.auth.hostname', + type: 'alias', + }, + 'system.auth.program': { + category: 'system', + name: 'system.auth.program', + type: 'alias', + }, + 'system.auth.pid': { + category: 'system', + name: 'system.auth.pid', + type: 'alias', + }, + 'system.auth.message': { + category: 'system', + name: 'system.auth.message', + type: 'alias', + }, + 'system.auth.user': { + category: 'system', + name: 'system.auth.user', + type: 'alias', + }, + 'system.auth.ssh.method': { + category: 'system', + description: 'The SSH authentication method. Can be one of "password" or "publickey". ', + name: 'system.auth.ssh.method', + }, + 'system.auth.ssh.signature': { + category: 'system', + description: 'The signature of the client public key. ', + name: 'system.auth.ssh.signature', + }, + 'system.auth.ssh.dropped_ip': { + category: 'system', + description: 'The client IP from SSH connections that are open and immediately dropped. ', + name: 'system.auth.ssh.dropped_ip', + type: 'ip', + }, + 'system.auth.ssh.event': { + category: 'system', + description: 'The SSH event as found in the logs (Accepted, Invalid, Failed, etc.) ', + example: 'Accepted', + name: 'system.auth.ssh.event', + }, + 'system.auth.ssh.ip': { + category: 'system', + name: 'system.auth.ssh.ip', + type: 'alias', + }, + 'system.auth.ssh.port': { + category: 'system', + name: 'system.auth.ssh.port', + type: 'alias', + }, + 'system.auth.ssh.geoip.continent_name': { + category: 'system', + name: 'system.auth.ssh.geoip.continent_name', + type: 'alias', + }, + 'system.auth.ssh.geoip.country_iso_code': { + category: 'system', + name: 'system.auth.ssh.geoip.country_iso_code', + type: 'alias', + }, + 'system.auth.ssh.geoip.location': { + category: 'system', + name: 'system.auth.ssh.geoip.location', + type: 'alias', + }, + 'system.auth.ssh.geoip.region_name': { + category: 'system', + name: 'system.auth.ssh.geoip.region_name', + type: 'alias', + }, + 'system.auth.ssh.geoip.city_name': { + category: 'system', + name: 'system.auth.ssh.geoip.city_name', + type: 'alias', + }, + 'system.auth.ssh.geoip.region_iso_code': { + category: 'system', + name: 'system.auth.ssh.geoip.region_iso_code', + type: 'alias', + }, + 'system.auth.sudo.error': { + category: 'system', + description: 'The error message in case the sudo command failed. ', + example: 'user NOT in sudoers', + name: 'system.auth.sudo.error', + }, + 'system.auth.sudo.tty': { + category: 'system', + description: 'The TTY where the sudo command is executed. ', + name: 'system.auth.sudo.tty', + }, + 'system.auth.sudo.pwd': { + category: 'system', + description: 'The current directory where the sudo command is executed. ', + name: 'system.auth.sudo.pwd', + }, + 'system.auth.sudo.user': { + category: 'system', + description: 'The target user to which the sudo command is switching. ', + example: 'root', + name: 'system.auth.sudo.user', + }, + 'system.auth.sudo.command': { + category: 'system', + description: 'The command executed via sudo. ', + name: 'system.auth.sudo.command', + }, + 'system.auth.useradd.home': { + category: 'system', + description: 'The home folder for the new user.', + name: 'system.auth.useradd.home', + }, + 'system.auth.useradd.shell': { + category: 'system', + description: 'The default shell for the new user.', + name: 'system.auth.useradd.shell', + }, + 'system.auth.useradd.name': { + category: 'system', + name: 'system.auth.useradd.name', + type: 'alias', + }, + 'system.auth.useradd.uid': { + category: 'system', + name: 'system.auth.useradd.uid', + type: 'alias', + }, + 'system.auth.useradd.gid': { + category: 'system', + name: 'system.auth.useradd.gid', + type: 'alias', + }, + 'system.auth.groupadd.name': { + category: 'system', + name: 'system.auth.groupadd.name', + type: 'alias', + }, + 'system.auth.groupadd.gid': { + category: 'system', + name: 'system.auth.groupadd.gid', + type: 'alias', + }, + 'system.syslog.timestamp': { + category: 'system', + name: 'system.syslog.timestamp', + type: 'alias', + }, + 'system.syslog.hostname': { + category: 'system', + name: 'system.syslog.hostname', + type: 'alias', + }, + 'system.syslog.program': { + category: 'system', + name: 'system.syslog.program', + type: 'alias', + }, + 'system.syslog.pid': { + category: 'system', + name: 'system.syslog.pid', + type: 'alias', + }, + 'system.syslog.message': { + category: 'system', + name: 'system.syslog.message', + type: 'alias', + }, + 'traefik.access.user_identifier': { + category: 'traefik', + description: 'Is the RFC 1413 identity of the client ', + name: 'traefik.access.user_identifier', + type: 'keyword', + }, + 'traefik.access.request_count': { + category: 'traefik', + description: 'The number of requests ', + name: 'traefik.access.request_count', + type: 'long', + }, + 'traefik.access.frontend_name': { + category: 'traefik', + description: 'The name of the frontend used ', + name: 'traefik.access.frontend_name', + type: 'keyword', + }, + 'traefik.access.backend_url': { + category: 'traefik', + description: 'The url of the backend where request is forwarded', + name: 'traefik.access.backend_url', + type: 'keyword', + }, + 'traefik.access.body_sent.bytes': { + category: 'traefik', + name: 'traefik.access.body_sent.bytes', + type: 'alias', + }, + 'traefik.access.remote_ip': { + category: 'traefik', + name: 'traefik.access.remote_ip', + type: 'alias', + }, + 'traefik.access.user_name': { + category: 'traefik', + name: 'traefik.access.user_name', + type: 'alias', + }, + 'traefik.access.method': { + category: 'traefik', + name: 'traefik.access.method', + type: 'alias', + }, + 'traefik.access.url': { + category: 'traefik', + name: 'traefik.access.url', + type: 'alias', + }, + 'traefik.access.http_version': { + category: 'traefik', + name: 'traefik.access.http_version', + type: 'alias', + }, + 'traefik.access.response_code': { + category: 'traefik', + name: 'traefik.access.response_code', + type: 'alias', + }, + 'traefik.access.referrer': { + category: 'traefik', + name: 'traefik.access.referrer', + type: 'alias', + }, + 'traefik.access.agent': { + category: 'traefik', + name: 'traefik.access.agent', + type: 'alias', + }, + 'traefik.access.user_agent.name': { + category: 'traefik', + name: 'traefik.access.user_agent.name', + type: 'alias', + }, + 'traefik.access.user_agent.os': { + category: 'traefik', + name: 'traefik.access.user_agent.os', + type: 'alias', + }, + 'traefik.access.user_agent.os_name': { + category: 'traefik', + name: 'traefik.access.user_agent.os_name', + type: 'alias', + }, + 'traefik.access.user_agent.original': { + category: 'traefik', + name: 'traefik.access.user_agent.original', + type: 'alias', + }, + 'traefik.access.geoip.continent_name': { + category: 'traefik', + name: 'traefik.access.geoip.continent_name', + type: 'alias', + }, + 'traefik.access.geoip.country_iso_code': { + category: 'traefik', + name: 'traefik.access.geoip.country_iso_code', + type: 'alias', + }, + 'traefik.access.geoip.location': { + category: 'traefik', + name: 'traefik.access.geoip.location', + type: 'alias', + }, + 'traefik.access.geoip.region_name': { + category: 'traefik', + name: 'traefik.access.geoip.region_name', + type: 'alias', + }, + 'traefik.access.geoip.city_name': { + category: 'traefik', + name: 'traefik.access.geoip.city_name', + type: 'alias', + }, + 'traefik.access.geoip.region_iso_code': { + category: 'traefik', + name: 'traefik.access.geoip.region_iso_code', + type: 'alias', + }, + 'activemq.caller': { + category: 'activemq', + description: 'Name of the caller issuing the logging request (class or resource). ', + name: 'activemq.caller', + type: 'keyword', + }, + 'activemq.thread': { + category: 'activemq', + description: 'Thread that generated the logging event. ', + name: 'activemq.thread', + type: 'keyword', + }, + 'activemq.user': { + category: 'activemq', + description: 'User that generated the logging event. ', + name: 'activemq.user', + type: 'keyword', + }, + 'activemq.audit': { + category: 'activemq', + description: 'Fields from ActiveMQ audit logs. ', + name: 'activemq.audit', + type: 'group', + }, + 'activemq.log.stack_trace': { + category: 'activemq', + name: 'activemq.log.stack_trace', + type: 'keyword', + }, + 'aws.cloudtrail.event_version': { + category: 'aws', + description: 'The CloudTrail version of the log event format. ', + name: 'aws.cloudtrail.event_version', + type: 'keyword', + }, + 'aws.cloudtrail.user_identity.type': { + category: 'aws', + description: 'The type of the identity ', + name: 'aws.cloudtrail.user_identity.type', + type: 'keyword', + }, + 'aws.cloudtrail.user_identity.arn': { + category: 'aws', + description: 'The Amazon Resource Name (ARN) of the principal that made the call.', + name: 'aws.cloudtrail.user_identity.arn', + type: 'keyword', + }, + 'aws.cloudtrail.user_identity.access_key_id': { + category: 'aws', + description: 'The access key ID that was used to sign the request.', + name: 'aws.cloudtrail.user_identity.access_key_id', + type: 'keyword', + }, + 'aws.cloudtrail.user_identity.session_context.mfa_authenticated': { + category: 'aws', + description: + 'The value is true if the root user or IAM user whose credentials were used for the request also was authenticated with an MFA device; otherwise, false.', + name: 'aws.cloudtrail.user_identity.session_context.mfa_authenticated', + type: 'keyword', + }, + 'aws.cloudtrail.user_identity.session_context.creation_date': { + category: 'aws', + description: 'The date and time when the temporary security credentials were issued.', + name: 'aws.cloudtrail.user_identity.session_context.creation_date', + type: 'date', + }, + 'aws.cloudtrail.user_identity.session_context.session_issuer.type': { + category: 'aws', + description: + 'The source of the temporary security credentials, such as Root, IAMUser, or Role.', + name: 'aws.cloudtrail.user_identity.session_context.session_issuer.type', + type: 'keyword', + }, + 'aws.cloudtrail.user_identity.session_context.session_issuer.principal_id': { + category: 'aws', + description: 'The internal ID of the entity that was used to get credentials.', + name: 'aws.cloudtrail.user_identity.session_context.session_issuer.principal_id', + type: 'keyword', + }, + 'aws.cloudtrail.user_identity.session_context.session_issuer.arn': { + category: 'aws', + description: + 'The ARN of the source (account, IAM user, or role) that was used to get temporary security credentials.', + name: 'aws.cloudtrail.user_identity.session_context.session_issuer.arn', + type: 'keyword', + }, + 'aws.cloudtrail.user_identity.session_context.session_issuer.account_id': { + category: 'aws', + description: 'The account that owns the entity that was used to get credentials.', + name: 'aws.cloudtrail.user_identity.session_context.session_issuer.account_id', + type: 'keyword', + }, + 'aws.cloudtrail.user_identity.invoked_by': { + category: 'aws', + description: + 'The name of the AWS service that made the request, such as Amazon EC2 Auto Scaling or AWS Elastic Beanstalk.', + name: 'aws.cloudtrail.user_identity.invoked_by', + type: 'keyword', + }, + 'aws.cloudtrail.error_code': { + category: 'aws', + description: 'The AWS service error if the request returns an error.', + name: 'aws.cloudtrail.error_code', + type: 'keyword', + }, + 'aws.cloudtrail.error_message': { + category: 'aws', + description: 'If the request returns an error, the description of the error.', + name: 'aws.cloudtrail.error_message', + type: 'keyword', + }, + 'aws.cloudtrail.request_parameters': { + category: 'aws', + description: 'The parameters, if any, that were sent with the request.', + name: 'aws.cloudtrail.request_parameters', + type: 'keyword', + }, + 'aws.cloudtrail.response_elements': { + category: 'aws', + description: + 'The response element for actions that make changes (create, update, or delete actions).', + name: 'aws.cloudtrail.response_elements', + type: 'keyword', + }, + 'aws.cloudtrail.additional_eventdata': { + category: 'aws', + description: 'Additional data about the event that was not part of the request or response.', + name: 'aws.cloudtrail.additional_eventdata', + type: 'keyword', + }, + 'aws.cloudtrail.request_id': { + category: 'aws', + description: + 'The value that identifies the request. The service being called generates this value.', + name: 'aws.cloudtrail.request_id', + type: 'keyword', + }, + 'aws.cloudtrail.event_type': { + category: 'aws', + description: 'Identifies the type of event that generated the event record.', + name: 'aws.cloudtrail.event_type', + type: 'keyword', + }, + 'aws.cloudtrail.api_version': { + category: 'aws', + description: 'Identifies the API version associated with the AwsApiCall eventType value.', + name: 'aws.cloudtrail.api_version', + type: 'keyword', + }, + 'aws.cloudtrail.management_event': { + category: 'aws', + description: 'A Boolean value that identifies whether the event is a management event.', + name: 'aws.cloudtrail.management_event', + type: 'keyword', + }, + 'aws.cloudtrail.read_only': { + category: 'aws', + description: 'Identifies whether this operation is a read-only operation.', + name: 'aws.cloudtrail.read_only', + type: 'keyword', + }, + 'aws.cloudtrail.resources.arn': { + category: 'aws', + description: 'Resource ARNs', + name: 'aws.cloudtrail.resources.arn', + type: 'keyword', + }, + 'aws.cloudtrail.resources.account_id': { + category: 'aws', + description: 'Account ID of the resource owner', + name: 'aws.cloudtrail.resources.account_id', + type: 'keyword', + }, + 'aws.cloudtrail.resources.type': { + category: 'aws', + description: 'Resource type identifier in the format: AWS::aws-service-name::data-type-name', + name: 'aws.cloudtrail.resources.type', + type: 'keyword', + }, + 'aws.cloudtrail.recipient_account_id': { + category: 'aws', + description: 'Represents the account ID that received this event.', + name: 'aws.cloudtrail.recipient_account_id', + type: 'keyword', + }, + 'aws.cloudtrail.service_event_details': { + category: 'aws', + description: 'Identifies the service event, including what triggered the event and the result.', + name: 'aws.cloudtrail.service_event_details', + type: 'keyword', + }, + 'aws.cloudtrail.shared_event_id': { + category: 'aws', + description: + 'GUID generated by CloudTrail to uniquely identify CloudTrail events from the same AWS action that is sent to different AWS accounts.', + name: 'aws.cloudtrail.shared_event_id', + type: 'keyword', + }, + 'aws.cloudtrail.vpc_endpoint_id': { + category: 'aws', + description: + 'Identifies the VPC endpoint in which requests were made from a VPC to another AWS service, such as Amazon S3.', + name: 'aws.cloudtrail.vpc_endpoint_id', + type: 'keyword', + }, + 'aws.cloudtrail.event_category': { + category: 'aws', + description: + 'Shows the event category that is used in LookupEvents calls. - For management events, the value is management. - For data events, the value is data. - For Insights events, the value is insight.', + name: 'aws.cloudtrail.event_category', + type: 'keyword', + }, + 'aws.cloudtrail.console_login.additional_eventdata.mobile_version': { + category: 'aws', + description: 'Identifies whether ConsoleLogin was from mobile version', + name: 'aws.cloudtrail.console_login.additional_eventdata.mobile_version', + type: 'boolean', + }, + 'aws.cloudtrail.console_login.additional_eventdata.login_to': { + category: 'aws', + description: 'URL for ConsoleLogin', + name: 'aws.cloudtrail.console_login.additional_eventdata.login_to', + type: 'keyword', + }, + 'aws.cloudtrail.console_login.additional_eventdata.mfa_used': { + category: 'aws', + description: 'Identifies whether multi factor authentication was used during ConsoleLogin', + name: 'aws.cloudtrail.console_login.additional_eventdata.mfa_used', + type: 'boolean', + }, + 'aws.cloudtrail.flattened.additional_eventdata': { + category: 'aws', + description: 'Additional data about the event that was not part of the request or response. ', + name: 'aws.cloudtrail.flattened.additional_eventdata', + type: 'flattened', + }, + 'aws.cloudtrail.flattened.request_parameters': { + category: 'aws', + description: 'The parameters, if any, that were sent with the request.', + name: 'aws.cloudtrail.flattened.request_parameters', + type: 'flattened', + }, + 'aws.cloudtrail.flattened.response_elements': { + category: 'aws', + description: + 'The response element for actions that make changes (create, update, or delete actions).', + name: 'aws.cloudtrail.flattened.response_elements', + type: 'flattened', + }, + 'aws.cloudtrail.flattened.service_event_details': { + category: 'aws', + description: 'Identifies the service event, including what triggered the event and the result.', + name: 'aws.cloudtrail.flattened.service_event_details', + type: 'flattened', + }, + 'aws.cloudtrail.digest.log_files': { + category: 'aws', + description: 'A list of Logfiles contained in the digest.', + name: 'aws.cloudtrail.digest.log_files', + type: 'nested', + }, + 'aws.cloudtrail.digest.start_time': { + category: 'aws', + description: + 'The starting UTC time range that the digest file covers, taking as a reference the time in which log files have been delivered by CloudTrail.', + name: 'aws.cloudtrail.digest.start_time', + type: 'date', + }, + 'aws.cloudtrail.digest.end_time': { + category: 'aws', + description: + 'The ending UTC time range that the digest file covers, taking as a reference the time in which log files have been delivered by CloudTrail.', + name: 'aws.cloudtrail.digest.end_time', + type: 'date', + }, + 'aws.cloudtrail.digest.s3_bucket': { + category: 'aws', + description: + 'The name of the Amazon S3 bucket to which the current digest file has been delivered.', + name: 'aws.cloudtrail.digest.s3_bucket', + type: 'keyword', + }, + 'aws.cloudtrail.digest.s3_object': { + category: 'aws', + description: + 'The Amazon S3 object key (that is, the Amazon S3 bucket location) of the current digest file.', + name: 'aws.cloudtrail.digest.s3_object', + type: 'keyword', + }, + 'aws.cloudtrail.digest.newest_event_time': { + category: 'aws', + description: + 'The UTC time of the most recent event among all of the events in the log files in the digest.', + name: 'aws.cloudtrail.digest.newest_event_time', + type: 'date', + }, + 'aws.cloudtrail.digest.oldest_event_time': { + category: 'aws', + description: + 'The UTC time of the oldest event among all of the events in the log files in the digest.', + name: 'aws.cloudtrail.digest.oldest_event_time', + type: 'date', + }, + 'aws.cloudtrail.digest.previous_s3_bucket': { + category: 'aws', + description: 'The Amazon S3 bucket to which the previous digest file was delivered.', + name: 'aws.cloudtrail.digest.previous_s3_bucket', + type: 'keyword', + }, + 'aws.cloudtrail.digest.previous_hash_algorithm': { + category: 'aws', + description: 'The name of the hash algorithm that was used to hash the previous digest file.', + name: 'aws.cloudtrail.digest.previous_hash_algorithm', + type: 'keyword', + }, + 'aws.cloudtrail.digest.public_key_fingerprint': { + category: 'aws', + description: + 'The hexadecimal encoded fingerprint of the public key that matches the private key used to sign this digest file.', + name: 'aws.cloudtrail.digest.public_key_fingerprint', + type: 'keyword', + }, + 'aws.cloudtrail.digest.signature_algorithm': { + category: 'aws', + description: 'The algorithm used to sign the digest file.', + name: 'aws.cloudtrail.digest.signature_algorithm', + type: 'keyword', + }, + 'aws.cloudtrail.insight_details': { + category: 'aws', + description: + 'Shows information about the underlying triggers of an Insights event, such as event source, user agent, statistics, API name, and whether the event is the start or end of the Insights event.', + name: 'aws.cloudtrail.insight_details', + type: 'flattened', + }, + 'aws.cloudwatch.message': { + category: 'aws', + description: 'CloudWatch log message. ', + name: 'aws.cloudwatch.message', + type: 'text', + }, + 'aws.ec2.ip_address': { + category: 'aws', + description: 'The internet address of the requester. ', + name: 'aws.ec2.ip_address', + type: 'keyword', + }, + 'aws.elb.name': { + category: 'aws', + description: 'The name of the load balancer. ', + name: 'aws.elb.name', + type: 'keyword', + }, + 'aws.elb.type': { + category: 'aws', + description: 'The type of the load balancer for v2 Load Balancers. ', + name: 'aws.elb.type', + type: 'keyword', + }, + 'aws.elb.target_group.arn': { + category: 'aws', + description: 'The ARN of the target group handling the request. ', + name: 'aws.elb.target_group.arn', + type: 'keyword', + }, + 'aws.elb.listener': { + category: 'aws', + description: 'The ELB listener that received the connection. ', + name: 'aws.elb.listener', + type: 'keyword', + }, + 'aws.elb.protocol': { + category: 'aws', + description: 'The protocol of the load balancer (http or tcp). ', + name: 'aws.elb.protocol', + type: 'keyword', + }, + 'aws.elb.request_processing_time.sec': { + category: 'aws', + description: + 'The total time in seconds since the connection or request is received until it is sent to a registered backend. ', + name: 'aws.elb.request_processing_time.sec', + type: 'float', + }, + 'aws.elb.backend_processing_time.sec': { + category: 'aws', + description: + 'The total time in seconds since the connection is sent to the backend till the backend starts responding. ', + name: 'aws.elb.backend_processing_time.sec', + type: 'float', + }, + 'aws.elb.response_processing_time.sec': { + category: 'aws', + description: + 'The total time in seconds since the response is received from the backend till it is sent to the client. ', + name: 'aws.elb.response_processing_time.sec', + type: 'float', + }, + 'aws.elb.connection_time.ms': { + category: 'aws', + description: + 'The total time of the connection in milliseconds, since it is opened till it is closed. ', + name: 'aws.elb.connection_time.ms', + type: 'long', + }, + 'aws.elb.tls_handshake_time.ms': { + category: 'aws', + description: + 'The total time for the TLS handshake to complete in milliseconds once the connection has been established. ', + name: 'aws.elb.tls_handshake_time.ms', + type: 'long', + }, + 'aws.elb.backend.ip': { + category: 'aws', + description: 'The IP address of the backend processing this connection. ', + name: 'aws.elb.backend.ip', + type: 'keyword', + }, + 'aws.elb.backend.port': { + category: 'aws', + description: 'The port in the backend processing this connection. ', + name: 'aws.elb.backend.port', + type: 'keyword', + }, + 'aws.elb.backend.http.response.status_code': { + category: 'aws', + description: + 'The status code from the backend (status code sent to the client from ELB is stored in `http.response.status_code` ', + name: 'aws.elb.backend.http.response.status_code', + type: 'keyword', + }, + 'aws.elb.ssl_cipher': { + category: 'aws', + description: 'The SSL cipher used in TLS/SSL connections. ', + name: 'aws.elb.ssl_cipher', + type: 'keyword', + }, + 'aws.elb.ssl_protocol': { + category: 'aws', + description: 'The SSL protocol used in TLS/SSL connections. ', + name: 'aws.elb.ssl_protocol', + type: 'keyword', + }, + 'aws.elb.chosen_cert.arn': { + category: 'aws', + description: + 'The ARN of the chosen certificate presented to the client in TLS/SSL connections. ', + name: 'aws.elb.chosen_cert.arn', + type: 'keyword', + }, + 'aws.elb.chosen_cert.serial': { + category: 'aws', + description: + 'The serial number of the chosen certificate presented to the client in TLS/SSL connections. ', + name: 'aws.elb.chosen_cert.serial', + type: 'keyword', + }, + 'aws.elb.incoming_tls_alert': { + category: 'aws', + description: + 'The integer value of TLS alerts received by the load balancer from the client, if present. ', + name: 'aws.elb.incoming_tls_alert', + type: 'keyword', + }, + 'aws.elb.tls_named_group': { + category: 'aws', + description: 'The TLS named group. ', + name: 'aws.elb.tls_named_group', + type: 'keyword', + }, + 'aws.elb.trace_id': { + category: 'aws', + description: 'The contents of the `X-Amzn-Trace-Id` header. ', + name: 'aws.elb.trace_id', + type: 'keyword', + }, + 'aws.elb.matched_rule_priority': { + category: 'aws', + description: 'The priority value of the rule that matched the request, if a rule matched. ', + name: 'aws.elb.matched_rule_priority', + type: 'keyword', + }, + 'aws.elb.action_executed': { + category: 'aws', + description: + 'The action executed when processing the request (forward, fixed-response, authenticate...). It can contain several values. ', + name: 'aws.elb.action_executed', + type: 'keyword', + }, + 'aws.elb.redirect_url': { + category: 'aws', + description: 'The URL used if a redirection action was executed. ', + name: 'aws.elb.redirect_url', + type: 'keyword', + }, + 'aws.elb.error.reason': { + category: 'aws', + description: 'The error reason if the executed action failed. ', + name: 'aws.elb.error.reason', + type: 'keyword', + }, + 'aws.elb.target_port': { + category: 'aws', + description: 'List of IP addresses and ports for the targets that processed this request. ', + name: 'aws.elb.target_port', + type: 'keyword', + }, + 'aws.elb.target_status_code': { + category: 'aws', + description: 'List of status codes from the responses of the targets. ', + name: 'aws.elb.target_status_code', + type: 'keyword', + }, + 'aws.elb.classification': { + category: 'aws', + description: 'The classification for desync mitigation. ', + name: 'aws.elb.classification', + type: 'keyword', + }, + 'aws.elb.classification_reason': { + category: 'aws', + description: 'The classification reason code. ', + name: 'aws.elb.classification_reason', + type: 'keyword', + }, + 'aws.s3access.bucket_owner': { + category: 'aws', + description: 'The canonical user ID of the owner of the source bucket. ', + name: 'aws.s3access.bucket_owner', + type: 'keyword', + }, + 'aws.s3access.bucket': { + category: 'aws', + description: 'The name of the bucket that the request was processed against. ', + name: 'aws.s3access.bucket', + type: 'keyword', + }, + 'aws.s3access.remote_ip': { + category: 'aws', + description: 'The apparent internet address of the requester. ', + name: 'aws.s3access.remote_ip', + type: 'ip', + }, + 'aws.s3access.requester': { + category: 'aws', + description: 'The canonical user ID of the requester, or a - for unauthenticated requests. ', + name: 'aws.s3access.requester', + type: 'keyword', + }, + 'aws.s3access.request_id': { + category: 'aws', + description: 'A string generated by Amazon S3 to uniquely identify each request. ', + name: 'aws.s3access.request_id', + type: 'keyword', + }, + 'aws.s3access.operation': { + category: 'aws', + description: + 'The operation listed here is declared as SOAP.operation, REST.HTTP_method.resource_type, WEBSITE.HTTP_method.resource_type, or BATCH.DELETE.OBJECT. ', + name: 'aws.s3access.operation', + type: 'keyword', + }, + 'aws.s3access.key': { + category: 'aws', + description: + 'The "key" part of the request, URL encoded, or "-" if the operation does not take a key parameter. ', + name: 'aws.s3access.key', + type: 'keyword', + }, + 'aws.s3access.request_uri': { + category: 'aws', + description: 'The Request-URI part of the HTTP request message. ', + name: 'aws.s3access.request_uri', + type: 'keyword', + }, + 'aws.s3access.http_status': { + category: 'aws', + description: 'The numeric HTTP status code of the response. ', + name: 'aws.s3access.http_status', + type: 'long', + }, + 'aws.s3access.error_code': { + category: 'aws', + description: 'The Amazon S3 Error Code, or "-" if no error occurred. ', + name: 'aws.s3access.error_code', + type: 'keyword', + }, + 'aws.s3access.bytes_sent': { + category: 'aws', + description: + 'The number of response bytes sent, excluding HTTP protocol overhead, or "-" if zero. ', + name: 'aws.s3access.bytes_sent', + type: 'long', + }, + 'aws.s3access.object_size': { + category: 'aws', + description: 'The total size of the object in question. ', + name: 'aws.s3access.object_size', + type: 'long', + }, + 'aws.s3access.total_time': { + category: 'aws', + description: + "The number of milliseconds the request was in flight from the server's perspective. ", + name: 'aws.s3access.total_time', + type: 'long', + }, + 'aws.s3access.turn_around_time': { + category: 'aws', + description: 'The number of milliseconds that Amazon S3 spent processing your request. ', + name: 'aws.s3access.turn_around_time', + type: 'long', + }, + 'aws.s3access.referrer': { + category: 'aws', + description: 'The value of the HTTP Referrer header, if present. ', + name: 'aws.s3access.referrer', + type: 'keyword', + }, + 'aws.s3access.user_agent': { + category: 'aws', + description: 'The value of the HTTP User-Agent header. ', + name: 'aws.s3access.user_agent', + type: 'keyword', + }, + 'aws.s3access.version_id': { + category: 'aws', + description: + 'The version ID in the request, or "-" if the operation does not take a versionId parameter. ', + name: 'aws.s3access.version_id', + type: 'keyword', + }, + 'aws.s3access.host_id': { + category: 'aws', + description: 'The x-amz-id-2 or Amazon S3 extended request ID. ', + name: 'aws.s3access.host_id', + type: 'keyword', + }, + 'aws.s3access.signature_version': { + category: 'aws', + description: + 'The signature version, SigV2 or SigV4, that was used to authenticate the request or a - for unauthenticated requests. ', + name: 'aws.s3access.signature_version', + type: 'keyword', + }, + 'aws.s3access.cipher_suite': { + category: 'aws', + description: + 'The Secure Sockets Layer (SSL) cipher that was negotiated for HTTPS request or a - for HTTP. ', + name: 'aws.s3access.cipher_suite', + type: 'keyword', + }, + 'aws.s3access.authentication_type': { + category: 'aws', + description: + 'The type of request authentication used, AuthHeader for authentication headers, QueryString for query string (pre-signed URL) or a - for unauthenticated requests. ', + name: 'aws.s3access.authentication_type', + type: 'keyword', + }, + 'aws.s3access.host_header': { + category: 'aws', + description: 'The endpoint used to connect to Amazon S3. ', + name: 'aws.s3access.host_header', + type: 'keyword', + }, + 'aws.s3access.tls_version': { + category: 'aws', + description: 'The Transport Layer Security (TLS) version negotiated by the client. ', + name: 'aws.s3access.tls_version', + type: 'keyword', + }, + 'aws.vpcflow.version': { + category: 'aws', + description: + 'The VPC Flow Logs version. If you use the default format, the version is 2. If you specify a custom format, the version is 3. ', + name: 'aws.vpcflow.version', + type: 'keyword', + }, + 'aws.vpcflow.account_id': { + category: 'aws', + description: 'The AWS account ID for the flow log. ', + name: 'aws.vpcflow.account_id', + type: 'keyword', + }, + 'aws.vpcflow.interface_id': { + category: 'aws', + description: 'The ID of the network interface for which the traffic is recorded. ', + name: 'aws.vpcflow.interface_id', + type: 'keyword', + }, + 'aws.vpcflow.action': { + category: 'aws', + description: 'The action that is associated with the traffic, ACCEPT or REJECT. ', + name: 'aws.vpcflow.action', + type: 'keyword', + }, + 'aws.vpcflow.log_status': { + category: 'aws', + description: 'The logging status of the flow log, OK, NODATA or SKIPDATA. ', + name: 'aws.vpcflow.log_status', + type: 'keyword', + }, + 'aws.vpcflow.instance_id': { + category: 'aws', + description: + "The ID of the instance that's associated with network interface for which the traffic is recorded, if the instance is owned by you. ", + name: 'aws.vpcflow.instance_id', + type: 'keyword', + }, + 'aws.vpcflow.pkt_srcaddr': { + category: 'aws', + description: 'The packet-level (original) source IP address of the traffic. ', + name: 'aws.vpcflow.pkt_srcaddr', + type: 'ip', + }, + 'aws.vpcflow.pkt_dstaddr': { + category: 'aws', + description: 'The packet-level (original) destination IP address for the traffic. ', + name: 'aws.vpcflow.pkt_dstaddr', + type: 'ip', + }, + 'aws.vpcflow.vpc_id': { + category: 'aws', + description: + 'The ID of the VPC that contains the network interface for which the traffic is recorded. ', + name: 'aws.vpcflow.vpc_id', + type: 'keyword', + }, + 'aws.vpcflow.subnet_id': { + category: 'aws', + description: + 'The ID of the subnet that contains the network interface for which the traffic is recorded. ', + name: 'aws.vpcflow.subnet_id', + type: 'keyword', + }, + 'aws.vpcflow.tcp_flags': { + category: 'aws', + description: 'The bitmask value for the following TCP flags: 2=SYN,18=SYN-ACK,1=FIN,4=RST ', + name: 'aws.vpcflow.tcp_flags', + type: 'keyword', + }, + 'aws.vpcflow.tcp_flags_array': { + category: 'aws', + description: "List of TCP flags: 'fin, syn, rst, psh, ack, urg' ", + name: 'aws.vpcflow.tcp_flags_array', + type: 'keyword', + }, + 'aws.vpcflow.type': { + category: 'aws', + description: 'The type of traffic: IPv4, IPv6, or EFA. ', + name: 'aws.vpcflow.type', + type: 'keyword', + }, + 'awsfargate.log': { + category: 'awsfargate', + description: 'Fields for Amazon Fargate container logs. ', + name: 'awsfargate.log', + type: 'group', + }, + 'azure.subscription_id': { + category: 'azure', + description: 'Azure subscription ID ', + name: 'azure.subscription_id', + type: 'keyword', + }, + 'azure.correlation_id': { + category: 'azure', + description: 'Correlation ID ', + name: 'azure.correlation_id', + type: 'keyword', + }, + 'azure.tenant_id': { + category: 'azure', + description: 'tenant ID ', + name: 'azure.tenant_id', + type: 'keyword', + }, + 'azure.resource.id': { + category: 'azure', + description: 'Resource ID ', + name: 'azure.resource.id', + type: 'keyword', + }, + 'azure.resource.group': { + category: 'azure', + description: 'Resource group ', + name: 'azure.resource.group', + type: 'keyword', + }, + 'azure.resource.provider': { + category: 'azure', + description: 'Resource type/namespace ', + name: 'azure.resource.provider', + type: 'keyword', + }, + 'azure.resource.namespace': { + category: 'azure', + description: 'Resource type/namespace ', + name: 'azure.resource.namespace', + type: 'keyword', + }, + 'azure.resource.name': { + category: 'azure', + description: 'Name ', + name: 'azure.resource.name', + type: 'keyword', + }, + 'azure.resource.authorization_rule': { + category: 'azure', + description: 'Authorization rule ', + name: 'azure.resource.authorization_rule', + type: 'keyword', + }, + 'azure.activitylogs.identity.claims_initiated_by_user.name': { + category: 'azure', + description: 'Name ', + name: 'azure.activitylogs.identity.claims_initiated_by_user.name', + type: 'keyword', + }, + 'azure.activitylogs.identity.claims_initiated_by_user.givenname': { + category: 'azure', + description: 'Givenname ', + name: 'azure.activitylogs.identity.claims_initiated_by_user.givenname', + type: 'keyword', + }, + 'azure.activitylogs.identity.claims_initiated_by_user.surname': { + category: 'azure', + description: 'Surname ', + name: 'azure.activitylogs.identity.claims_initiated_by_user.surname', + type: 'keyword', + }, + 'azure.activitylogs.identity.claims_initiated_by_user.fullname': { + category: 'azure', + description: 'Fullname ', + name: 'azure.activitylogs.identity.claims_initiated_by_user.fullname', + type: 'keyword', + }, + 'azure.activitylogs.identity.claims_initiated_by_user.schema': { + category: 'azure', + description: 'Schema ', + name: 'azure.activitylogs.identity.claims_initiated_by_user.schema', + type: 'keyword', + }, + 'azure.activitylogs.identity.claims.*': { + category: 'azure', + description: 'Claims ', + name: 'azure.activitylogs.identity.claims.*', + type: 'object', + }, + 'azure.activitylogs.identity.authorization.scope': { + category: 'azure', + description: 'Scope ', + name: 'azure.activitylogs.identity.authorization.scope', + type: 'keyword', + }, + 'azure.activitylogs.identity.authorization.action': { + category: 'azure', + description: 'Action ', + name: 'azure.activitylogs.identity.authorization.action', + type: 'keyword', + }, + 'azure.activitylogs.identity.authorization.evidence.role_assignment_scope': { + category: 'azure', + description: 'Role assignment scope ', + name: 'azure.activitylogs.identity.authorization.evidence.role_assignment_scope', + type: 'keyword', + }, + 'azure.activitylogs.identity.authorization.evidence.role_definition_id': { + category: 'azure', + description: 'Role definition ID ', + name: 'azure.activitylogs.identity.authorization.evidence.role_definition_id', + type: 'keyword', + }, + 'azure.activitylogs.identity.authorization.evidence.role': { + category: 'azure', + description: 'Role ', + name: 'azure.activitylogs.identity.authorization.evidence.role', + type: 'keyword', + }, + 'azure.activitylogs.identity.authorization.evidence.role_assignment_id': { + category: 'azure', + description: 'Role assignment ID ', + name: 'azure.activitylogs.identity.authorization.evidence.role_assignment_id', + type: 'keyword', + }, + 'azure.activitylogs.identity.authorization.evidence.principal_id': { + category: 'azure', + description: 'Principal ID ', + name: 'azure.activitylogs.identity.authorization.evidence.principal_id', + type: 'keyword', + }, + 'azure.activitylogs.identity.authorization.evidence.principal_type': { + category: 'azure', + description: 'Principal type ', + name: 'azure.activitylogs.identity.authorization.evidence.principal_type', + type: 'keyword', + }, + 'azure.activitylogs.operation_name': { + category: 'azure', + description: 'Operation name ', + name: 'azure.activitylogs.operation_name', + type: 'keyword', + }, + 'azure.activitylogs.result_type': { + category: 'azure', + description: 'Result type ', + name: 'azure.activitylogs.result_type', + type: 'keyword', + }, + 'azure.activitylogs.result_signature': { + category: 'azure', + description: 'Result signature ', + name: 'azure.activitylogs.result_signature', + type: 'keyword', + }, + 'azure.activitylogs.category': { + category: 'azure', + description: 'Category ', + name: 'azure.activitylogs.category', + type: 'keyword', + }, + 'azure.activitylogs.event_category': { + category: 'azure', + description: 'Event Category ', + name: 'azure.activitylogs.event_category', + type: 'keyword', + }, + 'azure.activitylogs.properties': { + category: 'azure', + description: 'Properties ', + name: 'azure.activitylogs.properties', + type: 'flattened', + }, + 'azure.auditlogs.category': { + category: 'azure', + description: 'The category of the operation. Currently, Audit is the only supported value. ', + name: 'azure.auditlogs.category', + type: 'keyword', + }, + 'azure.auditlogs.operation_name': { + category: 'azure', + description: 'The operation name ', + name: 'azure.auditlogs.operation_name', + type: 'keyword', + }, + 'azure.auditlogs.operation_version': { + category: 'azure', + description: 'The operation version ', + name: 'azure.auditlogs.operation_version', + type: 'keyword', + }, + 'azure.auditlogs.identity': { + category: 'azure', + description: 'Identity ', + name: 'azure.auditlogs.identity', + type: 'keyword', + }, + 'azure.auditlogs.tenant_id': { + category: 'azure', + description: 'Tenant ID ', + name: 'azure.auditlogs.tenant_id', + type: 'keyword', + }, + 'azure.auditlogs.result_signature': { + category: 'azure', + description: 'Result signature ', + name: 'azure.auditlogs.result_signature', + type: 'keyword', + }, + 'azure.auditlogs.properties.result': { + category: 'azure', + description: 'Log result ', + name: 'azure.auditlogs.properties.result', + type: 'keyword', + }, + 'azure.auditlogs.properties.activity_display_name': { + category: 'azure', + description: 'Activity display name ', + name: 'azure.auditlogs.properties.activity_display_name', + type: 'keyword', + }, + 'azure.auditlogs.properties.result_reason': { + category: 'azure', + description: 'Reason for the log result ', + name: 'azure.auditlogs.properties.result_reason', + type: 'keyword', + }, + 'azure.auditlogs.properties.correlation_id': { + category: 'azure', + description: 'Correlation ID ', + name: 'azure.auditlogs.properties.correlation_id', + type: 'keyword', + }, + 'azure.auditlogs.properties.logged_by_service': { + category: 'azure', + description: 'Logged by service ', + name: 'azure.auditlogs.properties.logged_by_service', + type: 'keyword', + }, + 'azure.auditlogs.properties.operation_type': { + category: 'azure', + description: 'Operation type ', + name: 'azure.auditlogs.properties.operation_type', + type: 'keyword', + }, + 'azure.auditlogs.properties.id': { + category: 'azure', + description: 'ID ', + name: 'azure.auditlogs.properties.id', + type: 'keyword', + }, + 'azure.auditlogs.properties.activity_datetime': { + category: 'azure', + description: 'Activity timestamp ', + name: 'azure.auditlogs.properties.activity_datetime', + type: 'date', + }, + 'azure.auditlogs.properties.category': { + category: 'azure', + description: 'category ', + name: 'azure.auditlogs.properties.category', + type: 'keyword', + }, + 'azure.auditlogs.properties.target_resources.*.display_name': { + category: 'azure', + description: 'Display name ', + name: 'azure.auditlogs.properties.target_resources.*.display_name', + type: 'keyword', + }, + 'azure.auditlogs.properties.target_resources.*.id': { + category: 'azure', + description: 'ID ', + name: 'azure.auditlogs.properties.target_resources.*.id', + type: 'keyword', + }, + 'azure.auditlogs.properties.target_resources.*.type': { + category: 'azure', + description: 'Type ', + name: 'azure.auditlogs.properties.target_resources.*.type', + type: 'keyword', + }, + 'azure.auditlogs.properties.target_resources.*.ip_address': { + category: 'azure', + description: 'ip Address ', + name: 'azure.auditlogs.properties.target_resources.*.ip_address', + type: 'keyword', + }, + 'azure.auditlogs.properties.target_resources.*.user_principal_name': { + category: 'azure', + description: 'User principal name ', + name: 'azure.auditlogs.properties.target_resources.*.user_principal_name', + type: 'keyword', + }, + 'azure.auditlogs.properties.target_resources.*.modified_properties.*.new_value': { + category: 'azure', + description: 'New value ', + name: 'azure.auditlogs.properties.target_resources.*.modified_properties.*.new_value', + type: 'keyword', + }, + 'azure.auditlogs.properties.target_resources.*.modified_properties.*.display_name': { + category: 'azure', + description: 'Display value ', + name: 'azure.auditlogs.properties.target_resources.*.modified_properties.*.display_name', + type: 'keyword', + }, + 'azure.auditlogs.properties.target_resources.*.modified_properties.*.old_value': { + category: 'azure', + description: 'Old value ', + name: 'azure.auditlogs.properties.target_resources.*.modified_properties.*.old_value', + type: 'keyword', + }, + 'azure.auditlogs.properties.initiated_by.app.servicePrincipalName': { + category: 'azure', + description: 'Service principal name ', + name: 'azure.auditlogs.properties.initiated_by.app.servicePrincipalName', + type: 'keyword', + }, + 'azure.auditlogs.properties.initiated_by.app.displayName': { + category: 'azure', + description: 'Display name ', + name: 'azure.auditlogs.properties.initiated_by.app.displayName', + type: 'keyword', + }, + 'azure.auditlogs.properties.initiated_by.app.appId': { + category: 'azure', + description: 'App ID ', + name: 'azure.auditlogs.properties.initiated_by.app.appId', + type: 'keyword', + }, + 'azure.auditlogs.properties.initiated_by.app.servicePrincipalId': { + category: 'azure', + description: 'Service principal ID ', + name: 'azure.auditlogs.properties.initiated_by.app.servicePrincipalId', + type: 'keyword', + }, + 'azure.auditlogs.properties.initiated_by.user.userPrincipalName': { + category: 'azure', + description: 'User principal name ', + name: 'azure.auditlogs.properties.initiated_by.user.userPrincipalName', + type: 'keyword', + }, + 'azure.auditlogs.properties.initiated_by.user.displayName': { + category: 'azure', + description: 'Display name ', + name: 'azure.auditlogs.properties.initiated_by.user.displayName', + type: 'keyword', + }, + 'azure.auditlogs.properties.initiated_by.user.id': { + category: 'azure', + description: 'ID ', + name: 'azure.auditlogs.properties.initiated_by.user.id', + type: 'keyword', + }, + 'azure.auditlogs.properties.initiated_by.user.ipAddress': { + category: 'azure', + description: 'ip Address ', + name: 'azure.auditlogs.properties.initiated_by.user.ipAddress', + type: 'keyword', + }, + 'azure.platformlogs.operation_name': { + category: 'azure', + description: 'Operation name ', + name: 'azure.platformlogs.operation_name', + type: 'keyword', + }, + 'azure.platformlogs.result_type': { + category: 'azure', + description: 'Result type ', + name: 'azure.platformlogs.result_type', + type: 'keyword', + }, + 'azure.platformlogs.result_signature': { + category: 'azure', + description: 'Result signature ', + name: 'azure.platformlogs.result_signature', + type: 'keyword', + }, + 'azure.platformlogs.category': { + category: 'azure', + description: 'Category ', + name: 'azure.platformlogs.category', + type: 'keyword', + }, + 'azure.platformlogs.event_category': { + category: 'azure', + description: 'Event Category ', + name: 'azure.platformlogs.event_category', + type: 'keyword', + }, + 'azure.platformlogs.status': { + category: 'azure', + description: 'Status ', + name: 'azure.platformlogs.status', + type: 'keyword', + }, + 'azure.platformlogs.ccpNamespace': { + category: 'azure', + description: 'ccpNamespace ', + name: 'azure.platformlogs.ccpNamespace', + type: 'keyword', + }, + 'azure.platformlogs.Cloud': { + category: 'azure', + description: 'Cloud ', + name: 'azure.platformlogs.Cloud', + type: 'keyword', + }, + 'azure.platformlogs.Environment': { + category: 'azure', + description: 'Environment ', + name: 'azure.platformlogs.Environment', + type: 'keyword', + }, + 'azure.platformlogs.EventTimeString': { + category: 'azure', + description: 'EventTimeString ', + name: 'azure.platformlogs.EventTimeString', + type: 'keyword', + }, + 'azure.platformlogs.Caller': { + category: 'azure', + description: 'Caller ', + name: 'azure.platformlogs.Caller', + type: 'keyword', + }, + 'azure.platformlogs.ScaleUnit': { + category: 'azure', + description: 'ScaleUnit ', + name: 'azure.platformlogs.ScaleUnit', + type: 'keyword', + }, + 'azure.platformlogs.ActivityId': { + category: 'azure', + description: 'ActivityId ', + name: 'azure.platformlogs.ActivityId', + type: 'keyword', + }, + 'azure.platformlogs.properties': { + category: 'azure', + description: 'Event inner properties ', + name: 'azure.platformlogs.properties', + type: 'flattened', + }, + 'azure.signinlogs.operation_name': { + category: 'azure', + description: 'The operation name ', + name: 'azure.signinlogs.operation_name', + type: 'keyword', + }, + 'azure.signinlogs.operation_version': { + category: 'azure', + description: 'The operation version ', + name: 'azure.signinlogs.operation_version', + type: 'keyword', + }, + 'azure.signinlogs.tenant_id': { + category: 'azure', + description: 'Tenant ID ', + name: 'azure.signinlogs.tenant_id', + type: 'keyword', + }, + 'azure.signinlogs.result_signature': { + category: 'azure', + description: 'Result signature ', + name: 'azure.signinlogs.result_signature', + type: 'keyword', + }, + 'azure.signinlogs.result_description': { + category: 'azure', + description: 'Result description ', + name: 'azure.signinlogs.result_description', + type: 'keyword', + }, + 'azure.signinlogs.result_type': { + category: 'azure', + description: 'Result type ', + name: 'azure.signinlogs.result_type', + type: 'keyword', + }, + 'azure.signinlogs.identity': { + category: 'azure', + description: 'Identity ', + name: 'azure.signinlogs.identity', + type: 'keyword', + }, + 'azure.signinlogs.category': { + category: 'azure', + description: 'Category ', + name: 'azure.signinlogs.category', + type: 'keyword', + }, + 'azure.signinlogs.properties.id': { + category: 'azure', + description: 'Unique ID representing the sign-in activity. ', + name: 'azure.signinlogs.properties.id', + type: 'keyword', + }, + 'azure.signinlogs.properties.created_at': { + category: 'azure', + description: 'Date and time (UTC) the sign-in was initiated. ', + name: 'azure.signinlogs.properties.created_at', + type: 'date', + }, + 'azure.signinlogs.properties.user_display_name': { + category: 'azure', + description: 'User display name ', + name: 'azure.signinlogs.properties.user_display_name', + type: 'keyword', + }, + 'azure.signinlogs.properties.correlation_id': { + category: 'azure', + description: 'Correlation ID ', + name: 'azure.signinlogs.properties.correlation_id', + type: 'keyword', + }, + 'azure.signinlogs.properties.user_principal_name': { + category: 'azure', + description: 'User principal name ', + name: 'azure.signinlogs.properties.user_principal_name', + type: 'keyword', + }, + 'azure.signinlogs.properties.user_id': { + category: 'azure', + description: 'User ID ', + name: 'azure.signinlogs.properties.user_id', + type: 'keyword', + }, + 'azure.signinlogs.properties.app_id': { + category: 'azure', + description: 'App ID ', + name: 'azure.signinlogs.properties.app_id', + type: 'keyword', + }, + 'azure.signinlogs.properties.app_display_name': { + category: 'azure', + description: 'App display name ', + name: 'azure.signinlogs.properties.app_display_name', + type: 'keyword', + }, + 'azure.signinlogs.properties.autonomous_system_number': { + category: 'azure', + description: 'Autonomous system number.', + name: 'azure.signinlogs.properties.autonomous_system_number', + type: 'long', + }, + 'azure.signinlogs.properties.client_app_used': { + category: 'azure', + description: 'Client app used ', + name: 'azure.signinlogs.properties.client_app_used', + type: 'keyword', + }, + 'azure.signinlogs.properties.conditional_access_status': { + category: 'azure', + description: 'Conditional access status ', + name: 'azure.signinlogs.properties.conditional_access_status', + type: 'keyword', + }, + 'azure.signinlogs.properties.original_request_id': { + category: 'azure', + description: 'Original request ID ', + name: 'azure.signinlogs.properties.original_request_id', + type: 'keyword', + }, + 'azure.signinlogs.properties.is_interactive': { + category: 'azure', + description: 'Is interactive ', + name: 'azure.signinlogs.properties.is_interactive', + type: 'boolean', + }, + 'azure.signinlogs.properties.token_issuer_name': { + category: 'azure', + description: 'Token issuer name ', + name: 'azure.signinlogs.properties.token_issuer_name', + type: 'keyword', + }, + 'azure.signinlogs.properties.token_issuer_type': { + category: 'azure', + description: 'Token issuer type ', + name: 'azure.signinlogs.properties.token_issuer_type', + type: 'keyword', + }, + 'azure.signinlogs.properties.processing_time_ms': { + category: 'azure', + description: 'Processing time in milliseconds ', + name: 'azure.signinlogs.properties.processing_time_ms', + type: 'float', + }, + 'azure.signinlogs.properties.risk_detail': { + category: 'azure', + description: 'Risk detail ', + name: 'azure.signinlogs.properties.risk_detail', + type: 'keyword', + }, + 'azure.signinlogs.properties.risk_level_aggregated': { + category: 'azure', + description: 'Risk level aggregated ', + name: 'azure.signinlogs.properties.risk_level_aggregated', + type: 'keyword', + }, + 'azure.signinlogs.properties.risk_level_during_signin': { + category: 'azure', + description: 'Risk level during signIn ', + name: 'azure.signinlogs.properties.risk_level_during_signin', + type: 'keyword', + }, + 'azure.signinlogs.properties.risk_state': { + category: 'azure', + description: 'Risk state ', + name: 'azure.signinlogs.properties.risk_state', + type: 'keyword', + }, + 'azure.signinlogs.properties.resource_display_name': { + category: 'azure', + description: 'Resource display name ', + name: 'azure.signinlogs.properties.resource_display_name', + type: 'keyword', + }, + 'azure.signinlogs.properties.status.error_code': { + category: 'azure', + description: 'Error code ', + name: 'azure.signinlogs.properties.status.error_code', + type: 'long', + }, + 'azure.signinlogs.properties.device_detail.device_id': { + category: 'azure', + description: 'Device ID ', + name: 'azure.signinlogs.properties.device_detail.device_id', + type: 'keyword', + }, + 'azure.signinlogs.properties.device_detail.operating_system': { + category: 'azure', + description: 'Operating system ', + name: 'azure.signinlogs.properties.device_detail.operating_system', + type: 'keyword', + }, + 'azure.signinlogs.properties.device_detail.browser': { + category: 'azure', + description: 'Browser ', + name: 'azure.signinlogs.properties.device_detail.browser', + type: 'keyword', + }, + 'azure.signinlogs.properties.device_detail.display_name': { + category: 'azure', + description: 'Display name ', + name: 'azure.signinlogs.properties.device_detail.display_name', + type: 'keyword', + }, + 'azure.signinlogs.properties.device_detail.trust_type': { + category: 'azure', + description: 'Trust type ', + name: 'azure.signinlogs.properties.device_detail.trust_type', + type: 'keyword', + }, + 'azure.signinlogs.properties.applied_conditional_access_policies': { + category: 'azure', + description: + 'A list of conditional access policies that are triggered by the corresponding sign-in activity. ', + name: 'azure.signinlogs.properties.applied_conditional_access_policies', + type: 'array', + }, + 'azure.signinlogs.properties.authentication_details': { + category: 'azure', + description: + 'The result of the authentication attempt and additional details on the authentication method. ', + name: 'azure.signinlogs.properties.authentication_details', + type: 'array', + }, + 'azure.signinlogs.properties.authentication_processing_details': { + category: 'azure', + description: + 'Additional authentication processing details, such as the agent name in case of PTA/PHS or Server/farm name in case of federated authentication. ', + name: 'azure.signinlogs.properties.authentication_processing_details', + type: 'flattened', + }, + 'azure.signinlogs.properties.authentication_requirement': { + category: 'azure', + description: + 'This holds the highest level of authentication needed through all the sign-in steps, for sign-in to succeed. ', + name: 'azure.signinlogs.properties.authentication_requirement', + type: 'keyword', + }, + 'azure.signinlogs.properties.authentication_requirement_policies': { + category: 'azure', + description: + 'Set of CA policies that apply to this sign-in, each as CA: policy name, and/or MFA: Per-user ', + name: 'azure.signinlogs.properties.authentication_requirement_policies', + type: 'keyword', + }, + 'azure.signinlogs.properties.flagged_for_review': { + category: 'azure', + name: 'azure.signinlogs.properties.flagged_for_review', + type: 'boolean', + }, + 'azure.signinlogs.properties.home_tenant_id': { + category: 'azure', + name: 'azure.signinlogs.properties.home_tenant_id', + type: 'keyword', + }, + 'azure.signinlogs.properties.network_location_details': { + category: 'azure', + description: 'The network location details including the type of network used and its names.', + name: 'azure.signinlogs.properties.network_location_details', + type: 'array', + }, + 'azure.signinlogs.properties.resource_id': { + category: 'azure', + description: 'The identifier of the resource that the user signed in to.', + name: 'azure.signinlogs.properties.resource_id', + type: 'keyword', + }, + 'azure.signinlogs.properties.resource_tenant_id': { + category: 'azure', + name: 'azure.signinlogs.properties.resource_tenant_id', + type: 'keyword', + }, + 'azure.signinlogs.properties.risk_event_types': { + category: 'azure', + description: + 'The list of risk event types associated with the sign-in. Possible values: unlikelyTravel, anonymizedIPAddress, maliciousIPAddress, unfamiliarFeatures, malwareInfectedIPAddress, suspiciousIPAddress, leakedCredentials, investigationsThreatIntelligence, generic, or unknownFutureValue. ', + name: 'azure.signinlogs.properties.risk_event_types', + type: 'keyword', + }, + 'azure.signinlogs.properties.risk_event_types_v2': { + category: 'azure', + description: + 'The list of risk event types associated with the sign-in. Possible values: unlikelyTravel, anonymizedIPAddress, maliciousIPAddress, unfamiliarFeatures, malwareInfectedIPAddress, suspiciousIPAddress, leakedCredentials, investigationsThreatIntelligence, generic, or unknownFutureValue. ', + name: 'azure.signinlogs.properties.risk_event_types_v2', + type: 'keyword', + }, + 'azure.signinlogs.properties.service_principal_name': { + category: 'azure', + description: + 'The application name used for sign-in. This field is populated when you are signing in using an application. ', + name: 'azure.signinlogs.properties.service_principal_name', + type: 'keyword', + }, + 'azure.signinlogs.properties.user_type': { + category: 'azure', + name: 'azure.signinlogs.properties.user_type', + type: 'keyword', + }, + 'azure.signinlogs.properties.service_principal_id': { + category: 'azure', + description: + 'The application identifier used for sign-in. This field is populated when you are signing in using an application. ', + name: 'azure.signinlogs.properties.service_principal_id', + type: 'keyword', + }, + 'azure.signinlogs.properties.cross_tenant_access_type': { + category: 'azure', + name: 'azure.signinlogs.properties.cross_tenant_access_type', + type: 'keyword', + }, + 'azure.signinlogs.properties.is_tenant_restricted': { + category: 'azure', + name: 'azure.signinlogs.properties.is_tenant_restricted', + type: 'boolean', + }, + 'azure.signinlogs.properties.sso_extension_version': { + category: 'azure', + name: 'azure.signinlogs.properties.sso_extension_version', + type: 'keyword', + }, + 'network.interface.name': { + category: 'network', + description: 'Name of the network interface where the traffic has been observed. ', + name: 'network.interface.name', + type: 'keyword', + }, + 'rsa.internal.msg': { + category: 'rsa', + description: 'This key is used to capture the raw message that comes into the Log Decoder', + name: 'rsa.internal.msg', + type: 'keyword', + }, + 'rsa.internal.messageid': { + category: 'rsa', + name: 'rsa.internal.messageid', + type: 'keyword', + }, + 'rsa.internal.event_desc': { + category: 'rsa', + name: 'rsa.internal.event_desc', + type: 'keyword', + }, + 'rsa.internal.message': { + category: 'rsa', + description: 'This key captures the contents of instant messages', + name: 'rsa.internal.message', + type: 'keyword', + }, + 'rsa.internal.time': { + category: 'rsa', + description: + 'This is the time at which a session hits a NetWitness Decoder. This key should never be used to parse Meta data from a session (Logs/Packets) Directly, this is a Reserved key in NetWitness.', + name: 'rsa.internal.time', + type: 'date', + }, + 'rsa.internal.level': { + category: 'rsa', + description: 'Deprecated key defined only in table map.', + name: 'rsa.internal.level', + type: 'long', + }, + 'rsa.internal.msg_id': { + category: 'rsa', + description: + 'This is the Message ID1 value that identifies the exact log parser definition which parses a particular log session. This key should never be used to parse Meta data from a session (Logs/Packets) Directly, this is a Reserved key in NetWitness', + name: 'rsa.internal.msg_id', + type: 'keyword', + }, + 'rsa.internal.msg_vid': { + category: 'rsa', + description: + 'This is the Message ID2 value that identifies the exact log parser definition which parses a particular log session. This key should never be used to parse Meta data from a session (Logs/Packets) Directly, this is a Reserved key in NetWitness', + name: 'rsa.internal.msg_vid', + type: 'keyword', + }, + 'rsa.internal.data': { + category: 'rsa', + description: 'Deprecated key defined only in table map.', + name: 'rsa.internal.data', + type: 'keyword', + }, + 'rsa.internal.obj_server': { + category: 'rsa', + description: 'Deprecated key defined only in table map.', + name: 'rsa.internal.obj_server', + type: 'keyword', + }, + 'rsa.internal.obj_val': { + category: 'rsa', + description: 'Deprecated key defined only in table map.', + name: 'rsa.internal.obj_val', + type: 'keyword', + }, + 'rsa.internal.resource': { + category: 'rsa', + description: 'Deprecated key defined only in table map.', + name: 'rsa.internal.resource', + type: 'keyword', + }, + 'rsa.internal.obj_id': { + category: 'rsa', + description: 'Deprecated key defined only in table map.', + name: 'rsa.internal.obj_id', + type: 'keyword', + }, + 'rsa.internal.statement': { + category: 'rsa', + description: 'Deprecated key defined only in table map.', + name: 'rsa.internal.statement', + type: 'keyword', + }, + 'rsa.internal.audit_class': { + category: 'rsa', + description: 'Deprecated key defined only in table map.', + name: 'rsa.internal.audit_class', + type: 'keyword', + }, + 'rsa.internal.entry': { + category: 'rsa', + description: 'Deprecated key defined only in table map.', + name: 'rsa.internal.entry', + type: 'keyword', + }, + 'rsa.internal.hcode': { + category: 'rsa', + description: 'Deprecated key defined only in table map.', + name: 'rsa.internal.hcode', + type: 'keyword', + }, + 'rsa.internal.inode': { + category: 'rsa', + description: 'Deprecated key defined only in table map.', + name: 'rsa.internal.inode', + type: 'long', + }, + 'rsa.internal.resource_class': { + category: 'rsa', + description: 'Deprecated key defined only in table map.', + name: 'rsa.internal.resource_class', + type: 'keyword', + }, + 'rsa.internal.dead': { + category: 'rsa', + description: 'Deprecated key defined only in table map.', + name: 'rsa.internal.dead', + type: 'long', + }, + 'rsa.internal.feed_desc': { + category: 'rsa', + description: + 'This is used to capture the description of the feed. This key should never be used to parse Meta data from a session (Logs/Packets) Directly, this is a Reserved key in NetWitness', + name: 'rsa.internal.feed_desc', + type: 'keyword', + }, + 'rsa.internal.feed_name': { + category: 'rsa', + description: + 'This is used to capture the name of the feed. This key should never be used to parse Meta data from a session (Logs/Packets) Directly, this is a Reserved key in NetWitness', + name: 'rsa.internal.feed_name', + type: 'keyword', + }, + 'rsa.internal.cid': { + category: 'rsa', + description: + 'This is the unique identifier used to identify a NetWitness Concentrator. This key should never be used to parse Meta data from a session (Logs/Packets) Directly, this is a Reserved key in NetWitness', + name: 'rsa.internal.cid', + type: 'keyword', + }, + 'rsa.internal.device_class': { + category: 'rsa', + description: + 'This is the Classification of the Log Event Source under a predefined fixed set of Event Source Classifications. This key should never be used to parse Meta data from a session (Logs/Packets) Directly, this is a Reserved key in NetWitness', + name: 'rsa.internal.device_class', + type: 'keyword', + }, + 'rsa.internal.device_group': { + category: 'rsa', + description: + 'This key should never be used to parse Meta data from a session (Logs/Packets) Directly, this is a Reserved key in NetWitness', + name: 'rsa.internal.device_group', + type: 'keyword', + }, + 'rsa.internal.device_host': { + category: 'rsa', + description: + 'This is the Hostname of the log Event Source sending the logs to NetWitness. This key should never be used to parse Meta data from a session (Logs/Packets) Directly, this is a Reserved key in NetWitness', + name: 'rsa.internal.device_host', + type: 'keyword', + }, + 'rsa.internal.device_ip': { + category: 'rsa', + description: + 'This is the IPv4 address of the Log Event Source sending the logs to NetWitness. This key should never be used to parse Meta data from a session (Logs/Packets) Directly, this is a Reserved key in NetWitness', + name: 'rsa.internal.device_ip', + type: 'ip', + }, + 'rsa.internal.device_ipv6': { + category: 'rsa', + description: + 'This is the IPv6 address of the Log Event Source sending the logs to NetWitness. This key should never be used to parse Meta data from a session (Logs/Packets) Directly, this is a Reserved key in NetWitness', + name: 'rsa.internal.device_ipv6', + type: 'ip', + }, + 'rsa.internal.device_type': { + category: 'rsa', + description: + 'This is the name of the log parser which parsed a given session. This key should never be used to parse Meta data from a session (Logs/Packets) Directly, this is a Reserved key in NetWitness', + name: 'rsa.internal.device_type', + type: 'keyword', + }, + 'rsa.internal.device_type_id': { + category: 'rsa', + description: 'Deprecated key defined only in table map.', + name: 'rsa.internal.device_type_id', + type: 'long', + }, + 'rsa.internal.did': { + category: 'rsa', + description: + 'This is the unique identifier used to identify a NetWitness Decoder. This key should never be used to parse Meta data from a session (Logs/Packets) Directly, this is a Reserved key in NetWitness', + name: 'rsa.internal.did', + type: 'keyword', + }, + 'rsa.internal.entropy_req': { + category: 'rsa', + description: + 'This key is only used by the Entropy Parser, the Meta Type can be either UInt16 or Float32 based on the configuration', + name: 'rsa.internal.entropy_req', + type: 'long', + }, + 'rsa.internal.entropy_res': { + category: 'rsa', + description: + 'This key is only used by the Entropy Parser, the Meta Type can be either UInt16 or Float32 based on the configuration', + name: 'rsa.internal.entropy_res', + type: 'long', + }, + 'rsa.internal.event_name': { + category: 'rsa', + description: 'Deprecated key defined only in table map.', + name: 'rsa.internal.event_name', + type: 'keyword', + }, + 'rsa.internal.feed_category': { + category: 'rsa', + description: + 'This is used to capture the category of the feed. This key should never be used to parse Meta data from a session (Logs/Packets) Directly, this is a Reserved key in NetWitness', + name: 'rsa.internal.feed_category', + type: 'keyword', + }, + 'rsa.internal.forward_ip': { + category: 'rsa', + description: + 'This key should be used to capture the IPV4 address of a relay system which forwarded the events from the original system to NetWitness.', + name: 'rsa.internal.forward_ip', + type: 'ip', + }, + 'rsa.internal.forward_ipv6': { + category: 'rsa', + description: + 'This key is used to capture the IPV6 address of a relay system which forwarded the events from the original system to NetWitness. This key should never be used to parse Meta data from a session (Logs/Packets) Directly, this is a Reserved key in NetWitness', + name: 'rsa.internal.forward_ipv6', + type: 'ip', + }, + 'rsa.internal.header_id': { + category: 'rsa', + description: + 'This is the Header ID value that identifies the exact log parser header definition that parses a particular log session. This key should never be used to parse Meta data from a session (Logs/Packets) Directly, this is a Reserved key in NetWitness', + name: 'rsa.internal.header_id', + type: 'keyword', + }, + 'rsa.internal.lc_cid': { + category: 'rsa', + description: + 'This is a unique Identifier of a Log Collector. This key should never be used to parse Meta data from a session (Logs/Packets) Directly, this is a Reserved key in NetWitness', + name: 'rsa.internal.lc_cid', + type: 'keyword', + }, + 'rsa.internal.lc_ctime': { + category: 'rsa', + description: + 'This is the time at which a log is collected in a NetWitness Log Collector. This key should never be used to parse Meta data from a session (Logs/Packets) Directly, this is a Reserved key in NetWitness', + name: 'rsa.internal.lc_ctime', + type: 'date', + }, + 'rsa.internal.mcb_req': { + category: 'rsa', + description: + 'This key is only used by the Entropy Parser, the most common byte request is simply which byte for each side (0 thru 255) was seen the most', + name: 'rsa.internal.mcb_req', + type: 'long', + }, + 'rsa.internal.mcb_res': { + category: 'rsa', + description: + 'This key is only used by the Entropy Parser, the most common byte response is simply which byte for each side (0 thru 255) was seen the most', + name: 'rsa.internal.mcb_res', + type: 'long', + }, + 'rsa.internal.mcbc_req': { + category: 'rsa', + description: + 'This key is only used by the Entropy Parser, the most common byte count is the number of times the most common byte (above) was seen in the session streams', + name: 'rsa.internal.mcbc_req', + type: 'long', + }, + 'rsa.internal.mcbc_res': { + category: 'rsa', + description: + 'This key is only used by the Entropy Parser, the most common byte count is the number of times the most common byte (above) was seen in the session streams', + name: 'rsa.internal.mcbc_res', + type: 'long', + }, + 'rsa.internal.medium': { + category: 'rsa', + description: + 'This key is used to identify if it’s a log/packet session or Layer 2 Encapsulation Type. This key should never be used to parse Meta data from a session (Logs/Packets) Directly, this is a Reserved key in NetWitness. 32 = log, 33 = correlation session, < 32 is packet session', + name: 'rsa.internal.medium', + type: 'long', + }, + 'rsa.internal.node_name': { + category: 'rsa', + description: 'Deprecated key defined only in table map.', + name: 'rsa.internal.node_name', + type: 'keyword', + }, + 'rsa.internal.nwe_callback_id': { + category: 'rsa', + description: 'This key denotes that event is endpoint related', + name: 'rsa.internal.nwe_callback_id', + type: 'keyword', + }, + 'rsa.internal.parse_error': { + category: 'rsa', + description: + 'This is a special key that stores any Meta key validation error found while parsing a log session. This key should never be used to parse Meta data from a session (Logs/Packets) Directly, this is a Reserved key in NetWitness', + name: 'rsa.internal.parse_error', + type: 'keyword', + }, + 'rsa.internal.payload_req': { + category: 'rsa', + description: + 'This key is only used by the Entropy Parser, the payload size metrics are the payload sizes of each session side at the time of parsing. However, in order to keep', + name: 'rsa.internal.payload_req', + type: 'long', + }, + 'rsa.internal.payload_res': { + category: 'rsa', + description: + 'This key is only used by the Entropy Parser, the payload size metrics are the payload sizes of each session side at the time of parsing. However, in order to keep', + name: 'rsa.internal.payload_res', + type: 'long', + }, + 'rsa.internal.process_vid_dst': { + category: 'rsa', + description: + 'Endpoint generates and uses a unique virtual ID to identify any similar group of process. This ID represents the target process.', + name: 'rsa.internal.process_vid_dst', + type: 'keyword', + }, + 'rsa.internal.process_vid_src': { + category: 'rsa', + description: + 'Endpoint generates and uses a unique virtual ID to identify any similar group of process. This ID represents the source process.', + name: 'rsa.internal.process_vid_src', + type: 'keyword', + }, + 'rsa.internal.rid': { + category: 'rsa', + description: + 'This is a special ID of the Remote Session created by NetWitness Decoder. This key should never be used to parse Meta data from a session (Logs/Packets) Directly, this is a Reserved key in NetWitness', + name: 'rsa.internal.rid', + type: 'long', + }, + 'rsa.internal.session_split': { + category: 'rsa', + description: + 'This key should never be used to parse Meta data from a session (Logs/Packets) Directly, this is a Reserved key in NetWitness', + name: 'rsa.internal.session_split', + type: 'keyword', + }, + 'rsa.internal.site': { + category: 'rsa', + description: 'Deprecated key defined only in table map.', + name: 'rsa.internal.site', + type: 'keyword', + }, + 'rsa.internal.size': { + category: 'rsa', + description: + 'This is the size of the session as seen by the NetWitness Decoder. This key should never be used to parse Meta data from a session (Logs/Packets) Directly, this is a Reserved key in NetWitness', + name: 'rsa.internal.size', + type: 'long', + }, + 'rsa.internal.sourcefile': { + category: 'rsa', + description: + 'This is the name of the log file or PCAPs that can be imported into NetWitness. This key should never be used to parse Meta data from a session (Logs/Packets) Directly, this is a Reserved key in NetWitness', + name: 'rsa.internal.sourcefile', + type: 'keyword', + }, + 'rsa.internal.ubc_req': { + category: 'rsa', + description: + 'This key is only used by the Entropy Parser, Unique byte count is the number of unique bytes seen in each stream. 256 would mean all byte values of 0 thru 255 were seen at least once', + name: 'rsa.internal.ubc_req', + type: 'long', + }, + 'rsa.internal.ubc_res': { + category: 'rsa', + description: + 'This key is only used by the Entropy Parser, Unique byte count is the number of unique bytes seen in each stream. 256 would mean all byte values of 0 thru 255 were seen at least once', + name: 'rsa.internal.ubc_res', + type: 'long', + }, + 'rsa.internal.word': { + category: 'rsa', + description: + 'This is used by the Word Parsing technology to capture the first 5 character of every word in an unparsed log', + name: 'rsa.internal.word', + type: 'keyword', + }, + 'rsa.time.event_time': { + category: 'rsa', + description: + 'This key is used to capture the time mentioned in a raw session that represents the actual time an event occured in a standard normalized form', + name: 'rsa.time.event_time', + type: 'date', + }, + 'rsa.time.duration_time': { + category: 'rsa', + description: 'This key is used to capture the normalized duration/lifetime in seconds.', + name: 'rsa.time.duration_time', + type: 'double', + }, + 'rsa.time.event_time_str': { + category: 'rsa', + description: + 'This key is used to capture the incomplete time mentioned in a session as a string', + name: 'rsa.time.event_time_str', + type: 'keyword', + }, + 'rsa.time.starttime': { + category: 'rsa', + description: + 'This key is used to capture the Start time mentioned in a session in a standard form', + name: 'rsa.time.starttime', + type: 'date', + }, + 'rsa.time.month': { + category: 'rsa', + name: 'rsa.time.month', + type: 'keyword', + }, + 'rsa.time.day': { + category: 'rsa', + name: 'rsa.time.day', + type: 'keyword', + }, + 'rsa.time.endtime': { + category: 'rsa', + description: + 'This key is used to capture the End time mentioned in a session in a standard form', + name: 'rsa.time.endtime', + type: 'date', + }, + 'rsa.time.timezone': { + category: 'rsa', + description: 'This key is used to capture the timezone of the Event Time', + name: 'rsa.time.timezone', + type: 'keyword', + }, + 'rsa.time.duration_str': { + category: 'rsa', + description: 'A text string version of the duration', + name: 'rsa.time.duration_str', + type: 'keyword', + }, + 'rsa.time.date': { + category: 'rsa', + name: 'rsa.time.date', + type: 'keyword', + }, + 'rsa.time.year': { + category: 'rsa', + name: 'rsa.time.year', + type: 'keyword', + }, + 'rsa.time.recorded_time': { + category: 'rsa', + description: + "The event time as recorded by the system the event is collected from. The usage scenario is a multi-tier application where the management layer of the system records it's own timestamp at the time of collection from its child nodes. Must be in timestamp format.", + name: 'rsa.time.recorded_time', + type: 'date', + }, + 'rsa.time.datetime': { + category: 'rsa', + name: 'rsa.time.datetime', + type: 'keyword', + }, + 'rsa.time.effective_time': { + category: 'rsa', + description: + 'This key is the effective time referenced by an individual event in a Standard Timestamp format', + name: 'rsa.time.effective_time', + type: 'date', + }, + 'rsa.time.expire_time': { + category: 'rsa', + description: 'This key is the timestamp that explicitly refers to an expiration.', + name: 'rsa.time.expire_time', + type: 'date', + }, + 'rsa.time.process_time': { + category: 'rsa', + description: 'Deprecated, use duration.time', + name: 'rsa.time.process_time', + type: 'keyword', + }, + 'rsa.time.hour': { + category: 'rsa', + name: 'rsa.time.hour', + type: 'keyword', + }, + 'rsa.time.min': { + category: 'rsa', + name: 'rsa.time.min', + type: 'keyword', + }, + 'rsa.time.timestamp': { + category: 'rsa', + name: 'rsa.time.timestamp', + type: 'keyword', + }, + 'rsa.time.event_queue_time': { + category: 'rsa', + description: 'This key is the Time that the event was queued.', + name: 'rsa.time.event_queue_time', + type: 'date', + }, + 'rsa.time.p_time1': { + category: 'rsa', + name: 'rsa.time.p_time1', + type: 'keyword', + }, + 'rsa.time.tzone': { + category: 'rsa', + name: 'rsa.time.tzone', + type: 'keyword', + }, + 'rsa.time.eventtime': { + category: 'rsa', + name: 'rsa.time.eventtime', + type: 'keyword', + }, + 'rsa.time.gmtdate': { + category: 'rsa', + name: 'rsa.time.gmtdate', + type: 'keyword', + }, + 'rsa.time.gmttime': { + category: 'rsa', + name: 'rsa.time.gmttime', + type: 'keyword', + }, + 'rsa.time.p_date': { + category: 'rsa', + name: 'rsa.time.p_date', + type: 'keyword', + }, + 'rsa.time.p_month': { + category: 'rsa', + name: 'rsa.time.p_month', + type: 'keyword', + }, + 'rsa.time.p_time': { + category: 'rsa', + name: 'rsa.time.p_time', + type: 'keyword', + }, + 'rsa.time.p_time2': { + category: 'rsa', + name: 'rsa.time.p_time2', + type: 'keyword', + }, + 'rsa.time.p_year': { + category: 'rsa', + name: 'rsa.time.p_year', + type: 'keyword', + }, + 'rsa.time.expire_time_str': { + category: 'rsa', + description: + 'This key is used to capture incomplete timestamp that explicitly refers to an expiration.', + name: 'rsa.time.expire_time_str', + type: 'keyword', + }, + 'rsa.time.stamp': { + category: 'rsa', + description: 'Deprecated key defined only in table map.', + name: 'rsa.time.stamp', + type: 'date', + }, + 'rsa.misc.action': { + category: 'rsa', + name: 'rsa.misc.action', + type: 'keyword', + }, + 'rsa.misc.result': { + category: 'rsa', + description: + 'This key is used to capture the outcome/result string value of an action in a session.', + name: 'rsa.misc.result', + type: 'keyword', + }, + 'rsa.misc.severity': { + category: 'rsa', + description: 'This key is used to capture the severity given the session', + name: 'rsa.misc.severity', + type: 'keyword', + }, + 'rsa.misc.event_type': { + category: 'rsa', + description: 'This key captures the event category type as specified by the event source.', + name: 'rsa.misc.event_type', + type: 'keyword', + }, + 'rsa.misc.reference_id': { + category: 'rsa', + description: 'This key is used to capture an event id from the session directly', + name: 'rsa.misc.reference_id', + type: 'keyword', + }, + 'rsa.misc.version': { + category: 'rsa', + description: + 'This key captures Version of the application or OS which is generating the event.', + name: 'rsa.misc.version', + type: 'keyword', + }, + 'rsa.misc.disposition': { + category: 'rsa', + description: 'This key captures the The end state of an action.', + name: 'rsa.misc.disposition', + type: 'keyword', + }, + 'rsa.misc.result_code': { + category: 'rsa', + description: + 'This key is used to capture the outcome/result numeric value of an action in a session', + name: 'rsa.misc.result_code', + type: 'keyword', + }, + 'rsa.misc.category': { + category: 'rsa', + description: + 'This key is used to capture the category of an event given by the vendor in the session', + name: 'rsa.misc.category', + type: 'keyword', + }, + 'rsa.misc.obj_name': { + category: 'rsa', + description: 'This is used to capture name of object', + name: 'rsa.misc.obj_name', + type: 'keyword', + }, + 'rsa.misc.obj_type': { + category: 'rsa', + description: 'This is used to capture type of object', + name: 'rsa.misc.obj_type', + type: 'keyword', + }, + 'rsa.misc.event_source': { + category: 'rsa', + description: 'This key captures Source of the event that’s not a hostname', + name: 'rsa.misc.event_source', + type: 'keyword', + }, + 'rsa.misc.log_session_id': { + category: 'rsa', + description: 'This key is used to capture a sessionid from the session directly', + name: 'rsa.misc.log_session_id', + type: 'keyword', + }, + 'rsa.misc.group': { + category: 'rsa', + description: 'This key captures the Group Name value', + name: 'rsa.misc.group', + type: 'keyword', + }, + 'rsa.misc.policy_name': { + category: 'rsa', + description: 'This key is used to capture the Policy Name only.', + name: 'rsa.misc.policy_name', + type: 'keyword', + }, + 'rsa.misc.rule_name': { + category: 'rsa', + description: 'This key captures the Rule Name', + name: 'rsa.misc.rule_name', + type: 'keyword', + }, + 'rsa.misc.context': { + category: 'rsa', + description: 'This key captures Information which adds additional context to the event.', + name: 'rsa.misc.context', + type: 'keyword', + }, + 'rsa.misc.change_new': { + category: 'rsa', + description: + 'This key is used to capture the new values of the attribute that’s changing in a session', + name: 'rsa.misc.change_new', + type: 'keyword', + }, + 'rsa.misc.space': { + category: 'rsa', + name: 'rsa.misc.space', + type: 'keyword', + }, + 'rsa.misc.client': { + category: 'rsa', + description: + 'This key is used to capture only the name of the client application requesting resources of the server. See the user.agent meta key for capture of the specific user agent identifier or browser identification string.', + name: 'rsa.misc.client', + type: 'keyword', + }, + 'rsa.misc.msgIdPart1': { + category: 'rsa', + name: 'rsa.misc.msgIdPart1', + type: 'keyword', + }, + 'rsa.misc.msgIdPart2': { + category: 'rsa', + name: 'rsa.misc.msgIdPart2', + type: 'keyword', + }, + 'rsa.misc.change_old': { + category: 'rsa', + description: + 'This key is used to capture the old value of the attribute that’s changing in a session', + name: 'rsa.misc.change_old', + type: 'keyword', + }, + 'rsa.misc.operation_id': { + category: 'rsa', + description: + 'An alert number or operation number. The values should be unique and non-repeating.', + name: 'rsa.misc.operation_id', + type: 'keyword', + }, + 'rsa.misc.event_state': { + category: 'rsa', + description: + 'This key captures the current state of the object/item referenced within the event. Describing an on-going event.', + name: 'rsa.misc.event_state', + type: 'keyword', + }, + 'rsa.misc.group_object': { + category: 'rsa', + description: 'This key captures a collection/grouping of entities. Specific usage', + name: 'rsa.misc.group_object', + type: 'keyword', + }, + 'rsa.misc.node': { + category: 'rsa', + description: + 'Common use case is the node name within a cluster. The cluster name is reflected by the host name.', + name: 'rsa.misc.node', + type: 'keyword', + }, + 'rsa.misc.rule': { + category: 'rsa', + description: 'This key captures the Rule number', + name: 'rsa.misc.rule', + type: 'keyword', + }, + 'rsa.misc.device_name': { + category: 'rsa', + description: + 'This is used to capture name of the Device associated with the node Like: a physical disk, printer, etc', + name: 'rsa.misc.device_name', + type: 'keyword', + }, + 'rsa.misc.param': { + category: 'rsa', + description: 'This key is the parameters passed as part of a command or application, etc.', + name: 'rsa.misc.param', + type: 'keyword', + }, + 'rsa.misc.change_attrib': { + category: 'rsa', + description: + 'This key is used to capture the name of the attribute that’s changing in a session', + name: 'rsa.misc.change_attrib', + type: 'keyword', + }, + 'rsa.misc.event_computer': { + category: 'rsa', + description: + 'This key is a windows only concept, where this key is used to capture fully qualified domain name in a windows log.', + name: 'rsa.misc.event_computer', + type: 'keyword', + }, + 'rsa.misc.reference_id1': { + category: 'rsa', + description: 'This key is for Linked ID to be used as an addition to "reference.id"', + name: 'rsa.misc.reference_id1', + type: 'keyword', + }, + 'rsa.misc.event_log': { + category: 'rsa', + description: 'This key captures the Name of the event log', + name: 'rsa.misc.event_log', + type: 'keyword', + }, + 'rsa.misc.OS': { + category: 'rsa', + description: 'This key captures the Name of the Operating System', + name: 'rsa.misc.OS', + type: 'keyword', + }, + 'rsa.misc.terminal': { + category: 'rsa', + description: 'This key captures the Terminal Names only', + name: 'rsa.misc.terminal', + type: 'keyword', + }, + 'rsa.misc.msgIdPart3': { + category: 'rsa', + name: 'rsa.misc.msgIdPart3', + type: 'keyword', + }, + 'rsa.misc.filter': { + category: 'rsa', + description: 'This key captures Filter used to reduce result set', + name: 'rsa.misc.filter', + type: 'keyword', + }, + 'rsa.misc.serial_number': { + category: 'rsa', + description: 'This key is the Serial number associated with a physical asset.', + name: 'rsa.misc.serial_number', + type: 'keyword', + }, + 'rsa.misc.checksum': { + category: 'rsa', + description: + 'This key is used to capture the checksum or hash of the entity such as a file or process. Checksum should be used over checksum.src or checksum.dst when it is unclear whether the entity is a source or target of an action.', + name: 'rsa.misc.checksum', + type: 'keyword', + }, + 'rsa.misc.event_user': { + category: 'rsa', + description: + 'This key is a windows only concept, where this key is used to capture combination of domain name and username in a windows log.', + name: 'rsa.misc.event_user', + type: 'keyword', + }, + 'rsa.misc.virusname': { + category: 'rsa', + description: 'This key captures the name of the virus', + name: 'rsa.misc.virusname', + type: 'keyword', + }, + 'rsa.misc.content_type': { + category: 'rsa', + description: 'This key is used to capture Content Type only.', + name: 'rsa.misc.content_type', + type: 'keyword', + }, + 'rsa.misc.group_id': { + category: 'rsa', + description: 'This key captures Group ID Number (related to the group name)', + name: 'rsa.misc.group_id', + type: 'keyword', + }, + 'rsa.misc.policy_id': { + category: 'rsa', + description: + 'This key is used to capture the Policy ID only, this should be a numeric value, use policy.name otherwise', + name: 'rsa.misc.policy_id', + type: 'keyword', + }, + 'rsa.misc.vsys': { + category: 'rsa', + description: 'This key captures Virtual System Name', + name: 'rsa.misc.vsys', + type: 'keyword', + }, + 'rsa.misc.connection_id': { + category: 'rsa', + description: 'This key captures the Connection ID', + name: 'rsa.misc.connection_id', + type: 'keyword', + }, + 'rsa.misc.reference_id2': { + category: 'rsa', + description: + 'This key is for the 2nd Linked ID. Can be either linked to "reference.id" or "reference.id1" value but should not be used unless the other two variables are in play.', + name: 'rsa.misc.reference_id2', + type: 'keyword', + }, + 'rsa.misc.sensor': { + category: 'rsa', + description: 'This key captures Name of the sensor. Typically used in IDS/IPS based devices', + name: 'rsa.misc.sensor', + type: 'keyword', + }, + 'rsa.misc.sig_id': { + category: 'rsa', + description: 'This key captures IDS/IPS Int Signature ID', + name: 'rsa.misc.sig_id', + type: 'long', + }, + 'rsa.misc.port_name': { + category: 'rsa', + description: + 'This key is used for Physical or logical port connection but does NOT include a network port. (Example: Printer port name).', + name: 'rsa.misc.port_name', + type: 'keyword', + }, + 'rsa.misc.rule_group': { + category: 'rsa', + description: 'This key captures the Rule group name', + name: 'rsa.misc.rule_group', + type: 'keyword', + }, + 'rsa.misc.risk_num': { + category: 'rsa', + description: 'This key captures a Numeric Risk value', + name: 'rsa.misc.risk_num', + type: 'double', + }, + 'rsa.misc.trigger_val': { + category: 'rsa', + description: 'This key captures the Value of the trigger or threshold condition.', + name: 'rsa.misc.trigger_val', + type: 'keyword', + }, + 'rsa.misc.log_session_id1': { + category: 'rsa', + description: + 'This key is used to capture a Linked (Related) Session ID from the session directly', + name: 'rsa.misc.log_session_id1', + type: 'keyword', + }, + 'rsa.misc.comp_version': { + category: 'rsa', + description: 'This key captures the Version level of a sub-component of a product.', + name: 'rsa.misc.comp_version', + type: 'keyword', + }, + 'rsa.misc.content_version': { + category: 'rsa', + description: 'This key captures Version level of a signature or database content.', + name: 'rsa.misc.content_version', + type: 'keyword', + }, + 'rsa.misc.hardware_id': { + category: 'rsa', + description: + 'This key is used to capture unique identifier for a device or system (NOT a Mac address)', + name: 'rsa.misc.hardware_id', + type: 'keyword', + }, + 'rsa.misc.risk': { + category: 'rsa', + description: 'This key captures the non-numeric risk value', + name: 'rsa.misc.risk', + type: 'keyword', + }, + 'rsa.misc.event_id': { + category: 'rsa', + name: 'rsa.misc.event_id', + type: 'keyword', + }, + 'rsa.misc.reason': { + category: 'rsa', + name: 'rsa.misc.reason', + type: 'keyword', + }, + 'rsa.misc.status': { + category: 'rsa', + name: 'rsa.misc.status', + type: 'keyword', + }, + 'rsa.misc.mail_id': { + category: 'rsa', + description: 'This key is used to capture the mailbox id/name', + name: 'rsa.misc.mail_id', + type: 'keyword', + }, + 'rsa.misc.rule_uid': { + category: 'rsa', + description: 'This key is the Unique Identifier for a rule.', + name: 'rsa.misc.rule_uid', + type: 'keyword', + }, + 'rsa.misc.trigger_desc': { + category: 'rsa', + description: 'This key captures the Description of the trigger or threshold condition.', + name: 'rsa.misc.trigger_desc', + type: 'keyword', + }, + 'rsa.misc.inout': { + category: 'rsa', + name: 'rsa.misc.inout', + type: 'keyword', + }, + 'rsa.misc.p_msgid': { + category: 'rsa', + name: 'rsa.misc.p_msgid', + type: 'keyword', + }, + 'rsa.misc.data_type': { + category: 'rsa', + name: 'rsa.misc.data_type', + type: 'keyword', + }, + 'rsa.misc.msgIdPart4': { + category: 'rsa', + name: 'rsa.misc.msgIdPart4', + type: 'keyword', + }, + 'rsa.misc.error': { + category: 'rsa', + description: 'This key captures All non successful Error codes or responses', + name: 'rsa.misc.error', + type: 'keyword', + }, + 'rsa.misc.index': { + category: 'rsa', + name: 'rsa.misc.index', + type: 'keyword', + }, + 'rsa.misc.listnum': { + category: 'rsa', + description: + 'This key is used to capture listname or listnumber, primarily for collecting access-list', + name: 'rsa.misc.listnum', + type: 'keyword', + }, + 'rsa.misc.ntype': { + category: 'rsa', + name: 'rsa.misc.ntype', + type: 'keyword', + }, + 'rsa.misc.observed_val': { + category: 'rsa', + description: + 'This key captures the Value observed (from the perspective of the device generating the log).', + name: 'rsa.misc.observed_val', + type: 'keyword', + }, + 'rsa.misc.policy_value': { + category: 'rsa', + description: + 'This key captures the contents of the policy. This contains details about the policy', + name: 'rsa.misc.policy_value', + type: 'keyword', + }, + 'rsa.misc.pool_name': { + category: 'rsa', + description: 'This key captures the name of a resource pool', + name: 'rsa.misc.pool_name', + type: 'keyword', + }, + 'rsa.misc.rule_template': { + category: 'rsa', + description: + 'A default set of parameters which are overlayed onto a rule (or rulename) which efffectively constitutes a template', + name: 'rsa.misc.rule_template', + type: 'keyword', + }, + 'rsa.misc.count': { + category: 'rsa', + name: 'rsa.misc.count', + type: 'keyword', + }, + 'rsa.misc.number': { + category: 'rsa', + name: 'rsa.misc.number', + type: 'keyword', + }, + 'rsa.misc.sigcat': { + category: 'rsa', + name: 'rsa.misc.sigcat', + type: 'keyword', + }, + 'rsa.misc.type': { + category: 'rsa', + name: 'rsa.misc.type', + type: 'keyword', + }, + 'rsa.misc.comments': { + category: 'rsa', + description: 'Comment information provided in the log message', + name: 'rsa.misc.comments', + type: 'keyword', + }, + 'rsa.misc.doc_number': { + category: 'rsa', + description: 'This key captures File Identification number', + name: 'rsa.misc.doc_number', + type: 'long', + }, + 'rsa.misc.expected_val': { + category: 'rsa', + description: + 'This key captures the Value expected (from the perspective of the device generating the log).', + name: 'rsa.misc.expected_val', + type: 'keyword', + }, + 'rsa.misc.job_num': { + category: 'rsa', + description: 'This key captures the Job Number', + name: 'rsa.misc.job_num', + type: 'keyword', + }, + 'rsa.misc.spi_dst': { + category: 'rsa', + description: 'Destination SPI Index', + name: 'rsa.misc.spi_dst', + type: 'keyword', + }, + 'rsa.misc.spi_src': { + category: 'rsa', + description: 'Source SPI Index', + name: 'rsa.misc.spi_src', + type: 'keyword', + }, + 'rsa.misc.code': { + category: 'rsa', + name: 'rsa.misc.code', + type: 'keyword', + }, + 'rsa.misc.agent_id': { + category: 'rsa', + description: 'This key is used to capture agent id', + name: 'rsa.misc.agent_id', + type: 'keyword', + }, + 'rsa.misc.message_body': { + category: 'rsa', + description: 'This key captures the The contents of the message body.', + name: 'rsa.misc.message_body', + type: 'keyword', + }, + 'rsa.misc.phone': { + category: 'rsa', + name: 'rsa.misc.phone', + type: 'keyword', + }, + 'rsa.misc.sig_id_str': { + category: 'rsa', + description: 'This key captures a string object of the sigid variable.', + name: 'rsa.misc.sig_id_str', + type: 'keyword', + }, + 'rsa.misc.cmd': { + category: 'rsa', + name: 'rsa.misc.cmd', + type: 'keyword', + }, + 'rsa.misc.misc': { + category: 'rsa', + name: 'rsa.misc.misc', + type: 'keyword', + }, + 'rsa.misc.name': { + category: 'rsa', + name: 'rsa.misc.name', + type: 'keyword', + }, + 'rsa.misc.cpu': { + category: 'rsa', + description: 'This key is the CPU time used in the execution of the event being recorded.', + name: 'rsa.misc.cpu', + type: 'long', + }, + 'rsa.misc.event_desc': { + category: 'rsa', + description: + 'This key is used to capture a description of an event available directly or inferred', + name: 'rsa.misc.event_desc', + type: 'keyword', + }, + 'rsa.misc.sig_id1': { + category: 'rsa', + description: 'This key captures IDS/IPS Int Signature ID. This must be linked to the sig.id', + name: 'rsa.misc.sig_id1', + type: 'long', + }, + 'rsa.misc.im_buddyid': { + category: 'rsa', + name: 'rsa.misc.im_buddyid', + type: 'keyword', + }, + 'rsa.misc.im_client': { + category: 'rsa', + name: 'rsa.misc.im_client', + type: 'keyword', + }, + 'rsa.misc.im_userid': { + category: 'rsa', + name: 'rsa.misc.im_userid', + type: 'keyword', + }, + 'rsa.misc.pid': { + category: 'rsa', + name: 'rsa.misc.pid', + type: 'keyword', + }, + 'rsa.misc.priority': { + category: 'rsa', + name: 'rsa.misc.priority', + type: 'keyword', + }, + 'rsa.misc.context_subject': { + category: 'rsa', + description: + 'This key is to be used in an audit context where the subject is the object being identified', + name: 'rsa.misc.context_subject', + type: 'keyword', + }, + 'rsa.misc.context_target': { + category: 'rsa', + name: 'rsa.misc.context_target', + type: 'keyword', + }, + 'rsa.misc.cve': { + category: 'rsa', + description: + 'This key captures CVE (Common Vulnerabilities and Exposures) - an identifier for known information security vulnerabilities.', + name: 'rsa.misc.cve', + type: 'keyword', + }, + 'rsa.misc.fcatnum': { + category: 'rsa', + description: 'This key captures Filter Category Number. Legacy Usage', + name: 'rsa.misc.fcatnum', + type: 'keyword', + }, + 'rsa.misc.library': { + category: 'rsa', + description: 'This key is used to capture library information in mainframe devices', + name: 'rsa.misc.library', + type: 'keyword', + }, + 'rsa.misc.parent_node': { + category: 'rsa', + description: 'This key captures the Parent Node Name. Must be related to node variable.', + name: 'rsa.misc.parent_node', + type: 'keyword', + }, + 'rsa.misc.risk_info': { + category: 'rsa', + description: 'Deprecated, use New Hunting Model (inv.*, ioc, boc, eoc, analysis.*)', + name: 'rsa.misc.risk_info', + type: 'keyword', + }, + 'rsa.misc.tcp_flags': { + category: 'rsa', + description: 'This key is captures the TCP flags set in any packet of session', + name: 'rsa.misc.tcp_flags', + type: 'long', + }, + 'rsa.misc.tos': { + category: 'rsa', + description: 'This key describes the type of service', + name: 'rsa.misc.tos', + type: 'long', + }, + 'rsa.misc.vm_target': { + category: 'rsa', + description: 'VMWare Target **VMWARE** only varaible.', + name: 'rsa.misc.vm_target', + type: 'keyword', + }, + 'rsa.misc.workspace': { + category: 'rsa', + description: 'This key captures Workspace Description', + name: 'rsa.misc.workspace', + type: 'keyword', + }, + 'rsa.misc.command': { + category: 'rsa', + name: 'rsa.misc.command', + type: 'keyword', + }, + 'rsa.misc.event_category': { + category: 'rsa', + name: 'rsa.misc.event_category', + type: 'keyword', + }, + 'rsa.misc.facilityname': { + category: 'rsa', + name: 'rsa.misc.facilityname', + type: 'keyword', + }, + 'rsa.misc.forensic_info': { + category: 'rsa', + name: 'rsa.misc.forensic_info', + type: 'keyword', + }, + 'rsa.misc.jobname': { + category: 'rsa', + name: 'rsa.misc.jobname', + type: 'keyword', + }, + 'rsa.misc.mode': { + category: 'rsa', + name: 'rsa.misc.mode', + type: 'keyword', + }, + 'rsa.misc.policy': { + category: 'rsa', + name: 'rsa.misc.policy', + type: 'keyword', + }, + 'rsa.misc.policy_waiver': { + category: 'rsa', + name: 'rsa.misc.policy_waiver', + type: 'keyword', + }, + 'rsa.misc.second': { + category: 'rsa', + name: 'rsa.misc.second', + type: 'keyword', + }, + 'rsa.misc.space1': { + category: 'rsa', + name: 'rsa.misc.space1', + type: 'keyword', + }, + 'rsa.misc.subcategory': { + category: 'rsa', + name: 'rsa.misc.subcategory', + type: 'keyword', + }, + 'rsa.misc.tbdstr2': { + category: 'rsa', + name: 'rsa.misc.tbdstr2', + type: 'keyword', + }, + 'rsa.misc.alert_id': { + category: 'rsa', + description: 'Deprecated, New Hunting Model (inv.*, ioc, boc, eoc, analysis.*)', + name: 'rsa.misc.alert_id', + type: 'keyword', + }, + 'rsa.misc.checksum_dst': { + category: 'rsa', + description: + 'This key is used to capture the checksum or hash of the the target entity such as a process or file.', + name: 'rsa.misc.checksum_dst', + type: 'keyword', + }, + 'rsa.misc.checksum_src': { + category: 'rsa', + description: + 'This key is used to capture the checksum or hash of the source entity such as a file or process.', + name: 'rsa.misc.checksum_src', + type: 'keyword', + }, + 'rsa.misc.fresult': { + category: 'rsa', + description: 'This key captures the Filter Result', + name: 'rsa.misc.fresult', + type: 'long', + }, + 'rsa.misc.payload_dst': { + category: 'rsa', + description: 'This key is used to capture destination payload', + name: 'rsa.misc.payload_dst', + type: 'keyword', + }, + 'rsa.misc.payload_src': { + category: 'rsa', + description: 'This key is used to capture source payload', + name: 'rsa.misc.payload_src', + type: 'keyword', + }, + 'rsa.misc.pool_id': { + category: 'rsa', + description: 'This key captures the identifier (typically numeric field) of a resource pool', + name: 'rsa.misc.pool_id', + type: 'keyword', + }, + 'rsa.misc.process_id_val': { + category: 'rsa', + description: 'This key is a failure key for Process ID when it is not an integer value', + name: 'rsa.misc.process_id_val', + type: 'keyword', + }, + 'rsa.misc.risk_num_comm': { + category: 'rsa', + description: 'This key captures Risk Number Community', + name: 'rsa.misc.risk_num_comm', + type: 'double', + }, + 'rsa.misc.risk_num_next': { + category: 'rsa', + description: 'This key captures Risk Number NextGen', + name: 'rsa.misc.risk_num_next', + type: 'double', + }, + 'rsa.misc.risk_num_sand': { + category: 'rsa', + description: 'This key captures Risk Number SandBox', + name: 'rsa.misc.risk_num_sand', + type: 'double', + }, + 'rsa.misc.risk_num_static': { + category: 'rsa', + description: 'This key captures Risk Number Static', + name: 'rsa.misc.risk_num_static', + type: 'double', + }, + 'rsa.misc.risk_suspicious': { + category: 'rsa', + description: 'Deprecated, use New Hunting Model (inv.*, ioc, boc, eoc, analysis.*)', + name: 'rsa.misc.risk_suspicious', + type: 'keyword', + }, + 'rsa.misc.risk_warning': { + category: 'rsa', + description: 'Deprecated, use New Hunting Model (inv.*, ioc, boc, eoc, analysis.*)', + name: 'rsa.misc.risk_warning', + type: 'keyword', + }, + 'rsa.misc.snmp_oid': { + category: 'rsa', + description: 'SNMP Object Identifier', + name: 'rsa.misc.snmp_oid', + type: 'keyword', + }, + 'rsa.misc.sql': { + category: 'rsa', + description: 'This key captures the SQL query', + name: 'rsa.misc.sql', + type: 'keyword', + }, + 'rsa.misc.vuln_ref': { + category: 'rsa', + description: 'This key captures the Vulnerability Reference details', + name: 'rsa.misc.vuln_ref', + type: 'keyword', + }, + 'rsa.misc.acl_id': { + category: 'rsa', + name: 'rsa.misc.acl_id', + type: 'keyword', + }, + 'rsa.misc.acl_op': { + category: 'rsa', + name: 'rsa.misc.acl_op', + type: 'keyword', + }, + 'rsa.misc.acl_pos': { + category: 'rsa', + name: 'rsa.misc.acl_pos', + type: 'keyword', + }, + 'rsa.misc.acl_table': { + category: 'rsa', + name: 'rsa.misc.acl_table', + type: 'keyword', + }, + 'rsa.misc.admin': { + category: 'rsa', + name: 'rsa.misc.admin', + type: 'keyword', + }, + 'rsa.misc.alarm_id': { + category: 'rsa', + name: 'rsa.misc.alarm_id', + type: 'keyword', + }, + 'rsa.misc.alarmname': { + category: 'rsa', + name: 'rsa.misc.alarmname', + type: 'keyword', + }, + 'rsa.misc.app_id': { + category: 'rsa', + name: 'rsa.misc.app_id', + type: 'keyword', + }, + 'rsa.misc.audit': { + category: 'rsa', + name: 'rsa.misc.audit', + type: 'keyword', + }, + 'rsa.misc.audit_object': { + category: 'rsa', + name: 'rsa.misc.audit_object', + type: 'keyword', + }, + 'rsa.misc.auditdata': { + category: 'rsa', + name: 'rsa.misc.auditdata', + type: 'keyword', + }, + 'rsa.misc.benchmark': { + category: 'rsa', + name: 'rsa.misc.benchmark', + type: 'keyword', + }, + 'rsa.misc.bypass': { + category: 'rsa', + name: 'rsa.misc.bypass', + type: 'keyword', + }, + 'rsa.misc.cache': { + category: 'rsa', + name: 'rsa.misc.cache', + type: 'keyword', + }, + 'rsa.misc.cache_hit': { + category: 'rsa', + name: 'rsa.misc.cache_hit', + type: 'keyword', + }, + 'rsa.misc.cefversion': { + category: 'rsa', + name: 'rsa.misc.cefversion', + type: 'keyword', + }, + 'rsa.misc.cfg_attr': { + category: 'rsa', + name: 'rsa.misc.cfg_attr', + type: 'keyword', + }, + 'rsa.misc.cfg_obj': { + category: 'rsa', + name: 'rsa.misc.cfg_obj', + type: 'keyword', + }, + 'rsa.misc.cfg_path': { + category: 'rsa', + name: 'rsa.misc.cfg_path', + type: 'keyword', + }, + 'rsa.misc.changes': { + category: 'rsa', + name: 'rsa.misc.changes', + type: 'keyword', + }, + 'rsa.misc.client_ip': { + category: 'rsa', + name: 'rsa.misc.client_ip', + type: 'keyword', + }, + 'rsa.misc.clustermembers': { + category: 'rsa', + name: 'rsa.misc.clustermembers', + type: 'keyword', + }, + 'rsa.misc.cn_acttimeout': { + category: 'rsa', + name: 'rsa.misc.cn_acttimeout', + type: 'keyword', + }, + 'rsa.misc.cn_asn_src': { + category: 'rsa', + name: 'rsa.misc.cn_asn_src', + type: 'keyword', + }, + 'rsa.misc.cn_bgpv4nxthop': { + category: 'rsa', + name: 'rsa.misc.cn_bgpv4nxthop', + type: 'keyword', + }, + 'rsa.misc.cn_ctr_dst_code': { + category: 'rsa', + name: 'rsa.misc.cn_ctr_dst_code', + type: 'keyword', + }, + 'rsa.misc.cn_dst_tos': { + category: 'rsa', + name: 'rsa.misc.cn_dst_tos', + type: 'keyword', + }, + 'rsa.misc.cn_dst_vlan': { + category: 'rsa', + name: 'rsa.misc.cn_dst_vlan', + type: 'keyword', + }, + 'rsa.misc.cn_engine_id': { + category: 'rsa', + name: 'rsa.misc.cn_engine_id', + type: 'keyword', + }, + 'rsa.misc.cn_engine_type': { + category: 'rsa', + name: 'rsa.misc.cn_engine_type', + type: 'keyword', + }, + 'rsa.misc.cn_f_switch': { + category: 'rsa', + name: 'rsa.misc.cn_f_switch', + type: 'keyword', + }, + 'rsa.misc.cn_flowsampid': { + category: 'rsa', + name: 'rsa.misc.cn_flowsampid', + type: 'keyword', + }, + 'rsa.misc.cn_flowsampintv': { + category: 'rsa', + name: 'rsa.misc.cn_flowsampintv', + type: 'keyword', + }, + 'rsa.misc.cn_flowsampmode': { + category: 'rsa', + name: 'rsa.misc.cn_flowsampmode', + type: 'keyword', + }, + 'rsa.misc.cn_inacttimeout': { + category: 'rsa', + name: 'rsa.misc.cn_inacttimeout', + type: 'keyword', + }, + 'rsa.misc.cn_inpermbyts': { + category: 'rsa', + name: 'rsa.misc.cn_inpermbyts', + type: 'keyword', + }, + 'rsa.misc.cn_inpermpckts': { + category: 'rsa', + name: 'rsa.misc.cn_inpermpckts', + type: 'keyword', + }, + 'rsa.misc.cn_invalid': { + category: 'rsa', + name: 'rsa.misc.cn_invalid', + type: 'keyword', + }, + 'rsa.misc.cn_ip_proto_ver': { + category: 'rsa', + name: 'rsa.misc.cn_ip_proto_ver', + type: 'keyword', + }, + 'rsa.misc.cn_ipv4_ident': { + category: 'rsa', + name: 'rsa.misc.cn_ipv4_ident', + type: 'keyword', + }, + 'rsa.misc.cn_l_switch': { + category: 'rsa', + name: 'rsa.misc.cn_l_switch', + type: 'keyword', + }, + 'rsa.misc.cn_log_did': { + category: 'rsa', + name: 'rsa.misc.cn_log_did', + type: 'keyword', + }, + 'rsa.misc.cn_log_rid': { + category: 'rsa', + name: 'rsa.misc.cn_log_rid', + type: 'keyword', + }, + 'rsa.misc.cn_max_ttl': { + category: 'rsa', + name: 'rsa.misc.cn_max_ttl', + type: 'keyword', + }, + 'rsa.misc.cn_maxpcktlen': { + category: 'rsa', + name: 'rsa.misc.cn_maxpcktlen', + type: 'keyword', + }, + 'rsa.misc.cn_min_ttl': { + category: 'rsa', + name: 'rsa.misc.cn_min_ttl', + type: 'keyword', + }, + 'rsa.misc.cn_minpcktlen': { + category: 'rsa', + name: 'rsa.misc.cn_minpcktlen', + type: 'keyword', + }, + 'rsa.misc.cn_mpls_lbl_1': { + category: 'rsa', + name: 'rsa.misc.cn_mpls_lbl_1', + type: 'keyword', + }, + 'rsa.misc.cn_mpls_lbl_10': { + category: 'rsa', + name: 'rsa.misc.cn_mpls_lbl_10', + type: 'keyword', + }, + 'rsa.misc.cn_mpls_lbl_2': { + category: 'rsa', + name: 'rsa.misc.cn_mpls_lbl_2', + type: 'keyword', + }, + 'rsa.misc.cn_mpls_lbl_3': { + category: 'rsa', + name: 'rsa.misc.cn_mpls_lbl_3', + type: 'keyword', + }, + 'rsa.misc.cn_mpls_lbl_4': { + category: 'rsa', + name: 'rsa.misc.cn_mpls_lbl_4', + type: 'keyword', + }, + 'rsa.misc.cn_mpls_lbl_5': { + category: 'rsa', + name: 'rsa.misc.cn_mpls_lbl_5', + type: 'keyword', + }, + 'rsa.misc.cn_mpls_lbl_6': { + category: 'rsa', + name: 'rsa.misc.cn_mpls_lbl_6', + type: 'keyword', + }, + 'rsa.misc.cn_mpls_lbl_7': { + category: 'rsa', + name: 'rsa.misc.cn_mpls_lbl_7', + type: 'keyword', + }, + 'rsa.misc.cn_mpls_lbl_8': { + category: 'rsa', + name: 'rsa.misc.cn_mpls_lbl_8', + type: 'keyword', + }, + 'rsa.misc.cn_mpls_lbl_9': { + category: 'rsa', + name: 'rsa.misc.cn_mpls_lbl_9', + type: 'keyword', + }, + 'rsa.misc.cn_mplstoplabel': { + category: 'rsa', + name: 'rsa.misc.cn_mplstoplabel', + type: 'keyword', + }, + 'rsa.misc.cn_mplstoplabip': { + category: 'rsa', + name: 'rsa.misc.cn_mplstoplabip', + type: 'keyword', + }, + 'rsa.misc.cn_mul_dst_byt': { + category: 'rsa', + name: 'rsa.misc.cn_mul_dst_byt', + type: 'keyword', + }, + 'rsa.misc.cn_mul_dst_pks': { + category: 'rsa', + name: 'rsa.misc.cn_mul_dst_pks', + type: 'keyword', + }, + 'rsa.misc.cn_muligmptype': { + category: 'rsa', + name: 'rsa.misc.cn_muligmptype', + type: 'keyword', + }, + 'rsa.misc.cn_sampalgo': { + category: 'rsa', + name: 'rsa.misc.cn_sampalgo', + type: 'keyword', + }, + 'rsa.misc.cn_sampint': { + category: 'rsa', + name: 'rsa.misc.cn_sampint', + type: 'keyword', + }, + 'rsa.misc.cn_seqctr': { + category: 'rsa', + name: 'rsa.misc.cn_seqctr', + type: 'keyword', + }, + 'rsa.misc.cn_spackets': { + category: 'rsa', + name: 'rsa.misc.cn_spackets', + type: 'keyword', + }, + 'rsa.misc.cn_src_tos': { + category: 'rsa', + name: 'rsa.misc.cn_src_tos', + type: 'keyword', + }, + 'rsa.misc.cn_src_vlan': { + category: 'rsa', + name: 'rsa.misc.cn_src_vlan', + type: 'keyword', + }, + 'rsa.misc.cn_sysuptime': { + category: 'rsa', + name: 'rsa.misc.cn_sysuptime', + type: 'keyword', + }, + 'rsa.misc.cn_template_id': { + category: 'rsa', + name: 'rsa.misc.cn_template_id', + type: 'keyword', + }, + 'rsa.misc.cn_totbytsexp': { + category: 'rsa', + name: 'rsa.misc.cn_totbytsexp', + type: 'keyword', + }, + 'rsa.misc.cn_totflowexp': { + category: 'rsa', + name: 'rsa.misc.cn_totflowexp', + type: 'keyword', + }, + 'rsa.misc.cn_totpcktsexp': { + category: 'rsa', + name: 'rsa.misc.cn_totpcktsexp', + type: 'keyword', + }, + 'rsa.misc.cn_unixnanosecs': { + category: 'rsa', + name: 'rsa.misc.cn_unixnanosecs', + type: 'keyword', + }, + 'rsa.misc.cn_v6flowlabel': { + category: 'rsa', + name: 'rsa.misc.cn_v6flowlabel', + type: 'keyword', + }, + 'rsa.misc.cn_v6optheaders': { + category: 'rsa', + name: 'rsa.misc.cn_v6optheaders', + type: 'keyword', + }, + 'rsa.misc.comp_class': { + category: 'rsa', + name: 'rsa.misc.comp_class', + type: 'keyword', + }, + 'rsa.misc.comp_name': { + category: 'rsa', + name: 'rsa.misc.comp_name', + type: 'keyword', + }, + 'rsa.misc.comp_rbytes': { + category: 'rsa', + name: 'rsa.misc.comp_rbytes', + type: 'keyword', + }, + 'rsa.misc.comp_sbytes': { + category: 'rsa', + name: 'rsa.misc.comp_sbytes', + type: 'keyword', + }, + 'rsa.misc.cpu_data': { + category: 'rsa', + name: 'rsa.misc.cpu_data', + type: 'keyword', + }, + 'rsa.misc.criticality': { + category: 'rsa', + name: 'rsa.misc.criticality', + type: 'keyword', + }, + 'rsa.misc.cs_agency_dst': { + category: 'rsa', + name: 'rsa.misc.cs_agency_dst', + type: 'keyword', + }, + 'rsa.misc.cs_analyzedby': { + category: 'rsa', + name: 'rsa.misc.cs_analyzedby', + type: 'keyword', + }, + 'rsa.misc.cs_av_other': { + category: 'rsa', + name: 'rsa.misc.cs_av_other', + type: 'keyword', + }, + 'rsa.misc.cs_av_primary': { + category: 'rsa', + name: 'rsa.misc.cs_av_primary', + type: 'keyword', + }, + 'rsa.misc.cs_av_secondary': { + category: 'rsa', + name: 'rsa.misc.cs_av_secondary', + type: 'keyword', + }, + 'rsa.misc.cs_bgpv6nxthop': { + category: 'rsa', + name: 'rsa.misc.cs_bgpv6nxthop', + type: 'keyword', + }, + 'rsa.misc.cs_bit9status': { + category: 'rsa', + name: 'rsa.misc.cs_bit9status', + type: 'keyword', + }, + 'rsa.misc.cs_context': { + category: 'rsa', + name: 'rsa.misc.cs_context', + type: 'keyword', + }, + 'rsa.misc.cs_control': { + category: 'rsa', + name: 'rsa.misc.cs_control', + type: 'keyword', + }, + 'rsa.misc.cs_data': { + category: 'rsa', + name: 'rsa.misc.cs_data', + type: 'keyword', + }, + 'rsa.misc.cs_datecret': { + category: 'rsa', + name: 'rsa.misc.cs_datecret', + type: 'keyword', + }, + 'rsa.misc.cs_dst_tld': { + category: 'rsa', + name: 'rsa.misc.cs_dst_tld', + type: 'keyword', + }, + 'rsa.misc.cs_eth_dst_ven': { + category: 'rsa', + name: 'rsa.misc.cs_eth_dst_ven', + type: 'keyword', + }, + 'rsa.misc.cs_eth_src_ven': { + category: 'rsa', + name: 'rsa.misc.cs_eth_src_ven', + type: 'keyword', + }, + 'rsa.misc.cs_event_uuid': { + category: 'rsa', + name: 'rsa.misc.cs_event_uuid', + type: 'keyword', + }, + 'rsa.misc.cs_filetype': { + category: 'rsa', + name: 'rsa.misc.cs_filetype', + type: 'keyword', + }, + 'rsa.misc.cs_fld': { + category: 'rsa', + name: 'rsa.misc.cs_fld', + type: 'keyword', + }, + 'rsa.misc.cs_if_desc': { + category: 'rsa', + name: 'rsa.misc.cs_if_desc', + type: 'keyword', + }, + 'rsa.misc.cs_if_name': { + category: 'rsa', + name: 'rsa.misc.cs_if_name', + type: 'keyword', + }, + 'rsa.misc.cs_ip_next_hop': { + category: 'rsa', + name: 'rsa.misc.cs_ip_next_hop', + type: 'keyword', + }, + 'rsa.misc.cs_ipv4dstpre': { + category: 'rsa', + name: 'rsa.misc.cs_ipv4dstpre', + type: 'keyword', + }, + 'rsa.misc.cs_ipv4srcpre': { + category: 'rsa', + name: 'rsa.misc.cs_ipv4srcpre', + type: 'keyword', + }, + 'rsa.misc.cs_lifetime': { + category: 'rsa', + name: 'rsa.misc.cs_lifetime', + type: 'keyword', + }, + 'rsa.misc.cs_log_medium': { + category: 'rsa', + name: 'rsa.misc.cs_log_medium', + type: 'keyword', + }, + 'rsa.misc.cs_loginname': { + category: 'rsa', + name: 'rsa.misc.cs_loginname', + type: 'keyword', + }, + 'rsa.misc.cs_modulescore': { + category: 'rsa', + name: 'rsa.misc.cs_modulescore', + type: 'keyword', + }, + 'rsa.misc.cs_modulesign': { + category: 'rsa', + name: 'rsa.misc.cs_modulesign', + type: 'keyword', + }, + 'rsa.misc.cs_opswatresult': { + category: 'rsa', + name: 'rsa.misc.cs_opswatresult', + type: 'keyword', + }, + 'rsa.misc.cs_payload': { + category: 'rsa', + name: 'rsa.misc.cs_payload', + type: 'keyword', + }, + 'rsa.misc.cs_registrant': { + category: 'rsa', + name: 'rsa.misc.cs_registrant', + type: 'keyword', + }, + 'rsa.misc.cs_registrar': { + category: 'rsa', + name: 'rsa.misc.cs_registrar', + type: 'keyword', + }, + 'rsa.misc.cs_represult': { + category: 'rsa', + name: 'rsa.misc.cs_represult', + type: 'keyword', + }, + 'rsa.misc.cs_rpayload': { + category: 'rsa', + name: 'rsa.misc.cs_rpayload', + type: 'keyword', + }, + 'rsa.misc.cs_sampler_name': { + category: 'rsa', + name: 'rsa.misc.cs_sampler_name', + type: 'keyword', + }, + 'rsa.misc.cs_sourcemodule': { + category: 'rsa', + name: 'rsa.misc.cs_sourcemodule', + type: 'keyword', + }, + 'rsa.misc.cs_streams': { + category: 'rsa', + name: 'rsa.misc.cs_streams', + type: 'keyword', + }, + 'rsa.misc.cs_targetmodule': { + category: 'rsa', + name: 'rsa.misc.cs_targetmodule', + type: 'keyword', + }, + 'rsa.misc.cs_v6nxthop': { + category: 'rsa', + name: 'rsa.misc.cs_v6nxthop', + type: 'keyword', + }, + 'rsa.misc.cs_whois_server': { + category: 'rsa', + name: 'rsa.misc.cs_whois_server', + type: 'keyword', + }, + 'rsa.misc.cs_yararesult': { + category: 'rsa', + name: 'rsa.misc.cs_yararesult', + type: 'keyword', + }, + 'rsa.misc.description': { + category: 'rsa', + name: 'rsa.misc.description', + type: 'keyword', + }, + 'rsa.misc.devvendor': { + category: 'rsa', + name: 'rsa.misc.devvendor', + type: 'keyword', + }, + 'rsa.misc.distance': { + category: 'rsa', + name: 'rsa.misc.distance', + type: 'keyword', + }, + 'rsa.misc.dstburb': { + category: 'rsa', + name: 'rsa.misc.dstburb', + type: 'keyword', + }, + 'rsa.misc.edomain': { + category: 'rsa', + name: 'rsa.misc.edomain', + type: 'keyword', + }, + 'rsa.misc.edomaub': { + category: 'rsa', + name: 'rsa.misc.edomaub', + type: 'keyword', + }, + 'rsa.misc.euid': { + category: 'rsa', + name: 'rsa.misc.euid', + type: 'keyword', + }, + 'rsa.misc.facility': { + category: 'rsa', + name: 'rsa.misc.facility', + type: 'keyword', + }, + 'rsa.misc.finterface': { + category: 'rsa', + name: 'rsa.misc.finterface', + type: 'keyword', + }, + 'rsa.misc.flags': { + category: 'rsa', + name: 'rsa.misc.flags', + type: 'keyword', + }, + 'rsa.misc.gaddr': { + category: 'rsa', + name: 'rsa.misc.gaddr', + type: 'keyword', + }, + 'rsa.misc.id3': { + category: 'rsa', + name: 'rsa.misc.id3', + type: 'keyword', + }, + 'rsa.misc.im_buddyname': { + category: 'rsa', + name: 'rsa.misc.im_buddyname', + type: 'keyword', + }, + 'rsa.misc.im_croomid': { + category: 'rsa', + name: 'rsa.misc.im_croomid', + type: 'keyword', + }, + 'rsa.misc.im_croomtype': { + category: 'rsa', + name: 'rsa.misc.im_croomtype', + type: 'keyword', + }, + 'rsa.misc.im_members': { + category: 'rsa', + name: 'rsa.misc.im_members', + type: 'keyword', + }, + 'rsa.misc.im_username': { + category: 'rsa', + name: 'rsa.misc.im_username', + type: 'keyword', + }, + 'rsa.misc.ipkt': { + category: 'rsa', + name: 'rsa.misc.ipkt', + type: 'keyword', + }, + 'rsa.misc.ipscat': { + category: 'rsa', + name: 'rsa.misc.ipscat', + type: 'keyword', + }, + 'rsa.misc.ipspri': { + category: 'rsa', + name: 'rsa.misc.ipspri', + type: 'keyword', + }, + 'rsa.misc.latitude': { + category: 'rsa', + name: 'rsa.misc.latitude', + type: 'keyword', + }, + 'rsa.misc.linenum': { + category: 'rsa', + name: 'rsa.misc.linenum', + type: 'keyword', + }, + 'rsa.misc.list_name': { + category: 'rsa', + name: 'rsa.misc.list_name', + type: 'keyword', + }, + 'rsa.misc.load_data': { + category: 'rsa', + name: 'rsa.misc.load_data', + type: 'keyword', + }, + 'rsa.misc.location_floor': { + category: 'rsa', + name: 'rsa.misc.location_floor', + type: 'keyword', + }, + 'rsa.misc.location_mark': { + category: 'rsa', + name: 'rsa.misc.location_mark', + type: 'keyword', + }, + 'rsa.misc.log_id': { + category: 'rsa', + name: 'rsa.misc.log_id', + type: 'keyword', + }, + 'rsa.misc.log_type': { + category: 'rsa', + name: 'rsa.misc.log_type', + type: 'keyword', + }, + 'rsa.misc.logid': { + category: 'rsa', + name: 'rsa.misc.logid', + type: 'keyword', + }, + 'rsa.misc.logip': { + category: 'rsa', + name: 'rsa.misc.logip', + type: 'keyword', + }, + 'rsa.misc.logname': { + category: 'rsa', + name: 'rsa.misc.logname', + type: 'keyword', + }, + 'rsa.misc.longitude': { + category: 'rsa', + name: 'rsa.misc.longitude', + type: 'keyword', + }, + 'rsa.misc.lport': { + category: 'rsa', + name: 'rsa.misc.lport', + type: 'keyword', + }, + 'rsa.misc.mbug_data': { + category: 'rsa', + name: 'rsa.misc.mbug_data', + type: 'keyword', + }, + 'rsa.misc.misc_name': { + category: 'rsa', + name: 'rsa.misc.misc_name', + type: 'keyword', + }, + 'rsa.misc.msg_type': { + category: 'rsa', + name: 'rsa.misc.msg_type', + type: 'keyword', + }, + 'rsa.misc.msgid': { + category: 'rsa', + name: 'rsa.misc.msgid', + type: 'keyword', + }, + 'rsa.misc.netsessid': { + category: 'rsa', + name: 'rsa.misc.netsessid', + type: 'keyword', + }, + 'rsa.misc.num': { + category: 'rsa', + name: 'rsa.misc.num', + type: 'keyword', + }, + 'rsa.misc.number1': { + category: 'rsa', + name: 'rsa.misc.number1', + type: 'keyword', + }, + 'rsa.misc.number2': { + category: 'rsa', + name: 'rsa.misc.number2', + type: 'keyword', + }, + 'rsa.misc.nwwn': { + category: 'rsa', + name: 'rsa.misc.nwwn', + type: 'keyword', + }, + 'rsa.misc.object': { + category: 'rsa', + name: 'rsa.misc.object', + type: 'keyword', + }, + 'rsa.misc.operation': { + category: 'rsa', + name: 'rsa.misc.operation', + type: 'keyword', + }, + 'rsa.misc.opkt': { + category: 'rsa', + name: 'rsa.misc.opkt', + type: 'keyword', + }, + 'rsa.misc.orig_from': { + category: 'rsa', + name: 'rsa.misc.orig_from', + type: 'keyword', + }, + 'rsa.misc.owner_id': { + category: 'rsa', + name: 'rsa.misc.owner_id', + type: 'keyword', + }, + 'rsa.misc.p_action': { + category: 'rsa', + name: 'rsa.misc.p_action', + type: 'keyword', + }, + 'rsa.misc.p_filter': { + category: 'rsa', + name: 'rsa.misc.p_filter', + type: 'keyword', + }, + 'rsa.misc.p_group_object': { + category: 'rsa', + name: 'rsa.misc.p_group_object', + type: 'keyword', + }, + 'rsa.misc.p_id': { + category: 'rsa', + name: 'rsa.misc.p_id', + type: 'keyword', + }, + 'rsa.misc.p_msgid1': { + category: 'rsa', + name: 'rsa.misc.p_msgid1', + type: 'keyword', + }, + 'rsa.misc.p_msgid2': { + category: 'rsa', + name: 'rsa.misc.p_msgid2', + type: 'keyword', + }, + 'rsa.misc.p_result1': { + category: 'rsa', + name: 'rsa.misc.p_result1', + type: 'keyword', + }, + 'rsa.misc.password_chg': { + category: 'rsa', + name: 'rsa.misc.password_chg', + type: 'keyword', + }, + 'rsa.misc.password_expire': { + category: 'rsa', + name: 'rsa.misc.password_expire', + type: 'keyword', + }, + 'rsa.misc.permgranted': { + category: 'rsa', + name: 'rsa.misc.permgranted', + type: 'keyword', + }, + 'rsa.misc.permwanted': { + category: 'rsa', + name: 'rsa.misc.permwanted', + type: 'keyword', + }, + 'rsa.misc.pgid': { + category: 'rsa', + name: 'rsa.misc.pgid', + type: 'keyword', + }, + 'rsa.misc.policyUUID': { + category: 'rsa', + name: 'rsa.misc.policyUUID', + type: 'keyword', + }, + 'rsa.misc.prog_asp_num': { + category: 'rsa', + name: 'rsa.misc.prog_asp_num', + type: 'keyword', + }, + 'rsa.misc.program': { + category: 'rsa', + name: 'rsa.misc.program', + type: 'keyword', + }, + 'rsa.misc.real_data': { + category: 'rsa', + name: 'rsa.misc.real_data', + type: 'keyword', + }, + 'rsa.misc.rec_asp_device': { + category: 'rsa', + name: 'rsa.misc.rec_asp_device', + type: 'keyword', + }, + 'rsa.misc.rec_asp_num': { + category: 'rsa', + name: 'rsa.misc.rec_asp_num', + type: 'keyword', + }, + 'rsa.misc.rec_library': { + category: 'rsa', + name: 'rsa.misc.rec_library', + type: 'keyword', + }, + 'rsa.misc.recordnum': { + category: 'rsa', + name: 'rsa.misc.recordnum', + type: 'keyword', + }, + 'rsa.misc.ruid': { + category: 'rsa', + name: 'rsa.misc.ruid', + type: 'keyword', + }, + 'rsa.misc.sburb': { + category: 'rsa', + name: 'rsa.misc.sburb', + type: 'keyword', + }, + 'rsa.misc.sdomain_fld': { + category: 'rsa', + name: 'rsa.misc.sdomain_fld', + type: 'keyword', + }, + 'rsa.misc.sec': { + category: 'rsa', + name: 'rsa.misc.sec', + type: 'keyword', + }, + 'rsa.misc.sensorname': { + category: 'rsa', + name: 'rsa.misc.sensorname', + type: 'keyword', + }, + 'rsa.misc.seqnum': { + category: 'rsa', + name: 'rsa.misc.seqnum', + type: 'keyword', + }, + 'rsa.misc.session': { + category: 'rsa', + name: 'rsa.misc.session', + type: 'keyword', + }, + 'rsa.misc.sessiontype': { + category: 'rsa', + name: 'rsa.misc.sessiontype', + type: 'keyword', + }, + 'rsa.misc.sigUUID': { + category: 'rsa', + name: 'rsa.misc.sigUUID', + type: 'keyword', + }, + 'rsa.misc.spi': { + category: 'rsa', + name: 'rsa.misc.spi', + type: 'keyword', + }, + 'rsa.misc.srcburb': { + category: 'rsa', + name: 'rsa.misc.srcburb', + type: 'keyword', + }, + 'rsa.misc.srcdom': { + category: 'rsa', + name: 'rsa.misc.srcdom', + type: 'keyword', + }, + 'rsa.misc.srcservice': { + category: 'rsa', + name: 'rsa.misc.srcservice', + type: 'keyword', + }, + 'rsa.misc.state': { + category: 'rsa', + name: 'rsa.misc.state', + type: 'keyword', + }, + 'rsa.misc.status1': { + category: 'rsa', + name: 'rsa.misc.status1', + type: 'keyword', + }, + 'rsa.misc.svcno': { + category: 'rsa', + name: 'rsa.misc.svcno', + type: 'keyword', + }, + 'rsa.misc.system': { + category: 'rsa', + name: 'rsa.misc.system', + type: 'keyword', + }, + 'rsa.misc.tbdstr1': { + category: 'rsa', + name: 'rsa.misc.tbdstr1', + type: 'keyword', + }, + 'rsa.misc.tgtdom': { + category: 'rsa', + name: 'rsa.misc.tgtdom', + type: 'keyword', + }, + 'rsa.misc.tgtdomain': { + category: 'rsa', + name: 'rsa.misc.tgtdomain', + type: 'keyword', + }, + 'rsa.misc.threshold': { + category: 'rsa', + name: 'rsa.misc.threshold', + type: 'keyword', + }, + 'rsa.misc.type1': { + category: 'rsa', + name: 'rsa.misc.type1', + type: 'keyword', + }, + 'rsa.misc.udb_class': { + category: 'rsa', + name: 'rsa.misc.udb_class', + type: 'keyword', + }, + 'rsa.misc.url_fld': { + category: 'rsa', + name: 'rsa.misc.url_fld', + type: 'keyword', + }, + 'rsa.misc.user_div': { + category: 'rsa', + name: 'rsa.misc.user_div', + type: 'keyword', + }, + 'rsa.misc.userid': { + category: 'rsa', + name: 'rsa.misc.userid', + type: 'keyword', + }, + 'rsa.misc.username_fld': { + category: 'rsa', + name: 'rsa.misc.username_fld', + type: 'keyword', + }, + 'rsa.misc.utcstamp': { + category: 'rsa', + name: 'rsa.misc.utcstamp', + type: 'keyword', + }, + 'rsa.misc.v_instafname': { + category: 'rsa', + name: 'rsa.misc.v_instafname', + type: 'keyword', + }, + 'rsa.misc.virt_data': { + category: 'rsa', + name: 'rsa.misc.virt_data', + type: 'keyword', + }, + 'rsa.misc.vpnid': { + category: 'rsa', + name: 'rsa.misc.vpnid', + type: 'keyword', + }, + 'rsa.misc.autorun_type': { + category: 'rsa', + description: 'This is used to capture Auto Run type', + name: 'rsa.misc.autorun_type', + type: 'keyword', + }, + 'rsa.misc.cc_number': { + category: 'rsa', + description: 'Valid Credit Card Numbers only', + name: 'rsa.misc.cc_number', + type: 'long', + }, + 'rsa.misc.content': { + category: 'rsa', + description: 'This key captures the content type from protocol headers', + name: 'rsa.misc.content', + type: 'keyword', + }, + 'rsa.misc.ein_number': { + category: 'rsa', + description: 'Employee Identification Numbers only', + name: 'rsa.misc.ein_number', + type: 'long', + }, + 'rsa.misc.found': { + category: 'rsa', + description: 'This is used to capture the results of regex match', + name: 'rsa.misc.found', + type: 'keyword', + }, + 'rsa.misc.language': { + category: 'rsa', + description: 'This is used to capture list of languages the client support and what it prefers', + name: 'rsa.misc.language', + type: 'keyword', + }, + 'rsa.misc.lifetime': { + category: 'rsa', + description: 'This key is used to capture the session lifetime in seconds.', + name: 'rsa.misc.lifetime', + type: 'long', + }, + 'rsa.misc.link': { + category: 'rsa', + description: + 'This key is used to link the sessions together. This key should never be used to parse Meta data from a session (Logs/Packets) Directly, this is a Reserved key in NetWitness', + name: 'rsa.misc.link', + type: 'keyword', + }, + 'rsa.misc.match': { + category: 'rsa', + description: 'This key is for regex match name from search.ini', + name: 'rsa.misc.match', + type: 'keyword', + }, + 'rsa.misc.param_dst': { + category: 'rsa', + description: 'This key captures the command line/launch argument of the target process or file', + name: 'rsa.misc.param_dst', + type: 'keyword', + }, + 'rsa.misc.param_src': { + category: 'rsa', + description: 'This key captures source parameter', + name: 'rsa.misc.param_src', + type: 'keyword', + }, + 'rsa.misc.search_text': { + category: 'rsa', + description: 'This key captures the Search Text used', + name: 'rsa.misc.search_text', + type: 'keyword', + }, + 'rsa.misc.sig_name': { + category: 'rsa', + description: 'This key is used to capture the Signature Name only.', + name: 'rsa.misc.sig_name', + type: 'keyword', + }, + 'rsa.misc.snmp_value': { + category: 'rsa', + description: 'SNMP set request value', + name: 'rsa.misc.snmp_value', + type: 'keyword', + }, + 'rsa.misc.streams': { + category: 'rsa', + description: 'This key captures number of streams in session', + name: 'rsa.misc.streams', + type: 'long', + }, + 'rsa.db.index': { + category: 'rsa', + description: 'This key captures IndexID of the index.', + name: 'rsa.db.index', + type: 'keyword', + }, + 'rsa.db.instance': { + category: 'rsa', + description: 'This key is used to capture the database server instance name', + name: 'rsa.db.instance', + type: 'keyword', + }, + 'rsa.db.database': { + category: 'rsa', + description: + 'This key is used to capture the name of a database or an instance as seen in a session', + name: 'rsa.db.database', + type: 'keyword', + }, + 'rsa.db.transact_id': { + category: 'rsa', + description: 'This key captures the SQL transantion ID of the current session', + name: 'rsa.db.transact_id', + type: 'keyword', + }, + 'rsa.db.permissions': { + category: 'rsa', + description: 'This key captures permission or privilege level assigned to a resource.', + name: 'rsa.db.permissions', + type: 'keyword', + }, + 'rsa.db.table_name': { + category: 'rsa', + description: 'This key is used to capture the table name', + name: 'rsa.db.table_name', + type: 'keyword', + }, + 'rsa.db.db_id': { + category: 'rsa', + description: 'This key is used to capture the unique identifier for a database', + name: 'rsa.db.db_id', + type: 'keyword', + }, + 'rsa.db.db_pid': { + category: 'rsa', + description: 'This key captures the process id of a connection with database server', + name: 'rsa.db.db_pid', + type: 'long', + }, + 'rsa.db.lread': { + category: 'rsa', + description: 'This key is used for the number of logical reads', + name: 'rsa.db.lread', + type: 'long', + }, + 'rsa.db.lwrite': { + category: 'rsa', + description: 'This key is used for the number of logical writes', + name: 'rsa.db.lwrite', + type: 'long', + }, + 'rsa.db.pread': { + category: 'rsa', + description: 'This key is used for the number of physical writes', + name: 'rsa.db.pread', + type: 'long', + }, + 'rsa.network.alias_host': { + category: 'rsa', + description: + 'This key should be used when the source or destination context of a hostname is not clear.Also it captures the Device Hostname. Any Hostname that isnt ad.computer.', + name: 'rsa.network.alias_host', + type: 'keyword', + }, + 'rsa.network.domain': { + category: 'rsa', + name: 'rsa.network.domain', + type: 'keyword', + }, + 'rsa.network.host_dst': { + category: 'rsa', + description: 'This key should only be used when it’s a Destination Hostname', + name: 'rsa.network.host_dst', + type: 'keyword', + }, + 'rsa.network.network_service': { + category: 'rsa', + description: 'This is used to capture layer 7 protocols/service names', + name: 'rsa.network.network_service', + type: 'keyword', + }, + 'rsa.network.interface': { + category: 'rsa', + description: + 'This key should be used when the source or destination context of an interface is not clear', + name: 'rsa.network.interface', + type: 'keyword', + }, + 'rsa.network.network_port': { + category: 'rsa', + description: + 'Deprecated, use port. NOTE: There is a type discrepancy as currently used, TM: Int32, INDEX: UInt64 (why neither chose the correct UInt16?!)', + name: 'rsa.network.network_port', + type: 'long', + }, + 'rsa.network.eth_host': { + category: 'rsa', + description: 'Deprecated, use alias.mac', + name: 'rsa.network.eth_host', + type: 'keyword', + }, + 'rsa.network.sinterface': { + category: 'rsa', + description: 'This key should only be used when it’s a Source Interface', + name: 'rsa.network.sinterface', + type: 'keyword', + }, + 'rsa.network.dinterface': { + category: 'rsa', + description: 'This key should only be used when it’s a Destination Interface', + name: 'rsa.network.dinterface', + type: 'keyword', + }, + 'rsa.network.vlan': { + category: 'rsa', + description: 'This key should only be used to capture the ID of the Virtual LAN', + name: 'rsa.network.vlan', + type: 'long', + }, + 'rsa.network.zone_src': { + category: 'rsa', + description: 'This key should only be used when it’s a Source Zone.', + name: 'rsa.network.zone_src', + type: 'keyword', + }, + 'rsa.network.zone': { + category: 'rsa', + description: + 'This key should be used when the source or destination context of a Zone is not clear', + name: 'rsa.network.zone', + type: 'keyword', + }, + 'rsa.network.zone_dst': { + category: 'rsa', + description: 'This key should only be used when it’s a Destination Zone.', + name: 'rsa.network.zone_dst', + type: 'keyword', + }, + 'rsa.network.gateway': { + category: 'rsa', + description: 'This key is used to capture the IP Address of the gateway', + name: 'rsa.network.gateway', + type: 'keyword', + }, + 'rsa.network.icmp_type': { + category: 'rsa', + description: 'This key is used to capture the ICMP type only', + name: 'rsa.network.icmp_type', + type: 'long', + }, + 'rsa.network.mask': { + category: 'rsa', + description: 'This key is used to capture the device network IPmask.', + name: 'rsa.network.mask', + type: 'keyword', + }, + 'rsa.network.icmp_code': { + category: 'rsa', + description: 'This key is used to capture the ICMP code only', + name: 'rsa.network.icmp_code', + type: 'long', + }, + 'rsa.network.protocol_detail': { + category: 'rsa', + description: 'This key should be used to capture additional protocol information', + name: 'rsa.network.protocol_detail', + type: 'keyword', + }, + 'rsa.network.dmask': { + category: 'rsa', + description: 'This key is used for Destionation Device network mask', + name: 'rsa.network.dmask', + type: 'keyword', + }, + 'rsa.network.port': { + category: 'rsa', + description: + 'This key should only be used to capture a Network Port when the directionality is not clear', + name: 'rsa.network.port', + type: 'long', + }, + 'rsa.network.smask': { + category: 'rsa', + description: 'This key is used for capturing source Network Mask', + name: 'rsa.network.smask', + type: 'keyword', + }, + 'rsa.network.netname': { + category: 'rsa', + description: + 'This key is used to capture the network name associated with an IP range. This is configured by the end user.', + name: 'rsa.network.netname', + type: 'keyword', + }, + 'rsa.network.paddr': { + category: 'rsa', + description: 'Deprecated', + name: 'rsa.network.paddr', + type: 'ip', + }, + 'rsa.network.faddr': { + category: 'rsa', + name: 'rsa.network.faddr', + type: 'keyword', + }, + 'rsa.network.lhost': { + category: 'rsa', + name: 'rsa.network.lhost', + type: 'keyword', + }, + 'rsa.network.origin': { + category: 'rsa', + name: 'rsa.network.origin', + type: 'keyword', + }, + 'rsa.network.remote_domain_id': { + category: 'rsa', + name: 'rsa.network.remote_domain_id', + type: 'keyword', + }, + 'rsa.network.addr': { + category: 'rsa', + name: 'rsa.network.addr', + type: 'keyword', + }, + 'rsa.network.dns_a_record': { + category: 'rsa', + name: 'rsa.network.dns_a_record', + type: 'keyword', + }, + 'rsa.network.dns_ptr_record': { + category: 'rsa', + name: 'rsa.network.dns_ptr_record', + type: 'keyword', + }, + 'rsa.network.fhost': { + category: 'rsa', + name: 'rsa.network.fhost', + type: 'keyword', + }, + 'rsa.network.fport': { + category: 'rsa', + name: 'rsa.network.fport', + type: 'keyword', + }, + 'rsa.network.laddr': { + category: 'rsa', + name: 'rsa.network.laddr', + type: 'keyword', + }, + 'rsa.network.linterface': { + category: 'rsa', + name: 'rsa.network.linterface', + type: 'keyword', + }, + 'rsa.network.phost': { + category: 'rsa', + name: 'rsa.network.phost', + type: 'keyword', + }, + 'rsa.network.ad_computer_dst': { + category: 'rsa', + description: 'Deprecated, use host.dst', + name: 'rsa.network.ad_computer_dst', + type: 'keyword', + }, + 'rsa.network.eth_type': { + category: 'rsa', + description: 'This key is used to capture Ethernet Type, Used for Layer 3 Protocols Only', + name: 'rsa.network.eth_type', + type: 'long', + }, + 'rsa.network.ip_proto': { + category: 'rsa', + description: + 'This key should be used to capture the Protocol number, all the protocol nubers are converted into string in UI', + name: 'rsa.network.ip_proto', + type: 'long', + }, + 'rsa.network.dns_cname_record': { + category: 'rsa', + name: 'rsa.network.dns_cname_record', + type: 'keyword', + }, + 'rsa.network.dns_id': { + category: 'rsa', + name: 'rsa.network.dns_id', + type: 'keyword', + }, + 'rsa.network.dns_opcode': { + category: 'rsa', + name: 'rsa.network.dns_opcode', + type: 'keyword', + }, + 'rsa.network.dns_resp': { + category: 'rsa', + name: 'rsa.network.dns_resp', + type: 'keyword', + }, + 'rsa.network.dns_type': { + category: 'rsa', + name: 'rsa.network.dns_type', + type: 'keyword', + }, + 'rsa.network.domain1': { + category: 'rsa', + name: 'rsa.network.domain1', + type: 'keyword', + }, + 'rsa.network.host_type': { + category: 'rsa', + name: 'rsa.network.host_type', + type: 'keyword', + }, + 'rsa.network.packet_length': { + category: 'rsa', + name: 'rsa.network.packet_length', + type: 'keyword', + }, + 'rsa.network.host_orig': { + category: 'rsa', + description: + 'This is used to capture the original hostname in case of a Forwarding Agent or a Proxy in between.', + name: 'rsa.network.host_orig', + type: 'keyword', + }, + 'rsa.network.rpayload': { + category: 'rsa', + description: + 'This key is used to capture the total number of payload bytes seen in the retransmitted packets.', + name: 'rsa.network.rpayload', + type: 'keyword', + }, + 'rsa.network.vlan_name': { + category: 'rsa', + description: 'This key should only be used to capture the name of the Virtual LAN', + name: 'rsa.network.vlan_name', + type: 'keyword', + }, + 'rsa.investigations.ec_activity': { + category: 'rsa', + description: 'This key captures the particular event activity(Ex:Logoff)', + name: 'rsa.investigations.ec_activity', + type: 'keyword', + }, + 'rsa.investigations.ec_theme': { + category: 'rsa', + description: 'This key captures the Theme of a particular Event(Ex:Authentication)', + name: 'rsa.investigations.ec_theme', + type: 'keyword', + }, + 'rsa.investigations.ec_subject': { + category: 'rsa', + description: 'This key captures the Subject of a particular Event(Ex:User)', + name: 'rsa.investigations.ec_subject', + type: 'keyword', + }, + 'rsa.investigations.ec_outcome': { + category: 'rsa', + description: 'This key captures the outcome of a particular Event(Ex:Success)', + name: 'rsa.investigations.ec_outcome', + type: 'keyword', + }, + 'rsa.investigations.event_cat': { + category: 'rsa', + description: 'This key captures the Event category number', + name: 'rsa.investigations.event_cat', + type: 'long', + }, + 'rsa.investigations.event_cat_name': { + category: 'rsa', + description: 'This key captures the event category name corresponding to the event cat code', + name: 'rsa.investigations.event_cat_name', + type: 'keyword', + }, + 'rsa.investigations.event_vcat': { + category: 'rsa', + description: + 'This is a vendor supplied category. This should be used in situations where the vendor has adopted their own event_category taxonomy.', + name: 'rsa.investigations.event_vcat', + type: 'keyword', + }, + 'rsa.investigations.analysis_file': { + category: 'rsa', + description: + 'This is used to capture all indicators used in a File Analysis. This key should be used to capture an analysis of a file', + name: 'rsa.investigations.analysis_file', + type: 'keyword', + }, + 'rsa.investigations.analysis_service': { + category: 'rsa', + description: + 'This is used to capture all indicators used in a Service Analysis. This key should be used to capture an analysis of a service', + name: 'rsa.investigations.analysis_service', + type: 'keyword', + }, + 'rsa.investigations.analysis_session': { + category: 'rsa', + description: + 'This is used to capture all indicators used for a Session Analysis. This key should be used to capture an analysis of a session', + name: 'rsa.investigations.analysis_session', + type: 'keyword', + }, + 'rsa.investigations.boc': { + category: 'rsa', + description: 'This is used to capture behaviour of compromise', + name: 'rsa.investigations.boc', + type: 'keyword', + }, + 'rsa.investigations.eoc': { + category: 'rsa', + description: 'This is used to capture Enablers of Compromise', + name: 'rsa.investigations.eoc', + type: 'keyword', + }, + 'rsa.investigations.inv_category': { + category: 'rsa', + description: 'This used to capture investigation category', + name: 'rsa.investigations.inv_category', + type: 'keyword', + }, + 'rsa.investigations.inv_context': { + category: 'rsa', + description: 'This used to capture investigation context', + name: 'rsa.investigations.inv_context', + type: 'keyword', + }, + 'rsa.investigations.ioc': { + category: 'rsa', + description: 'This is key capture indicator of compromise', + name: 'rsa.investigations.ioc', + type: 'keyword', + }, + 'rsa.counters.dclass_c1': { + category: 'rsa', + description: + 'This is a generic counter key that should be used with the label dclass.c1.str only', + name: 'rsa.counters.dclass_c1', + type: 'long', + }, + 'rsa.counters.dclass_c2': { + category: 'rsa', + description: + 'This is a generic counter key that should be used with the label dclass.c2.str only', + name: 'rsa.counters.dclass_c2', + type: 'long', + }, + 'rsa.counters.event_counter': { + category: 'rsa', + description: 'This is used to capture the number of times an event repeated', + name: 'rsa.counters.event_counter', + type: 'long', + }, + 'rsa.counters.dclass_r1': { + category: 'rsa', + description: + 'This is a generic ratio key that should be used with the label dclass.r1.str only', + name: 'rsa.counters.dclass_r1', + type: 'keyword', + }, + 'rsa.counters.dclass_c3': { + category: 'rsa', + description: + 'This is a generic counter key that should be used with the label dclass.c3.str only', + name: 'rsa.counters.dclass_c3', + type: 'long', + }, + 'rsa.counters.dclass_c1_str': { + category: 'rsa', + description: + 'This is a generic counter string key that should be used with the label dclass.c1 only', + name: 'rsa.counters.dclass_c1_str', + type: 'keyword', + }, + 'rsa.counters.dclass_c2_str': { + category: 'rsa', + description: + 'This is a generic counter string key that should be used with the label dclass.c2 only', + name: 'rsa.counters.dclass_c2_str', + type: 'keyword', + }, + 'rsa.counters.dclass_r1_str': { + category: 'rsa', + description: + 'This is a generic ratio string key that should be used with the label dclass.r1 only', + name: 'rsa.counters.dclass_r1_str', + type: 'keyword', + }, + 'rsa.counters.dclass_r2': { + category: 'rsa', + description: + 'This is a generic ratio key that should be used with the label dclass.r2.str only', + name: 'rsa.counters.dclass_r2', + type: 'keyword', + }, + 'rsa.counters.dclass_c3_str': { + category: 'rsa', + description: + 'This is a generic counter string key that should be used with the label dclass.c3 only', + name: 'rsa.counters.dclass_c3_str', + type: 'keyword', + }, + 'rsa.counters.dclass_r3': { + category: 'rsa', + description: + 'This is a generic ratio key that should be used with the label dclass.r3.str only', + name: 'rsa.counters.dclass_r3', + type: 'keyword', + }, + 'rsa.counters.dclass_r2_str': { + category: 'rsa', + description: + 'This is a generic ratio string key that should be used with the label dclass.r2 only', + name: 'rsa.counters.dclass_r2_str', + type: 'keyword', + }, + 'rsa.counters.dclass_r3_str': { + category: 'rsa', + description: + 'This is a generic ratio string key that should be used with the label dclass.r3 only', + name: 'rsa.counters.dclass_r3_str', + type: 'keyword', + }, + 'rsa.identity.auth_method': { + category: 'rsa', + description: 'This key is used to capture authentication methods used only', + name: 'rsa.identity.auth_method', + type: 'keyword', + }, + 'rsa.identity.user_role': { + category: 'rsa', + description: 'This key is used to capture the Role of a user only', + name: 'rsa.identity.user_role', + type: 'keyword', + }, + 'rsa.identity.dn': { + category: 'rsa', + description: 'X.500 (LDAP) Distinguished Name', + name: 'rsa.identity.dn', + type: 'keyword', + }, + 'rsa.identity.logon_type': { + category: 'rsa', + description: 'This key is used to capture the type of logon method used.', + name: 'rsa.identity.logon_type', + type: 'keyword', + }, + 'rsa.identity.profile': { + category: 'rsa', + description: 'This key is used to capture the user profile', + name: 'rsa.identity.profile', + type: 'keyword', + }, + 'rsa.identity.accesses': { + category: 'rsa', + description: 'This key is used to capture actual privileges used in accessing an object', + name: 'rsa.identity.accesses', + type: 'keyword', + }, + 'rsa.identity.realm': { + category: 'rsa', + description: 'Radius realm or similar grouping of accounts', + name: 'rsa.identity.realm', + type: 'keyword', + }, + 'rsa.identity.user_sid_dst': { + category: 'rsa', + description: 'This key captures Destination User Session ID', + name: 'rsa.identity.user_sid_dst', + type: 'keyword', + }, + 'rsa.identity.dn_src': { + category: 'rsa', + description: + 'An X.500 (LDAP) Distinguished name that is used in a context that indicates a Source dn', + name: 'rsa.identity.dn_src', + type: 'keyword', + }, + 'rsa.identity.org': { + category: 'rsa', + description: 'This key captures the User organization', + name: 'rsa.identity.org', + type: 'keyword', + }, + 'rsa.identity.dn_dst': { + category: 'rsa', + description: + 'An X.500 (LDAP) Distinguished name that used in a context that indicates a Destination dn', + name: 'rsa.identity.dn_dst', + type: 'keyword', + }, + 'rsa.identity.firstname': { + category: 'rsa', + description: + 'This key is for First Names only, this is used for Healthcare predominantly to capture Patients information', + name: 'rsa.identity.firstname', + type: 'keyword', + }, + 'rsa.identity.lastname': { + category: 'rsa', + description: + 'This key is for Last Names only, this is used for Healthcare predominantly to capture Patients information', + name: 'rsa.identity.lastname', + type: 'keyword', + }, + 'rsa.identity.user_dept': { + category: 'rsa', + description: "User's Department Names only", + name: 'rsa.identity.user_dept', + type: 'keyword', + }, + 'rsa.identity.user_sid_src': { + category: 'rsa', + description: 'This key captures Source User Session ID', + name: 'rsa.identity.user_sid_src', + type: 'keyword', + }, + 'rsa.identity.federated_sp': { + category: 'rsa', + description: + 'This key is the Federated Service Provider. This is the application requesting authentication.', + name: 'rsa.identity.federated_sp', + type: 'keyword', + }, + 'rsa.identity.federated_idp': { + category: 'rsa', + description: + 'This key is the federated Identity Provider. This is the server providing the authentication.', + name: 'rsa.identity.federated_idp', + type: 'keyword', + }, + 'rsa.identity.logon_type_desc': { + category: 'rsa', + description: + "This key is used to capture the textual description of an integer logon type as stored in the meta key 'logon.type'.", + name: 'rsa.identity.logon_type_desc', + type: 'keyword', + }, + 'rsa.identity.middlename': { + category: 'rsa', + description: + 'This key is for Middle Names only, this is used for Healthcare predominantly to capture Patients information', + name: 'rsa.identity.middlename', + type: 'keyword', + }, + 'rsa.identity.password': { + category: 'rsa', + description: 'This key is for Passwords seen in any session, plain text or encrypted', + name: 'rsa.identity.password', + type: 'keyword', + }, + 'rsa.identity.host_role': { + category: 'rsa', + description: 'This key should only be used to capture the role of a Host Machine', + name: 'rsa.identity.host_role', + type: 'keyword', + }, + 'rsa.identity.ldap': { + category: 'rsa', + description: + 'This key is for Uninterpreted LDAP values. Ldap Values that don’t have a clear query or response context', + name: 'rsa.identity.ldap', + type: 'keyword', + }, + 'rsa.identity.ldap_query': { + category: 'rsa', + description: 'This key is the Search criteria from an LDAP search', + name: 'rsa.identity.ldap_query', + type: 'keyword', + }, + 'rsa.identity.ldap_response': { + category: 'rsa', + description: 'This key is to capture Results from an LDAP search', + name: 'rsa.identity.ldap_response', + type: 'keyword', + }, + 'rsa.identity.owner': { + category: 'rsa', + description: + 'This is used to capture username the process or service is running as, the author of the task', + name: 'rsa.identity.owner', + type: 'keyword', + }, + 'rsa.identity.service_account': { + category: 'rsa', + description: + 'This key is a windows specific key, used for capturing name of the account a service (referenced in the event) is running under. Legacy Usage', + name: 'rsa.identity.service_account', + type: 'keyword', + }, + 'rsa.email.email_dst': { + category: 'rsa', + description: + 'This key is used to capture the Destination email address only, when the destination context is not clear use email', + name: 'rsa.email.email_dst', + type: 'keyword', + }, + 'rsa.email.email_src': { + category: 'rsa', + description: + 'This key is used to capture the source email address only, when the source context is not clear use email', + name: 'rsa.email.email_src', + type: 'keyword', + }, + 'rsa.email.subject': { + category: 'rsa', + description: 'This key is used to capture the subject string from an Email only.', + name: 'rsa.email.subject', + type: 'keyword', + }, + 'rsa.email.email': { + category: 'rsa', + description: + 'This key is used to capture a generic email address where the source or destination context is not clear', + name: 'rsa.email.email', + type: 'keyword', + }, + 'rsa.email.trans_from': { + category: 'rsa', + description: 'Deprecated key defined only in table map.', + name: 'rsa.email.trans_from', + type: 'keyword', + }, + 'rsa.email.trans_to': { + category: 'rsa', + description: 'Deprecated key defined only in table map.', + name: 'rsa.email.trans_to', + type: 'keyword', + }, + 'rsa.file.privilege': { + category: 'rsa', + description: 'Deprecated, use permissions', + name: 'rsa.file.privilege', + type: 'keyword', + }, + 'rsa.file.attachment': { + category: 'rsa', + description: 'This key captures the attachment file name', + name: 'rsa.file.attachment', + type: 'keyword', + }, + 'rsa.file.filesystem': { + category: 'rsa', + name: 'rsa.file.filesystem', + type: 'keyword', + }, + 'rsa.file.binary': { + category: 'rsa', + description: 'Deprecated key defined only in table map.', + name: 'rsa.file.binary', + type: 'keyword', + }, + 'rsa.file.filename_dst': { + category: 'rsa', + description: 'This is used to capture name of the file targeted by the action', + name: 'rsa.file.filename_dst', + type: 'keyword', + }, + 'rsa.file.filename_src': { + category: 'rsa', + description: + 'This is used to capture name of the parent filename, the file which performed the action', + name: 'rsa.file.filename_src', + type: 'keyword', + }, + 'rsa.file.filename_tmp': { + category: 'rsa', + name: 'rsa.file.filename_tmp', + type: 'keyword', + }, + 'rsa.file.directory_dst': { + category: 'rsa', + description: + 'This key is used to capture the directory of the target process or file', + name: 'rsa.file.directory_dst', + type: 'keyword', + }, + 'rsa.file.directory_src': { + category: 'rsa', + description: 'This key is used to capture the directory of the source process or file', + name: 'rsa.file.directory_src', + type: 'keyword', + }, + 'rsa.file.file_entropy': { + category: 'rsa', + description: 'This is used to capture entropy vale of a file', + name: 'rsa.file.file_entropy', + type: 'double', + }, + 'rsa.file.file_vendor': { + category: 'rsa', + description: 'This is used to capture Company name of file located in version_info', + name: 'rsa.file.file_vendor', + type: 'keyword', + }, + 'rsa.file.task_name': { + category: 'rsa', + description: 'This is used to capture name of the task', + name: 'rsa.file.task_name', + type: 'keyword', + }, + 'rsa.web.fqdn': { + category: 'rsa', + description: 'Fully Qualified Domain Names', + name: 'rsa.web.fqdn', + type: 'keyword', + }, + 'rsa.web.web_cookie': { + category: 'rsa', + description: 'This key is used to capture the Web cookies specifically.', + name: 'rsa.web.web_cookie', + type: 'keyword', + }, + 'rsa.web.alias_host': { + category: 'rsa', + name: 'rsa.web.alias_host', + type: 'keyword', + }, + 'rsa.web.reputation_num': { + category: 'rsa', + description: 'Reputation Number of an entity. Typically used for Web Domains', + name: 'rsa.web.reputation_num', + type: 'double', + }, + 'rsa.web.web_ref_domain': { + category: 'rsa', + description: "Web referer's domain", + name: 'rsa.web.web_ref_domain', + type: 'keyword', + }, + 'rsa.web.web_ref_query': { + category: 'rsa', + description: "This key captures Web referer's query portion of the URL", + name: 'rsa.web.web_ref_query', + type: 'keyword', + }, + 'rsa.web.remote_domain': { + category: 'rsa', + name: 'rsa.web.remote_domain', + type: 'keyword', + }, + 'rsa.web.web_ref_page': { + category: 'rsa', + description: "This key captures Web referer's page information", + name: 'rsa.web.web_ref_page', + type: 'keyword', + }, + 'rsa.web.web_ref_root': { + category: 'rsa', + description: "Web referer's root URL path", + name: 'rsa.web.web_ref_root', + type: 'keyword', + }, + 'rsa.web.cn_asn_dst': { + category: 'rsa', + name: 'rsa.web.cn_asn_dst', + type: 'keyword', + }, + 'rsa.web.cn_rpackets': { + category: 'rsa', + name: 'rsa.web.cn_rpackets', + type: 'keyword', + }, + 'rsa.web.urlpage': { + category: 'rsa', + name: 'rsa.web.urlpage', + type: 'keyword', + }, + 'rsa.web.urlroot': { + category: 'rsa', + name: 'rsa.web.urlroot', + type: 'keyword', + }, + 'rsa.web.p_url': { + category: 'rsa', + name: 'rsa.web.p_url', + type: 'keyword', + }, + 'rsa.web.p_user_agent': { + category: 'rsa', + name: 'rsa.web.p_user_agent', + type: 'keyword', + }, + 'rsa.web.p_web_cookie': { + category: 'rsa', + name: 'rsa.web.p_web_cookie', + type: 'keyword', + }, + 'rsa.web.p_web_method': { + category: 'rsa', + name: 'rsa.web.p_web_method', + type: 'keyword', + }, + 'rsa.web.p_web_referer': { + category: 'rsa', + name: 'rsa.web.p_web_referer', + type: 'keyword', + }, + 'rsa.web.web_extension_tmp': { + category: 'rsa', + name: 'rsa.web.web_extension_tmp', + type: 'keyword', + }, + 'rsa.web.web_page': { + category: 'rsa', + name: 'rsa.web.web_page', + type: 'keyword', + }, + 'rsa.threat.threat_category': { + category: 'rsa', + description: 'This key captures Threat Name/Threat Category/Categorization of alert', + name: 'rsa.threat.threat_category', + type: 'keyword', + }, + 'rsa.threat.threat_desc': { + category: 'rsa', + description: + 'This key is used to capture the threat description from the session directly or inferred', + name: 'rsa.threat.threat_desc', + type: 'keyword', + }, + 'rsa.threat.alert': { + category: 'rsa', + description: 'This key is used to capture name of the alert', + name: 'rsa.threat.alert', + type: 'keyword', + }, + 'rsa.threat.threat_source': { + category: 'rsa', + description: 'This key is used to capture source of the threat', + name: 'rsa.threat.threat_source', + type: 'keyword', + }, + 'rsa.crypto.crypto': { + category: 'rsa', + description: 'This key is used to capture the Encryption Type or Encryption Key only', + name: 'rsa.crypto.crypto', + type: 'keyword', + }, + 'rsa.crypto.cipher_src': { + category: 'rsa', + description: 'This key is for Source (Client) Cipher', + name: 'rsa.crypto.cipher_src', + type: 'keyword', + }, + 'rsa.crypto.cert_subject': { + category: 'rsa', + description: 'This key is used to capture the Certificate organization only', + name: 'rsa.crypto.cert_subject', + type: 'keyword', + }, + 'rsa.crypto.peer': { + category: 'rsa', + description: "This key is for Encryption peer's IP Address", + name: 'rsa.crypto.peer', + type: 'keyword', + }, + 'rsa.crypto.cipher_size_src': { + category: 'rsa', + description: 'This key captures Source (Client) Cipher Size', + name: 'rsa.crypto.cipher_size_src', + type: 'long', + }, + 'rsa.crypto.ike': { + category: 'rsa', + description: 'IKE negotiation phase.', + name: 'rsa.crypto.ike', + type: 'keyword', + }, + 'rsa.crypto.scheme': { + category: 'rsa', + description: 'This key captures the Encryption scheme used', + name: 'rsa.crypto.scheme', + type: 'keyword', + }, + 'rsa.crypto.peer_id': { + category: 'rsa', + description: 'This key is for Encryption peer’s identity', + name: 'rsa.crypto.peer_id', + type: 'keyword', + }, + 'rsa.crypto.sig_type': { + category: 'rsa', + description: 'This key captures the Signature Type', + name: 'rsa.crypto.sig_type', + type: 'keyword', + }, + 'rsa.crypto.cert_issuer': { + category: 'rsa', + name: 'rsa.crypto.cert_issuer', + type: 'keyword', + }, + 'rsa.crypto.cert_host_name': { + category: 'rsa', + description: 'Deprecated key defined only in table map.', + name: 'rsa.crypto.cert_host_name', + type: 'keyword', + }, + 'rsa.crypto.cert_error': { + category: 'rsa', + description: 'This key captures the Certificate Error String', + name: 'rsa.crypto.cert_error', + type: 'keyword', + }, + 'rsa.crypto.cipher_dst': { + category: 'rsa', + description: 'This key is for Destination (Server) Cipher', + name: 'rsa.crypto.cipher_dst', + type: 'keyword', + }, + 'rsa.crypto.cipher_size_dst': { + category: 'rsa', + description: 'This key captures Destination (Server) Cipher Size', + name: 'rsa.crypto.cipher_size_dst', + type: 'long', + }, + 'rsa.crypto.ssl_ver_src': { + category: 'rsa', + description: 'Deprecated, use version', + name: 'rsa.crypto.ssl_ver_src', + type: 'keyword', + }, + 'rsa.crypto.d_certauth': { + category: 'rsa', + name: 'rsa.crypto.d_certauth', + type: 'keyword', + }, + 'rsa.crypto.s_certauth': { + category: 'rsa', + name: 'rsa.crypto.s_certauth', + type: 'keyword', + }, + 'rsa.crypto.ike_cookie1': { + category: 'rsa', + description: 'ID of the negotiation — sent for ISAKMP Phase One', + name: 'rsa.crypto.ike_cookie1', + type: 'keyword', + }, + 'rsa.crypto.ike_cookie2': { + category: 'rsa', + description: 'ID of the negotiation — sent for ISAKMP Phase Two', + name: 'rsa.crypto.ike_cookie2', + type: 'keyword', + }, + 'rsa.crypto.cert_checksum': { + category: 'rsa', + name: 'rsa.crypto.cert_checksum', + type: 'keyword', + }, + 'rsa.crypto.cert_host_cat': { + category: 'rsa', + description: 'This key is used for the hostname category value of a certificate', + name: 'rsa.crypto.cert_host_cat', + type: 'keyword', + }, + 'rsa.crypto.cert_serial': { + category: 'rsa', + description: 'This key is used to capture the Certificate serial number only', + name: 'rsa.crypto.cert_serial', + type: 'keyword', + }, + 'rsa.crypto.cert_status': { + category: 'rsa', + description: 'This key captures Certificate validation status', + name: 'rsa.crypto.cert_status', + type: 'keyword', + }, + 'rsa.crypto.ssl_ver_dst': { + category: 'rsa', + description: 'Deprecated, use version', + name: 'rsa.crypto.ssl_ver_dst', + type: 'keyword', + }, + 'rsa.crypto.cert_keysize': { + category: 'rsa', + name: 'rsa.crypto.cert_keysize', + type: 'keyword', + }, + 'rsa.crypto.cert_username': { + category: 'rsa', + name: 'rsa.crypto.cert_username', + type: 'keyword', + }, + 'rsa.crypto.https_insact': { + category: 'rsa', + name: 'rsa.crypto.https_insact', + type: 'keyword', + }, + 'rsa.crypto.https_valid': { + category: 'rsa', + name: 'rsa.crypto.https_valid', + type: 'keyword', + }, + 'rsa.crypto.cert_ca': { + category: 'rsa', + description: 'This key is used to capture the Certificate signing authority only', + name: 'rsa.crypto.cert_ca', + type: 'keyword', + }, + 'rsa.crypto.cert_common': { + category: 'rsa', + description: 'This key is used to capture the Certificate common name only', + name: 'rsa.crypto.cert_common', + type: 'keyword', + }, + 'rsa.wireless.wlan_ssid': { + category: 'rsa', + description: 'This key is used to capture the ssid of a Wireless Session', + name: 'rsa.wireless.wlan_ssid', + type: 'keyword', + }, + 'rsa.wireless.access_point': { + category: 'rsa', + description: 'This key is used to capture the access point name.', + name: 'rsa.wireless.access_point', + type: 'keyword', + }, + 'rsa.wireless.wlan_channel': { + category: 'rsa', + description: 'This is used to capture the channel names', + name: 'rsa.wireless.wlan_channel', + type: 'long', + }, + 'rsa.wireless.wlan_name': { + category: 'rsa', + description: 'This key captures either WLAN number/name', + name: 'rsa.wireless.wlan_name', + type: 'keyword', + }, + 'rsa.storage.disk_volume': { + category: 'rsa', + description: 'A unique name assigned to logical units (volumes) within a physical disk', + name: 'rsa.storage.disk_volume', + type: 'keyword', + }, + 'rsa.storage.lun': { + category: 'rsa', + description: 'Logical Unit Number.This key is a very useful concept in Storage.', + name: 'rsa.storage.lun', + type: 'keyword', + }, + 'rsa.storage.pwwn': { + category: 'rsa', + description: 'This uniquely identifies a port on a HBA.', + name: 'rsa.storage.pwwn', + type: 'keyword', + }, + 'rsa.physical.org_dst': { + category: 'rsa', + description: + 'This is used to capture the destination organization based on the GEOPIP Maxmind database.', + name: 'rsa.physical.org_dst', + type: 'keyword', + }, + 'rsa.physical.org_src': { + category: 'rsa', + description: + 'This is used to capture the source organization based on the GEOPIP Maxmind database.', + name: 'rsa.physical.org_src', + type: 'keyword', + }, + 'rsa.healthcare.patient_fname': { + category: 'rsa', + description: + 'This key is for First Names only, this is used for Healthcare predominantly to capture Patients information', + name: 'rsa.healthcare.patient_fname', + type: 'keyword', + }, + 'rsa.healthcare.patient_id': { + category: 'rsa', + description: 'This key captures the unique ID for a patient', + name: 'rsa.healthcare.patient_id', + type: 'keyword', + }, + 'rsa.healthcare.patient_lname': { + category: 'rsa', + description: + 'This key is for Last Names only, this is used for Healthcare predominantly to capture Patients information', + name: 'rsa.healthcare.patient_lname', + type: 'keyword', + }, + 'rsa.healthcare.patient_mname': { + category: 'rsa', + description: + 'This key is for Middle Names only, this is used for Healthcare predominantly to capture Patients information', + name: 'rsa.healthcare.patient_mname', + type: 'keyword', + }, + 'rsa.endpoint.host_state': { + category: 'rsa', + description: + 'This key is used to capture the current state of the machine, such as blacklisted, infected, firewall disabled and so on', + name: 'rsa.endpoint.host_state', + type: 'keyword', + }, + 'rsa.endpoint.registry_key': { + category: 'rsa', + description: 'This key captures the path to the registry key', + name: 'rsa.endpoint.registry_key', + type: 'keyword', + }, + 'rsa.endpoint.registry_value': { + category: 'rsa', + description: 'This key captures values or decorators used within a registry entry', + name: 'rsa.endpoint.registry_value', + type: 'keyword', + }, + 'forcepoint.virus_id': { + category: 'forcepoint', + description: 'Virus ID ', + name: 'forcepoint.virus_id', + type: 'keyword', + }, + 'checkpoint.app_risk': { + category: 'checkpoint', + description: 'Application risk.', + name: 'checkpoint.app_risk', + type: 'keyword', + }, + 'checkpoint.app_severity': { + category: 'checkpoint', + description: 'Application threat severity.', + name: 'checkpoint.app_severity', + type: 'keyword', + }, + 'checkpoint.app_sig_id': { + category: 'checkpoint', + description: 'The signature ID which the application was detected by.', + name: 'checkpoint.app_sig_id', + type: 'keyword', + }, + 'checkpoint.auth_method': { + category: 'checkpoint', + description: 'Password authentication protocol used.', + name: 'checkpoint.auth_method', + type: 'keyword', + }, + 'checkpoint.category': { + category: 'checkpoint', + description: 'Category.', + name: 'checkpoint.category', + type: 'keyword', + }, + 'checkpoint.confidence_level': { + category: 'checkpoint', + description: 'Confidence level determined.', + name: 'checkpoint.confidence_level', + type: 'integer', + }, + 'checkpoint.connectivity_state': { + category: 'checkpoint', + description: 'Connectivity state.', + name: 'checkpoint.connectivity_state', + type: 'keyword', + }, + 'checkpoint.cookie': { + category: 'checkpoint', + description: 'IKE cookie.', + name: 'checkpoint.cookie', + type: 'keyword', + }, + 'checkpoint.dst_phone_number': { + category: 'checkpoint', + description: 'Destination IP-Phone.', + name: 'checkpoint.dst_phone_number', + type: 'keyword', + }, + 'checkpoint.email_control': { + category: 'checkpoint', + description: 'Engine name.', + name: 'checkpoint.email_control', + type: 'keyword', + }, + 'checkpoint.email_id': { + category: 'checkpoint', + description: 'Internal email ID.', + name: 'checkpoint.email_id', + type: 'keyword', + }, + 'checkpoint.email_recipients_num': { + category: 'checkpoint', + description: 'Number of recipients.', + name: 'checkpoint.email_recipients_num', + type: 'long', + }, + 'checkpoint.email_session_id': { + category: 'checkpoint', + description: 'Internal email session ID.', + name: 'checkpoint.email_session_id', + type: 'keyword', + }, + 'checkpoint.email_spool_id': { + category: 'checkpoint', + description: 'Internal email spool ID.', + name: 'checkpoint.email_spool_id', + type: 'keyword', + }, + 'checkpoint.email_subject': { + category: 'checkpoint', + description: 'Email subject.', + name: 'checkpoint.email_subject', + type: 'keyword', + }, + 'checkpoint.event_count': { + category: 'checkpoint', + description: 'Number of events associated with the log.', + name: 'checkpoint.event_count', + type: 'long', + }, + 'checkpoint.frequency': { + category: 'checkpoint', + description: 'Scan frequency.', + name: 'checkpoint.frequency', + type: 'keyword', + }, + 'checkpoint.icmp_type': { + category: 'checkpoint', + description: 'ICMP type.', + name: 'checkpoint.icmp_type', + type: 'long', + }, + 'checkpoint.icmp_code': { + category: 'checkpoint', + description: 'ICMP code.', + name: 'checkpoint.icmp_code', + type: 'long', + }, + 'checkpoint.identity_type': { + category: 'checkpoint', + description: 'Identity type.', + name: 'checkpoint.identity_type', + type: 'keyword', + }, + 'checkpoint.incident_extension': { + category: 'checkpoint', + description: 'Format of original data.', + name: 'checkpoint.incident_extension', + type: 'keyword', + }, + 'checkpoint.integrity_av_invoke_type': { + category: 'checkpoint', + description: 'Scan invoke type.', + name: 'checkpoint.integrity_av_invoke_type', + type: 'keyword', + }, + 'checkpoint.malware_family': { + category: 'checkpoint', + description: 'Malware family.', + name: 'checkpoint.malware_family', + type: 'keyword', + }, + 'checkpoint.peer_gateway': { + category: 'checkpoint', + description: 'Main IP of the peer Security Gateway.', + name: 'checkpoint.peer_gateway', + type: 'ip', + }, + 'checkpoint.performance_impact': { + category: 'checkpoint', + description: 'Protection performance impact.', + name: 'checkpoint.performance_impact', + type: 'integer', + }, + 'checkpoint.protection_id': { + category: 'checkpoint', + description: 'Protection malware ID.', + name: 'checkpoint.protection_id', + type: 'keyword', + }, + 'checkpoint.protection_name': { + category: 'checkpoint', + description: 'Specific signature name of the attack.', + name: 'checkpoint.protection_name', + type: 'keyword', + }, + 'checkpoint.protection_type': { + category: 'checkpoint', + description: 'Type of protection used to detect the attack.', + name: 'checkpoint.protection_type', + type: 'keyword', + }, + 'checkpoint.scan_result': { + category: 'checkpoint', + description: 'Scan result.', + name: 'checkpoint.scan_result', + type: 'keyword', + }, + 'checkpoint.sensor_mode': { + category: 'checkpoint', + description: 'Sensor mode.', + name: 'checkpoint.sensor_mode', + type: 'keyword', + }, + 'checkpoint.severity': { + category: 'checkpoint', + description: 'Threat severity.', + name: 'checkpoint.severity', + type: 'keyword', + }, + 'checkpoint.spyware_name': { + category: 'checkpoint', + description: 'Spyware name.', + name: 'checkpoint.spyware_name', + type: 'keyword', + }, + 'checkpoint.spyware_status': { + category: 'checkpoint', + description: 'Spyware status.', + name: 'checkpoint.spyware_status', + type: 'keyword', + }, + 'checkpoint.subs_exp': { + category: 'checkpoint', + description: 'The expiration date of the subscription.', + name: 'checkpoint.subs_exp', + type: 'date', + }, + 'checkpoint.tcp_flags': { + category: 'checkpoint', + description: 'TCP packet flags.', + name: 'checkpoint.tcp_flags', + type: 'keyword', + }, + 'checkpoint.termination_reason': { + category: 'checkpoint', + description: 'Termination reason.', + name: 'checkpoint.termination_reason', + type: 'keyword', + }, + 'checkpoint.update_status': { + category: 'checkpoint', + description: 'Update status.', + name: 'checkpoint.update_status', + type: 'keyword', + }, + 'checkpoint.user_status': { + category: 'checkpoint', + description: 'User response.', + name: 'checkpoint.user_status', + type: 'keyword', + }, + 'checkpoint.uuid': { + category: 'checkpoint', + description: 'External ID.', + name: 'checkpoint.uuid', + type: 'keyword', + }, + 'checkpoint.virus_name': { + category: 'checkpoint', + description: 'Virus name.', + name: 'checkpoint.virus_name', + type: 'keyword', + }, + 'checkpoint.voip_log_type': { + category: 'checkpoint', + description: 'VoIP log types.', + name: 'checkpoint.voip_log_type', + type: 'keyword', + }, + 'cef.extensions.cp_app_risk': { + category: 'cef', + name: 'cef.extensions.cp_app_risk', + type: 'keyword', + }, + 'cef.extensions.cp_severity': { + category: 'cef', + name: 'cef.extensions.cp_severity', + type: 'keyword', + }, + 'cef.extensions.ifname': { + category: 'cef', + name: 'cef.extensions.ifname', + type: 'keyword', + }, + 'cef.extensions.inzone': { + category: 'cef', + name: 'cef.extensions.inzone', + type: 'keyword', + }, + 'cef.extensions.layer_uuid': { + category: 'cef', + name: 'cef.extensions.layer_uuid', + type: 'keyword', + }, + 'cef.extensions.layer_name': { + category: 'cef', + name: 'cef.extensions.layer_name', + type: 'keyword', + }, + 'cef.extensions.logid': { + category: 'cef', + name: 'cef.extensions.logid', + type: 'keyword', + }, + 'cef.extensions.loguid': { + category: 'cef', + name: 'cef.extensions.loguid', + type: 'keyword', + }, + 'cef.extensions.match_id': { + category: 'cef', + name: 'cef.extensions.match_id', + type: 'keyword', + }, + 'cef.extensions.nat_addtnl_rulenum': { + category: 'cef', + name: 'cef.extensions.nat_addtnl_rulenum', + type: 'keyword', + }, + 'cef.extensions.nat_rulenum': { + category: 'cef', + name: 'cef.extensions.nat_rulenum', + type: 'keyword', + }, + 'cef.extensions.origin': { + category: 'cef', + name: 'cef.extensions.origin', + type: 'keyword', + }, + 'cef.extensions.originsicname': { + category: 'cef', + name: 'cef.extensions.originsicname', + type: 'keyword', + }, + 'cef.extensions.outzone': { + category: 'cef', + name: 'cef.extensions.outzone', + type: 'keyword', + }, + 'cef.extensions.parent_rule': { + category: 'cef', + name: 'cef.extensions.parent_rule', + type: 'keyword', + }, + 'cef.extensions.product': { + category: 'cef', + name: 'cef.extensions.product', + type: 'keyword', + }, + 'cef.extensions.rule_action': { + category: 'cef', + name: 'cef.extensions.rule_action', + type: 'keyword', + }, + 'cef.extensions.rule_uid': { + category: 'cef', + name: 'cef.extensions.rule_uid', + type: 'keyword', + }, + 'cef.extensions.sequencenum': { + category: 'cef', + name: 'cef.extensions.sequencenum', + type: 'keyword', + }, + 'cef.extensions.service_id': { + category: 'cef', + name: 'cef.extensions.service_id', + type: 'keyword', + }, + 'cef.extensions.version': { + category: 'cef', + name: 'cef.extensions.version', + type: 'keyword', + }, + 'checkpoint.calc_desc': { + category: 'checkpoint', + description: 'Log description. ', + name: 'checkpoint.calc_desc', + type: 'keyword', + }, + 'checkpoint.dst_country': { + category: 'checkpoint', + description: 'Destination country. ', + name: 'checkpoint.dst_country', + type: 'keyword', + }, + 'checkpoint.dst_user_name': { + category: 'checkpoint', + description: 'Connected user name on the destination IP. ', + name: 'checkpoint.dst_user_name', + type: 'keyword', + }, + 'checkpoint.sys_message': { + category: 'checkpoint', + description: 'System messages ', + name: 'checkpoint.sys_message', + type: 'keyword', + }, + 'checkpoint.logid': { + category: 'checkpoint', + description: 'System messages ', + name: 'checkpoint.logid', + type: 'keyword', + }, + 'checkpoint.failure_impact': { + category: 'checkpoint', + description: 'The impact of update service failure. ', + name: 'checkpoint.failure_impact', + type: 'keyword', + }, + 'checkpoint.id': { + category: 'checkpoint', + description: 'Override application ID. ', + name: 'checkpoint.id', + type: 'integer', + }, + 'checkpoint.information': { + category: 'checkpoint', + description: 'Policy installation status for a specific blade. ', + name: 'checkpoint.information', + type: 'keyword', + }, + 'checkpoint.layer_name': { + category: 'checkpoint', + description: 'Layer name. ', + name: 'checkpoint.layer_name', + type: 'keyword', + }, + 'checkpoint.layer_uuid': { + category: 'checkpoint', + description: 'Layer UUID. ', + name: 'checkpoint.layer_uuid', + type: 'keyword', + }, + 'checkpoint.log_id': { + category: 'checkpoint', + description: 'Unique identity for logs. ', + name: 'checkpoint.log_id', + type: 'integer', + }, + 'checkpoint.origin_sic_name': { + category: 'checkpoint', + description: 'Machine SIC. ', + name: 'checkpoint.origin_sic_name', + type: 'keyword', + }, + 'checkpoint.policy_mgmt': { + category: 'checkpoint', + description: 'Name of the Management Server that manages this Security Gateway. ', + name: 'checkpoint.policy_mgmt', + type: 'keyword', + }, + 'checkpoint.policy_name': { + category: 'checkpoint', + description: 'Name of the last policy that this Security Gateway fetched. ', + name: 'checkpoint.policy_name', + type: 'keyword', + }, + 'checkpoint.protocol': { + category: 'checkpoint', + description: 'Protocol detected on the connection. ', + name: 'checkpoint.protocol', + type: 'keyword', + }, + 'checkpoint.proxy_src_ip': { + category: 'checkpoint', + description: 'Sender source IP (even when using proxy). ', + name: 'checkpoint.proxy_src_ip', + type: 'ip', + }, + 'checkpoint.rule': { + category: 'checkpoint', + description: 'Matched rule number. ', + name: 'checkpoint.rule', + type: 'integer', + }, + 'checkpoint.rule_action': { + category: 'checkpoint', + description: 'Action of the matched rule in the access policy. ', + name: 'checkpoint.rule_action', + type: 'keyword', + }, + 'checkpoint.scan_direction': { + category: 'checkpoint', + description: 'Scan direction. ', + name: 'checkpoint.scan_direction', + type: 'keyword', + }, + 'checkpoint.session_id': { + category: 'checkpoint', + description: 'Log uuid. ', + name: 'checkpoint.session_id', + type: 'keyword', + }, + 'checkpoint.source_os': { + category: 'checkpoint', + description: 'OS which generated the attack. ', + name: 'checkpoint.source_os', + type: 'keyword', + }, + 'checkpoint.src_country': { + category: 'checkpoint', + description: 'Country name, derived from connection source IP address. ', + name: 'checkpoint.src_country', + type: 'keyword', + }, + 'checkpoint.src_user_name': { + category: 'checkpoint', + description: 'User name connected to source IP ', + name: 'checkpoint.src_user_name', + type: 'keyword', + }, + 'checkpoint.ticket_id': { + category: 'checkpoint', + description: 'Unique ID per file. ', + name: 'checkpoint.ticket_id', + type: 'keyword', + }, + 'checkpoint.tls_server_host_name': { + category: 'checkpoint', + description: 'SNI/CN from encrypted TLS connection used by URLF for categorization. ', + name: 'checkpoint.tls_server_host_name', + type: 'keyword', + }, + 'checkpoint.verdict': { + category: 'checkpoint', + description: 'TE engine verdict Possible values: Malicious/Benign/Error. ', + name: 'checkpoint.verdict', + type: 'keyword', + }, + 'checkpoint.user': { + category: 'checkpoint', + description: 'Source user name. ', + name: 'checkpoint.user', + type: 'keyword', + }, + 'checkpoint.vendor_list': { + category: 'checkpoint', + description: 'The vendor name that provided the verdict for a malicious URL. ', + name: 'checkpoint.vendor_list', + type: 'keyword', + }, + 'checkpoint.web_server_type': { + category: 'checkpoint', + description: 'Web server detected in the HTTP response. ', + name: 'checkpoint.web_server_type', + type: 'keyword', + }, + 'checkpoint.client_name': { + category: 'checkpoint', + description: 'Client Application or Software Blade that detected the event. ', + name: 'checkpoint.client_name', + type: 'keyword', + }, + 'checkpoint.client_version': { + category: 'checkpoint', + description: 'Build version of SandBlast Agent client installed on the computer. ', + name: 'checkpoint.client_version', + type: 'keyword', + }, + 'checkpoint.extension_version': { + category: 'checkpoint', + description: 'Build version of the SandBlast Agent browser extension. ', + name: 'checkpoint.extension_version', + type: 'keyword', + }, + 'checkpoint.host_time': { + category: 'checkpoint', + description: 'Local time on the endpoint computer. ', + name: 'checkpoint.host_time', + type: 'keyword', + }, + 'checkpoint.installed_products': { + category: 'checkpoint', + description: 'List of installed Endpoint Software Blades. ', + name: 'checkpoint.installed_products', + type: 'keyword', + }, + 'checkpoint.cc': { + category: 'checkpoint', + description: 'The Carbon Copy address of the email. ', + name: 'checkpoint.cc', + type: 'keyword', + }, + 'checkpoint.parent_process_username': { + category: 'checkpoint', + description: 'Owner username of the parent process of the process that triggered the attack. ', + name: 'checkpoint.parent_process_username', + type: 'keyword', + }, + 'checkpoint.process_username': { + category: 'checkpoint', + description: 'Owner username of the process that triggered the attack. ', + name: 'checkpoint.process_username', + type: 'keyword', + }, + 'checkpoint.audit_status': { + category: 'checkpoint', + description: 'Audit Status. Can be Success or Failure. ', + name: 'checkpoint.audit_status', + type: 'keyword', + }, + 'checkpoint.objecttable': { + category: 'checkpoint', + description: 'Table of affected objects. ', + name: 'checkpoint.objecttable', + type: 'keyword', + }, + 'checkpoint.objecttype': { + category: 'checkpoint', + description: 'The type of the affected object. ', + name: 'checkpoint.objecttype', + type: 'keyword', + }, + 'checkpoint.operation_number': { + category: 'checkpoint', + description: 'The operation nuber. ', + name: 'checkpoint.operation_number', + type: 'keyword', + }, + 'checkpoint.suppressed_logs': { + category: 'checkpoint', + description: + 'Aggregated connections for five minutes on the same source, destination and port. ', + name: 'checkpoint.suppressed_logs', + type: 'integer', + }, + 'checkpoint.blade_name': { + category: 'checkpoint', + description: 'Blade name. ', + name: 'checkpoint.blade_name', + type: 'keyword', + }, + 'checkpoint.status': { + category: 'checkpoint', + description: 'Ok/Warning/Error. ', + name: 'checkpoint.status', + type: 'keyword', + }, + 'checkpoint.short_desc': { + category: 'checkpoint', + description: 'Short description of the process that was executed. ', + name: 'checkpoint.short_desc', + type: 'keyword', + }, + 'checkpoint.long_desc': { + category: 'checkpoint', + description: 'More information on the process (usually describing error reason in failure). ', + name: 'checkpoint.long_desc', + type: 'keyword', + }, + 'checkpoint.scan_hosts_hour': { + category: 'checkpoint', + description: 'Number of unique hosts during the last hour. ', + name: 'checkpoint.scan_hosts_hour', + type: 'integer', + }, + 'checkpoint.scan_hosts_day': { + category: 'checkpoint', + description: 'Number of unique hosts during the last day. ', + name: 'checkpoint.scan_hosts_day', + type: 'integer', + }, + 'checkpoint.scan_hosts_week': { + category: 'checkpoint', + description: 'Number of unique hosts during the last week. ', + name: 'checkpoint.scan_hosts_week', + type: 'integer', + }, + 'checkpoint.unique_detected_hour': { + category: 'checkpoint', + description: 'Detected virus for a specific host during the last hour. ', + name: 'checkpoint.unique_detected_hour', + type: 'integer', + }, + 'checkpoint.unique_detected_day': { + category: 'checkpoint', + description: 'Detected virus for a specific host during the last day. ', + name: 'checkpoint.unique_detected_day', + type: 'integer', + }, + 'checkpoint.unique_detected_week': { + category: 'checkpoint', + description: 'Detected virus for a specific host during the last week. ', + name: 'checkpoint.unique_detected_week', + type: 'integer', + }, + 'checkpoint.scan_mail': { + category: 'checkpoint', + description: 'Number of emails that were scanned by "AB malicious activity" engine. ', + name: 'checkpoint.scan_mail', + type: 'integer', + }, + 'checkpoint.additional_ip': { + category: 'checkpoint', + description: 'DNS host name. ', + name: 'checkpoint.additional_ip', + type: 'keyword', + }, + 'checkpoint.description': { + category: 'checkpoint', + description: 'Additional explanation how the security gateway enforced the connection. ', + name: 'checkpoint.description', + type: 'keyword', + }, + 'checkpoint.email_spam_category': { + category: 'checkpoint', + description: 'Email categories. Possible values: spam/not spam/phishing. ', + name: 'checkpoint.email_spam_category', + type: 'keyword', + }, + 'checkpoint.email_control_analysis': { + category: 'checkpoint', + description: 'Message classification, received from spam vendor engine. ', + name: 'checkpoint.email_control_analysis', + type: 'keyword', + }, + 'checkpoint.scan_results': { + category: 'checkpoint', + description: '"Infected"/description of a failure. ', + name: 'checkpoint.scan_results', + type: 'keyword', + }, + 'checkpoint.original_queue_id': { + category: 'checkpoint', + description: 'Original postfix email queue id. ', + name: 'checkpoint.original_queue_id', + type: 'keyword', + }, + 'checkpoint.risk': { + category: 'checkpoint', + description: 'Risk level we got from the engine. ', + name: 'checkpoint.risk', + type: 'keyword', + }, + 'checkpoint.observable_name': { + category: 'checkpoint', + description: 'IOC observable signature name. ', + name: 'checkpoint.observable_name', + type: 'keyword', + }, + 'checkpoint.observable_id': { + category: 'checkpoint', + description: 'IOC observable signature id. ', + name: 'checkpoint.observable_id', + type: 'keyword', + }, + 'checkpoint.observable_comment': { + category: 'checkpoint', + description: 'IOC observable signature description. ', + name: 'checkpoint.observable_comment', + type: 'keyword', + }, + 'checkpoint.indicator_name': { + category: 'checkpoint', + description: 'IOC indicator name. ', + name: 'checkpoint.indicator_name', + type: 'keyword', + }, + 'checkpoint.indicator_description': { + category: 'checkpoint', + description: 'IOC indicator description. ', + name: 'checkpoint.indicator_description', + type: 'keyword', + }, + 'checkpoint.indicator_reference': { + category: 'checkpoint', + description: 'IOC indicator reference. ', + name: 'checkpoint.indicator_reference', + type: 'keyword', + }, + 'checkpoint.indicator_uuid': { + category: 'checkpoint', + description: 'IOC indicator uuid. ', + name: 'checkpoint.indicator_uuid', + type: 'keyword', + }, + 'checkpoint.app_desc': { + category: 'checkpoint', + description: 'Application description. ', + name: 'checkpoint.app_desc', + type: 'keyword', + }, + 'checkpoint.app_id': { + category: 'checkpoint', + description: 'Application ID. ', + name: 'checkpoint.app_id', + type: 'integer', + }, + 'checkpoint.certificate_resource': { + category: 'checkpoint', + description: 'HTTPS resource Possible values: SNI or domain name (DN). ', + name: 'checkpoint.certificate_resource', + type: 'keyword', + }, + 'checkpoint.certificate_validation': { + category: 'checkpoint', + description: + 'Precise error, describing HTTPS certificate failure under "HTTPS categorize websites" feature. ', + name: 'checkpoint.certificate_validation', + type: 'keyword', + }, + 'checkpoint.browse_time': { + category: 'checkpoint', + description: 'Application session browse time. ', + name: 'checkpoint.browse_time', + type: 'keyword', + }, + 'checkpoint.limit_requested': { + category: 'checkpoint', + description: 'Indicates whether data limit was requested for the session. ', + name: 'checkpoint.limit_requested', + type: 'integer', + }, + 'checkpoint.limit_applied': { + category: 'checkpoint', + description: 'Indicates whether the session was actually date limited. ', + name: 'checkpoint.limit_applied', + type: 'integer', + }, + 'checkpoint.dropped_total': { + category: 'checkpoint', + description: 'Amount of dropped packets (both incoming and outgoing). ', + name: 'checkpoint.dropped_total', + type: 'integer', + }, + 'checkpoint.client_type_os': { + category: 'checkpoint', + description: 'Client OS detected in the HTTP request. ', + name: 'checkpoint.client_type_os', + type: 'keyword', + }, + 'checkpoint.name': { + category: 'checkpoint', + description: 'Application name. ', + name: 'checkpoint.name', + type: 'keyword', + }, + 'checkpoint.properties': { + category: 'checkpoint', + description: 'Application categories. ', + name: 'checkpoint.properties', + type: 'keyword', + }, + 'checkpoint.sig_id': { + category: 'checkpoint', + description: "Application's signature ID which how it was detected by. ", + name: 'checkpoint.sig_id', + type: 'keyword', + }, + 'checkpoint.desc': { + category: 'checkpoint', + description: 'Override application description. ', + name: 'checkpoint.desc', + type: 'keyword', }, - 'mysql.slowlog.sort_rows': { - category: 'mysql', - description: 'Number of sorted rows. ', - name: 'mysql.slowlog.sort_rows', - type: 'long', + 'checkpoint.referrer_self_uid': { + category: 'checkpoint', + description: 'UUID of the current log. ', + name: 'checkpoint.referrer_self_uid', + type: 'keyword', }, - 'mysql.slowlog.sort_scan_count': { - category: 'mysql', - description: 'Number of sorts that were done by scanning the table. ', - name: 'mysql.slowlog.sort_scan_count', - type: 'long', + 'checkpoint.referrer_parent_uid': { + category: 'checkpoint', + description: 'Log UUID of the referring application. ', + name: 'checkpoint.referrer_parent_uid', + type: 'keyword', }, - 'mysql.slowlog.log_slow_rate_type': { - category: 'mysql', + 'checkpoint.needs_browse_time': { + category: 'checkpoint', + description: 'Browse time required for the connection. ', + name: 'checkpoint.needs_browse_time', + type: 'integer', + }, + 'checkpoint.cluster_info': { + category: 'checkpoint', description: - 'Type of slow log rate limit, it can be `session` if the rate limit is applied per session, or `query` if it applies per query. ', - name: 'mysql.slowlog.log_slow_rate_type', + 'Cluster information. Possible options: Failover reason/cluster state changes/CP cluster or 3rd party. ', + name: 'checkpoint.cluster_info', type: 'keyword', }, - 'mysql.slowlog.log_slow_rate_limit': { - category: 'mysql', - description: - 'Slow log rate limit, a value of 100 means that one in a hundred queries or sessions are being logged. ', - name: 'mysql.slowlog.log_slow_rate_limit', + 'checkpoint.sync': { + category: 'checkpoint', + description: 'Sync status and the reason (stable, at risk). ', + name: 'checkpoint.sync', type: 'keyword', }, - 'mysql.slowlog.read_first': { - category: 'mysql', - description: 'The number of times the first entry in an index was read. ', - name: 'mysql.slowlog.read_first', - type: 'long', + 'checkpoint.file_direction': { + category: 'checkpoint', + description: 'File direction. Possible options: upload/download. ', + name: 'checkpoint.file_direction', + type: 'keyword', }, - 'mysql.slowlog.read_last': { - category: 'mysql', - description: 'The number of times the last key in an index was read. ', - name: 'mysql.slowlog.read_last', - type: 'long', + 'checkpoint.invalid_file_size': { + category: 'checkpoint', + description: 'File_size field is valid only if this field is set to 0. ', + name: 'checkpoint.invalid_file_size', + type: 'integer', }, - 'mysql.slowlog.read_key': { - category: 'mysql', - description: 'The number of requests to read a row based on a key. ', - name: 'mysql.slowlog.read_key', - type: 'long', + 'checkpoint.top_archive_file_name': { + category: 'checkpoint', + description: 'In case of archive file: the file that was sent/received. ', + name: 'checkpoint.top_archive_file_name', + type: 'keyword', }, - 'mysql.slowlog.read_next': { - category: 'mysql', - description: 'The number of requests to read the next row in key order. ', - name: 'mysql.slowlog.read_next', - type: 'long', + 'checkpoint.data_type_name': { + category: 'checkpoint', + description: 'Data type in rulebase that was matched. ', + name: 'checkpoint.data_type_name', + type: 'keyword', }, - 'mysql.slowlog.read_prev': { - category: 'mysql', - description: 'The number of requests to read the previous row in key order. ', - name: 'mysql.slowlog.read_prev', - type: 'long', + 'checkpoint.specific_data_type_name': { + category: 'checkpoint', + description: 'Compound/Group scenario, data type that was matched. ', + name: 'checkpoint.specific_data_type_name', + type: 'keyword', }, - 'mysql.slowlog.read_rnd': { - category: 'mysql', - description: 'The number of requests to read a row based on a fixed position. ', - name: 'mysql.slowlog.read_rnd', - type: 'long', + 'checkpoint.word_list': { + category: 'checkpoint', + description: 'Words matched by data type. ', + name: 'checkpoint.word_list', + type: 'keyword', }, - 'mysql.slowlog.read_rnd_next': { - category: 'mysql', - description: 'The number of requests to read the next row in the data file. ', - name: 'mysql.slowlog.read_rnd_next', - type: 'long', + 'checkpoint.info': { + category: 'checkpoint', + description: 'Special log message. ', + name: 'checkpoint.info', + type: 'keyword', }, - 'mysql.slowlog.innodb.trx_id': { - category: 'mysql', - description: 'Transaction ID ', - name: 'mysql.slowlog.innodb.trx_id', + 'checkpoint.outgoing_url': { + category: 'checkpoint', + description: 'URL related to this log (for HTTP). ', + name: 'checkpoint.outgoing_url', type: 'keyword', }, - 'mysql.slowlog.innodb.io_r_ops': { - category: 'mysql', - description: 'Number of page read operations. ', - name: 'mysql.slowlog.innodb.io_r_ops', - type: 'long', + 'checkpoint.dlp_rule_name': { + category: 'checkpoint', + description: 'Matched rule name. ', + name: 'checkpoint.dlp_rule_name', + type: 'keyword', }, - 'mysql.slowlog.innodb.io_r_bytes': { - category: 'mysql', - description: 'Bytes read during page read operations. ', - name: 'mysql.slowlog.innodb.io_r_bytes', - type: 'long', - format: 'bytes', + 'checkpoint.dlp_recipients': { + category: 'checkpoint', + description: 'Mail recipients. ', + name: 'checkpoint.dlp_recipients', + type: 'keyword', }, - 'mysql.slowlog.innodb.io_r_wait.sec': { - category: 'mysql', - description: 'How long it took to read all needed data from storage. ', - name: 'mysql.slowlog.innodb.io_r_wait.sec', - type: 'long', + 'checkpoint.dlp_subject': { + category: 'checkpoint', + description: 'Mail subject. ', + name: 'checkpoint.dlp_subject', + type: 'keyword', }, - 'mysql.slowlog.innodb.rec_lock_wait.sec': { - category: 'mysql', - description: 'How long the query waited for locks. ', - name: 'mysql.slowlog.innodb.rec_lock_wait.sec', - type: 'long', + 'checkpoint.dlp_word_list': { + category: 'checkpoint', + description: 'Phrases matched by data type. ', + name: 'checkpoint.dlp_word_list', + type: 'keyword', }, - 'mysql.slowlog.innodb.queue_wait.sec': { - category: 'mysql', - description: - 'How long the query waited to enter the InnoDB queue and to be executed once in the queue. ', - name: 'mysql.slowlog.innodb.queue_wait.sec', - type: 'long', + 'checkpoint.dlp_template_score': { + category: 'checkpoint', + description: 'Template data type match score. ', + name: 'checkpoint.dlp_template_score', + type: 'keyword', }, - 'mysql.slowlog.innodb.pages_distinct': { - category: 'mysql', - description: 'Approximated count of pages accessed to execute the query. ', - name: 'mysql.slowlog.innodb.pages_distinct', - type: 'long', + 'checkpoint.message_size': { + category: 'checkpoint', + description: 'Mail/post size. ', + name: 'checkpoint.message_size', + type: 'integer', }, - 'mysql.slowlog.user': { - category: 'mysql', - name: 'mysql.slowlog.user', - type: 'alias', + 'checkpoint.dlp_incident_uid': { + category: 'checkpoint', + description: 'Unique ID of the matched rule. ', + name: 'checkpoint.dlp_incident_uid', + type: 'keyword', }, - 'mysql.slowlog.host': { - category: 'mysql', - name: 'mysql.slowlog.host', - type: 'alias', + 'checkpoint.dlp_related_incident_uid': { + category: 'checkpoint', + description: 'Other ID related to this one. ', + name: 'checkpoint.dlp_related_incident_uid', + type: 'keyword', }, - 'mysql.slowlog.ip': { - category: 'mysql', - name: 'mysql.slowlog.ip', - type: 'alias', + 'checkpoint.dlp_data_type_name': { + category: 'checkpoint', + description: 'Matched data type. ', + name: 'checkpoint.dlp_data_type_name', + type: 'keyword', }, - 'nats.log.client.id': { - category: 'nats', - description: 'The id of the client ', - name: 'nats.log.client.id', - type: 'integer', + 'checkpoint.dlp_data_type_uid': { + category: 'checkpoint', + description: 'Unique ID of the matched data type. ', + name: 'checkpoint.dlp_data_type_uid', + type: 'keyword', }, - 'nats.log.msg.bytes': { - category: 'nats', - description: 'Size of the payload in bytes ', - name: 'nats.log.msg.bytes', - type: 'long', - format: 'bytes', + 'checkpoint.dlp_violation_description': { + category: 'checkpoint', + description: 'Violation descriptions described in the rulebase. ', + name: 'checkpoint.dlp_violation_description', + type: 'keyword', }, - 'nats.log.msg.type': { - category: 'nats', - description: 'The protocol message type ', - name: 'nats.log.msg.type', + 'checkpoint.dlp_relevant_data_types': { + category: 'checkpoint', + description: 'In case of Compound/Group: the inner data types that were matched. ', + name: 'checkpoint.dlp_relevant_data_types', type: 'keyword', }, - 'nats.log.msg.subject': { - category: 'nats', - description: 'Subject name this message was received on ', - name: 'nats.log.msg.subject', + 'checkpoint.dlp_action_reason': { + category: 'checkpoint', + description: 'Action chosen reason. ', + name: 'checkpoint.dlp_action_reason', type: 'keyword', }, - 'nats.log.msg.sid': { - category: 'nats', - description: 'The unique alphanumeric subscription ID of the subject ', - name: 'nats.log.msg.sid', - type: 'integer', + 'checkpoint.dlp_categories': { + category: 'checkpoint', + description: 'Data type category. ', + name: 'checkpoint.dlp_categories', + type: 'keyword', }, - 'nats.log.msg.reply_to': { - category: 'nats', - description: 'The inbox subject on which the publisher is listening for responses ', - name: 'nats.log.msg.reply_to', + 'checkpoint.dlp_transint': { + category: 'checkpoint', + description: 'HTTP/SMTP/FTP. ', + name: 'checkpoint.dlp_transint', type: 'keyword', }, - 'nats.log.msg.max_messages': { - category: 'nats', - description: 'An optional number of messages to wait for before automatically unsubscribing ', - name: 'nats.log.msg.max_messages', - type: 'integer', + 'checkpoint.duplicate': { + category: 'checkpoint', + description: + 'Log marked as duplicated, when mail is split and the Security Gateway sees it twice. ', + name: 'checkpoint.duplicate', + type: 'keyword', }, - 'nats.log.msg.error.message': { - category: 'nats', - description: 'Details about the error occurred ', - name: 'nats.log.msg.error.message', - type: 'text', + 'checkpoint.matched_file': { + category: 'checkpoint', + description: 'Unique ID of the matched data type. ', + name: 'checkpoint.matched_file', + type: 'keyword', }, - 'nats.log.msg.queue_group': { - category: 'nats', - description: 'The queue group which subscriber will join ', - name: 'nats.log.msg.queue_group', - type: 'text', + 'checkpoint.matched_file_text_segments': { + category: 'checkpoint', + description: 'Fingerprint: number of text segments matched by this traffic. ', + name: 'checkpoint.matched_file_text_segments', + type: 'integer', }, - 'nginx.access.remote_ip_list': { - category: 'nginx', - description: - 'An array of remote IP addresses. It is a list because it is common to include, besides the client IP address, IP addresses from headers like `X-Forwarded-For`. Real source IP is restored to `source.ip`. ', - name: 'nginx.access.remote_ip_list', - type: 'array', + 'checkpoint.matched_file_percentage': { + category: 'checkpoint', + description: 'Fingerprint: match percentage of the traffic. ', + name: 'checkpoint.matched_file_percentage', + type: 'integer', }, - 'nginx.access.body_sent.bytes': { - category: 'nginx', - name: 'nginx.access.body_sent.bytes', - type: 'alias', + 'checkpoint.dlp_additional_action': { + category: 'checkpoint', + description: 'Watermark/None. ', + name: 'checkpoint.dlp_additional_action', + type: 'keyword', }, - 'nginx.access.user_name': { - category: 'nginx', - name: 'nginx.access.user_name', - type: 'alias', + 'checkpoint.dlp_watermark_profile': { + category: 'checkpoint', + description: 'Watermark which was applied. ', + name: 'checkpoint.dlp_watermark_profile', + type: 'keyword', }, - 'nginx.access.method': { - category: 'nginx', - name: 'nginx.access.method', - type: 'alias', + 'checkpoint.dlp_repository_id': { + category: 'checkpoint', + description: 'ID of scanned repository. ', + name: 'checkpoint.dlp_repository_id', + type: 'keyword', }, - 'nginx.access.url': { - category: 'nginx', - name: 'nginx.access.url', - type: 'alias', + 'checkpoint.dlp_repository_root_path': { + category: 'checkpoint', + description: 'Repository path. ', + name: 'checkpoint.dlp_repository_root_path', + type: 'keyword', }, - 'nginx.access.http_version': { - category: 'nginx', - name: 'nginx.access.http_version', - type: 'alias', + 'checkpoint.scan_id': { + category: 'checkpoint', + description: 'Sequential number of scan. ', + name: 'checkpoint.scan_id', + type: 'keyword', }, - 'nginx.access.response_code': { - category: 'nginx', - name: 'nginx.access.response_code', - type: 'alias', + 'checkpoint.special_properties': { + category: 'checkpoint', + description: + "If this field is set to '1' the log will not be shown (in use for monitoring scan progress). ", + name: 'checkpoint.special_properties', + type: 'integer', }, - 'nginx.access.referrer': { - category: 'nginx', - name: 'nginx.access.referrer', - type: 'alias', + 'checkpoint.dlp_repository_total_size': { + category: 'checkpoint', + description: 'Repository size. ', + name: 'checkpoint.dlp_repository_total_size', + type: 'integer', }, - 'nginx.access.agent': { - category: 'nginx', - name: 'nginx.access.agent', - type: 'alias', + 'checkpoint.dlp_repository_files_number': { + category: 'checkpoint', + description: 'Number of files in repository. ', + name: 'checkpoint.dlp_repository_files_number', + type: 'integer', }, - 'nginx.access.user_agent.device': { - category: 'nginx', - name: 'nginx.access.user_agent.device', - type: 'alias', + 'checkpoint.dlp_repository_scanned_files_number': { + category: 'checkpoint', + description: 'Number of scanned files in repository. ', + name: 'checkpoint.dlp_repository_scanned_files_number', + type: 'integer', }, - 'nginx.access.user_agent.name': { - category: 'nginx', - name: 'nginx.access.user_agent.name', - type: 'alias', + 'checkpoint.duration': { + category: 'checkpoint', + description: 'Scan duration. ', + name: 'checkpoint.duration', + type: 'keyword', }, - 'nginx.access.user_agent.os': { - category: 'nginx', - name: 'nginx.access.user_agent.os', - type: 'alias', + 'checkpoint.dlp_fingerprint_long_status': { + category: 'checkpoint', + description: 'Scan status - long format. ', + name: 'checkpoint.dlp_fingerprint_long_status', + type: 'keyword', }, - 'nginx.access.user_agent.os_name': { - category: 'nginx', - name: 'nginx.access.user_agent.os_name', - type: 'alias', + 'checkpoint.dlp_fingerprint_short_status': { + category: 'checkpoint', + description: 'Scan status - short format. ', + name: 'checkpoint.dlp_fingerprint_short_status', + type: 'keyword', }, - 'nginx.access.user_agent.original': { - category: 'nginx', - name: 'nginx.access.user_agent.original', - type: 'alias', + 'checkpoint.dlp_repository_directories_number': { + category: 'checkpoint', + description: 'Number of directories in repository. ', + name: 'checkpoint.dlp_repository_directories_number', + type: 'integer', }, - 'nginx.access.geoip.continent_name': { - category: 'nginx', - name: 'nginx.access.geoip.continent_name', - type: 'alias', + 'checkpoint.dlp_repository_unreachable_directories_number': { + category: 'checkpoint', + description: 'Number of directories the Security Gateway was unable to read. ', + name: 'checkpoint.dlp_repository_unreachable_directories_number', + type: 'integer', }, - 'nginx.access.geoip.country_iso_code': { - category: 'nginx', - name: 'nginx.access.geoip.country_iso_code', - type: 'alias', + 'checkpoint.dlp_fingerprint_files_number': { + category: 'checkpoint', + description: 'Number of successfully scanned files in repository. ', + name: 'checkpoint.dlp_fingerprint_files_number', + type: 'integer', }, - 'nginx.access.geoip.location': { - category: 'nginx', - name: 'nginx.access.geoip.location', - type: 'alias', + 'checkpoint.dlp_repository_skipped_files_number': { + category: 'checkpoint', + description: 'Skipped number of files because of configuration. ', + name: 'checkpoint.dlp_repository_skipped_files_number', + type: 'integer', }, - 'nginx.access.geoip.region_name': { - category: 'nginx', - name: 'nginx.access.geoip.region_name', - type: 'alias', + 'checkpoint.dlp_repository_scanned_directories_number': { + category: 'checkpoint', + description: 'Amount of directories scanned. ', + name: 'checkpoint.dlp_repository_scanned_directories_number', + type: 'integer', }, - 'nginx.access.geoip.city_name': { - category: 'nginx', - name: 'nginx.access.geoip.city_name', - type: 'alias', + 'checkpoint.number_of_errors': { + category: 'checkpoint', + description: 'Number of files that were not scanned due to an error. ', + name: 'checkpoint.number_of_errors', + type: 'integer', }, - 'nginx.access.geoip.region_iso_code': { - category: 'nginx', - name: 'nginx.access.geoip.region_iso_code', - type: 'alias', + 'checkpoint.next_scheduled_scan_date': { + category: 'checkpoint', + description: 'Next scan scheduled time according to time object. ', + name: 'checkpoint.next_scheduled_scan_date', + type: 'keyword', }, - 'nginx.error.connection_id': { - category: 'nginx', - description: 'Connection identifier. ', - name: 'nginx.error.connection_id', - type: 'long', + 'checkpoint.dlp_repository_scanned_total_size': { + category: 'checkpoint', + description: 'Size scanned. ', + name: 'checkpoint.dlp_repository_scanned_total_size', + type: 'integer', }, - 'nginx.error.level': { - category: 'nginx', - name: 'nginx.error.level', - type: 'alias', + 'checkpoint.dlp_repository_reached_directories_number': { + category: 'checkpoint', + description: 'Number of scanned directories in repository. ', + name: 'checkpoint.dlp_repository_reached_directories_number', + type: 'integer', }, - 'nginx.error.pid': { - category: 'nginx', - name: 'nginx.error.pid', - type: 'alias', + 'checkpoint.dlp_repository_not_scanned_directories_percentage': { + category: 'checkpoint', + description: 'Percentage of directories the Security Gateway was unable to read. ', + name: 'checkpoint.dlp_repository_not_scanned_directories_percentage', + type: 'integer', }, - 'nginx.error.tid': { - category: 'nginx', - name: 'nginx.error.tid', - type: 'alias', + 'checkpoint.speed': { + category: 'checkpoint', + description: 'Current scan speed. ', + name: 'checkpoint.speed', + type: 'integer', }, - 'nginx.error.message': { - category: 'nginx', - name: 'nginx.error.message', - type: 'alias', + 'checkpoint.dlp_repository_scan_progress': { + category: 'checkpoint', + description: 'Scan percentage. ', + name: 'checkpoint.dlp_repository_scan_progress', + type: 'integer', }, - 'nginx.ingress_controller.remote_ip_list': { - category: 'nginx', - description: - 'An array of remote IP addresses. It is a list because it is common to include, besides the client IP address, IP addresses from headers like `X-Forwarded-For`. Real source IP is restored to `source.ip`. ', - name: 'nginx.ingress_controller.remote_ip_list', - type: 'array', + 'checkpoint.sub_policy_name': { + category: 'checkpoint', + description: 'Layer name. ', + name: 'checkpoint.sub_policy_name', + type: 'keyword', }, - 'nginx.ingress_controller.http.request.length': { - category: 'nginx', - description: 'The request length (including request line, header, and request body) ', - name: 'nginx.ingress_controller.http.request.length', - type: 'long', - format: 'bytes', + 'checkpoint.sub_policy_uid': { + category: 'checkpoint', + description: 'Layer uid. ', + name: 'checkpoint.sub_policy_uid', + type: 'keyword', }, - 'nginx.ingress_controller.http.request.time': { - category: 'nginx', - description: 'Time elapsed since the first bytes were read from the client ', - name: 'nginx.ingress_controller.http.request.time', - type: 'double', - format: 'duration', + 'checkpoint.fw_message': { + category: 'checkpoint', + description: 'Used for various firewall errors. ', + name: 'checkpoint.fw_message', + type: 'keyword', }, - 'nginx.ingress_controller.upstream.name': { - category: 'nginx', - description: 'The name of the upstream. ', - name: 'nginx.ingress_controller.upstream.name', + 'checkpoint.message': { + category: 'checkpoint', + description: 'ISP link has failed. ', + name: 'checkpoint.message', type: 'keyword', }, - 'nginx.ingress_controller.upstream.alternative_name': { - category: 'nginx', - description: 'The name of the alternative upstream. ', - name: 'nginx.ingress_controller.upstream.alternative_name', + 'checkpoint.isp_link': { + category: 'checkpoint', + description: 'Name of ISP link. ', + name: 'checkpoint.isp_link', type: 'keyword', }, - 'nginx.ingress_controller.upstream.response.length': { - category: 'nginx', - description: 'The length of the response obtained from the upstream server ', - name: 'nginx.ingress_controller.upstream.response.length', - type: 'long', - format: 'bytes', + 'checkpoint.fw_subproduct': { + category: 'checkpoint', + description: 'Can be vpn/non vpn. ', + name: 'checkpoint.fw_subproduct', + type: 'keyword', }, - 'nginx.ingress_controller.upstream.response.time': { - category: 'nginx', - description: - 'The time spent on receiving the response from the upstream server as seconds with millisecond resolution ', - name: 'nginx.ingress_controller.upstream.response.time', - type: 'double', - format: 'duration', + 'checkpoint.sctp_error': { + category: 'checkpoint', + description: 'Error information, what caused sctp to fail on out_of_state. ', + name: 'checkpoint.sctp_error', + type: 'keyword', }, - 'nginx.ingress_controller.upstream.response.status_code': { - category: 'nginx', - description: 'The status code of the response obtained from the upstream server ', - name: 'nginx.ingress_controller.upstream.response.status_code', - type: 'long', + 'checkpoint.chunk_type': { + category: 'checkpoint', + description: 'Chunck of the sctp stream. ', + name: 'checkpoint.chunk_type', + type: 'keyword', }, - 'nginx.ingress_controller.http.request.id': { - category: 'nginx', - description: 'The randomly generated ID of the request ', - name: 'nginx.ingress_controller.http.request.id', + 'checkpoint.sctp_association_state': { + category: 'checkpoint', + description: 'The bad state you were trying to update to. ', + name: 'checkpoint.sctp_association_state', type: 'keyword', }, - 'nginx.ingress_controller.upstream.ip': { - category: 'nginx', - description: - 'The IP address of the upstream server. If several servers were contacted during request processing, their addresses are separated by commas. ', - name: 'nginx.ingress_controller.upstream.ip', - type: 'ip', + 'checkpoint.tcp_packet_out_of_state': { + category: 'checkpoint', + description: 'State violation. ', + name: 'checkpoint.tcp_packet_out_of_state', + type: 'keyword', }, - 'nginx.ingress_controller.upstream.port': { - category: 'nginx', - description: 'The port of the upstream server. ', - name: 'nginx.ingress_controller.upstream.port', - type: 'long', + 'checkpoint.connectivity_level': { + category: 'checkpoint', + description: 'Log for a new connection in wire mode. ', + name: 'checkpoint.connectivity_level', + type: 'keyword', }, - 'nginx.ingress_controller.body_sent.bytes': { - category: 'nginx', - name: 'nginx.ingress_controller.body_sent.bytes', - type: 'alias', + 'checkpoint.ip_option': { + category: 'checkpoint', + description: 'IP option that was dropped. ', + name: 'checkpoint.ip_option', + type: 'integer', }, - 'nginx.ingress_controller.user_name': { - category: 'nginx', - name: 'nginx.ingress_controller.user_name', - type: 'alias', + 'checkpoint.tcp_state': { + category: 'checkpoint', + description: 'Log reinting a tcp state change. ', + name: 'checkpoint.tcp_state', + type: 'keyword', }, - 'nginx.ingress_controller.method': { - category: 'nginx', - name: 'nginx.ingress_controller.method', - type: 'alias', + 'checkpoint.expire_time': { + category: 'checkpoint', + description: 'Connection closing time. ', + name: 'checkpoint.expire_time', + type: 'keyword', }, - 'nginx.ingress_controller.url': { - category: 'nginx', - name: 'nginx.ingress_controller.url', - type: 'alias', + 'checkpoint.rpc_prog': { + category: 'checkpoint', + description: 'Log for new RPC state - prog values. ', + name: 'checkpoint.rpc_prog', + type: 'integer', }, - 'nginx.ingress_controller.http_version': { - category: 'nginx', - name: 'nginx.ingress_controller.http_version', - type: 'alias', + 'checkpoint.dce-rpc_interface_uuid': { + category: 'checkpoint', + description: 'Log for new RPC state - UUID values ', + name: 'checkpoint.dce-rpc_interface_uuid', + type: 'keyword', }, - 'nginx.ingress_controller.response_code': { - category: 'nginx', - name: 'nginx.ingress_controller.response_code', - type: 'alias', + 'checkpoint.elapsed': { + category: 'checkpoint', + description: 'Time passed since start time. ', + name: 'checkpoint.elapsed', + type: 'keyword', }, - 'nginx.ingress_controller.referrer': { - category: 'nginx', - name: 'nginx.ingress_controller.referrer', - type: 'alias', + 'checkpoint.icmp': { + category: 'checkpoint', + description: 'Number of packets, received by the client. ', + name: 'checkpoint.icmp', + type: 'keyword', }, - 'nginx.ingress_controller.agent': { - category: 'nginx', - name: 'nginx.ingress_controller.agent', - type: 'alias', + 'checkpoint.capture_uuid': { + category: 'checkpoint', + description: 'UUID generated for the capture. Used when enabling the capture when logging. ', + name: 'checkpoint.capture_uuid', + type: 'keyword', }, - 'nginx.ingress_controller.user_agent.device': { - category: 'nginx', - name: 'nginx.ingress_controller.user_agent.device', - type: 'alias', + 'checkpoint.diameter_app_ID': { + category: 'checkpoint', + description: 'The ID of diameter application. ', + name: 'checkpoint.diameter_app_ID', + type: 'integer', }, - 'nginx.ingress_controller.user_agent.name': { - category: 'nginx', - name: 'nginx.ingress_controller.user_agent.name', - type: 'alias', + 'checkpoint.diameter_cmd_code': { + category: 'checkpoint', + description: 'Diameter not allowed application command id. ', + name: 'checkpoint.diameter_cmd_code', + type: 'integer', }, - 'nginx.ingress_controller.user_agent.os': { - category: 'nginx', - name: 'nginx.ingress_controller.user_agent.os', - type: 'alias', + 'checkpoint.diameter_msg_type': { + category: 'checkpoint', + description: 'Diameter message type. ', + name: 'checkpoint.diameter_msg_type', + type: 'keyword', }, - 'nginx.ingress_controller.user_agent.os_name': { - category: 'nginx', - name: 'nginx.ingress_controller.user_agent.os_name', - type: 'alias', + 'checkpoint.cp_message': { + category: 'checkpoint', + description: 'Used to log a general message. ', + name: 'checkpoint.cp_message', + type: 'integer', }, - 'nginx.ingress_controller.user_agent.original': { - category: 'nginx', - name: 'nginx.ingress_controller.user_agent.original', - type: 'alias', + 'checkpoint.log_delay': { + category: 'checkpoint', + description: 'Time left before deleting template. ', + name: 'checkpoint.log_delay', + type: 'integer', }, - 'nginx.ingress_controller.geoip.continent_name': { - category: 'nginx', - name: 'nginx.ingress_controller.geoip.continent_name', - type: 'alias', + 'checkpoint.attack_status': { + category: 'checkpoint', + description: 'In case of a malicious event on an endpoint computer, the status of the attack. ', + name: 'checkpoint.attack_status', + type: 'keyword', }, - 'nginx.ingress_controller.geoip.country_iso_code': { - category: 'nginx', - name: 'nginx.ingress_controller.geoip.country_iso_code', - type: 'alias', + 'checkpoint.impacted_files': { + category: 'checkpoint', + description: + 'In case of an infection on an endpoint computer, the list of files that the malware impacted. ', + name: 'checkpoint.impacted_files', + type: 'keyword', }, - 'nginx.ingress_controller.geoip.location': { - category: 'nginx', - name: 'nginx.ingress_controller.geoip.location', - type: 'alias', + 'checkpoint.remediated_files': { + category: 'checkpoint', + description: + 'In case of an infection and a successful cleaning of that infection, this is a list of remediated files on the computer. ', + name: 'checkpoint.remediated_files', + type: 'keyword', }, - 'nginx.ingress_controller.geoip.region_name': { - category: 'nginx', - name: 'nginx.ingress_controller.geoip.region_name', - type: 'alias', + 'checkpoint.triggered_by': { + category: 'checkpoint', + description: + 'The name of the mechanism that triggered the Software Blade to enforce a protection. ', + name: 'checkpoint.triggered_by', + type: 'keyword', }, - 'nginx.ingress_controller.geoip.city_name': { - category: 'nginx', - name: 'nginx.ingress_controller.geoip.city_name', - type: 'alias', + 'checkpoint.https_inspection_rule_id': { + category: 'checkpoint', + description: 'ID of the matched rule. ', + name: 'checkpoint.https_inspection_rule_id', + type: 'keyword', }, - 'nginx.ingress_controller.geoip.region_iso_code': { - category: 'nginx', - name: 'nginx.ingress_controller.geoip.region_iso_code', - type: 'alias', + 'checkpoint.https_inspection_rule_name': { + category: 'checkpoint', + description: 'Name of the matched rule. ', + name: 'checkpoint.https_inspection_rule_name', + type: 'keyword', }, - 'osquery.result.name': { - category: 'osquery', - description: 'The name of the query that generated this event. ', - name: 'osquery.result.name', + 'checkpoint.app_properties': { + category: 'checkpoint', + description: 'List of all found categories. ', + name: 'checkpoint.app_properties', type: 'keyword', }, - 'osquery.result.action': { - category: 'osquery', - description: - 'For incremental data, marks whether the entry was added or removed. It can be one of "added", "removed", or "snapshot". ', - name: 'osquery.result.action', + 'checkpoint.https_validation': { + category: 'checkpoint', + description: 'Precise error, describing HTTPS inspection failure. ', + name: 'checkpoint.https_validation', type: 'keyword', }, - 'osquery.result.host_identifier': { - category: 'osquery', - description: - 'The identifier for the host on which the osquery agent is running. Normally the hostname. ', - name: 'osquery.result.host_identifier', + 'checkpoint.https_inspection_action': { + category: 'checkpoint', + description: 'HTTPS inspection action (Inspect/Bypass/Error). ', + name: 'checkpoint.https_inspection_action', type: 'keyword', }, - 'osquery.result.unix_time': { - category: 'osquery', - description: - 'Unix timestamp of the event, in seconds since the epoch. Used for computing the `@timestamp` column. ', - name: 'osquery.result.unix_time', - type: 'long', + 'checkpoint.icap_service_id': { + category: 'checkpoint', + description: 'Service ID, can work with multiple servers, treated as services. ', + name: 'checkpoint.icap_service_id', + type: 'integer', }, - 'osquery.result.calendar_time': { - category: 'osquery', - description: 'String representation of the collection time, as formatted by osquery. ', - name: 'osquery.result.calendar_time', + 'checkpoint.icap_server_name': { + category: 'checkpoint', + description: 'Server name. ', + name: 'checkpoint.icap_server_name', type: 'keyword', }, - 'postgresql.log.timestamp': { - category: 'postgresql', - description: 'The timestamp from the log line. ', - name: 'postgresql.log.timestamp', + 'checkpoint.internal_error': { + category: 'checkpoint', + description: 'Internal error, for troubleshooting ', + name: 'checkpoint.internal_error', + type: 'keyword', }, - 'postgresql.log.core_id': { - category: 'postgresql', - description: 'Core id ', - name: 'postgresql.log.core_id', - type: 'long', + 'checkpoint.icap_more_info': { + category: 'checkpoint', + description: 'Free text for verdict. ', + name: 'checkpoint.icap_more_info', + type: 'integer', }, - 'postgresql.log.database': { - category: 'postgresql', - description: 'Name of database ', - example: 'mydb', - name: 'postgresql.log.database', + 'checkpoint.reply_status': { + category: 'checkpoint', + description: 'ICAP reply status code, e.g. 200 or 204. ', + name: 'checkpoint.reply_status', + type: 'integer', }, - 'postgresql.log.query': { - category: 'postgresql', - description: 'Query statement. ', - example: 'SELECT * FROM users;', - name: 'postgresql.log.query', + 'checkpoint.icap_server_service': { + category: 'checkpoint', + description: 'Service name, as given in the ICAP URI ', + name: 'checkpoint.icap_server_service', + type: 'keyword', }, - 'postgresql.log.query_step': { - category: 'postgresql', + 'checkpoint.mirror_and_decrypt_type': { + category: 'checkpoint', description: - 'Statement step when using extended query protocol (one of statement, parse, bind or execute) ', - example: 'parse', - name: 'postgresql.log.query_step', + 'Information about decrypt and forward. Possible values: Mirror only, Decrypt and mirror, Partial mirroring (HTTPS inspection Bypass). ', + name: 'checkpoint.mirror_and_decrypt_type', + type: 'keyword', }, - 'postgresql.log.query_name': { - category: 'postgresql', - description: - 'Name given to a query when using extended query protocol. If it is "", or not present, this field is ignored. ', - example: 'pdo_stmt_00000001', - name: 'postgresql.log.query_name', + 'checkpoint.interface_name': { + category: 'checkpoint', + description: 'Designated interface for mirror And decrypt. ', + name: 'checkpoint.interface_name', + type: 'keyword', }, - 'postgresql.log.error.code': { - category: 'postgresql', - description: 'Error code returned by Postgres (if any)', - name: 'postgresql.log.error.code', - type: 'long', + 'checkpoint.session_uid': { + category: 'checkpoint', + description: 'HTTP session-id. ', + name: 'checkpoint.session_uid', + type: 'keyword', }, - 'postgresql.log.timezone': { - category: 'postgresql', - name: 'postgresql.log.timezone', - type: 'alias', + 'checkpoint.broker_publisher': { + category: 'checkpoint', + description: 'IP address of the broker publisher who shared the session information. ', + name: 'checkpoint.broker_publisher', + type: 'ip', }, - 'postgresql.log.thread_id': { - category: 'postgresql', - name: 'postgresql.log.thread_id', - type: 'alias', + 'checkpoint.src_user_dn': { + category: 'checkpoint', + description: 'User distinguished name connected to source IP. ', + name: 'checkpoint.src_user_dn', + type: 'keyword', }, - 'postgresql.log.user': { - category: 'postgresql', - name: 'postgresql.log.user', - type: 'alias', + 'checkpoint.proxy_user_name': { + category: 'checkpoint', + description: 'User name connected to proxy IP. ', + name: 'checkpoint.proxy_user_name', + type: 'keyword', }, - 'postgresql.log.level': { - category: 'postgresql', - name: 'postgresql.log.level', - type: 'alias', + 'checkpoint.proxy_machine_name': { + category: 'checkpoint', + description: 'Machine name connected to proxy IP. ', + name: 'checkpoint.proxy_machine_name', + type: 'integer', }, - 'postgresql.log.message': { - category: 'postgresql', - name: 'postgresql.log.message', - type: 'alias', + 'checkpoint.proxy_user_dn': { + category: 'checkpoint', + description: 'User distinguished name connected to proxy IP. ', + name: 'checkpoint.proxy_user_dn', + type: 'keyword', }, - 'redis.log.role': { - category: 'redis', - description: - 'The role of the Redis instance. Can be one of `master`, `slave`, `child` (for RDF/AOF writing child), or `sentinel`. ', - name: 'redis.log.role', + 'checkpoint.query': { + category: 'checkpoint', + description: 'DNS query. ', + name: 'checkpoint.query', type: 'keyword', }, - 'redis.log.pid': { - category: 'redis', - name: 'redis.log.pid', - type: 'alias', + 'checkpoint.dns_query': { + category: 'checkpoint', + description: 'DNS query. ', + name: 'checkpoint.dns_query', + type: 'keyword', }, - 'redis.log.level': { - category: 'redis', - name: 'redis.log.level', - type: 'alias', + 'checkpoint.inspection_item': { + category: 'checkpoint', + description: 'Blade element performed inspection. ', + name: 'checkpoint.inspection_item', + type: 'keyword', }, - 'redis.log.message': { - category: 'redis', - name: 'redis.log.message', - type: 'alias', + 'checkpoint.inspection_category': { + category: 'checkpoint', + description: 'Inspection category: protocol anomaly, signature etc. ', + name: 'checkpoint.inspection_category', + type: 'keyword', }, - 'redis.slowlog.cmd': { - category: 'redis', - description: 'The command executed. ', - name: 'redis.slowlog.cmd', + 'checkpoint.inspection_profile': { + category: 'checkpoint', + description: 'Profile which the activated protection belongs to. ', + name: 'checkpoint.inspection_profile', type: 'keyword', }, - 'redis.slowlog.duration.us': { - category: 'redis', - description: 'How long it took to execute the command in microseconds. ', - name: 'redis.slowlog.duration.us', - type: 'long', + 'checkpoint.summary': { + category: 'checkpoint', + description: 'Summary message of a non-compliant DNS traffic drops or detects. ', + name: 'checkpoint.summary', + type: 'keyword', }, - 'redis.slowlog.id': { - category: 'redis', - description: 'The ID of the query. ', - name: 'redis.slowlog.id', - type: 'long', + 'checkpoint.question_rdata': { + category: 'checkpoint', + description: 'List of question records domains. ', + name: 'checkpoint.question_rdata', + type: 'keyword', }, - 'redis.slowlog.key': { - category: 'redis', - description: 'The key on which the command was executed. ', - name: 'redis.slowlog.key', + 'checkpoint.answer_rdata': { + category: 'checkpoint', + description: 'List of answer resource records to the questioned domains. ', + name: 'checkpoint.answer_rdata', type: 'keyword', }, - 'redis.slowlog.args': { - category: 'redis', - description: 'The arguments with which the command was called. ', - name: 'redis.slowlog.args', + 'checkpoint.authority_rdata': { + category: 'checkpoint', + description: 'List of authoritative servers. ', + name: 'checkpoint.authority_rdata', type: 'keyword', }, - 'santa.action': { - category: 'santa', - description: 'Action', - example: 'EXEC', - name: 'santa.action', + 'checkpoint.additional_rdata': { + category: 'checkpoint', + description: 'List of additional resource records. ', + name: 'checkpoint.additional_rdata', type: 'keyword', }, - 'santa.decision': { - category: 'santa', - description: 'Decision that santad took.', - example: 'ALLOW', - name: 'santa.decision', + 'checkpoint.files_names': { + category: 'checkpoint', + description: 'List of files requested by FTP. ', + name: 'checkpoint.files_names', type: 'keyword', }, - 'santa.reason': { - category: 'santa', - description: 'Reason for the decsision.', - example: 'CERT', - name: 'santa.reason', + 'checkpoint.ftp_user': { + category: 'checkpoint', + description: 'FTP username. ', + name: 'checkpoint.ftp_user', type: 'keyword', }, - 'santa.mode': { - category: 'santa', - description: 'Operating mode of Santa.', - example: 'M', - name: 'santa.mode', + 'checkpoint.mime_from': { + category: 'checkpoint', + description: "Sender's address. ", + name: 'checkpoint.mime_from', type: 'keyword', }, - 'santa.disk.volume': { - category: 'santa', - description: 'The volume name.', - name: 'santa.disk.volume', + 'checkpoint.mime_to': { + category: 'checkpoint', + description: 'List of receiver address. ', + name: 'checkpoint.mime_to', + type: 'keyword', }, - 'santa.disk.bus': { - category: 'santa', - description: 'The disk bus protocol.', - name: 'santa.disk.bus', + 'checkpoint.bcc': { + category: 'checkpoint', + description: 'List of BCC addresses. ', + name: 'checkpoint.bcc', + type: 'keyword', }, - 'santa.disk.serial': { - category: 'santa', - description: 'The disk serial number.', - name: 'santa.disk.serial', + 'checkpoint.content_type': { + category: 'checkpoint', + description: + 'Mail content type. Possible values: application/msword, text/html, image/gif etc. ', + name: 'checkpoint.content_type', + type: 'keyword', }, - 'santa.disk.bsdname': { - category: 'santa', - description: 'The disk BSD name.', - example: 'disk1s3', - name: 'santa.disk.bsdname', + 'checkpoint.user_agent': { + category: 'checkpoint', + description: 'String identifying requesting software user agent. ', + name: 'checkpoint.user_agent', + type: 'keyword', }, - 'santa.disk.model': { - category: 'santa', - description: 'The disk model.', - example: 'APPLE SSD SM0512L', - name: 'santa.disk.model', + 'checkpoint.referrer': { + category: 'checkpoint', + description: 'Referrer HTTP request header, previous web page address. ', + name: 'checkpoint.referrer', + type: 'keyword', }, - 'santa.disk.fs': { - category: 'santa', - description: 'The disk volume kind (filesystem type).', - example: 'apfs', - name: 'santa.disk.fs', + 'checkpoint.http_location': { + category: 'checkpoint', + description: 'Response header, indicates the URL to redirect a page to. ', + name: 'checkpoint.http_location', + type: 'keyword', }, - 'santa.disk.mount': { - category: 'santa', - description: 'The disk volume path.', - name: 'santa.disk.mount', + 'checkpoint.content_disposition': { + category: 'checkpoint', + description: 'Indicates how the content is expected to be displayed inline in the browser. ', + name: 'checkpoint.content_disposition', + type: 'keyword', }, - 'santa.certificate.common_name': { - category: 'santa', - description: 'Common name from code signing certificate.', - name: 'santa.certificate.common_name', + 'checkpoint.via': { + category: 'checkpoint', + description: + 'Via header is added by proxies for tracking purposes to avoid sending reqests in loop. ', + name: 'checkpoint.via', type: 'keyword', }, - 'santa.certificate.sha256': { - category: 'santa', - description: 'SHA256 hash of code signing certificate.', - name: 'santa.certificate.sha256', + 'checkpoint.http_server': { + category: 'checkpoint', + description: + 'Server HTTP header value, contains information about the software used by the origin server, which handles the request. ', + name: 'checkpoint.http_server', type: 'keyword', }, - 'system.auth.timestamp': { - category: 'system', - name: 'system.auth.timestamp', - type: 'alias', + 'checkpoint.content_length': { + category: 'checkpoint', + description: 'Indicates the size of the entity-body of the HTTP header. ', + name: 'checkpoint.content_length', + type: 'keyword', }, - 'system.auth.hostname': { - category: 'system', - name: 'system.auth.hostname', - type: 'alias', + 'checkpoint.authorization': { + category: 'checkpoint', + description: 'Authorization HTTP header value. ', + name: 'checkpoint.authorization', + type: 'keyword', }, - 'system.auth.program': { - category: 'system', - name: 'system.auth.program', - type: 'alias', + 'checkpoint.http_host': { + category: 'checkpoint', + description: 'Domain name of the server that the HTTP request is sent to. ', + name: 'checkpoint.http_host', + type: 'keyword', }, - 'system.auth.pid': { - category: 'system', - name: 'system.auth.pid', - type: 'alias', + 'checkpoint.inspection_settings_log': { + category: 'checkpoint', + description: 'Indicats that the log was released by inspection settings. ', + name: 'checkpoint.inspection_settings_log', + type: 'keyword', }, - 'system.auth.message': { - category: 'system', - name: 'system.auth.message', - type: 'alias', + 'checkpoint.cvpn_resource': { + category: 'checkpoint', + description: 'Mobile Access application. ', + name: 'checkpoint.cvpn_resource', + type: 'keyword', }, - 'system.auth.user': { - category: 'system', - name: 'system.auth.user', - type: 'alias', + 'checkpoint.cvpn_category': { + category: 'checkpoint', + description: 'Mobile Access application type. ', + name: 'checkpoint.cvpn_category', + type: 'keyword', }, - 'system.auth.ssh.method': { - category: 'system', - description: 'The SSH authentication method. Can be one of "password" or "publickey". ', - name: 'system.auth.ssh.method', + 'checkpoint.url': { + category: 'checkpoint', + description: 'Translated URL. ', + name: 'checkpoint.url', + type: 'keyword', }, - 'system.auth.ssh.signature': { - category: 'system', - description: 'The signature of the client public key. ', - name: 'system.auth.ssh.signature', + 'checkpoint.reject_id': { + category: 'checkpoint', + description: + 'A reject ID that corresponds to the one presented in the Mobile Access error page. ', + name: 'checkpoint.reject_id', + type: 'keyword', }, - 'system.auth.ssh.dropped_ip': { - category: 'system', - description: 'The client IP from SSH connections that are open and immediately dropped. ', - name: 'system.auth.ssh.dropped_ip', - type: 'ip', + 'checkpoint.fs-proto': { + category: 'checkpoint', + description: 'The file share protocol used in mobile acess file share application. ', + name: 'checkpoint.fs-proto', + type: 'keyword', }, - 'system.auth.ssh.event': { - category: 'system', - description: 'The SSH event as found in the logs (Accepted, Invalid, Failed, etc.) ', - example: 'Accepted', - name: 'system.auth.ssh.event', + 'checkpoint.app_package': { + category: 'checkpoint', + description: 'Unique identifier of the application on the protected mobile device. ', + name: 'checkpoint.app_package', + type: 'keyword', }, - 'system.auth.ssh.ip': { - category: 'system', - name: 'system.auth.ssh.ip', - type: 'alias', + 'checkpoint.appi_name': { + category: 'checkpoint', + description: 'Name of application downloaded on the protected mobile device. ', + name: 'checkpoint.appi_name', + type: 'keyword', }, - 'system.auth.ssh.port': { - category: 'system', - name: 'system.auth.ssh.port', - type: 'alias', + 'checkpoint.app_repackaged': { + category: 'checkpoint', + description: + 'Indicates whether the original application was repackage not by the official developer. ', + name: 'checkpoint.app_repackaged', + type: 'keyword', }, - 'system.auth.ssh.geoip.continent_name': { - category: 'system', - name: 'system.auth.ssh.geoip.continent_name', - type: 'alias', + 'checkpoint.app_sid_id': { + category: 'checkpoint', + description: 'Unique SHA identifier of a mobile application. ', + name: 'checkpoint.app_sid_id', + type: 'keyword', }, - 'system.auth.ssh.geoip.country_iso_code': { - category: 'system', - name: 'system.auth.ssh.geoip.country_iso_code', - type: 'alias', + 'checkpoint.app_version': { + category: 'checkpoint', + description: 'Version of the application downloaded on the protected mobile device. ', + name: 'checkpoint.app_version', + type: 'keyword', }, - 'system.auth.ssh.geoip.location': { - category: 'system', - name: 'system.auth.ssh.geoip.location', - type: 'alias', + 'checkpoint.developer_certificate_name': { + category: 'checkpoint', + description: + "Name of the developer's certificate that was used to sign the mobile application. ", + name: 'checkpoint.developer_certificate_name', + type: 'keyword', }, - 'system.auth.ssh.geoip.region_name': { - category: 'system', - name: 'system.auth.ssh.geoip.region_name', - type: 'alias', + 'checkpoint.email_message_id': { + category: 'checkpoint', + description: 'Email session id (uniqe ID of the mail). ', + name: 'checkpoint.email_message_id', + type: 'keyword', }, - 'system.auth.ssh.geoip.city_name': { - category: 'system', - name: 'system.auth.ssh.geoip.city_name', - type: 'alias', + 'checkpoint.email_queue_id': { + category: 'checkpoint', + description: 'Postfix email queue id. ', + name: 'checkpoint.email_queue_id', + type: 'keyword', }, - 'system.auth.ssh.geoip.region_iso_code': { - category: 'system', - name: 'system.auth.ssh.geoip.region_iso_code', - type: 'alias', + 'checkpoint.email_queue_name': { + category: 'checkpoint', + description: 'Postfix email queue name. ', + name: 'checkpoint.email_queue_name', + type: 'keyword', }, - 'system.auth.sudo.error': { - category: 'system', - description: 'The error message in case the sudo command failed. ', - example: 'user NOT in sudoers', - name: 'system.auth.sudo.error', + 'checkpoint.file_name': { + category: 'checkpoint', + description: 'Malicious file name. ', + name: 'checkpoint.file_name', + type: 'keyword', }, - 'system.auth.sudo.tty': { - category: 'system', - description: 'The TTY where the sudo command is executed. ', - name: 'system.auth.sudo.tty', + 'checkpoint.failure_reason': { + category: 'checkpoint', + description: 'MTA failure description. ', + name: 'checkpoint.failure_reason', + type: 'keyword', }, - 'system.auth.sudo.pwd': { - category: 'system', - description: 'The current directory where the sudo command is executed. ', - name: 'system.auth.sudo.pwd', + 'checkpoint.email_headers': { + category: 'checkpoint', + description: 'String containing all the email headers. ', + name: 'checkpoint.email_headers', + type: 'keyword', }, - 'system.auth.sudo.user': { - category: 'system', - description: 'The target user to which the sudo command is switching. ', - example: 'root', - name: 'system.auth.sudo.user', + 'checkpoint.arrival_time': { + category: 'checkpoint', + description: 'Email arrival timestamp. ', + name: 'checkpoint.arrival_time', + type: 'keyword', }, - 'system.auth.sudo.command': { - category: 'system', - description: 'The command executed via sudo. ', - name: 'system.auth.sudo.command', + 'checkpoint.email_status': { + category: 'checkpoint', + description: + "Describes the email's state. Possible options: delivered, deferred, skipped, bounced, hold, new, scan_started, scan_ended ", + name: 'checkpoint.email_status', + type: 'keyword', }, - 'system.auth.useradd.home': { - category: 'system', - description: 'The home folder for the new user.', - name: 'system.auth.useradd.home', + 'checkpoint.status_update': { + category: 'checkpoint', + description: 'Last time log was updated. ', + name: 'checkpoint.status_update', + type: 'keyword', }, - 'system.auth.useradd.shell': { - category: 'system', - description: 'The default shell for the new user.', - name: 'system.auth.useradd.shell', + 'checkpoint.delivery_time': { + category: 'checkpoint', + description: 'Timestamp of when email was delivered (MTA finished handling the email. ', + name: 'checkpoint.delivery_time', + type: 'keyword', }, - 'system.auth.useradd.name': { - category: 'system', - name: 'system.auth.useradd.name', - type: 'alias', + 'checkpoint.links_num': { + category: 'checkpoint', + description: 'Number of links in the mail. ', + name: 'checkpoint.links_num', + type: 'integer', }, - 'system.auth.useradd.uid': { - category: 'system', - name: 'system.auth.useradd.uid', - type: 'alias', + 'checkpoint.attachments_num': { + category: 'checkpoint', + description: 'Number of attachments in the mail. ', + name: 'checkpoint.attachments_num', + type: 'integer', }, - 'system.auth.useradd.gid': { - category: 'system', - name: 'system.auth.useradd.gid', - type: 'alias', + 'checkpoint.email_content': { + category: 'checkpoint', + description: + 'Mail contents. Possible options: attachments/links & attachments/links/text only. ', + name: 'checkpoint.email_content', + type: 'keyword', }, - 'system.auth.groupadd.name': { - category: 'system', - name: 'system.auth.groupadd.name', - type: 'alias', + 'checkpoint.allocated_ports': { + category: 'checkpoint', + description: 'Amount of allocated ports. ', + name: 'checkpoint.allocated_ports', + type: 'integer', }, - 'system.auth.groupadd.gid': { - category: 'system', - name: 'system.auth.groupadd.gid', - type: 'alias', + 'checkpoint.capacity': { + category: 'checkpoint', + description: 'Capacity of the ports. ', + name: 'checkpoint.capacity', + type: 'integer', }, - 'system.syslog.timestamp': { - category: 'system', - name: 'system.syslog.timestamp', - type: 'alias', + 'checkpoint.ports_usage': { + category: 'checkpoint', + description: 'Percentage of allocated ports. ', + name: 'checkpoint.ports_usage', + type: 'integer', }, - 'system.syslog.hostname': { - category: 'system', - name: 'system.syslog.hostname', - type: 'alias', + 'checkpoint.nat_exhausted_pool': { + category: 'checkpoint', + description: '4-tuple of an exhausted pool. ', + name: 'checkpoint.nat_exhausted_pool', + type: 'keyword', }, - 'system.syslog.program': { - category: 'system', - name: 'system.syslog.program', - type: 'alias', + 'checkpoint.nat_rulenum': { + category: 'checkpoint', + description: 'NAT rulebase first matched rule. ', + name: 'checkpoint.nat_rulenum', + type: 'integer', }, - 'system.syslog.pid': { - category: 'system', - name: 'system.syslog.pid', - type: 'alias', + 'checkpoint.nat_addtnl_rulenum': { + category: 'checkpoint', + description: + 'When matching 2 automatic rules , second rule match will be shown otherwise field will be 0. ', + name: 'checkpoint.nat_addtnl_rulenum', + type: 'integer', }, - 'system.syslog.message': { - category: 'system', - name: 'system.syslog.message', - type: 'alias', + 'checkpoint.message_info': { + category: 'checkpoint', + description: 'Used for information messages, for example:NAT connection has ended. ', + name: 'checkpoint.message_info', + type: 'keyword', }, - 'traefik.access.user_identifier': { - category: 'traefik', - description: 'Is the RFC 1413 identity of the client ', - name: 'traefik.access.user_identifier', + 'checkpoint.nat46': { + category: 'checkpoint', + description: 'NAT 46 status, in most cases "enabled". ', + name: 'checkpoint.nat46', type: 'keyword', }, - 'traefik.access.request_count': { - category: 'traefik', - description: 'The number of requests ', - name: 'traefik.access.request_count', - type: 'long', + 'checkpoint.end_time': { + category: 'checkpoint', + description: 'TCP connection end time. ', + name: 'checkpoint.end_time', + type: 'keyword', }, - 'traefik.access.frontend_name': { - category: 'traefik', - description: 'The name of the frontend used ', - name: 'traefik.access.frontend_name', + 'checkpoint.tcp_end_reason': { + category: 'checkpoint', + description: 'Reason for TCP connection closure. ', + name: 'checkpoint.tcp_end_reason', type: 'keyword', }, - 'traefik.access.backend_url': { - category: 'traefik', - description: 'The url of the backend where request is forwarded', - name: 'traefik.access.backend_url', + 'checkpoint.cgnet': { + category: 'checkpoint', + description: 'Describes NAT allocation for specific subscriber. ', + name: 'checkpoint.cgnet', type: 'keyword', }, - 'traefik.access.body_sent.bytes': { - category: 'traefik', - name: 'traefik.access.body_sent.bytes', - type: 'alias', + 'checkpoint.subscriber': { + category: 'checkpoint', + description: 'Source IP before CGNAT. ', + name: 'checkpoint.subscriber', + type: 'ip', + }, + 'checkpoint.hide_ip': { + category: 'checkpoint', + description: 'Source IP which will be used after CGNAT. ', + name: 'checkpoint.hide_ip', + type: 'ip', + }, + 'checkpoint.int_start': { + category: 'checkpoint', + description: 'Subscriber start int which will be used for NAT. ', + name: 'checkpoint.int_start', + type: 'integer', }, - 'traefik.access.remote_ip': { - category: 'traefik', - name: 'traefik.access.remote_ip', - type: 'alias', + 'checkpoint.int_end': { + category: 'checkpoint', + description: 'Subscriber end int which will be used for NAT. ', + name: 'checkpoint.int_end', + type: 'integer', }, - 'traefik.access.user_name': { - category: 'traefik', - name: 'traefik.access.user_name', - type: 'alias', + 'checkpoint.packet_amount': { + category: 'checkpoint', + description: 'Amount of packets dropped. ', + name: 'checkpoint.packet_amount', + type: 'integer', }, - 'traefik.access.method': { - category: 'traefik', - name: 'traefik.access.method', - type: 'alias', + 'checkpoint.monitor_reason': { + category: 'checkpoint', + description: 'Aggregated logs of monitored packets. ', + name: 'checkpoint.monitor_reason', + type: 'keyword', }, - 'traefik.access.url': { - category: 'traefik', - name: 'traefik.access.url', - type: 'alias', + 'checkpoint.drops_amount': { + category: 'checkpoint', + description: 'Amount of multicast packets dropped. ', + name: 'checkpoint.drops_amount', + type: 'integer', }, - 'traefik.access.http_version': { - category: 'traefik', - name: 'traefik.access.http_version', - type: 'alias', + 'checkpoint.securexl_message': { + category: 'checkpoint', + description: + 'Two options for a SecureXL message: 1. Missed accounting records after heavy load on logging system. 2. FW log message regarding a packet drop. ', + name: 'checkpoint.securexl_message', + type: 'keyword', }, - 'traefik.access.response_code': { - category: 'traefik', - name: 'traefik.access.response_code', - type: 'alias', + 'checkpoint.conns_amount': { + category: 'checkpoint', + description: 'Connections amount of aggregated log info. ', + name: 'checkpoint.conns_amount', + type: 'integer', }, - 'traefik.access.referrer': { - category: 'traefik', - name: 'traefik.access.referrer', - type: 'alias', + 'checkpoint.scope': { + category: 'checkpoint', + description: 'IP related to the attack. ', + name: 'checkpoint.scope', + type: 'keyword', }, - 'traefik.access.agent': { - category: 'traefik', - name: 'traefik.access.agent', - type: 'alias', + 'checkpoint.analyzed_on': { + category: 'checkpoint', + description: 'Check Point ThreatCloud / emulator name. ', + name: 'checkpoint.analyzed_on', + type: 'keyword', }, - 'traefik.access.user_agent.device': { - category: 'traefik', - name: 'traefik.access.user_agent.device', - type: 'alias', + 'checkpoint.detected_on': { + category: 'checkpoint', + description: 'System and applications version the file was emulated on. ', + name: 'checkpoint.detected_on', + type: 'keyword', }, - 'traefik.access.user_agent.name': { - category: 'traefik', - name: 'traefik.access.user_agent.name', - type: 'alias', + 'checkpoint.dropped_file_name': { + category: 'checkpoint', + description: 'List of names dropped from the original file. ', + name: 'checkpoint.dropped_file_name', + type: 'keyword', }, - 'traefik.access.user_agent.os': { - category: 'traefik', - name: 'traefik.access.user_agent.os', - type: 'alias', + 'checkpoint.dropped_file_type': { + category: 'checkpoint', + description: 'List of file types dropped from the original file. ', + name: 'checkpoint.dropped_file_type', + type: 'keyword', }, - 'traefik.access.user_agent.os_name': { - category: 'traefik', - name: 'traefik.access.user_agent.os_name', - type: 'alias', + 'checkpoint.dropped_file_hash': { + category: 'checkpoint', + description: 'List of file hashes dropped from the original file. ', + name: 'checkpoint.dropped_file_hash', + type: 'keyword', }, - 'traefik.access.user_agent.original': { - category: 'traefik', - name: 'traefik.access.user_agent.original', - type: 'alias', + 'checkpoint.dropped_file_verdict': { + category: 'checkpoint', + description: 'List of file verdics dropped from the original file. ', + name: 'checkpoint.dropped_file_verdict', + type: 'keyword', }, - 'traefik.access.geoip.continent_name': { - category: 'traefik', - name: 'traefik.access.geoip.continent_name', - type: 'alias', + 'checkpoint.emulated_on': { + category: 'checkpoint', + description: 'Images the files were emulated on. ', + name: 'checkpoint.emulated_on', + type: 'keyword', }, - 'traefik.access.geoip.country_iso_code': { - category: 'traefik', - name: 'traefik.access.geoip.country_iso_code', - type: 'alias', + 'checkpoint.extracted_file_type': { + category: 'checkpoint', + description: 'Types of extracted files in case of an archive. ', + name: 'checkpoint.extracted_file_type', + type: 'keyword', }, - 'traefik.access.geoip.location': { - category: 'traefik', - name: 'traefik.access.geoip.location', - type: 'alias', + 'checkpoint.extracted_file_names': { + category: 'checkpoint', + description: 'Names of extracted files in case of an archive. ', + name: 'checkpoint.extracted_file_names', + type: 'keyword', }, - 'traefik.access.geoip.region_name': { - category: 'traefik', - name: 'traefik.access.geoip.region_name', - type: 'alias', + 'checkpoint.extracted_file_hash': { + category: 'checkpoint', + description: 'Archive hash in case of extracted files. ', + name: 'checkpoint.extracted_file_hash', + type: 'keyword', }, - 'traefik.access.geoip.city_name': { - category: 'traefik', - name: 'traefik.access.geoip.city_name', - type: 'alias', + 'checkpoint.extracted_file_verdict': { + category: 'checkpoint', + description: 'Verdict of extracted files in case of an archive. ', + name: 'checkpoint.extracted_file_verdict', + type: 'keyword', }, - 'traefik.access.geoip.region_iso_code': { - category: 'traefik', - name: 'traefik.access.geoip.region_iso_code', - type: 'alias', + 'checkpoint.extracted_file_uid': { + category: 'checkpoint', + description: 'UID of extracted files in case of an archive. ', + name: 'checkpoint.extracted_file_uid', + type: 'keyword', }, - 'activemq.caller': { - category: 'activemq', - description: 'Name of the caller issuing the logging request (class or resource). ', - name: 'activemq.caller', + 'checkpoint.mitre_initial_access': { + category: 'checkpoint', + description: 'The adversary is trying to break into your network. ', + name: 'checkpoint.mitre_initial_access', type: 'keyword', }, - 'activemq.thread': { - category: 'activemq', - description: 'Thread that generated the logging event. ', - name: 'activemq.thread', + 'checkpoint.mitre_execution': { + category: 'checkpoint', + description: 'The adversary is trying to run malicious code. ', + name: 'checkpoint.mitre_execution', type: 'keyword', }, - 'activemq.user': { - category: 'activemq', - description: 'User that generated the logging event. ', - name: 'activemq.user', + 'checkpoint.mitre_persistence': { + category: 'checkpoint', + description: 'The adversary is trying to maintain his foothold. ', + name: 'checkpoint.mitre_persistence', type: 'keyword', }, - 'activemq.audit': { - category: 'activemq', - description: 'Fields from ActiveMQ audit logs. ', - name: 'activemq.audit', - type: 'group', + 'checkpoint.mitre_privilege_escalation': { + category: 'checkpoint', + description: 'The adversary is trying to gain higher-level permissions. ', + name: 'checkpoint.mitre_privilege_escalation', + type: 'keyword', }, - 'activemq.log.stack_trace': { - category: 'activemq', - name: 'activemq.log.stack_trace', + 'checkpoint.mitre_defense_evasion': { + category: 'checkpoint', + description: 'The adversary is trying to avoid being detected. ', + name: 'checkpoint.mitre_defense_evasion', type: 'keyword', }, - 'aws.cloudtrail.event_version': { - category: 'aws', - description: 'The CloudTrail version of the log event format. ', - name: 'aws.cloudtrail.event_version', + 'checkpoint.mitre_credential_access': { + category: 'checkpoint', + description: 'The adversary is trying to steal account names and passwords. ', + name: 'checkpoint.mitre_credential_access', type: 'keyword', }, - 'aws.cloudtrail.user_identity.type': { - category: 'aws', - description: 'The type of the identity ', - name: 'aws.cloudtrail.user_identity.type', + 'checkpoint.mitre_discovery': { + category: 'checkpoint', + description: 'The adversary is trying to expose information about your environment. ', + name: 'checkpoint.mitre_discovery', type: 'keyword', }, - 'aws.cloudtrail.user_identity.arn': { - category: 'aws', - description: 'The Amazon Resource Name (ARN) of the principal that made the call.', - name: 'aws.cloudtrail.user_identity.arn', + 'checkpoint.mitre_lateral_movement': { + category: 'checkpoint', + description: 'The adversary is trying to explore your environment. ', + name: 'checkpoint.mitre_lateral_movement', type: 'keyword', }, - 'aws.cloudtrail.user_identity.access_key_id': { - category: 'aws', - description: 'The access key ID that was used to sign the request.', - name: 'aws.cloudtrail.user_identity.access_key_id', + 'checkpoint.mitre_collection': { + category: 'checkpoint', + description: 'The adversary is trying to collect data of interest to achieve his goal. ', + name: 'checkpoint.mitre_collection', type: 'keyword', }, - 'aws.cloudtrail.user_identity.session_context.mfa_authenticated': { - category: 'aws', + 'checkpoint.mitre_command_and_control': { + category: 'checkpoint', description: - 'The value is true if the root user or IAM user whose credentials were used for the request also was authenticated with an MFA device; otherwise, false.', - name: 'aws.cloudtrail.user_identity.session_context.mfa_authenticated', + 'The adversary is trying to communicate with compromised systems in order to control them. ', + name: 'checkpoint.mitre_command_and_control', type: 'keyword', }, - 'aws.cloudtrail.user_identity.session_context.creation_date': { - category: 'aws', - description: 'The date and time when the temporary security credentials were issued.', - name: 'aws.cloudtrail.user_identity.session_context.creation_date', - type: 'date', + 'checkpoint.mitre_exfiltration': { + category: 'checkpoint', + description: 'The adversary is trying to steal data. ', + name: 'checkpoint.mitre_exfiltration', + type: 'keyword', }, - 'aws.cloudtrail.user_identity.session_context.session_issuer.type': { - category: 'aws', + 'checkpoint.mitre_impact': { + category: 'checkpoint', description: - 'The source of the temporary security credentials, such as Root, IAMUser, or Role.', - name: 'aws.cloudtrail.user_identity.session_context.session_issuer.type', + 'The adversary is trying to manipulate, interrupt, or destroy your systems and data. ', + name: 'checkpoint.mitre_impact', type: 'keyword', }, - 'aws.cloudtrail.user_identity.session_context.session_issuer.principal_id': { - category: 'aws', - description: 'The internal ID of the entity that was used to get credentials.', - name: 'aws.cloudtrail.user_identity.session_context.session_issuer.principal_id', + 'checkpoint.parent_file_hash': { + category: 'checkpoint', + description: "Archive's hash in case of extracted files. ", + name: 'checkpoint.parent_file_hash', type: 'keyword', }, - 'aws.cloudtrail.user_identity.session_context.session_issuer.arn': { - category: 'aws', - description: - 'The ARN of the source (account, IAM user, or role) that was used to get temporary security credentials.', - name: 'aws.cloudtrail.user_identity.session_context.session_issuer.arn', + 'checkpoint.parent_file_name': { + category: 'checkpoint', + description: "Archive's name in case of extracted files. ", + name: 'checkpoint.parent_file_name', type: 'keyword', }, - 'aws.cloudtrail.user_identity.session_context.session_issuer.account_id': { - category: 'aws', - description: 'The account that owns the entity that was used to get credentials.', - name: 'aws.cloudtrail.user_identity.session_context.session_issuer.account_id', + 'checkpoint.parent_file_uid': { + category: 'checkpoint', + description: "Archive's UID in case of extracted files. ", + name: 'checkpoint.parent_file_uid', type: 'keyword', }, - 'aws.cloudtrail.user_identity.invoked_by': { - category: 'aws', - description: - 'The name of the AWS service that made the request, such as Amazon EC2 Auto Scaling or AWS Elastic Beanstalk.', - name: 'aws.cloudtrail.user_identity.invoked_by', + 'checkpoint.similiar_iocs': { + category: 'checkpoint', + description: 'Other IoCs similar to the ones found, related to the malicious file. ', + name: 'checkpoint.similiar_iocs', type: 'keyword', }, - 'aws.cloudtrail.error_code': { - category: 'aws', - description: 'The AWS service error if the request returns an error.', - name: 'aws.cloudtrail.error_code', + 'checkpoint.similar_hashes': { + category: 'checkpoint', + description: 'Hashes found similar to the malicious file. ', + name: 'checkpoint.similar_hashes', type: 'keyword', }, - 'aws.cloudtrail.error_message': { - category: 'aws', - description: 'If the request returns an error, the description of the error.', - name: 'aws.cloudtrail.error_message', + 'checkpoint.similar_strings': { + category: 'checkpoint', + description: 'Strings found similar to the malicious file. ', + name: 'checkpoint.similar_strings', type: 'keyword', }, - 'aws.cloudtrail.request_parameters': { - category: 'aws', - description: 'The parameters, if any, that were sent with the request.', - name: 'aws.cloudtrail.request_parameters', + 'checkpoint.similar_communication': { + category: 'checkpoint', + description: 'Network action found similar to the malicious file. ', + name: 'checkpoint.similar_communication', type: 'keyword', }, - 'aws.cloudtrail.response_elements': { - category: 'aws', - description: - 'The response element for actions that make changes (create, update, or delete actions).', - name: 'aws.cloudtrail.response_elements', + 'checkpoint.te_verdict_determined_by': { + category: 'checkpoint', + description: 'Emulators determined file verdict. ', + name: 'checkpoint.te_verdict_determined_by', type: 'keyword', }, - 'aws.cloudtrail.additional_eventdata': { - category: 'aws', - description: 'Additional data about the event that was not part of the request or response.', - name: 'aws.cloudtrail.additional_eventdata', + 'checkpoint.packet_capture_unique_id': { + category: 'checkpoint', + description: 'Identifier of the packet capture files. ', + name: 'checkpoint.packet_capture_unique_id', type: 'keyword', }, - 'aws.cloudtrail.request_id': { - category: 'aws', - description: - 'The value that identifies the request. The service being called generates this value.', - name: 'aws.cloudtrail.request_id', + 'checkpoint.total_attachments': { + category: 'checkpoint', + description: 'The number of attachments in an email. ', + name: 'checkpoint.total_attachments', + type: 'integer', + }, + 'checkpoint.additional_info': { + category: 'checkpoint', + description: 'ID of original file/mail which are sent by admin. ', + name: 'checkpoint.additional_info', type: 'keyword', }, - 'aws.cloudtrail.event_type': { - category: 'aws', - description: 'Identifies the type of event that generated the event record.', - name: 'aws.cloudtrail.event_type', + 'checkpoint.content_risk': { + category: 'checkpoint', + description: 'File risk. ', + name: 'checkpoint.content_risk', + type: 'integer', + }, + 'checkpoint.operation': { + category: 'checkpoint', + description: 'Operation made by Threat Extraction. ', + name: 'checkpoint.operation', type: 'keyword', }, - 'aws.cloudtrail.api_version': { - category: 'aws', - description: 'Identifies the API version associated with the AwsApiCall eventType value.', - name: 'aws.cloudtrail.api_version', + 'checkpoint.scrubbed_content': { + category: 'checkpoint', + description: 'Active content that was found. ', + name: 'checkpoint.scrubbed_content', type: 'keyword', }, - 'aws.cloudtrail.management_event': { - category: 'aws', - description: 'A Boolean value that identifies whether the event is a management event.', - name: 'aws.cloudtrail.management_event', + 'checkpoint.scrub_time': { + category: 'checkpoint', + description: 'Extraction process duration. ', + name: 'checkpoint.scrub_time', type: 'keyword', }, - 'aws.cloudtrail.read_only': { - category: 'aws', - description: 'Identifies whether this operation is a read-only operation.', - name: 'aws.cloudtrail.read_only', + 'checkpoint.scrub_download_time': { + category: 'checkpoint', + description: 'File download time from resource. ', + name: 'checkpoint.scrub_download_time', type: 'keyword', }, - 'aws.cloudtrail.resources.arn': { - category: 'aws', - description: 'Resource ARNs', - name: 'aws.cloudtrail.resources.arn', + 'checkpoint.scrub_total_time': { + category: 'checkpoint', + description: 'Threat extraction total file handling time. ', + name: 'checkpoint.scrub_total_time', type: 'keyword', }, - 'aws.cloudtrail.resources.account_id': { - category: 'aws', - description: 'Account ID of the resource owner', - name: 'aws.cloudtrail.resources.account_id', + 'checkpoint.scrub_activity': { + category: 'checkpoint', + description: 'The result of the extraction ', + name: 'checkpoint.scrub_activity', type: 'keyword', }, - 'aws.cloudtrail.resources.type': { - category: 'aws', - description: 'Resource type identifier in the format: AWS::aws-service-name::data-type-name', - name: 'aws.cloudtrail.resources.type', + 'checkpoint.watermark': { + category: 'checkpoint', + description: 'Reports whether watermark is added to the cleaned file. ', + name: 'checkpoint.watermark', type: 'keyword', }, - 'aws.cloudtrail.recipient_account_id': { - category: 'aws', - description: 'Represents the account ID that received this event.', - name: 'aws.cloudtrail.recipient_account_id', + 'checkpoint.source_object': { + category: 'checkpoint', + description: 'Matched object name on source column. ', + name: 'checkpoint.source_object', type: 'keyword', }, - 'aws.cloudtrail.service_event_details': { - category: 'aws', - description: 'Identifies the service event, including what triggered the event and the result.', - name: 'aws.cloudtrail.service_event_details', + 'checkpoint.destination_object': { + category: 'checkpoint', + description: 'Matched object name on destination column. ', + name: 'checkpoint.destination_object', type: 'keyword', }, - 'aws.cloudtrail.shared_event_id': { - category: 'aws', - description: - 'GUID generated by CloudTrail to uniquely identify CloudTrail events from the same AWS action that is sent to different AWS accounts.', - name: 'aws.cloudtrail.shared_event_id', + 'checkpoint.drop_reason': { + category: 'checkpoint', + description: 'Drop reason description. ', + name: 'checkpoint.drop_reason', type: 'keyword', }, - 'aws.cloudtrail.vpc_endpoint_id': { - category: 'aws', + 'checkpoint.hit': { + category: 'checkpoint', + description: 'Number of hits on a rule. ', + name: 'checkpoint.hit', + type: 'integer', + }, + 'checkpoint.rulebase_id': { + category: 'checkpoint', + description: 'Layer number. ', + name: 'checkpoint.rulebase_id', + type: 'integer', + }, + 'checkpoint.first_hit_time': { + category: 'checkpoint', + description: 'First hit time in current interval. ', + name: 'checkpoint.first_hit_time', + type: 'integer', + }, + 'checkpoint.last_hit_time': { + category: 'checkpoint', + description: 'Last hit time in current interval. ', + name: 'checkpoint.last_hit_time', + type: 'integer', + }, + 'checkpoint.rematch_info': { + category: 'checkpoint', description: - 'Identifies the VPC endpoint in which requests were made from a VPC to another AWS service, such as Amazon S3.', - name: 'aws.cloudtrail.vpc_endpoint_id', + 'Information sent when old connections cannot be matched during policy installation. ', + name: 'checkpoint.rematch_info', type: 'keyword', }, - 'aws.cloudtrail.console_login.additional_eventdata.mobile_version': { - category: 'aws', - description: 'Identifies whether ConsoleLogin was from mobile version', - name: 'aws.cloudtrail.console_login.additional_eventdata.mobile_version', - type: 'boolean', + 'checkpoint.last_rematch_time': { + category: 'checkpoint', + description: 'Connection rematched time. ', + name: 'checkpoint.last_rematch_time', + type: 'keyword', }, - 'aws.cloudtrail.console_login.additional_eventdata.login_to': { - category: 'aws', - description: 'URL for ConsoleLogin', - name: 'aws.cloudtrail.console_login.additional_eventdata.login_to', + 'checkpoint.action_reason': { + category: 'checkpoint', + description: 'Connection drop reason. ', + name: 'checkpoint.action_reason', + type: 'integer', + }, + 'checkpoint.action_reason_msg': { + category: 'checkpoint', + description: 'Connection drop reason message. ', + name: 'checkpoint.action_reason_msg', type: 'keyword', }, - 'aws.cloudtrail.console_login.additional_eventdata.mfa_used': { - category: 'aws', - description: 'Identifies whether multi factor authentication was used during ConsoleLogin', - name: 'aws.cloudtrail.console_login.additional_eventdata.mfa_used', - type: 'boolean', + 'checkpoint.c_bytes': { + category: 'checkpoint', + description: 'Boolean value indicates whether bytes sent from the client side are used. ', + name: 'checkpoint.c_bytes', + type: 'integer', + }, + 'checkpoint.context_num': { + category: 'checkpoint', + description: 'Serial number of the log for a specific connection. ', + name: 'checkpoint.context_num', + type: 'integer', }, - 'aws.cloudtrail.flattened.additional_eventdata': { - category: 'aws', - description: 'Additional data about the event that was not part of the request or response. ', - name: 'aws.cloudtrail.flattened.additional_eventdata', - type: 'flattened', + 'checkpoint.match_id': { + category: 'checkpoint', + description: 'Private key of the rule ', + name: 'checkpoint.match_id', + type: 'integer', }, - 'aws.cloudtrail.flattened.request_parameters': { - category: 'aws', - description: 'The parameters, if any, that were sent with the request.', - name: 'aws.cloudtrail.flattened.request_parameters', - type: 'flattened', + 'checkpoint.alert': { + category: 'checkpoint', + description: 'Alert level of matched rule (for connection logs). ', + name: 'checkpoint.alert', + type: 'keyword', }, - 'aws.cloudtrail.flattened.response_elements': { - category: 'aws', - description: - 'The response element for actions that make changes (create, update, or delete actions).', - name: 'aws.cloudtrail.flattened.response_elements', - type: 'flattened', + 'checkpoint.parent_rule': { + category: 'checkpoint', + description: 'Parent rule number, in case of inline layer. ', + name: 'checkpoint.parent_rule', + type: 'integer', }, - 'aws.cloudtrail.flattened.service_event_details': { - category: 'aws', - description: 'Identifies the service event, including what triggered the event and the result.', - name: 'aws.cloudtrail.flattened.service_event_details', - type: 'flattened', + 'checkpoint.match_fk': { + category: 'checkpoint', + description: 'Rule number. ', + name: 'checkpoint.match_fk', + type: 'integer', }, - 'aws.cloudwatch.message': { - category: 'aws', - description: 'CloudWatch log message. ', - name: 'aws.cloudwatch.message', - type: 'text', + 'checkpoint.dropped_outgoing': { + category: 'checkpoint', + description: 'Number of outgoing bytes dropped when using UP-limit feature. ', + name: 'checkpoint.dropped_outgoing', + type: 'integer', }, - 'aws.ec2.ip_address': { - category: 'aws', - description: 'The internet address of the requester. ', - name: 'aws.ec2.ip_address', - type: 'keyword', + 'checkpoint.dropped_incoming': { + category: 'checkpoint', + description: 'Number of incoming bytes dropped when using UP-limit feature. ', + name: 'checkpoint.dropped_incoming', + type: 'integer', }, - 'aws.elb.name': { - category: 'aws', - description: 'The name of the load balancer. ', - name: 'aws.elb.name', + 'checkpoint.media_type': { + category: 'checkpoint', + description: 'Media used (audio, video, etc.) ', + name: 'checkpoint.media_type', type: 'keyword', }, - 'aws.elb.type': { - category: 'aws', - description: 'The type of the load balancer for v2 Load Balancers. ', - name: 'aws.elb.type', + 'checkpoint.sip_reason': { + category: 'checkpoint', + description: "Explains why 'source_ip' isn't allowed to redirect (handover). ", + name: 'checkpoint.sip_reason', type: 'keyword', }, - 'aws.elb.target_group.arn': { - category: 'aws', - description: 'The ARN of the target group handling the request. ', - name: 'aws.elb.target_group.arn', + 'checkpoint.voip_method': { + category: 'checkpoint', + description: 'Registration request. ', + name: 'checkpoint.voip_method', type: 'keyword', }, - 'aws.elb.listener': { - category: 'aws', - description: 'The ELB listener that received the connection. ', - name: 'aws.elb.listener', + 'checkpoint.registered_ip-phones': { + category: 'checkpoint', + description: 'Registered IP-Phones. ', + name: 'checkpoint.registered_ip-phones', type: 'keyword', }, - 'aws.elb.protocol': { - category: 'aws', - description: 'The protocol of the load balancer (http or tcp). ', - name: 'aws.elb.protocol', + 'checkpoint.voip_reg_user_type': { + category: 'checkpoint', + description: 'Registered IP-Phone type. ', + name: 'checkpoint.voip_reg_user_type', type: 'keyword', }, - 'aws.elb.request_processing_time.sec': { - category: 'aws', - description: - 'The total time in seconds since the connection or request is received until it is sent to a registered backend. ', - name: 'aws.elb.request_processing_time.sec', - type: 'float', - }, - 'aws.elb.backend_processing_time.sec': { - category: 'aws', - description: - 'The total time in seconds since the connection is sent to the backend till the backend starts responding. ', - name: 'aws.elb.backend_processing_time.sec', - type: 'float', + 'checkpoint.voip_call_id': { + category: 'checkpoint', + description: 'Call-ID. ', + name: 'checkpoint.voip_call_id', + type: 'keyword', }, - 'aws.elb.response_processing_time.sec': { - category: 'aws', - description: - 'The total time in seconds since the response is received from the backend till it is sent to the client. ', - name: 'aws.elb.response_processing_time.sec', - type: 'float', + 'checkpoint.voip_reg_int': { + category: 'checkpoint', + description: 'Registration port. ', + name: 'checkpoint.voip_reg_int', + type: 'integer', }, - 'aws.elb.connection_time.ms': { - category: 'aws', - description: - 'The total time of the connection in milliseconds, since it is opened till it is closed. ', - name: 'aws.elb.connection_time.ms', - type: 'long', + 'checkpoint.voip_reg_ipp': { + category: 'checkpoint', + description: 'Registration IP protocol. ', + name: 'checkpoint.voip_reg_ipp', + type: 'integer', }, - 'aws.elb.tls_handshake_time.ms': { - category: 'aws', - description: - 'The total time for the TLS handshake to complete in milliseconds once the connection has been established. ', - name: 'aws.elb.tls_handshake_time.ms', - type: 'long', + 'checkpoint.voip_reg_period': { + category: 'checkpoint', + description: 'Registration period. ', + name: 'checkpoint.voip_reg_period', + type: 'integer', }, - 'aws.elb.backend.ip': { - category: 'aws', - description: 'The IP address of the backend processing this connection. ', - name: 'aws.elb.backend.ip', + 'checkpoint.src_phone_number': { + category: 'checkpoint', + description: 'Source IP-Phone. ', + name: 'checkpoint.src_phone_number', type: 'keyword', }, - 'aws.elb.backend.port': { - category: 'aws', - description: 'The port in the backend processing this connection. ', - name: 'aws.elb.backend.port', + 'checkpoint.voip_from_user_type': { + category: 'checkpoint', + description: 'Source IP-Phone type. ', + name: 'checkpoint.voip_from_user_type', type: 'keyword', }, - 'aws.elb.backend.http.response.status_code': { - category: 'aws', - description: - 'The status code from the backend (status code sent to the client from ELB is stored in `http.response.status_code` ', - name: 'aws.elb.backend.http.response.status_code', + 'checkpoint.voip_to_user_type': { + category: 'checkpoint', + description: 'Destination IP-Phone type. ', + name: 'checkpoint.voip_to_user_type', type: 'keyword', }, - 'aws.elb.ssl_cipher': { - category: 'aws', - description: 'The SSL cipher used in TLS/SSL connections. ', - name: 'aws.elb.ssl_cipher', + 'checkpoint.voip_call_dir': { + category: 'checkpoint', + description: 'Call direction: in/out. ', + name: 'checkpoint.voip_call_dir', type: 'keyword', }, - 'aws.elb.ssl_protocol': { - category: 'aws', - description: 'The SSL protocol used in TLS/SSL connections. ', - name: 'aws.elb.ssl_protocol', + 'checkpoint.voip_call_state': { + category: 'checkpoint', + description: 'Call state. Possible values: in/out. ', + name: 'checkpoint.voip_call_state', type: 'keyword', }, - 'aws.elb.chosen_cert.arn': { - category: 'aws', - description: - 'The ARN of the chosen certificate presented to the client in TLS/SSL connections. ', - name: 'aws.elb.chosen_cert.arn', + 'checkpoint.voip_call_term_time': { + category: 'checkpoint', + description: 'Call termination time stamp. ', + name: 'checkpoint.voip_call_term_time', type: 'keyword', }, - 'aws.elb.chosen_cert.serial': { - category: 'aws', - description: - 'The serial number of the chosen certificate presented to the client in TLS/SSL connections. ', - name: 'aws.elb.chosen_cert.serial', + 'checkpoint.voip_duration': { + category: 'checkpoint', + description: 'Call duration (seconds). ', + name: 'checkpoint.voip_duration', type: 'keyword', }, - 'aws.elb.incoming_tls_alert': { - category: 'aws', - description: - 'The integer value of TLS alerts received by the load balancer from the client, if present. ', - name: 'aws.elb.incoming_tls_alert', + 'checkpoint.voip_media_port': { + category: 'checkpoint', + description: 'Media int. ', + name: 'checkpoint.voip_media_port', type: 'keyword', }, - 'aws.elb.tls_named_group': { - category: 'aws', - description: 'The TLS named group. ', - name: 'aws.elb.tls_named_group', + 'checkpoint.voip_media_ipp': { + category: 'checkpoint', + description: 'Media IP protocol. ', + name: 'checkpoint.voip_media_ipp', type: 'keyword', }, - 'aws.elb.trace_id': { - category: 'aws', - description: 'The contents of the `X-Amzn-Trace-Id` header. ', - name: 'aws.elb.trace_id', + 'checkpoint.voip_est_codec': { + category: 'checkpoint', + description: 'Estimated codec. ', + name: 'checkpoint.voip_est_codec', type: 'keyword', }, - 'aws.elb.matched_rule_priority': { - category: 'aws', - description: 'The priority value of the rule that matched the request, if a rule matched. ', - name: 'aws.elb.matched_rule_priority', - type: 'keyword', + 'checkpoint.voip_exp': { + category: 'checkpoint', + description: 'Expiration. ', + name: 'checkpoint.voip_exp', + type: 'integer', }, - 'aws.elb.action_executed': { - category: 'aws', - description: - 'The action executed when processing the request (forward, fixed-response, authenticate...). It can contain several values. ', - name: 'aws.elb.action_executed', + 'checkpoint.voip_attach_sz': { + category: 'checkpoint', + description: 'Attachment size. ', + name: 'checkpoint.voip_attach_sz', + type: 'integer', + }, + 'checkpoint.voip_attach_action_info': { + category: 'checkpoint', + description: 'Attachment action Info. ', + name: 'checkpoint.voip_attach_action_info', type: 'keyword', }, - 'aws.elb.redirect_url': { - category: 'aws', - description: 'The URL used if a redirection action was executed. ', - name: 'aws.elb.redirect_url', + 'checkpoint.voip_media_codec': { + category: 'checkpoint', + description: 'Estimated codec. ', + name: 'checkpoint.voip_media_codec', type: 'keyword', }, - 'aws.elb.error.reason': { - category: 'aws', - description: 'The error reason if the executed action failed. ', - name: 'aws.elb.error.reason', + 'checkpoint.voip_reject_reason': { + category: 'checkpoint', + description: 'Reject reason. ', + name: 'checkpoint.voip_reject_reason', type: 'keyword', }, - 'aws.s3access.bucket_owner': { - category: 'aws', - description: 'The canonical user ID of the owner of the source bucket. ', - name: 'aws.s3access.bucket_owner', + 'checkpoint.voip_reason_info': { + category: 'checkpoint', + description: 'Information. ', + name: 'checkpoint.voip_reason_info', type: 'keyword', }, - 'aws.s3access.bucket': { - category: 'aws', - description: 'The name of the bucket that the request was processed against. ', - name: 'aws.s3access.bucket', + 'checkpoint.voip_config': { + category: 'checkpoint', + description: 'Configuration. ', + name: 'checkpoint.voip_config', type: 'keyword', }, - 'aws.s3access.remote_ip': { - category: 'aws', - description: 'The apparent internet address of the requester. ', - name: 'aws.s3access.remote_ip', + 'checkpoint.voip_reg_server': { + category: 'checkpoint', + description: 'Registrar server IP address. ', + name: 'checkpoint.voip_reg_server', type: 'ip', }, - 'aws.s3access.requester': { - category: 'aws', - description: 'The canonical user ID of the requester, or a - for unauthenticated requests. ', - name: 'aws.s3access.requester', + 'checkpoint.scv_user': { + category: 'checkpoint', + description: 'Username whose packets are dropped on SCV. ', + name: 'checkpoint.scv_user', type: 'keyword', }, - 'aws.s3access.request_id': { - category: 'aws', - description: 'A string generated by Amazon S3 to uniquely identify each request. ', - name: 'aws.s3access.request_id', + 'checkpoint.scv_message_info': { + category: 'checkpoint', + description: 'Drop reason. ', + name: 'checkpoint.scv_message_info', type: 'keyword', }, - 'aws.s3access.operation': { - category: 'aws', - description: - 'The operation listed here is declared as SOAP.operation, REST.HTTP_method.resource_type, WEBSITE.HTTP_method.resource_type, or BATCH.DELETE.OBJECT. ', - name: 'aws.s3access.operation', + 'checkpoint.ppp': { + category: 'checkpoint', + description: 'Authentication status. ', + name: 'checkpoint.ppp', type: 'keyword', }, - 'aws.s3access.key': { - category: 'aws', - description: - 'The "key" part of the request, URL encoded, or "-" if the operation does not take a key parameter. ', - name: 'aws.s3access.key', + 'checkpoint.scheme': { + category: 'checkpoint', + description: 'Describes the scheme used for the log. ', + name: 'checkpoint.scheme', type: 'keyword', }, - 'aws.s3access.request_uri': { - category: 'aws', - description: 'The Request-URI part of the HTTP request message. ', - name: 'aws.s3access.request_uri', + 'checkpoint.machine': { + category: 'checkpoint', + description: 'L2TP machine which triggered the log and the log refers to it. ', + name: 'checkpoint.machine', type: 'keyword', }, - 'aws.s3access.http_status': { - category: 'aws', - description: 'The numeric HTTP status code of the response. ', - name: 'aws.s3access.http_status', - type: 'long', - }, - 'aws.s3access.error_code': { - category: 'aws', - description: 'The Amazon S3 Error Code, or "-" if no error occurred. ', - name: 'aws.s3access.error_code', + 'checkpoint.vpn_feature_name': { + category: 'checkpoint', + description: 'L2TP /IKE / Link Selection. ', + name: 'checkpoint.vpn_feature_name', type: 'keyword', }, - 'aws.s3access.bytes_sent': { - category: 'aws', - description: - 'The number of response bytes sent, excluding HTTP protocol overhead, or "-" if zero. ', - name: 'aws.s3access.bytes_sent', - type: 'long', + 'checkpoint.reject_category': { + category: 'checkpoint', + description: 'Authentication failure reason. ', + name: 'checkpoint.reject_category', + type: 'keyword', }, - 'aws.s3access.object_size': { - category: 'aws', - description: 'The total size of the object in question. ', - name: 'aws.s3access.object_size', - type: 'long', + 'checkpoint.peer_ip_probing_status_update': { + category: 'checkpoint', + description: 'IP address response status. ', + name: 'checkpoint.peer_ip_probing_status_update', + type: 'keyword', }, - 'aws.s3access.total_time': { - category: 'aws', - description: - "The number of milliseconds the request was in flight from the server's perspective. ", - name: 'aws.s3access.total_time', - type: 'long', + 'checkpoint.peer_ip': { + category: 'checkpoint', + description: 'IP address which the client connects to. ', + name: 'checkpoint.peer_ip', + type: 'keyword', }, - 'aws.s3access.turn_around_time': { - category: 'aws', - description: 'The number of milliseconds that Amazon S3 spent processing your request. ', - name: 'aws.s3access.turn_around_time', - type: 'long', + 'checkpoint.link_probing_status_update': { + category: 'checkpoint', + description: 'IP address response status. ', + name: 'checkpoint.link_probing_status_update', + type: 'keyword', }, - 'aws.s3access.referrer': { - category: 'aws', - description: 'The value of the HTTP Referrer header, if present. ', - name: 'aws.s3access.referrer', + 'checkpoint.source_interface': { + category: 'checkpoint', + description: 'External Interface name for source interface or Null if not found. ', + name: 'checkpoint.source_interface', type: 'keyword', }, - 'aws.s3access.user_agent': { - category: 'aws', - description: 'The value of the HTTP User-Agent header. ', - name: 'aws.s3access.user_agent', + 'checkpoint.next_hop_ip': { + category: 'checkpoint', + description: 'Next hop IP address. ', + name: 'checkpoint.next_hop_ip', type: 'keyword', }, - 'aws.s3access.version_id': { - category: 'aws', - description: - 'The version ID in the request, or "-" if the operation does not take a versionId parameter. ', - name: 'aws.s3access.version_id', + 'checkpoint.srckeyid': { + category: 'checkpoint', + description: 'Initiator Spi ID. ', + name: 'checkpoint.srckeyid', type: 'keyword', }, - 'aws.s3access.host_id': { - category: 'aws', - description: 'The x-amz-id-2 or Amazon S3 extended request ID. ', - name: 'aws.s3access.host_id', + 'checkpoint.dstkeyid': { + category: 'checkpoint', + description: 'Responder Spi ID. ', + name: 'checkpoint.dstkeyid', type: 'keyword', }, - 'aws.s3access.signature_version': { - category: 'aws', - description: - 'The signature version, SigV2 or SigV4, that was used to authenticate the request or a - for unauthenticated requests. ', - name: 'aws.s3access.signature_version', + 'checkpoint.encryption_failure': { + category: 'checkpoint', + description: 'Message indicating why the encryption failed. ', + name: 'checkpoint.encryption_failure', type: 'keyword', }, - 'aws.s3access.cipher_suite': { - category: 'aws', - description: - 'The Secure Sockets Layer (SSL) cipher that was negotiated for HTTPS request or a - for HTTP. ', - name: 'aws.s3access.cipher_suite', + 'checkpoint.ike_ids': { + category: 'checkpoint', + description: 'All QM ids. ', + name: 'checkpoint.ike_ids', type: 'keyword', }, - 'aws.s3access.authentication_type': { - category: 'aws', - description: - 'The type of request authentication used, AuthHeader for authentication headers, QueryString for query string (pre-signed URL) or a - for unauthenticated requests. ', - name: 'aws.s3access.authentication_type', + 'checkpoint.community': { + category: 'checkpoint', + description: 'Community name for the IPSec key and the use of the IKEv. ', + name: 'checkpoint.community', type: 'keyword', }, - 'aws.s3access.host_header': { - category: 'aws', - description: 'The endpoint used to connect to Amazon S3. ', - name: 'aws.s3access.host_header', + 'checkpoint.ike': { + category: 'checkpoint', + description: 'IKEMode (PHASE1, PHASE2, etc..). ', + name: 'checkpoint.ike', type: 'keyword', }, - 'aws.s3access.tls_version': { - category: 'aws', - description: 'The Transport Layer Security (TLS) version negotiated by the client. ', - name: 'aws.s3access.tls_version', + 'checkpoint.cookieI': { + category: 'checkpoint', + description: 'Initiator cookie. ', + name: 'checkpoint.cookieI', type: 'keyword', }, - 'aws.vpcflow.version': { - category: 'aws', - description: - 'The VPC Flow Logs version. If you use the default format, the version is 2. If you specify a custom format, the version is 3. ', - name: 'aws.vpcflow.version', + 'checkpoint.cookieR': { + category: 'checkpoint', + description: 'Responder cookie. ', + name: 'checkpoint.cookieR', type: 'keyword', }, - 'aws.vpcflow.account_id': { - category: 'aws', - description: 'The AWS account ID for the flow log. ', - name: 'aws.vpcflow.account_id', + 'checkpoint.msgid': { + category: 'checkpoint', + description: 'Message ID. ', + name: 'checkpoint.msgid', type: 'keyword', }, - 'aws.vpcflow.interface_id': { - category: 'aws', - description: 'The ID of the network interface for which the traffic is recorded. ', - name: 'aws.vpcflow.interface_id', + 'checkpoint.methods': { + category: 'checkpoint', + description: 'IPSEc methods. ', + name: 'checkpoint.methods', type: 'keyword', }, - 'aws.vpcflow.action': { - category: 'aws', - description: 'The action that is associated with the traffic, ACCEPT or REJECT. ', - name: 'aws.vpcflow.action', + 'checkpoint.connection_uid': { + category: 'checkpoint', + description: 'Calculation of md5 of the IP and user name as UID. ', + name: 'checkpoint.connection_uid', type: 'keyword', }, - 'aws.vpcflow.log_status': { - category: 'aws', - description: 'The logging status of the flow log, OK, NODATA or SKIPDATA. ', - name: 'aws.vpcflow.log_status', + 'checkpoint.site_name': { + category: 'checkpoint', + description: 'Site name. ', + name: 'checkpoint.site_name', type: 'keyword', }, - 'aws.vpcflow.instance_id': { - category: 'aws', - description: - "The ID of the instance that's associated with network interface for which the traffic is recorded, if the instance is owned by you. ", - name: 'aws.vpcflow.instance_id', + 'checkpoint.esod_rule_name': { + category: 'checkpoint', + description: 'Unknown rule name. ', + name: 'checkpoint.esod_rule_name', type: 'keyword', }, - 'aws.vpcflow.pkt_srcaddr': { - category: 'aws', - description: 'The packet-level (original) source IP address of the traffic. ', - name: 'aws.vpcflow.pkt_srcaddr', - type: 'ip', + 'checkpoint.esod_rule_action': { + category: 'checkpoint', + description: 'Unknown rule action. ', + name: 'checkpoint.esod_rule_action', + type: 'keyword', }, - 'aws.vpcflow.pkt_dstaddr': { - category: 'aws', - description: 'The packet-level (original) destination IP address for the traffic. ', - name: 'aws.vpcflow.pkt_dstaddr', - type: 'ip', + 'checkpoint.esod_rule_type': { + category: 'checkpoint', + description: 'Unknown rule type. ', + name: 'checkpoint.esod_rule_type', + type: 'keyword', }, - 'aws.vpcflow.vpc_id': { - category: 'aws', - description: - 'The ID of the VPC that contains the network interface for which the traffic is recorded. ', - name: 'aws.vpcflow.vpc_id', + 'checkpoint.esod_noncompliance_reason': { + category: 'checkpoint', + description: 'Non-compliance reason. ', + name: 'checkpoint.esod_noncompliance_reason', type: 'keyword', }, - 'aws.vpcflow.subnet_id': { - category: 'aws', - description: - 'The ID of the subnet that contains the network interface for which the traffic is recorded. ', - name: 'aws.vpcflow.subnet_id', + 'checkpoint.esod_associated_policies': { + category: 'checkpoint', + description: 'Associated policies. ', + name: 'checkpoint.esod_associated_policies', type: 'keyword', }, - 'aws.vpcflow.tcp_flags': { - category: 'aws', - description: 'The bitmask value for the following TCP flags: 2=SYN,18=SYN-ACK,1=FIN,4=RST ', - name: 'aws.vpcflow.tcp_flags', + 'checkpoint.spyware_type': { + category: 'checkpoint', + description: 'Spyware type. ', + name: 'checkpoint.spyware_type', type: 'keyword', }, - 'aws.vpcflow.type': { - category: 'aws', - description: 'The type of traffic: IPv4, IPv6, or EFA. ', - name: 'aws.vpcflow.type', + 'checkpoint.anti_virus_type': { + category: 'checkpoint', + description: 'Anti virus type. ', + name: 'checkpoint.anti_virus_type', type: 'keyword', }, - 'azure.subscription_id': { - category: 'azure', - description: 'Azure subscription ID ', - name: 'azure.subscription_id', + 'checkpoint.end_user_firewall_type': { + category: 'checkpoint', + description: 'End user firewall type. ', + name: 'checkpoint.end_user_firewall_type', type: 'keyword', }, - 'azure.correlation_id': { - category: 'azure', - description: 'Correlation ID ', - name: 'azure.correlation_id', + 'checkpoint.esod_scan_status': { + category: 'checkpoint', + description: 'Scan failed. ', + name: 'checkpoint.esod_scan_status', type: 'keyword', }, - 'azure.tenant_id': { - category: 'azure', - description: 'tenant ID ', - name: 'azure.tenant_id', + 'checkpoint.esod_access_status': { + category: 'checkpoint', + description: 'Access denied. ', + name: 'checkpoint.esod_access_status', type: 'keyword', }, - 'azure.resource.id': { - category: 'azure', - description: 'Resource ID ', - name: 'azure.resource.id', + 'checkpoint.client_type': { + category: 'checkpoint', + description: 'Endpoint Connect. ', + name: 'checkpoint.client_type', type: 'keyword', }, - 'azure.resource.group': { - category: 'azure', - description: 'Resource group ', - name: 'azure.resource.group', + 'checkpoint.precise_error': { + category: 'checkpoint', + description: 'HTTP parser error. ', + name: 'checkpoint.precise_error', type: 'keyword', }, - 'azure.resource.provider': { - category: 'azure', - description: 'Resource type/namespace ', - name: 'azure.resource.provider', + 'checkpoint.method': { + category: 'checkpoint', + description: 'HTTP method. ', + name: 'checkpoint.method', type: 'keyword', }, - 'azure.resource.namespace': { - category: 'azure', - description: 'Resource type/namespace ', - name: 'azure.resource.namespace', + 'checkpoint.trusted_domain': { + category: 'checkpoint', + description: 'In case of phishing event, the domain, which the attacker was impersonating. ', + name: 'checkpoint.trusted_domain', type: 'keyword', }, - 'azure.resource.name': { - category: 'azure', - description: 'Name ', - name: 'azure.resource.name', + 'cisco.amp.timestamp_nanoseconds': { + category: 'cisco', + description: 'The timestamp in Epoch nanoseconds. ', + name: 'cisco.amp.timestamp_nanoseconds', + type: 'date', + }, + 'cisco.amp.event_type_id': { + category: 'cisco', + description: 'A sub ID of the event, depending on event type. ', + name: 'cisco.amp.event_type_id', type: 'keyword', }, - 'azure.resource.authorization_rule': { - category: 'azure', - description: 'Authorization rule ', - name: 'azure.resource.authorization_rule', + 'cisco.amp.detection': { + category: 'cisco', + description: 'The name of the malware detected. ', + name: 'cisco.amp.detection', type: 'keyword', }, - 'azure.activitylogs.identity.claims_initiated_by_user.name': { - category: 'azure', - description: 'Name ', - name: 'azure.activitylogs.identity.claims_initiated_by_user.name', + 'cisco.amp.detection_id': { + category: 'cisco', + description: 'The ID of the detection. ', + name: 'cisco.amp.detection_id', type: 'keyword', }, - 'azure.activitylogs.identity.claims_initiated_by_user.givenname': { - category: 'azure', - description: 'Givenname ', - name: 'azure.activitylogs.identity.claims_initiated_by_user.givenname', + 'cisco.amp.connector_guid': { + category: 'cisco', + description: 'The GUID of the connector sending information to AMP. ', + name: 'cisco.amp.connector_guid', type: 'keyword', }, - 'azure.activitylogs.identity.claims_initiated_by_user.surname': { - category: 'azure', - description: 'Surname ', - name: 'azure.activitylogs.identity.claims_initiated_by_user.surname', + 'cisco.amp.group_guids': { + category: 'cisco', + description: 'An array of group GUIDS related to the connector sending information to AMP. ', + name: 'cisco.amp.group_guids', type: 'keyword', }, - 'azure.activitylogs.identity.claims_initiated_by_user.fullname': { - category: 'azure', - description: 'Fullname ', - name: 'azure.activitylogs.identity.claims_initiated_by_user.fullname', + 'cisco.amp.vulnerabilities': { + category: 'cisco', + description: 'An array of related vulnerabilities to the malicious event. ', + name: 'cisco.amp.vulnerabilities', + type: 'flattened', + }, + 'cisco.amp.scan.description': { + category: 'cisco', + description: + 'Description of an event related to a scan being initiated, for example the specific directory name. ', + name: 'cisco.amp.scan.description', type: 'keyword', }, - 'azure.activitylogs.identity.claims_initiated_by_user.schema': { - category: 'azure', - description: 'Schema ', - name: 'azure.activitylogs.identity.claims_initiated_by_user.schema', + 'cisco.amp.scan.clean': { + category: 'cisco', + description: 'Boolean value if a scanned file was clean or not. ', + name: 'cisco.amp.scan.clean', + type: 'boolean', + }, + 'cisco.amp.scan.scanned_files': { + category: 'cisco', + description: 'Count of files scanned in a directory. ', + name: 'cisco.amp.scan.scanned_files', + type: 'long', + }, + 'cisco.amp.scan.scanned_processes': { + category: 'cisco', + description: 'Count of processes scanned related to a single scan event. ', + name: 'cisco.amp.scan.scanned_processes', + type: 'long', + }, + 'cisco.amp.scan.scanned_paths': { + category: 'cisco', + description: 'Count of different directories scanned related to a single scan event. ', + name: 'cisco.amp.scan.scanned_paths', + type: 'long', + }, + 'cisco.amp.scan.malicious_detections': { + category: 'cisco', + description: 'Count of malicious files or documents detected related to a single scan event. ', + name: 'cisco.amp.scan.malicious_detections', + type: 'long', + }, + 'cisco.amp.computer.connector_guid': { + category: 'cisco', + description: + 'The GUID of the connector, similar to top level connector_guid, but unique if multiple connectors are involved. ', + name: 'cisco.amp.computer.connector_guid', type: 'keyword', }, - 'azure.activitylogs.identity.claims.*': { - category: 'azure', - description: 'Claims ', - name: 'azure.activitylogs.identity.claims.*', - type: 'object', + 'cisco.amp.computer.external_ip': { + category: 'cisco', + description: 'The external IP of the related host. ', + name: 'cisco.amp.computer.external_ip', + type: 'ip', }, - 'azure.activitylogs.identity.authorization.scope': { - category: 'azure', - description: 'Scope ', - name: 'azure.activitylogs.identity.authorization.scope', + 'cisco.amp.computer.active': { + category: 'cisco', + description: 'If the current endpoint is active or not. ', + name: 'cisco.amp.computer.active', + type: 'boolean', + }, + 'cisco.amp.computer.network_addresses': { + category: 'cisco', + description: 'All network interface information on the related host. ', + name: 'cisco.amp.computer.network_addresses', + type: 'flattened', + }, + 'cisco.amp.file.disposition': { + category: 'cisco', + description: 'Categorization of file, for example "Malicious" or "Clean". ', + name: 'cisco.amp.file.disposition', type: 'keyword', }, - 'azure.activitylogs.identity.authorization.action': { - category: 'azure', - description: 'Action ', - name: 'azure.activitylogs.identity.authorization.action', + 'cisco.amp.network_info.disposition': { + category: 'cisco', + description: + 'Categorization of a network event related to a file, for example "Malicious" or "Clean". ', + name: 'cisco.amp.network_info.disposition', type: 'keyword', }, - 'azure.activitylogs.identity.authorization.evidence.role_assignment_scope': { - category: 'azure', - description: 'Role assignment scope ', - name: 'azure.activitylogs.identity.authorization.evidence.role_assignment_scope', + 'cisco.amp.network_info.nfm.direction': { + category: 'cisco', + description: 'The current direction based on source and destination IP. ', + name: 'cisco.amp.network_info.nfm.direction', type: 'keyword', }, - 'azure.activitylogs.identity.authorization.evidence.role_definition_id': { - category: 'azure', - description: 'Role definition ID ', - name: 'azure.activitylogs.identity.authorization.evidence.role_definition_id', + 'cisco.amp.related.mac': { + category: 'cisco', + description: 'An array of all related MAC addresses. ', + name: 'cisco.amp.related.mac', type: 'keyword', }, - 'azure.activitylogs.identity.authorization.evidence.role': { - category: 'azure', - description: 'Role ', - name: 'azure.activitylogs.identity.authorization.evidence.role', + 'cisco.amp.related.cve': { + category: 'cisco', + description: 'An array of all related MAC addresses. ', + name: 'cisco.amp.related.cve', type: 'keyword', }, - 'azure.activitylogs.identity.authorization.evidence.role_assignment_id': { - category: 'azure', - description: 'Role assignment ID ', - name: 'azure.activitylogs.identity.authorization.evidence.role_assignment_id', + 'cisco.amp.cloud_ioc.description': { + category: 'cisco', + description: 'Description of the related IOC for specific IOC events from AMP. ', + name: 'cisco.amp.cloud_ioc.description', type: 'keyword', }, - 'azure.activitylogs.identity.authorization.evidence.principal_id': { - category: 'azure', - description: 'Principal ID ', - name: 'azure.activitylogs.identity.authorization.evidence.principal_id', + 'cisco.amp.cloud_ioc.short_description': { + category: 'cisco', + description: 'Short description of the related IOC for specific IOC events from AMP. ', + name: 'cisco.amp.cloud_ioc.short_description', type: 'keyword', }, - 'azure.activitylogs.identity.authorization.evidence.principal_type': { - category: 'azure', - description: 'Principal type ', - name: 'azure.activitylogs.identity.authorization.evidence.principal_type', + 'cisco.amp.network_info.parent.disposition': { + category: 'cisco', + description: 'Categorization of a IOC for example "Malicious" or "Clean". ', + name: 'cisco.amp.network_info.parent.disposition', type: 'keyword', }, - 'azure.activitylogs.operation_name': { - category: 'azure', - description: 'Operation name ', - name: 'azure.activitylogs.operation_name', + 'cisco.amp.network_info.parent.identity.md5': { + category: 'cisco', + description: 'MD5 hash of the related IOC. ', + name: 'cisco.amp.network_info.parent.identity.md5', type: 'keyword', }, - 'azure.activitylogs.result_type': { - category: 'azure', - description: 'Result type ', - name: 'azure.activitylogs.result_type', + 'cisco.amp.network_info.parent.identity.sha1': { + category: 'cisco', + description: 'SHA1 hash of the related IOC. ', + name: 'cisco.amp.network_info.parent.identity.sha1', type: 'keyword', }, - 'azure.activitylogs.result_signature': { - category: 'azure', - description: 'Result signature ', - name: 'azure.activitylogs.result_signature', + 'cisco.amp.network_info.parent.identify.sha256': { + category: 'cisco', + description: 'SHA256 hash of the related IOC. ', + name: 'cisco.amp.network_info.parent.identify.sha256', type: 'keyword', }, - 'azure.activitylogs.category': { - category: 'azure', - description: 'Category ', - name: 'azure.activitylogs.category', + 'cisco.amp.file.archived_file.disposition': { + category: 'cisco', + description: + 'Categorization of a file archive related to a file, for example "Malicious" or "Clean". ', + name: 'cisco.amp.file.archived_file.disposition', type: 'keyword', }, - 'azure.activitylogs.event_category': { - category: 'azure', - description: 'Event Category ', - name: 'azure.activitylogs.event_category', + 'cisco.amp.file.archived_file.identity.md5': { + category: 'cisco', + description: 'MD5 hash of the archived file related to the malicious event. ', + name: 'cisco.amp.file.archived_file.identity.md5', type: 'keyword', }, - 'azure.activitylogs.properties.service_request_id': { - category: 'azure', - description: 'Service Request Id ', - name: 'azure.activitylogs.properties.service_request_id', + 'cisco.amp.file.archived_file.identity.sha1': { + category: 'cisco', + description: 'SHA1 hash of the archived file related to the malicious event. ', + name: 'cisco.amp.file.archived_file.identity.sha1', type: 'keyword', }, - 'azure.activitylogs.properties.status_code': { - category: 'azure', - description: 'Status code ', - name: 'azure.activitylogs.properties.status_code', + 'cisco.amp.file.archived_file.identity.sha256': { + category: 'cisco', + description: 'SHA256 hash of the archived file related to the malicious event. ', + name: 'cisco.amp.file.archived_file.identity.sha256', type: 'keyword', }, - 'azure.auditlogs.category': { - category: 'azure', - description: 'The category of the operation. Currently, Audit is the only supported value. ', - name: 'azure.auditlogs.category', + 'cisco.amp.file.attack_details.application': { + category: 'cisco', + description: 'The application name related to Exploit Prevention events. ', + name: 'cisco.amp.file.attack_details.application', type: 'keyword', }, - 'azure.auditlogs.operation_name': { - category: 'azure', - description: 'The operation name ', - name: 'azure.auditlogs.operation_name', + 'cisco.amp.file.attack_details.attacked_module': { + category: 'cisco', + description: + 'Path to the executable or dll that was attacked and detected by Exploit Prevention. ', + name: 'cisco.amp.file.attack_details.attacked_module', type: 'keyword', }, - 'azure.auditlogs.operation_version': { - category: 'azure', - description: 'The operation version ', - name: 'azure.auditlogs.operation_version', + 'cisco.amp.file.attack_details.base_address': { + category: 'cisco', + description: 'The base memory address related to the exploit detected. ', + name: 'cisco.amp.file.attack_details.base_address', type: 'keyword', }, - 'azure.auditlogs.identity': { - category: 'azure', - description: 'Identity ', - name: 'azure.auditlogs.identity', + 'cisco.amp.file.attack_details.suspicious_files': { + category: 'cisco', + description: 'An array of related files when an attack is detected by Exploit Prevention. ', + name: 'cisco.amp.file.attack_details.suspicious_files', type: 'keyword', }, - 'azure.auditlogs.tenant_id': { - category: 'azure', - description: 'Tenant ID ', - name: 'azure.auditlogs.tenant_id', + 'cisco.amp.file.parent.disposition': { + category: 'cisco', + description: 'Categorization of parrent, for example "Malicious" or "Clean". ', + name: 'cisco.amp.file.parent.disposition', type: 'keyword', }, - 'azure.auditlogs.result_signature': { - category: 'azure', - description: 'Result signature ', - name: 'azure.auditlogs.result_signature', + 'cisco.amp.error.description': { + category: 'cisco', + description: 'Description of an endpoint error event. ', + name: 'cisco.amp.error.description', type: 'keyword', }, - 'azure.auditlogs.properties.result': { - category: 'azure', - description: 'Log result ', - name: 'azure.auditlogs.properties.result', + 'cisco.amp.error.error_code': { + category: 'cisco', + description: 'The error code describing the related error event. ', + name: 'cisco.amp.error.error_code', type: 'keyword', }, - 'azure.auditlogs.properties.activity_display_name': { - category: 'azure', - description: 'Activity display name ', - name: 'azure.auditlogs.properties.activity_display_name', + 'cisco.amp.threat_hunting.severity': { + category: 'cisco', + description: + 'Severity result of the threat hunt registered to the malicious event. Can be Low-Critical. ', + name: 'cisco.amp.threat_hunting.severity', type: 'keyword', }, - 'azure.auditlogs.properties.result_reason': { - category: 'azure', - description: 'Reason for the log result ', - name: 'azure.auditlogs.properties.result_reason', + 'cisco.amp.threat_hunting.incident_report_guid': { + category: 'cisco', + description: 'The GUID of the related threat hunting report. ', + name: 'cisco.amp.threat_hunting.incident_report_guid', type: 'keyword', }, - 'azure.auditlogs.properties.correlation_id': { - category: 'azure', - description: 'Correlation ID ', - name: 'azure.auditlogs.properties.correlation_id', + 'cisco.amp.threat_hunting.incident_hunt_guid': { + category: 'cisco', + description: 'The GUID of the related investigation tracking issue. ', + name: 'cisco.amp.threat_hunting.incident_hunt_guid', type: 'keyword', }, - 'azure.auditlogs.properties.logged_by_service': { - category: 'azure', - description: 'Logged by service ', - name: 'azure.auditlogs.properties.logged_by_service', + 'cisco.amp.threat_hunting.incident_title': { + category: 'cisco', + description: 'Title of the incident related to the threat hunting activity. ', + name: 'cisco.amp.threat_hunting.incident_title', type: 'keyword', }, - 'azure.auditlogs.properties.operation_type': { - category: 'azure', - description: 'Operation type ', - name: 'azure.auditlogs.properties.operation_type', + 'cisco.amp.threat_hunting.incident_summary': { + category: 'cisco', + description: 'Summary of the outcome on the threat hunting activity. ', + name: 'cisco.amp.threat_hunting.incident_summary', type: 'keyword', }, - 'azure.auditlogs.properties.id': { - category: 'azure', - description: 'ID ', - name: 'azure.auditlogs.properties.id', + 'cisco.amp.threat_hunting.incident_remediation': { + category: 'cisco', + description: 'Recommendations to resolve the vulnerability or exploited host. ', + name: 'cisco.amp.threat_hunting.incident_remediation', type: 'keyword', }, - 'azure.auditlogs.properties.activity_datetime': { - category: 'azure', - description: 'Activity timestamp ', - name: 'azure.auditlogs.properties.activity_datetime', + 'cisco.amp.threat_hunting.incident_id': { + category: 'cisco', + description: 'The id of the related incident for the threat hunting activity. ', + name: 'cisco.amp.threat_hunting.incident_id', + type: 'keyword', + }, + 'cisco.amp.threat_hunting.incident_end_time': { + category: 'cisco', + description: 'When the threat hunt finalized or closed. ', + name: 'cisco.amp.threat_hunting.incident_end_time', type: 'date', }, - 'azure.auditlogs.properties.category': { - category: 'azure', - description: 'category ', - name: 'azure.auditlogs.properties.category', - type: 'keyword', + 'cisco.amp.threat_hunting.incident_start_time': { + category: 'cisco', + description: 'When the threat hunt was initiated. ', + name: 'cisco.amp.threat_hunting.incident_start_time', + type: 'date', }, - 'azure.auditlogs.properties.target_resources.*.display_name': { - category: 'azure', - description: 'Display name ', - name: 'azure.auditlogs.properties.target_resources.*.display_name', - type: 'keyword', + 'cisco.amp.file.attack_details.indicators': { + category: 'cisco', + description: + 'Different indicator types that matches the exploit detected, for example different MITRE tactics. ', + name: 'cisco.amp.file.attack_details.indicators', + type: 'flattened', }, - 'azure.auditlogs.properties.target_resources.*.id': { - category: 'azure', - description: 'ID ', - name: 'azure.auditlogs.properties.target_resources.*.id', - type: 'keyword', + 'cisco.amp.threat_hunting.tactics': { + category: 'cisco', + description: 'List of all MITRE tactics related to the incident found. ', + name: 'cisco.amp.threat_hunting.tactics', + type: 'flattened', }, - 'azure.auditlogs.properties.target_resources.*.type': { - category: 'azure', - description: 'Type ', - name: 'azure.auditlogs.properties.target_resources.*.type', - type: 'keyword', + 'cisco.amp.threat_hunting.techniques': { + category: 'cisco', + description: 'List of all MITRE techniques related to the incident found. ', + name: 'cisco.amp.threat_hunting.techniques', + type: 'flattened', }, - 'azure.auditlogs.properties.target_resources.*.ip_address': { - category: 'azure', - description: 'ip Address ', - name: 'azure.auditlogs.properties.target_resources.*.ip_address', - type: 'keyword', + 'cisco.amp.tactics': { + category: 'cisco', + description: 'List of all MITRE tactics related to the incident found. ', + name: 'cisco.amp.tactics', + type: 'flattened', }, - 'azure.auditlogs.properties.target_resources.*.user_principal_name': { - category: 'azure', - description: 'User principal name ', - name: 'azure.auditlogs.properties.target_resources.*.user_principal_name', + 'cisco.amp.mitre_tactics': { + category: 'cisco', + description: "Array of all related mitre tactic ID's ", + name: 'cisco.amp.mitre_tactics', type: 'keyword', }, - 'azure.auditlogs.properties.target_resources.*.modified_properties.*.new_value': { - category: 'azure', - description: 'New value ', - name: 'azure.auditlogs.properties.target_resources.*.modified_properties.*.new_value', - type: 'keyword', + 'cisco.amp.techniques': { + category: 'cisco', + description: 'List of all MITRE techniques related to the incident found. ', + name: 'cisco.amp.techniques', + type: 'flattened', }, - 'azure.auditlogs.properties.target_resources.*.modified_properties.*.display_name': { - category: 'azure', - description: 'Display value ', - name: 'azure.auditlogs.properties.target_resources.*.modified_properties.*.display_name', + 'cisco.amp.mitre_techniques': { + category: 'cisco', + description: "Array of all related mitre technique ID's ", + name: 'cisco.amp.mitre_techniques', type: 'keyword', }, - 'azure.auditlogs.properties.target_resources.*.modified_properties.*.old_value': { - category: 'azure', - description: 'Old value ', - name: 'azure.auditlogs.properties.target_resources.*.modified_properties.*.old_value', + 'cisco.amp.command_line.arguments': { + category: 'cisco', + description: 'The CLI arguments related to the Cloud Threat IOC reported by Cisco. ', + name: 'cisco.amp.command_line.arguments', type: 'keyword', }, - 'azure.auditlogs.properties.initiated_by.app.servicePrincipalName': { - category: 'azure', - description: 'Service principal name ', - name: 'azure.auditlogs.properties.initiated_by.app.servicePrincipalName', - type: 'keyword', + 'cisco.amp.bp_data': { + category: 'cisco', + description: 'Endpoint isolation information ', + name: 'cisco.amp.bp_data', + type: 'flattened', }, - 'azure.auditlogs.properties.initiated_by.app.displayName': { - category: 'azure', - description: 'Display name ', - name: 'azure.auditlogs.properties.initiated_by.app.displayName', + 'cisco.asa.message_id': { + category: 'cisco', + description: 'The Cisco ASA message identifier. ', + name: 'cisco.asa.message_id', type: 'keyword', }, - 'azure.auditlogs.properties.initiated_by.app.appId': { - category: 'azure', - description: 'App ID ', - name: 'azure.auditlogs.properties.initiated_by.app.appId', + 'cisco.asa.suffix': { + category: 'cisco', + description: 'Optional suffix after %ASA identifier. ', + example: 'session', + name: 'cisco.asa.suffix', type: 'keyword', }, - 'azure.auditlogs.properties.initiated_by.app.servicePrincipalId': { - category: 'azure', - description: 'Service principal ID ', - name: 'azure.auditlogs.properties.initiated_by.app.servicePrincipalId', + 'cisco.asa.source_interface': { + category: 'cisco', + description: 'Source interface for the flow or event. ', + name: 'cisco.asa.source_interface', type: 'keyword', }, - 'azure.auditlogs.properties.initiated_by.user.userPrincipalName': { - category: 'azure', - description: 'User principal name ', - name: 'azure.auditlogs.properties.initiated_by.user.userPrincipalName', + 'cisco.asa.destination_interface': { + category: 'cisco', + description: 'Destination interface for the flow or event. ', + name: 'cisco.asa.destination_interface', type: 'keyword', }, - 'azure.auditlogs.properties.initiated_by.user.displayName': { - category: 'azure', - description: 'Display name ', - name: 'azure.auditlogs.properties.initiated_by.user.displayName', + 'cisco.asa.rule_name': { + category: 'cisco', + description: 'Name of the Access Control List rule that matched this event. ', + name: 'cisco.asa.rule_name', type: 'keyword', }, - 'azure.auditlogs.properties.initiated_by.user.id': { - category: 'azure', - description: 'ID ', - name: 'azure.auditlogs.properties.initiated_by.user.id', + 'cisco.asa.source_username': { + category: 'cisco', + description: 'Name of the user that is the source for this event. ', + name: 'cisco.asa.source_username', type: 'keyword', }, - 'azure.auditlogs.properties.initiated_by.user.ipAddress': { - category: 'azure', - description: 'ip Address ', - name: 'azure.auditlogs.properties.initiated_by.user.ipAddress', + 'cisco.asa.destination_username': { + category: 'cisco', + description: 'Name of the user that is the destination for this event. ', + name: 'cisco.asa.destination_username', type: 'keyword', }, - 'azure.signinlogs.operation_name': { - category: 'azure', - description: 'The operation name ', - name: 'azure.signinlogs.operation_name', - type: 'keyword', + 'cisco.asa.mapped_source_ip': { + category: 'cisco', + description: 'The translated source IP address. ', + name: 'cisco.asa.mapped_source_ip', + type: 'ip', }, - 'azure.signinlogs.operation_version': { - category: 'azure', - description: 'The operation version ', - name: 'azure.signinlogs.operation_version', + 'cisco.asa.mapped_source_host': { + category: 'cisco', + description: 'The translated source host. ', + name: 'cisco.asa.mapped_source_host', type: 'keyword', }, - 'azure.signinlogs.tenant_id': { - category: 'azure', - description: 'Tenant ID ', - name: 'azure.signinlogs.tenant_id', - type: 'keyword', + 'cisco.asa.mapped_source_port': { + category: 'cisco', + description: 'The translated source port. ', + name: 'cisco.asa.mapped_source_port', + type: 'long', }, - 'azure.signinlogs.result_signature': { - category: 'azure', - description: 'Result signature ', - name: 'azure.signinlogs.result_signature', - type: 'keyword', + 'cisco.asa.mapped_destination_ip': { + category: 'cisco', + description: 'The translated destination IP address. ', + name: 'cisco.asa.mapped_destination_ip', + type: 'ip', }, - 'azure.signinlogs.result_description': { - category: 'azure', - description: 'Result description ', - name: 'azure.signinlogs.result_description', + 'cisco.asa.mapped_destination_host': { + category: 'cisco', + description: 'The translated destination host. ', + name: 'cisco.asa.mapped_destination_host', type: 'keyword', }, - 'azure.signinlogs.result_type': { - category: 'azure', - description: 'Result type ', - name: 'azure.signinlogs.result_type', - type: 'keyword', + 'cisco.asa.mapped_destination_port': { + category: 'cisco', + description: 'The translated destination port. ', + name: 'cisco.asa.mapped_destination_port', + type: 'long', }, - 'azure.signinlogs.identity': { - category: 'azure', - description: 'Identity ', - name: 'azure.signinlogs.identity', + 'cisco.asa.threat_level': { + category: 'cisco', + description: + 'Threat level for malware / botnet traffic. One of very-low, low, moderate, high or very-high. ', + name: 'cisco.asa.threat_level', type: 'keyword', }, - 'azure.signinlogs.category': { - category: 'azure', - description: 'Category ', - name: 'azure.signinlogs.category', + 'cisco.asa.threat_category': { + category: 'cisco', + description: + 'Category for the malware / botnet traffic. For example: virus, botnet, trojan, etc. ', + name: 'cisco.asa.threat_category', type: 'keyword', }, - 'azure.signinlogs.properties.id': { - category: 'azure', - description: 'ID ', - name: 'azure.signinlogs.properties.id', + 'cisco.asa.connection_id': { + category: 'cisco', + description: 'Unique identifier for a flow. ', + name: 'cisco.asa.connection_id', type: 'keyword', }, - 'azure.signinlogs.properties.created_at': { - category: 'azure', - description: 'Created date time ', - name: 'azure.signinlogs.properties.created_at', - type: 'date', + 'cisco.asa.icmp_type': { + category: 'cisco', + description: 'ICMP type. ', + name: 'cisco.asa.icmp_type', + type: 'short', }, - 'azure.signinlogs.properties.user_display_name': { - category: 'azure', - description: 'User display name ', - name: 'azure.signinlogs.properties.user_display_name', - type: 'keyword', + 'cisco.asa.icmp_code': { + category: 'cisco', + description: 'ICMP code. ', + name: 'cisco.asa.icmp_code', + type: 'short', }, - 'azure.signinlogs.properties.correlation_id': { - category: 'azure', - description: 'Correlation ID ', - name: 'azure.signinlogs.properties.correlation_id', + 'cisco.asa.connection_type': { + category: 'cisco', + description: 'The VPN connection type ', + name: 'cisco.asa.connection_type', type: 'keyword', }, - 'azure.signinlogs.properties.user_principal_name': { - category: 'azure', - description: 'User principal name ', - name: 'azure.signinlogs.properties.user_principal_name', + 'cisco.asa.dap_records': { + category: 'cisco', + description: 'The assigned DAP records ', + name: 'cisco.asa.dap_records', type: 'keyword', }, - 'azure.signinlogs.properties.user_id': { - category: 'azure', - description: 'User ID ', - name: 'azure.signinlogs.properties.user_id', + 'cisco.asa.command_line_arguments': { + category: 'cisco', + description: 'The command line arguments logged by the local audit log ', + name: 'cisco.asa.command_line_arguments', type: 'keyword', }, - 'azure.signinlogs.properties.app_id': { - category: 'azure', - description: 'App ID ', - name: 'azure.signinlogs.properties.app_id', - type: 'keyword', + 'cisco.asa.assigned_ip': { + category: 'cisco', + description: 'The IP address assigned to a VPN client successfully connecting ', + name: 'cisco.asa.assigned_ip', + type: 'ip', }, - 'azure.signinlogs.properties.app_display_name': { - category: 'azure', - description: 'App display name ', - name: 'azure.signinlogs.properties.app_display_name', + 'cisco.asa.privilege.old': { + category: 'cisco', + description: 'When a users privilege is changed this is the old value ', + name: 'cisco.asa.privilege.old', type: 'keyword', }, - 'azure.signinlogs.properties.ip_address': { - category: 'azure', - description: 'Ip address ', - name: 'azure.signinlogs.properties.ip_address', + 'cisco.asa.privilege.new': { + category: 'cisco', + description: 'When a users privilege is changed this is the new value ', + name: 'cisco.asa.privilege.new', type: 'keyword', }, - 'azure.signinlogs.properties.client_app_used': { - category: 'azure', - description: 'Client app used ', - name: 'azure.signinlogs.properties.client_app_used', + 'cisco.asa.burst.object': { + category: 'cisco', + description: 'The related object for burst warnings ', + name: 'cisco.asa.burst.object', type: 'keyword', }, - 'azure.signinlogs.properties.conditional_access_status': { - category: 'azure', - description: 'Conditional access status ', - name: 'azure.signinlogs.properties.conditional_access_status', + 'cisco.asa.burst.id': { + category: 'cisco', + description: 'The related rate ID for burst warnings ', + name: 'cisco.asa.burst.id', type: 'keyword', }, - 'azure.signinlogs.properties.original_request_id': { - category: 'azure', - description: 'Original request ID ', - name: 'azure.signinlogs.properties.original_request_id', + 'cisco.asa.burst.current_rate': { + category: 'cisco', + description: 'The current burst rate seen ', + name: 'cisco.asa.burst.current_rate', type: 'keyword', }, - 'azure.signinlogs.properties.is_interactive': { - category: 'azure', - description: 'Is interactive ', - name: 'azure.signinlogs.properties.is_interactive', + 'cisco.asa.burst.configured_rate': { + category: 'cisco', + description: 'The current configured burst rate ', + name: 'cisco.asa.burst.configured_rate', type: 'keyword', }, - 'azure.signinlogs.properties.token_issuer_name': { - category: 'azure', - description: 'Token issuer name ', - name: 'azure.signinlogs.properties.token_issuer_name', + 'cisco.asa.burst.avg_rate': { + category: 'cisco', + description: 'The current average burst rate seen ', + name: 'cisco.asa.burst.avg_rate', type: 'keyword', }, - 'azure.signinlogs.properties.token_issuer_type': { - category: 'azure', - description: 'Token issuer type ', - name: 'azure.signinlogs.properties.token_issuer_type', + 'cisco.asa.burst.configured_avg_rate': { + category: 'cisco', + description: 'The current configured average burst rate allowed ', + name: 'cisco.asa.burst.configured_avg_rate', type: 'keyword', }, - 'azure.signinlogs.properties.processing_time_ms': { - category: 'azure', - description: 'Processing time in milliseconds ', - name: 'azure.signinlogs.properties.processing_time_ms', - type: 'float', - }, - 'azure.signinlogs.properties.risk_detail': { - category: 'azure', - description: 'Risk detail ', - name: 'azure.signinlogs.properties.risk_detail', + 'cisco.asa.burst.cumulative_count': { + category: 'cisco', + description: 'The total count of burst rate hits since the object was created or cleared ', + name: 'cisco.asa.burst.cumulative_count', type: 'keyword', }, - 'azure.signinlogs.properties.risk_level_aggregated': { - category: 'azure', - description: 'Risk level aggregated ', - name: 'azure.signinlogs.properties.risk_level_aggregated', + 'cisco.asa.termination_user': { + category: 'cisco', + description: 'AAA name of user requesting termination ', + name: 'cisco.asa.termination_user', type: 'keyword', }, - 'azure.signinlogs.properties.risk_level_during_signin': { - category: 'azure', - description: 'Risk level during signIn ', - name: 'azure.signinlogs.properties.risk_level_during_signin', + 'cisco.asa.webvpn.group_name': { + category: 'cisco', + description: 'The WebVPN group name the user belongs to ', + name: 'cisco.asa.webvpn.group_name', type: 'keyword', }, - 'azure.signinlogs.properties.risk_state': { - category: 'azure', - description: 'Risk state ', - name: 'azure.signinlogs.properties.risk_state', + 'cisco.asa.termination_initiator': { + category: 'cisco', + description: 'Interface name of the side that initiated the teardown ', + name: 'cisco.asa.termination_initiator', type: 'keyword', }, - 'azure.signinlogs.properties.resource_display_name': { - category: 'azure', - description: 'Resource display name ', - name: 'azure.signinlogs.properties.resource_display_name', + 'cisco.asa.tunnel_type': { + category: 'cisco', + description: 'SA type (remote access or L2L) ', + name: 'cisco.asa.tunnel_type', type: 'keyword', }, - 'azure.signinlogs.properties.status.error_code': { - category: 'azure', - description: 'Error code ', - name: 'azure.signinlogs.properties.status.error_code', + 'cisco.asa.session_type': { + category: 'cisco', + description: 'Session type (for example, IPsec or UDP) ', + name: 'cisco.asa.session_type', type: 'keyword', }, - 'azure.signinlogs.properties.device_detail.device_id': { - category: 'azure', - description: 'Device ID ', - name: 'azure.signinlogs.properties.device_detail.device_id', + 'cisco.ftd.message_id': { + category: 'cisco', + description: 'The Cisco FTD message identifier. ', + name: 'cisco.ftd.message_id', type: 'keyword', }, - 'azure.signinlogs.properties.device_detail.operating_system': { - category: 'azure', - description: 'Operating system ', - name: 'azure.signinlogs.properties.device_detail.operating_system', + 'cisco.ftd.suffix': { + category: 'cisco', + description: 'Optional suffix after %FTD identifier. ', + example: 'session', + name: 'cisco.ftd.suffix', type: 'keyword', }, - 'azure.signinlogs.properties.device_detail.browser': { - category: 'azure', - description: 'Browser ', - name: 'azure.signinlogs.properties.device_detail.browser', + 'cisco.ftd.source_interface': { + category: 'cisco', + description: 'Source interface for the flow or event. ', + name: 'cisco.ftd.source_interface', type: 'keyword', }, - 'azure.signinlogs.properties.device_detail.display_name': { - category: 'azure', - description: 'Display name ', - name: 'azure.signinlogs.properties.device_detail.display_name', + 'cisco.ftd.destination_interface': { + category: 'cisco', + description: 'Destination interface for the flow or event. ', + name: 'cisco.ftd.destination_interface', type: 'keyword', }, - 'azure.signinlogs.properties.device_detail.trust_type': { - category: 'azure', - description: 'Trust type ', - name: 'azure.signinlogs.properties.device_detail.trust_type', + 'cisco.ftd.rule_name': { + category: 'cisco', + description: 'Name of the Access Control List rule that matched this event. ', + name: 'cisco.ftd.rule_name', type: 'keyword', }, - 'azure.signinlogs.properties.service_principal_id': { - category: 'azure', - description: 'Status ', - name: 'azure.signinlogs.properties.service_principal_id', + 'cisco.ftd.source_username': { + category: 'cisco', + description: 'Name of the user that is the source for this event. ', + name: 'cisco.ftd.source_username', type: 'keyword', }, - 'network.interface.name': { - category: 'network', - description: 'Name of the network interface where the traffic has been observed. ', - name: 'network.interface.name', + 'cisco.ftd.destination_username': { + category: 'cisco', + description: 'Name of the user that is the destination for this event. ', + name: 'cisco.ftd.destination_username', type: 'keyword', }, - 'rsa.internal.msg': { - category: 'rsa', - description: 'This key is used to capture the raw message that comes into the Log Decoder', - name: 'rsa.internal.msg', - type: 'keyword', + 'cisco.ftd.mapped_source_ip': { + category: 'cisco', + description: 'The translated source IP address. Use ECS source.nat.ip. ', + name: 'cisco.ftd.mapped_source_ip', + type: 'ip', }, - 'rsa.internal.messageid': { - category: 'rsa', - name: 'rsa.internal.messageid', + 'cisco.ftd.mapped_source_host': { + category: 'cisco', + description: 'The translated source host. ', + name: 'cisco.ftd.mapped_source_host', type: 'keyword', }, - 'rsa.internal.event_desc': { - category: 'rsa', - name: 'rsa.internal.event_desc', - type: 'keyword', + 'cisco.ftd.mapped_source_port': { + category: 'cisco', + description: 'The translated source port. Use ECS source.nat.port. ', + name: 'cisco.ftd.mapped_source_port', + type: 'long', }, - 'rsa.internal.message': { - category: 'rsa', - description: 'This key captures the contents of instant messages', - name: 'rsa.internal.message', - type: 'keyword', + 'cisco.ftd.mapped_destination_ip': { + category: 'cisco', + description: 'The translated destination IP address. Use ECS destination.nat.ip. ', + name: 'cisco.ftd.mapped_destination_ip', + type: 'ip', }, - 'rsa.internal.time': { - category: 'rsa', - description: - 'This is the time at which a session hits a NetWitness Decoder. This key should never be used to parse Meta data from a session (Logs/Packets) Directly, this is a Reserved key in NetWitness.', - name: 'rsa.internal.time', - type: 'date', + 'cisco.ftd.mapped_destination_host': { + category: 'cisco', + description: 'The translated destination host. ', + name: 'cisco.ftd.mapped_destination_host', + type: 'keyword', }, - 'rsa.internal.level': { - category: 'rsa', - description: 'Deprecated key defined only in table map.', - name: 'rsa.internal.level', + 'cisco.ftd.mapped_destination_port': { + category: 'cisco', + description: 'The translated destination port. Use ECS destination.nat.port. ', + name: 'cisco.ftd.mapped_destination_port', type: 'long', }, - 'rsa.internal.msg_id': { - category: 'rsa', + 'cisco.ftd.threat_level': { + category: 'cisco', description: - 'This is the Message ID1 value that identifies the exact log parser definition which parses a particular log session. This key should never be used to parse Meta data from a session (Logs/Packets) Directly, this is a Reserved key in NetWitness', - name: 'rsa.internal.msg_id', + 'Threat level for malware / botnet traffic. One of very-low, low, moderate, high or very-high. ', + name: 'cisco.ftd.threat_level', type: 'keyword', }, - 'rsa.internal.msg_vid': { - category: 'rsa', + 'cisco.ftd.threat_category': { + category: 'cisco', description: - 'This is the Message ID2 value that identifies the exact log parser definition which parses a particular log session. This key should never be used to parse Meta data from a session (Logs/Packets) Directly, this is a Reserved key in NetWitness', - name: 'rsa.internal.msg_vid', + 'Category for the malware / botnet traffic. For example: virus, botnet, trojan, etc. ', + name: 'cisco.ftd.threat_category', type: 'keyword', }, - 'rsa.internal.data': { - category: 'rsa', - description: 'Deprecated key defined only in table map.', - name: 'rsa.internal.data', + 'cisco.ftd.connection_id': { + category: 'cisco', + description: 'Unique identifier for a flow. ', + name: 'cisco.ftd.connection_id', type: 'keyword', }, - 'rsa.internal.obj_server': { - category: 'rsa', - description: 'Deprecated key defined only in table map.', - name: 'rsa.internal.obj_server', - type: 'keyword', + 'cisco.ftd.icmp_type': { + category: 'cisco', + description: 'ICMP type. ', + name: 'cisco.ftd.icmp_type', + type: 'short', }, - 'rsa.internal.obj_val': { - category: 'rsa', - description: 'Deprecated key defined only in table map.', - name: 'rsa.internal.obj_val', - type: 'keyword', + 'cisco.ftd.icmp_code': { + category: 'cisco', + description: 'ICMP code. ', + name: 'cisco.ftd.icmp_code', + type: 'short', }, - 'rsa.internal.resource': { - category: 'rsa', - description: 'Deprecated key defined only in table map.', - name: 'rsa.internal.resource', - type: 'keyword', + 'cisco.ftd.security': { + category: 'cisco', + description: 'Raw fields for Security Events.', + name: 'cisco.ftd.security', + type: 'object', }, - 'rsa.internal.obj_id': { - category: 'rsa', - description: 'Deprecated key defined only in table map.', - name: 'rsa.internal.obj_id', + 'cisco.ftd.connection_type': { + category: 'cisco', + description: 'The VPN connection type ', + name: 'cisco.ftd.connection_type', type: 'keyword', }, - 'rsa.internal.statement': { - category: 'rsa', - description: 'Deprecated key defined only in table map.', - name: 'rsa.internal.statement', + 'cisco.ftd.dap_records': { + category: 'cisco', + description: 'The assigned DAP records ', + name: 'cisco.ftd.dap_records', type: 'keyword', }, - 'rsa.internal.audit_class': { - category: 'rsa', - description: 'Deprecated key defined only in table map.', - name: 'rsa.internal.audit_class', + 'cisco.ftd.termination_user': { + category: 'cisco', + description: 'AAA name of user requesting termination ', + name: 'cisco.ftd.termination_user', type: 'keyword', }, - 'rsa.internal.entry': { - category: 'rsa', - description: 'Deprecated key defined only in table map.', - name: 'rsa.internal.entry', + 'cisco.ftd.webvpn.group_name': { + category: 'cisco', + description: 'The WebVPN group name the user belongs to ', + name: 'cisco.ftd.webvpn.group_name', type: 'keyword', }, - 'rsa.internal.hcode': { - category: 'rsa', - description: 'Deprecated key defined only in table map.', - name: 'rsa.internal.hcode', + 'cisco.ftd.termination_initiator': { + category: 'cisco', + description: 'Interface name of the side that initiated the teardown ', + name: 'cisco.ftd.termination_initiator', type: 'keyword', }, - 'rsa.internal.inode': { - category: 'rsa', - description: 'Deprecated key defined only in table map.', - name: 'rsa.internal.inode', - type: 'long', - }, - 'rsa.internal.resource_class': { - category: 'rsa', - description: 'Deprecated key defined only in table map.', - name: 'rsa.internal.resource_class', + 'cisco.ios.access_list': { + category: 'cisco', + description: 'Name of the IP access list. ', + name: 'cisco.ios.access_list', type: 'keyword', }, - 'rsa.internal.dead': { - category: 'rsa', - description: 'Deprecated key defined only in table map.', - name: 'rsa.internal.dead', - type: 'long', - }, - 'rsa.internal.feed_desc': { - category: 'rsa', + 'cisco.ios.facility': { + category: 'cisco', description: - 'This is used to capture the description of the feed. This key should never be used to parse Meta data from a session (Logs/Packets) Directly, this is a Reserved key in NetWitness', - name: 'rsa.internal.feed_desc', + 'The facility to which the message refers (for example, SNMP, SYS, and so forth). A facility can be a hardware device, a protocol, or a module of the system software. It denotes the source or the cause of the system message. ', + example: 'SEC', + name: 'cisco.ios.facility', type: 'keyword', }, - 'rsa.internal.feed_name': { - category: 'rsa', - description: - 'This is used to capture the name of the feed. This key should never be used to parse Meta data from a session (Logs/Packets) Directly, this is a Reserved key in NetWitness', - name: 'rsa.internal.feed_name', + 'cisco.umbrella.identities': { + category: 'cisco', + description: 'An array of the different identities related to the event. ', + name: 'cisco.umbrella.identities', type: 'keyword', }, - 'rsa.internal.cid': { - category: 'rsa', - description: - 'This is the unique identifier used to identify a NetWitness Concentrator. This key should never be used to parse Meta data from a session (Logs/Packets) Directly, this is a Reserved key in NetWitness', - name: 'rsa.internal.cid', + 'cisco.umbrella.categories': { + category: 'cisco', + description: 'The security or content categories that the destination matches. ', + name: 'cisco.umbrella.categories', type: 'keyword', }, - 'rsa.internal.device_class': { - category: 'rsa', + 'cisco.umbrella.policy_identity_type': { + category: 'cisco', description: - 'This is the Classification of the Log Event Source under a predefined fixed set of Event Source Classifications. This key should never be used to parse Meta data from a session (Logs/Packets) Directly, this is a Reserved key in NetWitness', - name: 'rsa.internal.device_class', + 'The first identity type matched with this request. Available in version 3 and above. ', + name: 'cisco.umbrella.policy_identity_type', type: 'keyword', }, - 'rsa.internal.device_group': { - category: 'rsa', + 'cisco.umbrella.identity_types': { + category: 'cisco', description: - 'This key should never be used to parse Meta data from a session (Logs/Packets) Directly, this is a Reserved key in NetWitness', - name: 'rsa.internal.device_group', + 'The type of identity that made the request. For example, Roaming Computer or Network. ', + name: 'cisco.umbrella.identity_types', type: 'keyword', }, - 'rsa.internal.device_host': { - category: 'rsa', + 'cisco.umbrella.blocked_categories': { + category: 'cisco', description: - 'This is the Hostname of the log Event Source sending the logs to NetWitness. This key should never be used to parse Meta data from a session (Logs/Packets) Directly, this is a Reserved key in NetWitness', - name: 'rsa.internal.device_host', + 'The categories that resulted in the destination being blocked. Available in version 4 and above. ', + name: 'cisco.umbrella.blocked_categories', type: 'keyword', }, - 'rsa.internal.device_ip': { - category: 'rsa', - description: - 'This is the IPv4 address of the Log Event Source sending the logs to NetWitness. This key should never be used to parse Meta data from a session (Logs/Packets) Directly, this is a Reserved key in NetWitness', - name: 'rsa.internal.device_ip', - type: 'ip', - }, - 'rsa.internal.device_ipv6': { - category: 'rsa', - description: - 'This is the IPv6 address of the Log Event Source sending the logs to NetWitness. This key should never be used to parse Meta data from a session (Logs/Packets) Directly, this is a Reserved key in NetWitness', - name: 'rsa.internal.device_ipv6', - type: 'ip', + 'cisco.umbrella.content_type': { + category: 'cisco', + description: 'The type of web content, typically text/html. ', + name: 'cisco.umbrella.content_type', + type: 'keyword', }, - 'rsa.internal.device_type': { - category: 'rsa', - description: - 'This is the name of the log parser which parsed a given session. This key should never be used to parse Meta data from a session (Logs/Packets) Directly, this is a Reserved key in NetWitness', - name: 'rsa.internal.device_type', + 'cisco.umbrella.sha_sha256': { + category: 'cisco', + description: 'Hex digest of the response content. ', + name: 'cisco.umbrella.sha_sha256', type: 'keyword', }, - 'rsa.internal.device_type_id': { - category: 'rsa', - description: 'Deprecated key defined only in table map.', - name: 'rsa.internal.device_type_id', - type: 'long', + 'cisco.umbrella.av_detections': { + category: 'cisco', + description: 'The detection name according to the antivirus engine used in file inspection. ', + name: 'cisco.umbrella.av_detections', + type: 'keyword', }, - 'rsa.internal.did': { - category: 'rsa', + 'cisco.umbrella.puas': { + category: 'cisco', description: - 'This is the unique identifier used to identify a NetWitness Decoder. This key should never be used to parse Meta data from a session (Logs/Packets) Directly, this is a Reserved key in NetWitness', - name: 'rsa.internal.did', + 'A list of all potentially unwanted application (PUA) results for the proxied file as returned by the antivirus scanner. ', + name: 'cisco.umbrella.puas', type: 'keyword', }, - 'rsa.internal.entropy_req': { - category: 'rsa', + 'cisco.umbrella.amp_disposition': { + category: 'cisco', description: - 'This key is only used by the Entropy Parser, the Meta Type can be either UInt16 or Float32 based on the configuration', - name: 'rsa.internal.entropy_req', - type: 'long', + 'The status of the files proxied and scanned by Cisco Advanced Malware Protection (AMP) as part of the Umbrella File Inspection feature; can be Clean, Malicious or Unknown. ', + name: 'cisco.umbrella.amp_disposition', + type: 'keyword', }, - 'rsa.internal.entropy_res': { - category: 'rsa', + 'cisco.umbrella.amp_malware_name': { + category: 'cisco', + description: 'If Malicious, the name of the malware according to AMP. ', + name: 'cisco.umbrella.amp_malware_name', + type: 'keyword', + }, + 'cisco.umbrella.amp_score': { + category: 'cisco', description: - 'This key is only used by the Entropy Parser, the Meta Type can be either UInt16 or Float32 based on the configuration', - name: 'rsa.internal.entropy_res', - type: 'long', + 'The score of the malware from AMP. This field is not currently used and will be blank. ', + name: 'cisco.umbrella.amp_score', + type: 'keyword', }, - 'rsa.internal.event_name': { - category: 'rsa', - description: 'Deprecated key defined only in table map.', - name: 'rsa.internal.event_name', + 'cisco.umbrella.datacenter': { + category: 'cisco', + description: 'The name of the Umbrella Data Center that processed the user-generated traffic. ', + name: 'cisco.umbrella.datacenter', type: 'keyword', }, - 'rsa.internal.feed_category': { - category: 'rsa', - description: - 'This is used to capture the category of the feed. This key should never be used to parse Meta data from a session (Logs/Packets) Directly, this is a Reserved key in NetWitness', - name: 'rsa.internal.feed_category', + 'cisco.umbrella.origin_id': { + category: 'cisco', + description: 'The unique identity of the network tunnel. ', + name: 'cisco.umbrella.origin_id', type: 'keyword', }, - 'rsa.internal.forward_ip': { - category: 'rsa', - description: - 'This key should be used to capture the IPV4 address of a relay system which forwarded the events from the original system to NetWitness.', - name: 'rsa.internal.forward_ip', - type: 'ip', + 'coredns.query.size': { + category: 'coredns', + description: 'size of the DNS query ', + name: 'coredns.query.size', + type: 'integer', + format: 'bytes', }, - 'rsa.internal.forward_ipv6': { - category: 'rsa', + 'coredns.response.size': { + category: 'coredns', + description: 'size of the DNS response ', + name: 'coredns.response.size', + type: 'integer', + format: 'bytes', + }, + 'crowdstrike.metadata.eventType': { + category: 'crowdstrike', description: - 'This key is used to capture the IPV6 address of a relay system which forwarded the events from the original system to NetWitness. This key should never be used to parse Meta data from a session (Logs/Packets) Directly, this is a Reserved key in NetWitness', - name: 'rsa.internal.forward_ipv6', - type: 'ip', + 'DetectionSummaryEvent, FirewallMatchEvent, IncidentSummaryEvent, RemoteResponseSessionStartEvent, RemoteResponseSessionEndEvent, AuthActivityAuditEvent, or UserActivityAuditEvent ', + name: 'crowdstrike.metadata.eventType', + type: 'keyword', + }, + 'crowdstrike.metadata.eventCreationTime': { + category: 'crowdstrike', + description: 'The time this event occurred on the endpoint in UTC UNIX_MS format. ', + name: 'crowdstrike.metadata.eventCreationTime', + type: 'date', }, - 'rsa.internal.header_id': { - category: 'rsa', + 'crowdstrike.metadata.offset': { + category: 'crowdstrike', description: - 'This is the Header ID value that identifies the exact log parser header definition that parses a particular log session. This key should never be used to parse Meta data from a session (Logs/Packets) Directly, this is a Reserved key in NetWitness', - name: 'rsa.internal.header_id', + 'Offset number that tracks the location of the event in stream. This is used to identify unique detection events. ', + name: 'crowdstrike.metadata.offset', + type: 'integer', + }, + 'crowdstrike.metadata.customerIDString': { + category: 'crowdstrike', + description: 'Customer identifier ', + name: 'crowdstrike.metadata.customerIDString', type: 'keyword', }, - 'rsa.internal.lc_cid': { - category: 'rsa', - description: - 'This is a unique Identifier of a Log Collector. This key should never be used to parse Meta data from a session (Logs/Packets) Directly, this is a Reserved key in NetWitness', - name: 'rsa.internal.lc_cid', + 'crowdstrike.metadata.version': { + category: 'crowdstrike', + description: 'Schema version ', + name: 'crowdstrike.metadata.version', type: 'keyword', }, - 'rsa.internal.lc_ctime': { - category: 'rsa', - description: - 'This is the time at which a log is collected in a NetWitness Log Collector. This key should never be used to parse Meta data from a session (Logs/Packets) Directly, this is a Reserved key in NetWitness', - name: 'rsa.internal.lc_ctime', + 'crowdstrike.event.ProcessStartTime': { + category: 'crowdstrike', + description: 'The process start time in UTC UNIX_MS format. ', + name: 'crowdstrike.event.ProcessStartTime', type: 'date', }, - 'rsa.internal.mcb_req': { - category: 'rsa', - description: - 'This key is only used by the Entropy Parser, the most common byte request is simply which byte for each side (0 thru 255) was seen the most', - name: 'rsa.internal.mcb_req', - type: 'long', - }, - 'rsa.internal.mcb_res': { - category: 'rsa', - description: - 'This key is only used by the Entropy Parser, the most common byte response is simply which byte for each side (0 thru 255) was seen the most', - name: 'rsa.internal.mcb_res', - type: 'long', + 'crowdstrike.event.ProcessEndTime': { + category: 'crowdstrike', + description: 'The process termination time in UTC UNIX_MS format. ', + name: 'crowdstrike.event.ProcessEndTime', + type: 'date', }, - 'rsa.internal.mcbc_req': { - category: 'rsa', - description: - 'This key is only used by the Entropy Parser, the most common byte count is the number of times the most common byte (above) was seen in the session streams', - name: 'rsa.internal.mcbc_req', - type: 'long', + 'crowdstrike.event.ProcessId': { + category: 'crowdstrike', + description: 'Process ID related to the detection. ', + name: 'crowdstrike.event.ProcessId', + type: 'integer', }, - 'rsa.internal.mcbc_res': { - category: 'rsa', - description: - 'This key is only used by the Entropy Parser, the most common byte count is the number of times the most common byte (above) was seen in the session streams', - name: 'rsa.internal.mcbc_res', - type: 'long', + 'crowdstrike.event.ParentProcessId': { + category: 'crowdstrike', + description: 'Parent process ID related to the detection. ', + name: 'crowdstrike.event.ParentProcessId', + type: 'integer', }, - 'rsa.internal.medium': { - category: 'rsa', - description: - 'This key is used to identify if it’s a log/packet session or Layer 2 Encapsulation Type. This key should never be used to parse Meta data from a session (Logs/Packets) Directly, this is a Reserved key in NetWitness. 32 = log, 33 = correlation session, < 32 is packet session', - name: 'rsa.internal.medium', - type: 'long', + 'crowdstrike.event.ComputerName': { + category: 'crowdstrike', + description: 'Name of the computer where the detection occurred. ', + name: 'crowdstrike.event.ComputerName', + type: 'keyword', }, - 'rsa.internal.node_name': { - category: 'rsa', - description: 'Deprecated key defined only in table map.', - name: 'rsa.internal.node_name', + 'crowdstrike.event.UserName': { + category: 'crowdstrike', + description: 'User name associated with the detection. ', + name: 'crowdstrike.event.UserName', type: 'keyword', }, - 'rsa.internal.nwe_callback_id': { - category: 'rsa', - description: 'This key denotes that event is endpoint related', - name: 'rsa.internal.nwe_callback_id', + 'crowdstrike.event.DetectName': { + category: 'crowdstrike', + description: 'Name of the detection. ', + name: 'crowdstrike.event.DetectName', type: 'keyword', }, - 'rsa.internal.parse_error': { - category: 'rsa', - description: - 'This is a special key that stores any Meta key validation error found while parsing a log session. This key should never be used to parse Meta data from a session (Logs/Packets) Directly, this is a Reserved key in NetWitness', - name: 'rsa.internal.parse_error', + 'crowdstrike.event.DetectDescription': { + category: 'crowdstrike', + description: 'Description of the detection. ', + name: 'crowdstrike.event.DetectDescription', type: 'keyword', }, - 'rsa.internal.payload_req': { - category: 'rsa', - description: - 'This key is only used by the Entropy Parser, the payload size metrics are the payload sizes of each session side at the time of parsing. However, in order to keep', - name: 'rsa.internal.payload_req', - type: 'long', + 'crowdstrike.event.Severity': { + category: 'crowdstrike', + description: 'Severity score of the detection. ', + name: 'crowdstrike.event.Severity', + type: 'integer', }, - 'rsa.internal.payload_res': { - category: 'rsa', - description: - 'This key is only used by the Entropy Parser, the payload size metrics are the payload sizes of each session side at the time of parsing. However, in order to keep', - name: 'rsa.internal.payload_res', - type: 'long', + 'crowdstrike.event.SeverityName': { + category: 'crowdstrike', + description: 'Severity score text. ', + name: 'crowdstrike.event.SeverityName', + type: 'keyword', }, - 'rsa.internal.process_vid_dst': { - category: 'rsa', - description: - 'Endpoint generates and uses a unique virtual ID to identify any similar group of process. This ID represents the target process.', - name: 'rsa.internal.process_vid_dst', + 'crowdstrike.event.FileName': { + category: 'crowdstrike', + description: 'File name of the associated process for the detection. ', + name: 'crowdstrike.event.FileName', type: 'keyword', }, - 'rsa.internal.process_vid_src': { - category: 'rsa', - description: - 'Endpoint generates and uses a unique virtual ID to identify any similar group of process. This ID represents the source process.', - name: 'rsa.internal.process_vid_src', + 'crowdstrike.event.FilePath': { + category: 'crowdstrike', + description: 'Path of the executable associated with the detection. ', + name: 'crowdstrike.event.FilePath', type: 'keyword', }, - 'rsa.internal.rid': { - category: 'rsa', - description: - 'This is a special ID of the Remote Session created by NetWitness Decoder. This key should never be used to parse Meta data from a session (Logs/Packets) Directly, this is a Reserved key in NetWitness', - name: 'rsa.internal.rid', - type: 'long', + 'crowdstrike.event.CommandLine': { + category: 'crowdstrike', + description: 'Executable path with command line arguments. ', + name: 'crowdstrike.event.CommandLine', + type: 'keyword', }, - 'rsa.internal.session_split': { - category: 'rsa', - description: - 'This key should never be used to parse Meta data from a session (Logs/Packets) Directly, this is a Reserved key in NetWitness', - name: 'rsa.internal.session_split', + 'crowdstrike.event.SHA1String': { + category: 'crowdstrike', + description: 'SHA1 sum of the executable associated with the detection. ', + name: 'crowdstrike.event.SHA1String', type: 'keyword', }, - 'rsa.internal.site': { - category: 'rsa', - description: 'Deprecated key defined only in table map.', - name: 'rsa.internal.site', + 'crowdstrike.event.SHA256String': { + category: 'crowdstrike', + description: 'SHA256 sum of the executable associated with the detection. ', + name: 'crowdstrike.event.SHA256String', type: 'keyword', }, - 'rsa.internal.size': { - category: 'rsa', - description: - 'This is the size of the session as seen by the NetWitness Decoder. This key should never be used to parse Meta data from a session (Logs/Packets) Directly, this is a Reserved key in NetWitness', - name: 'rsa.internal.size', - type: 'long', + 'crowdstrike.event.MD5String': { + category: 'crowdstrike', + description: 'MD5 sum of the executable associated with the detection. ', + name: 'crowdstrike.event.MD5String', + type: 'keyword', }, - 'rsa.internal.sourcefile': { - category: 'rsa', - description: - 'This is the name of the log file or PCAPs that can be imported into NetWitness. This key should never be used to parse Meta data from a session (Logs/Packets) Directly, this is a Reserved key in NetWitness', - name: 'rsa.internal.sourcefile', + 'crowdstrike.event.MachineDomain': { + category: 'crowdstrike', + description: 'Domain for the machine associated with the detection. ', + name: 'crowdstrike.event.MachineDomain', type: 'keyword', }, - 'rsa.internal.ubc_req': { - category: 'rsa', - description: - 'This key is only used by the Entropy Parser, Unique byte count is the number of unique bytes seen in each stream. 256 would mean all byte values of 0 thru 255 were seen at least once', - name: 'rsa.internal.ubc_req', - type: 'long', + 'crowdstrike.event.FalconHostLink': { + category: 'crowdstrike', + description: 'URL to view the detection in Falcon. ', + name: 'crowdstrike.event.FalconHostLink', + type: 'keyword', }, - 'rsa.internal.ubc_res': { - category: 'rsa', - description: - 'This key is only used by the Entropy Parser, Unique byte count is the number of unique bytes seen in each stream. 256 would mean all byte values of 0 thru 255 were seen at least once', - name: 'rsa.internal.ubc_res', - type: 'long', + 'crowdstrike.event.SensorId': { + category: 'crowdstrike', + description: 'Unique ID associated with the Falcon sensor. ', + name: 'crowdstrike.event.SensorId', + type: 'keyword', }, - 'rsa.internal.word': { - category: 'rsa', - description: - 'This is used by the Word Parsing technology to capture the first 5 character of every word in an unparsed log', - name: 'rsa.internal.word', + 'crowdstrike.event.DetectId': { + category: 'crowdstrike', + description: 'Unique ID associated with the detection. ', + name: 'crowdstrike.event.DetectId', type: 'keyword', }, - 'rsa.time.event_time': { - category: 'rsa', - description: - 'This key is used to capture the time mentioned in a raw session that represents the actual time an event occured in a standard normalized form', - name: 'rsa.time.event_time', - type: 'date', + 'crowdstrike.event.LocalIP': { + category: 'crowdstrike', + description: 'IP address of the host associated with the detection. ', + name: 'crowdstrike.event.LocalIP', + type: 'keyword', }, - 'rsa.time.duration_time': { - category: 'rsa', - description: 'This key is used to capture the normalized duration/lifetime in seconds.', - name: 'rsa.time.duration_time', - type: 'double', + 'crowdstrike.event.MACAddress': { + category: 'crowdstrike', + description: 'MAC address of the host associated with the detection. ', + name: 'crowdstrike.event.MACAddress', + type: 'keyword', }, - 'rsa.time.event_time_str': { - category: 'rsa', - description: - 'This key is used to capture the incomplete time mentioned in a session as a string', - name: 'rsa.time.event_time_str', + 'crowdstrike.event.Tactic': { + category: 'crowdstrike', + description: 'MITRE tactic category of the detection. ', + name: 'crowdstrike.event.Tactic', type: 'keyword', }, - 'rsa.time.starttime': { - category: 'rsa', - description: - 'This key is used to capture the Start time mentioned in a session in a standard form', - name: 'rsa.time.starttime', - type: 'date', + 'crowdstrike.event.Technique': { + category: 'crowdstrike', + description: 'MITRE technique category of the detection. ', + name: 'crowdstrike.event.Technique', + type: 'keyword', }, - 'rsa.time.month': { - category: 'rsa', - name: 'rsa.time.month', + 'crowdstrike.event.Objective': { + category: 'crowdstrike', + description: 'Method of detection. ', + name: 'crowdstrike.event.Objective', type: 'keyword', }, - 'rsa.time.day': { - category: 'rsa', - name: 'rsa.time.day', + 'crowdstrike.event.PatternDispositionDescription': { + category: 'crowdstrike', + description: 'Action taken by Falcon. ', + name: 'crowdstrike.event.PatternDispositionDescription', type: 'keyword', }, - 'rsa.time.endtime': { - category: 'rsa', - description: - 'This key is used to capture the End time mentioned in a session in a standard form', - name: 'rsa.time.endtime', + 'crowdstrike.event.PatternDispositionValue': { + category: 'crowdstrike', + description: 'Unique ID associated with action taken. ', + name: 'crowdstrike.event.PatternDispositionValue', + type: 'integer', + }, + 'crowdstrike.event.PatternDispositionFlags': { + category: 'crowdstrike', + description: 'Flags indicating actions taken. ', + name: 'crowdstrike.event.PatternDispositionFlags', + type: 'object', + }, + 'crowdstrike.event.State': { + category: 'crowdstrike', + description: 'Whether the incident summary is open and ongoing or closed. ', + name: 'crowdstrike.event.State', + type: 'keyword', + }, + 'crowdstrike.event.IncidentStartTime': { + category: 'crowdstrike', + description: 'Start time for the incident in UTC UNIX format. ', + name: 'crowdstrike.event.IncidentStartTime', type: 'date', }, - 'rsa.time.timezone': { - category: 'rsa', - description: 'This key is used to capture the timezone of the Event Time', - name: 'rsa.time.timezone', + 'crowdstrike.event.IncidentEndTime': { + category: 'crowdstrike', + description: 'End time for the incident in UTC UNIX format. ', + name: 'crowdstrike.event.IncidentEndTime', + type: 'date', + }, + 'crowdstrike.event.FineScore': { + category: 'crowdstrike', + description: 'Score for incident. ', + name: 'crowdstrike.event.FineScore', + type: 'float', + }, + 'crowdstrike.event.UserId': { + category: 'crowdstrike', + description: 'Email address or user ID associated with the event. ', + name: 'crowdstrike.event.UserId', type: 'keyword', }, - 'rsa.time.duration_str': { - category: 'rsa', - description: 'A text string version of the duration', - name: 'rsa.time.duration_str', + 'crowdstrike.event.UserIp': { + category: 'crowdstrike', + description: 'IP address associated with the user. ', + name: 'crowdstrike.event.UserIp', type: 'keyword', }, - 'rsa.time.date': { - category: 'rsa', - name: 'rsa.time.date', + 'crowdstrike.event.OperationName': { + category: 'crowdstrike', + description: 'Event subtype. ', + name: 'crowdstrike.event.OperationName', type: 'keyword', }, - 'rsa.time.year': { - category: 'rsa', - name: 'rsa.time.year', + 'crowdstrike.event.ServiceName': { + category: 'crowdstrike', + description: 'Service associated with this event. ', + name: 'crowdstrike.event.ServiceName', type: 'keyword', }, - 'rsa.time.recorded_time': { - category: 'rsa', - description: - "The event time as recorded by the system the event is collected from. The usage scenario is a multi-tier application where the management layer of the system records it's own timestamp at the time of collection from its child nodes. Must be in timestamp format.", - name: 'rsa.time.recorded_time', + 'crowdstrike.event.Success': { + category: 'crowdstrike', + description: 'Indicator of whether or not this event was successful. ', + name: 'crowdstrike.event.Success', + type: 'boolean', + }, + 'crowdstrike.event.UTCTimestamp': { + category: 'crowdstrike', + description: 'Timestamp associated with this event in UTC UNIX format. ', + name: 'crowdstrike.event.UTCTimestamp', type: 'date', }, - 'rsa.time.datetime': { - category: 'rsa', - name: 'rsa.time.datetime', + 'crowdstrike.event.AuditKeyValues': { + category: 'crowdstrike', + description: 'Fields that were changed in this event. ', + name: 'crowdstrike.event.AuditKeyValues', + type: 'nested', + }, + 'crowdstrike.event.ExecutablesWritten': { + category: 'crowdstrike', + description: 'Detected executables written to disk by a process. ', + name: 'crowdstrike.event.ExecutablesWritten', + type: 'nested', + }, + 'crowdstrike.event.SessionId': { + category: 'crowdstrike', + description: 'Session ID of the remote response session. ', + name: 'crowdstrike.event.SessionId', type: 'keyword', }, - 'rsa.time.effective_time': { - category: 'rsa', - description: - 'This key is the effective time referenced by an individual event in a Standard Timestamp format', - name: 'rsa.time.effective_time', + 'crowdstrike.event.HostnameField': { + category: 'crowdstrike', + description: 'Host name of the machine for the remote session. ', + name: 'crowdstrike.event.HostnameField', + type: 'keyword', + }, + 'crowdstrike.event.StartTimestamp': { + category: 'crowdstrike', + description: 'Start time for the remote session in UTC UNIX format. ', + name: 'crowdstrike.event.StartTimestamp', type: 'date', }, - 'rsa.time.expire_time': { - category: 'rsa', - description: 'This key is the timestamp that explicitly refers to an expiration.', - name: 'rsa.time.expire_time', + 'crowdstrike.event.EndTimestamp': { + category: 'crowdstrike', + description: 'End time for the remote session in UTC UNIX format. ', + name: 'crowdstrike.event.EndTimestamp', type: 'date', }, - 'rsa.time.process_time': { - category: 'rsa', - description: 'Deprecated, use duration.time', - name: 'rsa.time.process_time', + 'crowdstrike.event.LateralMovement': { + category: 'crowdstrike', + description: 'Lateral movement field for incident. ', + name: 'crowdstrike.event.LateralMovement', + type: 'long', + }, + 'crowdstrike.event.ParentImageFileName': { + category: 'crowdstrike', + description: 'Path to the parent process. ', + name: 'crowdstrike.event.ParentImageFileName', type: 'keyword', }, - 'rsa.time.hour': { - category: 'rsa', - name: 'rsa.time.hour', + 'crowdstrike.event.ParentCommandLine': { + category: 'crowdstrike', + description: 'Parent process command line arguments. ', + name: 'crowdstrike.event.ParentCommandLine', type: 'keyword', }, - 'rsa.time.min': { - category: 'rsa', - name: 'rsa.time.min', + 'crowdstrike.event.GrandparentImageFileName': { + category: 'crowdstrike', + description: 'Path to the grandparent process. ', + name: 'crowdstrike.event.GrandparentImageFileName', type: 'keyword', }, - 'rsa.time.timestamp': { - category: 'rsa', - name: 'rsa.time.timestamp', + 'crowdstrike.event.GrandparentCommandLine': { + category: 'crowdstrike', + description: 'Grandparent process command line arguments. ', + name: 'crowdstrike.event.GrandparentCommandLine', type: 'keyword', }, - 'rsa.time.event_queue_time': { - category: 'rsa', - description: 'This key is the Time that the event was queued.', - name: 'rsa.time.event_queue_time', - type: 'date', + 'crowdstrike.event.IOCType': { + category: 'crowdstrike', + description: 'CrowdStrike type for indicator of compromise. ', + name: 'crowdstrike.event.IOCType', + type: 'keyword', }, - 'rsa.time.p_time1': { - category: 'rsa', - name: 'rsa.time.p_time1', + 'crowdstrike.event.IOCValue': { + category: 'crowdstrike', + description: 'CrowdStrike value for indicator of compromise. ', + name: 'crowdstrike.event.IOCValue', type: 'keyword', }, - 'rsa.time.tzone': { - category: 'rsa', - name: 'rsa.time.tzone', + 'crowdstrike.event.CustomerId': { + category: 'crowdstrike', + description: 'Customer identifier. ', + name: 'crowdstrike.event.CustomerId', type: 'keyword', }, - 'rsa.time.eventtime': { - category: 'rsa', - name: 'rsa.time.eventtime', + 'crowdstrike.event.DeviceId': { + category: 'crowdstrike', + description: 'Device on which the event occurred. ', + name: 'crowdstrike.event.DeviceId', type: 'keyword', }, - 'rsa.time.gmtdate': { - category: 'rsa', - name: 'rsa.time.gmtdate', + 'crowdstrike.event.Ipv': { + category: 'crowdstrike', + description: 'Protocol for network request. ', + name: 'crowdstrike.event.Ipv', type: 'keyword', }, - 'rsa.time.gmttime': { - category: 'rsa', - name: 'rsa.time.gmttime', + 'crowdstrike.event.ConnectionDirection': { + category: 'crowdstrike', + description: 'Direction for network connection. ', + name: 'crowdstrike.event.ConnectionDirection', type: 'keyword', }, - 'rsa.time.p_date': { - category: 'rsa', - name: 'rsa.time.p_date', + 'crowdstrike.event.EventType': { + category: 'crowdstrike', + description: 'CrowdStrike provided event type. ', + name: 'crowdstrike.event.EventType', type: 'keyword', }, - 'rsa.time.p_month': { - category: 'rsa', - name: 'rsa.time.p_month', + 'crowdstrike.event.HostName': { + category: 'crowdstrike', + description: 'Host name of the local machine. ', + name: 'crowdstrike.event.HostName', type: 'keyword', }, - 'rsa.time.p_time': { - category: 'rsa', - name: 'rsa.time.p_time', + 'crowdstrike.event.ICMPCode': { + category: 'crowdstrike', + description: 'RFC2780 ICMP Code field. ', + name: 'crowdstrike.event.ICMPCode', type: 'keyword', }, - 'rsa.time.p_time2': { - category: 'rsa', - name: 'rsa.time.p_time2', + 'crowdstrike.event.ICMPType': { + category: 'crowdstrike', + description: 'RFC2780 ICMP Type field. ', + name: 'crowdstrike.event.ICMPType', type: 'keyword', }, - 'rsa.time.p_year': { - category: 'rsa', - name: 'rsa.time.p_year', + 'crowdstrike.event.ImageFileName': { + category: 'crowdstrike', + description: 'File name of the associated process for the detection. ', + name: 'crowdstrike.event.ImageFileName', type: 'keyword', }, - 'rsa.time.expire_time_str': { - category: 'rsa', - description: - 'This key is used to capture incomplete timestamp that explicitly refers to an expiration.', - name: 'rsa.time.expire_time_str', - type: 'keyword', + 'crowdstrike.event.PID': { + category: 'crowdstrike', + description: 'Associated process id for the detection. ', + name: 'crowdstrike.event.PID', + type: 'long', }, - 'rsa.time.stamp': { - category: 'rsa', - description: 'Deprecated key defined only in table map.', - name: 'rsa.time.stamp', - type: 'date', + 'crowdstrike.event.LocalAddress': { + category: 'crowdstrike', + description: 'IP address of local machine. ', + name: 'crowdstrike.event.LocalAddress', + type: 'ip', }, - 'rsa.misc.action': { - category: 'rsa', - name: 'rsa.misc.action', - type: 'keyword', + 'crowdstrike.event.LocalPort': { + category: 'crowdstrike', + description: 'Port of local machine. ', + name: 'crowdstrike.event.LocalPort', + type: 'long', }, - 'rsa.misc.result': { - category: 'rsa', - description: - 'This key is used to capture the outcome/result string value of an action in a session.', - name: 'rsa.misc.result', - type: 'keyword', + 'crowdstrike.event.RemoteAddress': { + category: 'crowdstrike', + description: 'IP address of remote machine. ', + name: 'crowdstrike.event.RemoteAddress', + type: 'ip', }, - 'rsa.misc.severity': { - category: 'rsa', - description: 'This key is used to capture the severity given the session', - name: 'rsa.misc.severity', - type: 'keyword', + 'crowdstrike.event.RemotePort': { + category: 'crowdstrike', + description: 'Port of remote machine. ', + name: 'crowdstrike.event.RemotePort', + type: 'long', }, - 'rsa.misc.event_type': { - category: 'rsa', - description: 'This key captures the event category type as specified by the event source.', - name: 'rsa.misc.event_type', + 'crowdstrike.event.RuleAction': { + category: 'crowdstrike', + description: 'Firewall rule action. ', + name: 'crowdstrike.event.RuleAction', type: 'keyword', }, - 'rsa.misc.reference_id': { - category: 'rsa', - description: 'This key is used to capture an event id from the session directly', - name: 'rsa.misc.reference_id', + 'crowdstrike.event.RuleDescription': { + category: 'crowdstrike', + description: 'Firewall rule description. ', + name: 'crowdstrike.event.RuleDescription', type: 'keyword', }, - 'rsa.misc.version': { - category: 'rsa', - description: - 'This key captures Version of the application or OS which is generating the event.', - name: 'rsa.misc.version', + 'crowdstrike.event.RuleFamilyID': { + category: 'crowdstrike', + description: 'Firewall rule family id. ', + name: 'crowdstrike.event.RuleFamilyID', type: 'keyword', }, - 'rsa.misc.disposition': { - category: 'rsa', - description: 'This key captures the The end state of an action.', - name: 'rsa.misc.disposition', + 'crowdstrike.event.RuleGroupName': { + category: 'crowdstrike', + description: 'Firewall rule group name. ', + name: 'crowdstrike.event.RuleGroupName', type: 'keyword', }, - 'rsa.misc.result_code': { - category: 'rsa', - description: - 'This key is used to capture the outcome/result numeric value of an action in a session', - name: 'rsa.misc.result_code', + 'crowdstrike.event.RuleName': { + category: 'crowdstrike', + description: 'Firewall rule name. ', + name: 'crowdstrike.event.RuleName', type: 'keyword', }, - 'rsa.misc.category': { - category: 'rsa', - description: - 'This key is used to capture the category of an event given by the vendor in the session', - name: 'rsa.misc.category', + 'crowdstrike.event.RuleId': { + category: 'crowdstrike', + description: 'Firewall rule id. ', + name: 'crowdstrike.event.RuleId', type: 'keyword', }, - 'rsa.misc.obj_name': { - category: 'rsa', - description: 'This is used to capture name of object', - name: 'rsa.misc.obj_name', - type: 'keyword', + 'crowdstrike.event.MatchCount': { + category: 'crowdstrike', + description: 'Number of firewall rule matches. ', + name: 'crowdstrike.event.MatchCount', + type: 'long', }, - 'rsa.misc.obj_type': { - category: 'rsa', - description: 'This is used to capture type of object', - name: 'rsa.misc.obj_type', - type: 'keyword', + 'crowdstrike.event.MatchCountSinceLastReport': { + category: 'crowdstrike', + description: 'Number of firewall rule matches since the last report. ', + name: 'crowdstrike.event.MatchCountSinceLastReport', + type: 'long', }, - 'rsa.misc.event_source': { - category: 'rsa', - description: 'This key captures Source of the event that’s not a hostname', - name: 'rsa.misc.event_source', - type: 'keyword', + 'crowdstrike.event.Timestamp': { + category: 'crowdstrike', + description: 'Firewall rule triggered timestamp. ', + name: 'crowdstrike.event.Timestamp', + type: 'date', }, - 'rsa.misc.log_session_id': { - category: 'rsa', - description: 'This key is used to capture a sessionid from the session directly', - name: 'rsa.misc.log_session_id', - type: 'keyword', + 'crowdstrike.event.Flags.Audit': { + category: 'crowdstrike', + description: 'CrowdStrike audit flag. ', + name: 'crowdstrike.event.Flags.Audit', + type: 'boolean', }, - 'rsa.misc.group': { - category: 'rsa', - description: 'This key captures the Group Name value', - name: 'rsa.misc.group', - type: 'keyword', + 'crowdstrike.event.Flags.Log': { + category: 'crowdstrike', + description: 'CrowdStrike log flag. ', + name: 'crowdstrike.event.Flags.Log', + type: 'boolean', }, - 'rsa.misc.policy_name': { - category: 'rsa', - description: 'This key is used to capture the Policy Name only.', - name: 'rsa.misc.policy_name', - type: 'keyword', + 'crowdstrike.event.Flags.Monitor': { + category: 'crowdstrike', + description: 'CrowdStrike monitor flag. ', + name: 'crowdstrike.event.Flags.Monitor', + type: 'boolean', }, - 'rsa.misc.rule_name': { - category: 'rsa', - description: 'This key captures the Rule Name', - name: 'rsa.misc.rule_name', + 'crowdstrike.event.Protocol': { + category: 'crowdstrike', + description: 'CrowdStrike provided protocol. ', + name: 'crowdstrike.event.Protocol', type: 'keyword', }, - 'rsa.misc.context': { - category: 'rsa', - description: 'This key captures Information which adds additional context to the event.', - name: 'rsa.misc.context', + 'crowdstrike.event.NetworkProfile': { + category: 'crowdstrike', + description: 'CrowdStrike network profile. ', + name: 'crowdstrike.event.NetworkProfile', type: 'keyword', }, - 'rsa.misc.change_new': { - category: 'rsa', - description: - 'This key is used to capture the new values of the attribute that’s changing in a session', - name: 'rsa.misc.change_new', + 'crowdstrike.event.PolicyName': { + category: 'crowdstrike', + description: 'CrowdStrike policy name. ', + name: 'crowdstrike.event.PolicyName', type: 'keyword', }, - 'rsa.misc.space': { - category: 'rsa', - name: 'rsa.misc.space', + 'crowdstrike.event.PolicyID': { + category: 'crowdstrike', + description: 'CrowdStrike policy id. ', + name: 'crowdstrike.event.PolicyID', type: 'keyword', }, - 'rsa.misc.client': { - category: 'rsa', - description: - 'This key is used to capture only the name of the client application requesting resources of the server. See the user.agent meta key for capture of the specific user agent identifier or browser identification string.', - name: 'rsa.misc.client', + 'crowdstrike.event.Status': { + category: 'crowdstrike', + description: 'CrowdStrike status. ', + name: 'crowdstrike.event.Status', type: 'keyword', }, - 'rsa.misc.msgIdPart1': { - category: 'rsa', - name: 'rsa.misc.msgIdPart1', + 'crowdstrike.event.TreeID': { + category: 'crowdstrike', + description: 'CrowdStrike tree id. ', + name: 'crowdstrike.event.TreeID', type: 'keyword', }, - 'rsa.misc.msgIdPart2': { - category: 'rsa', - name: 'rsa.misc.msgIdPart2', + 'crowdstrike.event.Commands': { + category: 'crowdstrike', + description: 'Commands run in a remote session. ', + name: 'crowdstrike.event.Commands', type: 'keyword', }, - 'rsa.misc.change_old': { - category: 'rsa', - description: - 'This key is used to capture the old value of the attribute that’s changing in a session', - name: 'rsa.misc.change_old', + 'cyberarkpas.audit.action': { + category: 'cyberarkpas', + description: 'A description of the audit record.', + name: 'cyberarkpas.audit.action', type: 'keyword', }, - 'rsa.misc.operation_id': { - category: 'rsa', - description: - 'An alert number or operation number. The values should be unique and non-repeating.', - name: 'rsa.misc.operation_id', + 'cyberarkpas.audit.ca_properties.address': { + category: 'cyberarkpas', + name: 'cyberarkpas.audit.ca_properties.address', type: 'keyword', }, - 'rsa.misc.event_state': { - category: 'rsa', - description: - 'This key captures the current state of the object/item referenced within the event. Describing an on-going event.', - name: 'rsa.misc.event_state', + 'cyberarkpas.audit.ca_properties.cpm_disabled': { + category: 'cyberarkpas', + name: 'cyberarkpas.audit.ca_properties.cpm_disabled', type: 'keyword', }, - 'rsa.misc.group_object': { - category: 'rsa', - description: 'This key captures a collection/grouping of entities. Specific usage', - name: 'rsa.misc.group_object', + 'cyberarkpas.audit.ca_properties.cpm_error_details': { + category: 'cyberarkpas', + name: 'cyberarkpas.audit.ca_properties.cpm_error_details', type: 'keyword', }, - 'rsa.misc.node': { - category: 'rsa', - description: - 'Common use case is the node name within a cluster. The cluster name is reflected by the host name.', - name: 'rsa.misc.node', + 'cyberarkpas.audit.ca_properties.cpm_status': { + category: 'cyberarkpas', + name: 'cyberarkpas.audit.ca_properties.cpm_status', type: 'keyword', }, - 'rsa.misc.rule': { - category: 'rsa', - description: 'This key captures the Rule number', - name: 'rsa.misc.rule', + 'cyberarkpas.audit.ca_properties.creation_method': { + category: 'cyberarkpas', + name: 'cyberarkpas.audit.ca_properties.creation_method', type: 'keyword', }, - 'rsa.misc.device_name': { - category: 'rsa', - description: - 'This is used to capture name of the Device associated with the node Like: a physical disk, printer, etc', - name: 'rsa.misc.device_name', + 'cyberarkpas.audit.ca_properties.customer': { + category: 'cyberarkpas', + name: 'cyberarkpas.audit.ca_properties.customer', type: 'keyword', }, - 'rsa.misc.param': { - category: 'rsa', - description: 'This key is the parameters passed as part of a command or application, etc.', - name: 'rsa.misc.param', + 'cyberarkpas.audit.ca_properties.database': { + category: 'cyberarkpas', + name: 'cyberarkpas.audit.ca_properties.database', type: 'keyword', }, - 'rsa.misc.change_attrib': { - category: 'rsa', - description: - 'This key is used to capture the name of the attribute that’s changing in a session', - name: 'rsa.misc.change_attrib', + 'cyberarkpas.audit.ca_properties.device_type': { + category: 'cyberarkpas', + name: 'cyberarkpas.audit.ca_properties.device_type', type: 'keyword', }, - 'rsa.misc.event_computer': { - category: 'rsa', - description: - 'This key is a windows only concept, where this key is used to capture fully qualified domain name in a windows log.', - name: 'rsa.misc.event_computer', + 'cyberarkpas.audit.ca_properties.dual_account_status': { + category: 'cyberarkpas', + name: 'cyberarkpas.audit.ca_properties.dual_account_status', type: 'keyword', }, - 'rsa.misc.reference_id1': { - category: 'rsa', - description: 'This key is for Linked ID to be used as an addition to "reference.id"', - name: 'rsa.misc.reference_id1', + 'cyberarkpas.audit.ca_properties.group_name': { + category: 'cyberarkpas', + name: 'cyberarkpas.audit.ca_properties.group_name', type: 'keyword', }, - 'rsa.misc.event_log': { - category: 'rsa', - description: 'This key captures the Name of the event log', - name: 'rsa.misc.event_log', + 'cyberarkpas.audit.ca_properties.in_process': { + category: 'cyberarkpas', + name: 'cyberarkpas.audit.ca_properties.in_process', type: 'keyword', }, - 'rsa.misc.OS': { - category: 'rsa', - description: 'This key captures the Name of the Operating System', - name: 'rsa.misc.OS', + 'cyberarkpas.audit.ca_properties.index': { + category: 'cyberarkpas', + name: 'cyberarkpas.audit.ca_properties.index', type: 'keyword', }, - 'rsa.misc.terminal': { - category: 'rsa', - description: 'This key captures the Terminal Names only', - name: 'rsa.misc.terminal', + 'cyberarkpas.audit.ca_properties.last_fail_date': { + category: 'cyberarkpas', + name: 'cyberarkpas.audit.ca_properties.last_fail_date', type: 'keyword', }, - 'rsa.misc.msgIdPart3': { - category: 'rsa', - name: 'rsa.misc.msgIdPart3', + 'cyberarkpas.audit.ca_properties.last_success_change': { + category: 'cyberarkpas', + name: 'cyberarkpas.audit.ca_properties.last_success_change', type: 'keyword', }, - 'rsa.misc.filter': { - category: 'rsa', - description: 'This key captures Filter used to reduce result set', - name: 'rsa.misc.filter', + 'cyberarkpas.audit.ca_properties.last_success_reconciliation': { + category: 'cyberarkpas', + name: 'cyberarkpas.audit.ca_properties.last_success_reconciliation', type: 'keyword', }, - 'rsa.misc.serial_number': { - category: 'rsa', - description: 'This key is the Serial number associated with a physical asset.', - name: 'rsa.misc.serial_number', + 'cyberarkpas.audit.ca_properties.last_success_verification': { + category: 'cyberarkpas', + name: 'cyberarkpas.audit.ca_properties.last_success_verification', type: 'keyword', }, - 'rsa.misc.checksum': { - category: 'rsa', - description: - 'This key is used to capture the checksum or hash of the entity such as a file or process. Checksum should be used over checksum.src or checksum.dst when it is unclear whether the entity is a source or target of an action.', - name: 'rsa.misc.checksum', + 'cyberarkpas.audit.ca_properties.last_task': { + category: 'cyberarkpas', + name: 'cyberarkpas.audit.ca_properties.last_task', type: 'keyword', }, - 'rsa.misc.event_user': { - category: 'rsa', - description: - 'This key is a windows only concept, where this key is used to capture combination of domain name and username in a windows log.', - name: 'rsa.misc.event_user', + 'cyberarkpas.audit.ca_properties.logon_domain': { + category: 'cyberarkpas', + name: 'cyberarkpas.audit.ca_properties.logon_domain', type: 'keyword', }, - 'rsa.misc.virusname': { - category: 'rsa', - description: 'This key captures the name of the virus', - name: 'rsa.misc.virusname', + 'cyberarkpas.audit.ca_properties.policy_id': { + category: 'cyberarkpas', + name: 'cyberarkpas.audit.ca_properties.policy_id', type: 'keyword', }, - 'rsa.misc.content_type': { - category: 'rsa', - description: 'This key is used to capture Content Type only.', - name: 'rsa.misc.content_type', + 'cyberarkpas.audit.ca_properties.port': { + category: 'cyberarkpas', + name: 'cyberarkpas.audit.ca_properties.port', type: 'keyword', }, - 'rsa.misc.group_id': { - category: 'rsa', - description: 'This key captures Group ID Number (related to the group name)', - name: 'rsa.misc.group_id', + 'cyberarkpas.audit.ca_properties.privcloud': { + category: 'cyberarkpas', + name: 'cyberarkpas.audit.ca_properties.privcloud', type: 'keyword', }, - 'rsa.misc.policy_id': { - category: 'rsa', - description: - 'This key is used to capture the Policy ID only, this should be a numeric value, use policy.name otherwise', - name: 'rsa.misc.policy_id', + 'cyberarkpas.audit.ca_properties.reset_immediately': { + category: 'cyberarkpas', + name: 'cyberarkpas.audit.ca_properties.reset_immediately', type: 'keyword', }, - 'rsa.misc.vsys': { - category: 'rsa', - description: 'This key captures Virtual System Name', - name: 'rsa.misc.vsys', + 'cyberarkpas.audit.ca_properties.retries_count': { + category: 'cyberarkpas', + name: 'cyberarkpas.audit.ca_properties.retries_count', type: 'keyword', }, - 'rsa.misc.connection_id': { - category: 'rsa', - description: 'This key captures the Connection ID', - name: 'rsa.misc.connection_id', + 'cyberarkpas.audit.ca_properties.sequence_id': { + category: 'cyberarkpas', + name: 'cyberarkpas.audit.ca_properties.sequence_id', type: 'keyword', }, - 'rsa.misc.reference_id2': { - category: 'rsa', - description: - 'This key is for the 2nd Linked ID. Can be either linked to "reference.id" or "reference.id1" value but should not be used unless the other two variables are in play.', - name: 'rsa.misc.reference_id2', + 'cyberarkpas.audit.ca_properties.tags': { + category: 'cyberarkpas', + name: 'cyberarkpas.audit.ca_properties.tags', type: 'keyword', }, - 'rsa.misc.sensor': { - category: 'rsa', - description: 'This key captures Name of the sensor. Typically used in IDS/IPS based devices', - name: 'rsa.misc.sensor', + 'cyberarkpas.audit.ca_properties.user_dn': { + category: 'cyberarkpas', + name: 'cyberarkpas.audit.ca_properties.user_dn', type: 'keyword', }, - 'rsa.misc.sig_id': { - category: 'rsa', - description: 'This key captures IDS/IPS Int Signature ID', - name: 'rsa.misc.sig_id', - type: 'long', - }, - 'rsa.misc.port_name': { - category: 'rsa', - description: - 'This key is used for Physical or logical port connection but does NOT include a network port. (Example: Printer port name).', - name: 'rsa.misc.port_name', + 'cyberarkpas.audit.ca_properties.user_name': { + category: 'cyberarkpas', + name: 'cyberarkpas.audit.ca_properties.user_name', type: 'keyword', }, - 'rsa.misc.rule_group': { - category: 'rsa', - description: 'This key captures the Rule group name', - name: 'rsa.misc.rule_group', + 'cyberarkpas.audit.ca_properties.virtual_username': { + category: 'cyberarkpas', + name: 'cyberarkpas.audit.ca_properties.virtual_username', type: 'keyword', }, - 'rsa.misc.risk_num': { - category: 'rsa', - description: 'This key captures a Numeric Risk value', - name: 'rsa.misc.risk_num', - type: 'double', + 'cyberarkpas.audit.ca_properties.other': { + category: 'cyberarkpas', + name: 'cyberarkpas.audit.ca_properties.other', + type: 'flattened', }, - 'rsa.misc.trigger_val': { - category: 'rsa', - description: 'This key captures the Value of the trigger or threshold condition.', - name: 'rsa.misc.trigger_val', + 'cyberarkpas.audit.category': { + category: 'cyberarkpas', + description: 'The category name (for category-related operations).', + name: 'cyberarkpas.audit.category', type: 'keyword', }, - 'rsa.misc.log_session_id1': { - category: 'rsa', - description: - 'This key is used to capture a Linked (Related) Session ID from the session directly', - name: 'rsa.misc.log_session_id1', + 'cyberarkpas.audit.desc': { + category: 'cyberarkpas', + description: 'A static value that displays a description of the audit codes.', + name: 'cyberarkpas.audit.desc', type: 'keyword', }, - 'rsa.misc.comp_version': { - category: 'rsa', - description: 'This key captures the Version level of a sub-component of a product.', - name: 'rsa.misc.comp_version', + 'cyberarkpas.audit.extra_details.ad_process_id': { + category: 'cyberarkpas', + name: 'cyberarkpas.audit.extra_details.ad_process_id', type: 'keyword', }, - 'rsa.misc.content_version': { - category: 'rsa', - description: 'This key captures Version level of a signature or database content.', - name: 'rsa.misc.content_version', + 'cyberarkpas.audit.extra_details.ad_process_name': { + category: 'cyberarkpas', + name: 'cyberarkpas.audit.extra_details.ad_process_name', type: 'keyword', }, - 'rsa.misc.hardware_id': { - category: 'rsa', - description: - 'This key is used to capture unique identifier for a device or system (NOT a Mac address)', - name: 'rsa.misc.hardware_id', + 'cyberarkpas.audit.extra_details.application_type': { + category: 'cyberarkpas', + name: 'cyberarkpas.audit.extra_details.application_type', type: 'keyword', }, - 'rsa.misc.risk': { - category: 'rsa', - description: 'This key captures the non-numeric risk value', - name: 'rsa.misc.risk', + 'cyberarkpas.audit.extra_details.command': { + category: 'cyberarkpas', + name: 'cyberarkpas.audit.extra_details.command', type: 'keyword', }, - 'rsa.misc.event_id': { - category: 'rsa', - name: 'rsa.misc.event_id', + 'cyberarkpas.audit.extra_details.connection_component_id': { + category: 'cyberarkpas', + name: 'cyberarkpas.audit.extra_details.connection_component_id', type: 'keyword', }, - 'rsa.misc.reason': { - category: 'rsa', - name: 'rsa.misc.reason', + 'cyberarkpas.audit.extra_details.dst_host': { + category: 'cyberarkpas', + name: 'cyberarkpas.audit.extra_details.dst_host', type: 'keyword', }, - 'rsa.misc.status': { - category: 'rsa', - name: 'rsa.misc.status', + 'cyberarkpas.audit.extra_details.logon_account': { + category: 'cyberarkpas', + name: 'cyberarkpas.audit.extra_details.logon_account', type: 'keyword', }, - 'rsa.misc.mail_id': { - category: 'rsa', - description: 'This key is used to capture the mailbox id/name', - name: 'rsa.misc.mail_id', + 'cyberarkpas.audit.extra_details.managed_account': { + category: 'cyberarkpas', + name: 'cyberarkpas.audit.extra_details.managed_account', type: 'keyword', }, - 'rsa.misc.rule_uid': { - category: 'rsa', - description: 'This key is the Unique Identifier for a rule.', - name: 'rsa.misc.rule_uid', + 'cyberarkpas.audit.extra_details.process_id': { + category: 'cyberarkpas', + name: 'cyberarkpas.audit.extra_details.process_id', type: 'keyword', }, - 'rsa.misc.trigger_desc': { - category: 'rsa', - description: 'This key captures the Description of the trigger or threshold condition.', - name: 'rsa.misc.trigger_desc', + 'cyberarkpas.audit.extra_details.process_name': { + category: 'cyberarkpas', + name: 'cyberarkpas.audit.extra_details.process_name', type: 'keyword', }, - 'rsa.misc.inout': { - category: 'rsa', - name: 'rsa.misc.inout', + 'cyberarkpas.audit.extra_details.protocol': { + category: 'cyberarkpas', + name: 'cyberarkpas.audit.extra_details.protocol', type: 'keyword', }, - 'rsa.misc.p_msgid': { - category: 'rsa', - name: 'rsa.misc.p_msgid', + 'cyberarkpas.audit.extra_details.psmid': { + category: 'cyberarkpas', + name: 'cyberarkpas.audit.extra_details.psmid', type: 'keyword', }, - 'rsa.misc.data_type': { - category: 'rsa', - name: 'rsa.misc.data_type', + 'cyberarkpas.audit.extra_details.session_duration': { + category: 'cyberarkpas', + name: 'cyberarkpas.audit.extra_details.session_duration', type: 'keyword', }, - 'rsa.misc.msgIdPart4': { - category: 'rsa', - name: 'rsa.misc.msgIdPart4', + 'cyberarkpas.audit.extra_details.session_id': { + category: 'cyberarkpas', + name: 'cyberarkpas.audit.extra_details.session_id', type: 'keyword', }, - 'rsa.misc.error': { - category: 'rsa', - description: 'This key captures All non successful Error codes or responses', - name: 'rsa.misc.error', + 'cyberarkpas.audit.extra_details.src_host': { + category: 'cyberarkpas', + name: 'cyberarkpas.audit.extra_details.src_host', type: 'keyword', }, - 'rsa.misc.index': { - category: 'rsa', - name: 'rsa.misc.index', + 'cyberarkpas.audit.extra_details.username': { + category: 'cyberarkpas', + name: 'cyberarkpas.audit.extra_details.username', type: 'keyword', }, - 'rsa.misc.listnum': { - category: 'rsa', - description: - 'This key is used to capture listname or listnumber, primarily for collecting access-list', - name: 'rsa.misc.listnum', - type: 'keyword', + 'cyberarkpas.audit.extra_details.other': { + category: 'cyberarkpas', + name: 'cyberarkpas.audit.extra_details.other', + type: 'flattened', }, - 'rsa.misc.ntype': { - category: 'rsa', - name: 'rsa.misc.ntype', + 'cyberarkpas.audit.file': { + category: 'cyberarkpas', + description: 'The name of the target file.', + name: 'cyberarkpas.audit.file', type: 'keyword', }, - 'rsa.misc.observed_val': { - category: 'rsa', - description: - 'This key captures the Value observed (from the perspective of the device generating the log).', - name: 'rsa.misc.observed_val', - type: 'keyword', + 'cyberarkpas.audit.gateway_station': { + category: 'cyberarkpas', + description: 'The IP of the web application machine (PVWA).', + name: 'cyberarkpas.audit.gateway_station', + type: 'ip', }, - 'rsa.misc.policy_value': { - category: 'rsa', - description: - 'This key captures the contents of the policy. This contains details about the policy', - name: 'rsa.misc.policy_value', + 'cyberarkpas.audit.hostname': { + category: 'cyberarkpas', + description: 'The hostname, in upper case.', + example: 'MY-COMPUTER', + name: 'cyberarkpas.audit.hostname', type: 'keyword', }, - 'rsa.misc.pool_name': { - category: 'rsa', - description: 'This key captures the name of a resource pool', - name: 'rsa.misc.pool_name', - type: 'keyword', + 'cyberarkpas.audit.iso_timestamp': { + category: 'cyberarkpas', + description: 'The timestamp, in ISO Timestamp format (RFC 3339).', + example: '"2013-06-25T10:47:19.000Z"', + name: 'cyberarkpas.audit.iso_timestamp', + type: 'date', }, - 'rsa.misc.rule_template': { - category: 'rsa', + 'cyberarkpas.audit.issuer': { + category: 'cyberarkpas', description: - 'A default set of parameters which are overlayed onto a rule (or rulename) which efffectively constitutes a template', - name: 'rsa.misc.rule_template', - type: 'keyword', - }, - 'rsa.misc.count': { - category: 'rsa', - name: 'rsa.misc.count', + 'The Vault user who wrote the audit. This is usually the user who performed the operation.', + name: 'cyberarkpas.audit.issuer', type: 'keyword', }, - 'rsa.misc.number': { - category: 'rsa', - name: 'rsa.misc.number', + 'cyberarkpas.audit.location': { + category: 'cyberarkpas', + description: 'The target Location (for Location operations).', + name: 'cyberarkpas.audit.location', type: 'keyword', }, - 'rsa.misc.sigcat': { - category: 'rsa', - name: 'rsa.misc.sigcat', + 'cyberarkpas.audit.message': { + category: 'cyberarkpas', + description: 'A description of the audit records (same information as in the Desc field).', + name: 'cyberarkpas.audit.message', type: 'keyword', }, - 'rsa.misc.type': { - category: 'rsa', - name: 'rsa.misc.type', + 'cyberarkpas.audit.message_id': { + category: 'cyberarkpas', + description: 'The code ID of the audit records.', + name: 'cyberarkpas.audit.message_id', type: 'keyword', }, - 'rsa.misc.comments': { - category: 'rsa', - description: 'Comment information provided in the log message', - name: 'rsa.misc.comments', + 'cyberarkpas.audit.product': { + category: 'cyberarkpas', + description: 'A static value that represents the product.', + name: 'cyberarkpas.audit.product', type: 'keyword', }, - 'rsa.misc.doc_number': { - category: 'rsa', - description: 'This key captures File Identification number', - name: 'rsa.misc.doc_number', - type: 'long', + 'cyberarkpas.audit.pvwa_details': { + category: 'cyberarkpas', + description: 'Specific details of the PVWA audit records.', + name: 'cyberarkpas.audit.pvwa_details', + type: 'flattened', }, - 'rsa.misc.expected_val': { - category: 'rsa', + 'cyberarkpas.audit.raw': { + category: 'cyberarkpas', description: - 'This key captures the Value expected (from the perspective of the device generating the log).', - name: 'rsa.misc.expected_val', + 'Raw XML for the original audit record. Only present when XSLT file has debugging enabled. ', + name: 'cyberarkpas.audit.raw', type: 'keyword', }, - 'rsa.misc.job_num': { - category: 'rsa', - description: 'This key captures the Job Number', - name: 'rsa.misc.job_num', - type: 'keyword', + 'cyberarkpas.audit.reason': { + category: 'cyberarkpas', + description: 'The reason entered by the user.', + name: 'cyberarkpas.audit.reason', + type: 'text', }, - 'rsa.misc.spi_dst': { - category: 'rsa', - description: 'Destination SPI Index', - name: 'rsa.misc.spi_dst', - type: 'keyword', + 'cyberarkpas.audit.rfc5424': { + category: 'cyberarkpas', + description: 'Whether the syslog format complies with RFC5424.', + example: 'yes', + name: 'cyberarkpas.audit.rfc5424', + type: 'boolean', }, - 'rsa.misc.spi_src': { - category: 'rsa', - description: 'Source SPI Index', - name: 'rsa.misc.spi_src', + 'cyberarkpas.audit.safe': { + category: 'cyberarkpas', + description: 'The name of the target Safe.', + name: 'cyberarkpas.audit.safe', type: 'keyword', }, - 'rsa.misc.code': { - category: 'rsa', - name: 'rsa.misc.code', + 'cyberarkpas.audit.severity': { + category: 'cyberarkpas', + description: 'The severity of the audit records.', + name: 'cyberarkpas.audit.severity', type: 'keyword', }, - 'rsa.misc.agent_id': { - category: 'rsa', - description: 'This key is used to capture agent id', - name: 'rsa.misc.agent_id', + 'cyberarkpas.audit.source_user': { + category: 'cyberarkpas', + description: 'The name of the Vault user who performed the operation.', + name: 'cyberarkpas.audit.source_user', type: 'keyword', }, - 'rsa.misc.message_body': { - category: 'rsa', - description: 'This key captures the The contents of the message body.', - name: 'rsa.misc.message_body', + 'cyberarkpas.audit.station': { + category: 'cyberarkpas', + description: + 'The IP from where the operation was performed. For PVWA sessions, this will be the real client machine IP.', + name: 'cyberarkpas.audit.station', + type: 'ip', + }, + 'cyberarkpas.audit.target_user': { + category: 'cyberarkpas', + description: 'The name of the Vault user on which the operation was performed.', + name: 'cyberarkpas.audit.target_user', type: 'keyword', }, - 'rsa.misc.phone': { - category: 'rsa', - name: 'rsa.misc.phone', + 'cyberarkpas.audit.timestamp': { + category: 'cyberarkpas', + description: 'The timestamp, in MMM DD HH:MM:SS format.', + example: 'Jun 25 10:47:19', + name: 'cyberarkpas.audit.timestamp', type: 'keyword', }, - 'rsa.misc.sig_id_str': { - category: 'rsa', - description: 'This key captures a string object of the sigid variable.', - name: 'rsa.misc.sig_id_str', + 'cyberarkpas.audit.vendor': { + category: 'cyberarkpas', + description: 'A static value that represents the vendor.', + name: 'cyberarkpas.audit.vendor', type: 'keyword', }, - 'rsa.misc.cmd': { - category: 'rsa', - name: 'rsa.misc.cmd', + 'cyberarkpas.audit.version': { + category: 'cyberarkpas', + description: 'A static value that represents the version of the Vault.', + name: 'cyberarkpas.audit.version', type: 'keyword', }, - 'rsa.misc.misc': { - category: 'rsa', - name: 'rsa.misc.misc', + 'envoyproxy.log_type': { + category: 'envoyproxy', + description: 'Envoy log type, normally ACCESS ', + name: 'envoyproxy.log_type', type: 'keyword', }, - 'rsa.misc.name': { - category: 'rsa', - name: 'rsa.misc.name', + 'envoyproxy.response_flags': { + category: 'envoyproxy', + description: 'Response flags ', + name: 'envoyproxy.response_flags', type: 'keyword', }, - 'rsa.misc.cpu': { - category: 'rsa', - description: 'This key is the CPU time used in the execution of the event being recorded.', - name: 'rsa.misc.cpu', + 'envoyproxy.upstream_service_time': { + category: 'envoyproxy', + description: 'Upstream service time in nanoseconds ', + name: 'envoyproxy.upstream_service_time', type: 'long', + format: 'duration', }, - 'rsa.misc.event_desc': { - category: 'rsa', - description: - 'This key is used to capture a description of an event available directly or inferred', - name: 'rsa.misc.event_desc', + 'envoyproxy.request_id': { + category: 'envoyproxy', + description: 'ID of the request ', + name: 'envoyproxy.request_id', type: 'keyword', }, - 'rsa.misc.sig_id1': { - category: 'rsa', - description: 'This key captures IDS/IPS Int Signature ID. This must be linked to the sig.id', - name: 'rsa.misc.sig_id1', - type: 'long', - }, - 'rsa.misc.im_buddyid': { - category: 'rsa', - name: 'rsa.misc.im_buddyid', + 'envoyproxy.authority': { + category: 'envoyproxy', + description: 'Envoy proxy authority field ', + name: 'envoyproxy.authority', type: 'keyword', }, - 'rsa.misc.im_client': { - category: 'rsa', - name: 'rsa.misc.im_client', + 'envoyproxy.proxy_type': { + category: 'envoyproxy', + description: 'Envoy proxy type, tcp or http ', + name: 'envoyproxy.proxy_type', type: 'keyword', }, - 'rsa.misc.im_userid': { - category: 'rsa', - name: 'rsa.misc.im_userid', + 'fortinet.file.hash.crc32': { + category: 'fortinet', + description: 'CRC32 Hash of file ', + name: 'fortinet.file.hash.crc32', type: 'keyword', }, - 'rsa.misc.pid': { - category: 'rsa', - name: 'rsa.misc.pid', + 'fortinet.firewall.acct_stat': { + category: 'fortinet', + description: 'Accounting state (RADIUS) ', + name: 'fortinet.firewall.acct_stat', type: 'keyword', }, - 'rsa.misc.priority': { - category: 'rsa', - name: 'rsa.misc.priority', + 'fortinet.firewall.acktime': { + category: 'fortinet', + description: 'Alarm Acknowledge Time ', + name: 'fortinet.firewall.acktime', type: 'keyword', }, - 'rsa.misc.context_subject': { - category: 'rsa', - description: - 'This key is to be used in an audit context where the subject is the object being identified', - name: 'rsa.misc.context_subject', + 'fortinet.firewall.act': { + category: 'fortinet', + description: 'Action ', + name: 'fortinet.firewall.act', type: 'keyword', }, - 'rsa.misc.context_target': { - category: 'rsa', - name: 'rsa.misc.context_target', + 'fortinet.firewall.action': { + category: 'fortinet', + description: 'Status of the session ', + name: 'fortinet.firewall.action', type: 'keyword', }, - 'rsa.misc.cve': { - category: 'rsa', - description: - 'This key captures CVE (Common Vulnerabilities and Exposures) - an identifier for known information security vulnerabilities.', - name: 'rsa.misc.cve', + 'fortinet.firewall.activity': { + category: 'fortinet', + description: 'HA activity message ', + name: 'fortinet.firewall.activity', type: 'keyword', }, - 'rsa.misc.fcatnum': { - category: 'rsa', - description: 'This key captures Filter Category Number. Legacy Usage', - name: 'rsa.misc.fcatnum', + 'fortinet.firewall.addr': { + category: 'fortinet', + description: 'IP Address ', + name: 'fortinet.firewall.addr', + type: 'ip', + }, + 'fortinet.firewall.addr_type': { + category: 'fortinet', + description: 'Address Type ', + name: 'fortinet.firewall.addr_type', type: 'keyword', }, - 'rsa.misc.library': { - category: 'rsa', - description: 'This key is used to capture library information in mainframe devices', - name: 'rsa.misc.library', + 'fortinet.firewall.addrgrp': { + category: 'fortinet', + description: 'Address Group ', + name: 'fortinet.firewall.addrgrp', type: 'keyword', }, - 'rsa.misc.parent_node': { - category: 'rsa', - description: 'This key captures the Parent Node Name. Must be related to node variable.', - name: 'rsa.misc.parent_node', + 'fortinet.firewall.adgroup': { + category: 'fortinet', + description: 'AD Group Name ', + name: 'fortinet.firewall.adgroup', type: 'keyword', }, - 'rsa.misc.risk_info': { - category: 'rsa', - description: 'Deprecated, use New Hunting Model (inv.*, ioc, boc, eoc, analysis.*)', - name: 'rsa.misc.risk_info', + 'fortinet.firewall.admin': { + category: 'fortinet', + description: 'Admin User ', + name: 'fortinet.firewall.admin', type: 'keyword', }, - 'rsa.misc.tcp_flags': { - category: 'rsa', - description: 'This key is captures the TCP flags set in any packet of session', - name: 'rsa.misc.tcp_flags', - type: 'long', + 'fortinet.firewall.age': { + category: 'fortinet', + description: 'Time in seconds - time passed since last seen ', + name: 'fortinet.firewall.age', + type: 'integer', }, - 'rsa.misc.tos': { - category: 'rsa', - description: 'This key describes the type of service', - name: 'rsa.misc.tos', - type: 'long', + 'fortinet.firewall.agent': { + category: 'fortinet', + description: 'User agent - eg. agent="Mozilla/5.0" ', + name: 'fortinet.firewall.agent', + type: 'keyword', }, - 'rsa.misc.vm_target': { - category: 'rsa', - description: 'VMWare Target **VMWARE** only varaible.', - name: 'rsa.misc.vm_target', + 'fortinet.firewall.alarmid': { + category: 'fortinet', + description: 'Alarm ID ', + name: 'fortinet.firewall.alarmid', + type: 'integer', + }, + 'fortinet.firewall.alert': { + category: 'fortinet', + description: 'Alert ', + name: 'fortinet.firewall.alert', type: 'keyword', }, - 'rsa.misc.workspace': { - category: 'rsa', - description: 'This key captures Workspace Description', - name: 'rsa.misc.workspace', + 'fortinet.firewall.analyticscksum': { + category: 'fortinet', + description: 'The checksum of the file submitted for analytics ', + name: 'fortinet.firewall.analyticscksum', type: 'keyword', }, - 'rsa.misc.command': { - category: 'rsa', - name: 'rsa.misc.command', + 'fortinet.firewall.analyticssubmit': { + category: 'fortinet', + description: 'The flag for analytics submission ', + name: 'fortinet.firewall.analyticssubmit', type: 'keyword', }, - 'rsa.misc.event_category': { - category: 'rsa', - name: 'rsa.misc.event_category', + 'fortinet.firewall.ap': { + category: 'fortinet', + description: 'Access Point ', + name: 'fortinet.firewall.ap', type: 'keyword', }, - 'rsa.misc.facilityname': { - category: 'rsa', - name: 'rsa.misc.facilityname', + 'fortinet.firewall.app-type': { + category: 'fortinet', + description: 'Address Type ', + name: 'fortinet.firewall.app-type', type: 'keyword', }, - 'rsa.misc.forensic_info': { - category: 'rsa', - name: 'rsa.misc.forensic_info', + 'fortinet.firewall.appact': { + category: 'fortinet', + description: 'The security action from app control ', + name: 'fortinet.firewall.appact', type: 'keyword', }, - 'rsa.misc.jobname': { - category: 'rsa', - name: 'rsa.misc.jobname', + 'fortinet.firewall.appid': { + category: 'fortinet', + description: 'Application ID ', + name: 'fortinet.firewall.appid', + type: 'integer', + }, + 'fortinet.firewall.applist': { + category: 'fortinet', + description: 'Application Control profile ', + name: 'fortinet.firewall.applist', type: 'keyword', }, - 'rsa.misc.mode': { - category: 'rsa', - name: 'rsa.misc.mode', + 'fortinet.firewall.apprisk': { + category: 'fortinet', + description: 'Application Risk Level ', + name: 'fortinet.firewall.apprisk', type: 'keyword', }, - 'rsa.misc.policy': { - category: 'rsa', - name: 'rsa.misc.policy', + 'fortinet.firewall.apscan': { + category: 'fortinet', + description: 'The name of the AP, which scanned and detected the rogue AP ', + name: 'fortinet.firewall.apscan', type: 'keyword', }, - 'rsa.misc.policy_waiver': { - category: 'rsa', - name: 'rsa.misc.policy_waiver', + 'fortinet.firewall.apsn': { + category: 'fortinet', + description: 'Access Point ', + name: 'fortinet.firewall.apsn', type: 'keyword', }, - 'rsa.misc.second': { - category: 'rsa', - name: 'rsa.misc.second', + 'fortinet.firewall.apstatus': { + category: 'fortinet', + description: 'Access Point status ', + name: 'fortinet.firewall.apstatus', type: 'keyword', }, - 'rsa.misc.space1': { - category: 'rsa', - name: 'rsa.misc.space1', + 'fortinet.firewall.aptype': { + category: 'fortinet', + description: 'Access Point type ', + name: 'fortinet.firewall.aptype', type: 'keyword', }, - 'rsa.misc.subcategory': { - category: 'rsa', - name: 'rsa.misc.subcategory', + 'fortinet.firewall.assigned': { + category: 'fortinet', + description: 'Assigned IP Address ', + name: 'fortinet.firewall.assigned', + type: 'ip', + }, + 'fortinet.firewall.assignip': { + category: 'fortinet', + description: 'Assigned IP Address ', + name: 'fortinet.firewall.assignip', + type: 'ip', + }, + 'fortinet.firewall.attachment': { + category: 'fortinet', + description: 'The flag for email attachement ', + name: 'fortinet.firewall.attachment', type: 'keyword', }, - 'rsa.misc.tbdstr2': { - category: 'rsa', - name: 'rsa.misc.tbdstr2', + 'fortinet.firewall.attack': { + category: 'fortinet', + description: 'Attack Name ', + name: 'fortinet.firewall.attack', type: 'keyword', }, - 'rsa.misc.alert_id': { - category: 'rsa', - description: 'Deprecated, New Hunting Model (inv.*, ioc, boc, eoc, analysis.*)', - name: 'rsa.misc.alert_id', + 'fortinet.firewall.attackcontext': { + category: 'fortinet', + description: 'The trigger patterns and the packetdata with base64 encoding ', + name: 'fortinet.firewall.attackcontext', type: 'keyword', }, - 'rsa.misc.checksum_dst': { - category: 'rsa', - description: - 'This key is used to capture the checksum or hash of the the target entity such as a process or file.', - name: 'rsa.misc.checksum_dst', + 'fortinet.firewall.attackcontextid': { + category: 'fortinet', + description: 'Attack context id / total ', + name: 'fortinet.firewall.attackcontextid', type: 'keyword', }, - 'rsa.misc.checksum_src': { - category: 'rsa', - description: - 'This key is used to capture the checksum or hash of the source entity such as a file or process.', - name: 'rsa.misc.checksum_src', + 'fortinet.firewall.attackid': { + category: 'fortinet', + description: 'Attack ID ', + name: 'fortinet.firewall.attackid', + type: 'integer', + }, + 'fortinet.firewall.auditid': { + category: 'fortinet', + description: 'Audit ID ', + name: 'fortinet.firewall.auditid', + type: 'long', + }, + 'fortinet.firewall.auditscore': { + category: 'fortinet', + description: 'The Audit Score ', + name: 'fortinet.firewall.auditscore', type: 'keyword', }, - 'rsa.misc.fresult': { - category: 'rsa', - description: 'This key captures the Filter Result', - name: 'rsa.misc.fresult', + 'fortinet.firewall.audittime': { + category: 'fortinet', + description: 'The time of the audit ', + name: 'fortinet.firewall.audittime', type: 'long', }, - 'rsa.misc.payload_dst': { - category: 'rsa', - description: 'This key is used to capture destination payload', - name: 'rsa.misc.payload_dst', + 'fortinet.firewall.authgrp': { + category: 'fortinet', + description: 'Authorization Group ', + name: 'fortinet.firewall.authgrp', type: 'keyword', }, - 'rsa.misc.payload_src': { - category: 'rsa', - description: 'This key is used to capture source payload', - name: 'rsa.misc.payload_src', + 'fortinet.firewall.authid': { + category: 'fortinet', + description: 'Authentication ID ', + name: 'fortinet.firewall.authid', type: 'keyword', }, - 'rsa.misc.pool_id': { - category: 'rsa', - description: 'This key captures the identifier (typically numeric field) of a resource pool', - name: 'rsa.misc.pool_id', + 'fortinet.firewall.authproto': { + category: 'fortinet', + description: 'The protocol that initiated the authentication ', + name: 'fortinet.firewall.authproto', type: 'keyword', }, - 'rsa.misc.process_id_val': { - category: 'rsa', - description: 'This key is a failure key for Process ID when it is not an integer value', - name: 'rsa.misc.process_id_val', + 'fortinet.firewall.authserver': { + category: 'fortinet', + description: 'Authentication server ', + name: 'fortinet.firewall.authserver', type: 'keyword', }, - 'rsa.misc.risk_num_comm': { - category: 'rsa', - description: 'This key captures Risk Number Community', - name: 'rsa.misc.risk_num_comm', - type: 'double', + 'fortinet.firewall.bandwidth': { + category: 'fortinet', + description: 'Bandwidth ', + name: 'fortinet.firewall.bandwidth', + type: 'keyword', }, - 'rsa.misc.risk_num_next': { - category: 'rsa', - description: 'This key captures Risk Number NextGen', - name: 'rsa.misc.risk_num_next', - type: 'double', + 'fortinet.firewall.banned_rule': { + category: 'fortinet', + description: 'NAC quarantine Banned Rule Name ', + name: 'fortinet.firewall.banned_rule', + type: 'keyword', }, - 'rsa.misc.risk_num_sand': { - category: 'rsa', - description: 'This key captures Risk Number SandBox', - name: 'rsa.misc.risk_num_sand', - type: 'double', + 'fortinet.firewall.banned_src': { + category: 'fortinet', + description: 'NAC quarantine Banned Source IP ', + name: 'fortinet.firewall.banned_src', + type: 'keyword', }, - 'rsa.misc.risk_num_static': { - category: 'rsa', - description: 'This key captures Risk Number Static', - name: 'rsa.misc.risk_num_static', - type: 'double', + 'fortinet.firewall.banword': { + category: 'fortinet', + description: 'Banned word ', + name: 'fortinet.firewall.banword', + type: 'keyword', }, - 'rsa.misc.risk_suspicious': { - category: 'rsa', - description: 'Deprecated, use New Hunting Model (inv.*, ioc, boc, eoc, analysis.*)', - name: 'rsa.misc.risk_suspicious', + 'fortinet.firewall.botnetdomain': { + category: 'fortinet', + description: 'Botnet Domain Name ', + name: 'fortinet.firewall.botnetdomain', type: 'keyword', }, - 'rsa.misc.risk_warning': { - category: 'rsa', - description: 'Deprecated, use New Hunting Model (inv.*, ioc, boc, eoc, analysis.*)', - name: 'rsa.misc.risk_warning', + 'fortinet.firewall.botnetip': { + category: 'fortinet', + description: 'Botnet IP Address ', + name: 'fortinet.firewall.botnetip', + type: 'ip', + }, + 'fortinet.firewall.bssid': { + category: 'fortinet', + description: 'Service Set ID ', + name: 'fortinet.firewall.bssid', type: 'keyword', }, - 'rsa.misc.snmp_oid': { - category: 'rsa', - description: 'SNMP Object Identifier', - name: 'rsa.misc.snmp_oid', + 'fortinet.firewall.call_id': { + category: 'fortinet', + description: 'Caller ID ', + name: 'fortinet.firewall.call_id', type: 'keyword', }, - 'rsa.misc.sql': { - category: 'rsa', - description: 'This key captures the SQL query', - name: 'rsa.misc.sql', + 'fortinet.firewall.carrier_ep': { + category: 'fortinet', + description: 'The FortiOS Carrier end-point identification ', + name: 'fortinet.firewall.carrier_ep', type: 'keyword', }, - 'rsa.misc.vuln_ref': { - category: 'rsa', - description: 'This key captures the Vulnerability Reference details', - name: 'rsa.misc.vuln_ref', + 'fortinet.firewall.cat': { + category: 'fortinet', + description: 'DNS category ID ', + name: 'fortinet.firewall.cat', + type: 'integer', + }, + 'fortinet.firewall.category': { + category: 'fortinet', + description: 'Authentication category ', + name: 'fortinet.firewall.category', type: 'keyword', }, - 'rsa.misc.acl_id': { - category: 'rsa', - name: 'rsa.misc.acl_id', + 'fortinet.firewall.cc': { + category: 'fortinet', + description: 'CC Email Address ', + name: 'fortinet.firewall.cc', type: 'keyword', }, - 'rsa.misc.acl_op': { - category: 'rsa', - name: 'rsa.misc.acl_op', + 'fortinet.firewall.cdrcontent': { + category: 'fortinet', + description: 'Cdrcontent ', + name: 'fortinet.firewall.cdrcontent', + type: 'keyword', + }, + 'fortinet.firewall.centralnatid': { + category: 'fortinet', + description: 'Central NAT ID ', + name: 'fortinet.firewall.centralnatid', + type: 'integer', + }, + 'fortinet.firewall.cert': { + category: 'fortinet', + description: 'Certificate ', + name: 'fortinet.firewall.cert', + type: 'keyword', + }, + 'fortinet.firewall.cert-type': { + category: 'fortinet', + description: 'Certificate type ', + name: 'fortinet.firewall.cert-type', + type: 'keyword', + }, + 'fortinet.firewall.certhash': { + category: 'fortinet', + description: 'Certificate hash ', + name: 'fortinet.firewall.certhash', type: 'keyword', }, - 'rsa.misc.acl_pos': { - category: 'rsa', - name: 'rsa.misc.acl_pos', + 'fortinet.firewall.cfgattr': { + category: 'fortinet', + description: 'Configuration attribute ', + name: 'fortinet.firewall.cfgattr', type: 'keyword', }, - 'rsa.misc.acl_table': { - category: 'rsa', - name: 'rsa.misc.acl_table', + 'fortinet.firewall.cfgobj': { + category: 'fortinet', + description: 'Configuration object ', + name: 'fortinet.firewall.cfgobj', type: 'keyword', }, - 'rsa.misc.admin': { - category: 'rsa', - name: 'rsa.misc.admin', + 'fortinet.firewall.cfgpath': { + category: 'fortinet', + description: 'Configuration path ', + name: 'fortinet.firewall.cfgpath', type: 'keyword', }, - 'rsa.misc.alarm_id': { - category: 'rsa', - name: 'rsa.misc.alarm_id', + 'fortinet.firewall.cfgtid': { + category: 'fortinet', + description: 'Configuration transaction ID ', + name: 'fortinet.firewall.cfgtid', type: 'keyword', }, - 'rsa.misc.alarmname': { - category: 'rsa', - name: 'rsa.misc.alarmname', - type: 'keyword', + 'fortinet.firewall.cfgtxpower': { + category: 'fortinet', + description: 'Configuration TX power ', + name: 'fortinet.firewall.cfgtxpower', + type: 'integer', }, - 'rsa.misc.app_id': { - category: 'rsa', - name: 'rsa.misc.app_id', - type: 'keyword', + 'fortinet.firewall.channel': { + category: 'fortinet', + description: 'Wireless Channel ', + name: 'fortinet.firewall.channel', + type: 'integer', }, - 'rsa.misc.audit': { - category: 'rsa', - name: 'rsa.misc.audit', + 'fortinet.firewall.channeltype': { + category: 'fortinet', + description: 'SSH channel type ', + name: 'fortinet.firewall.channeltype', type: 'keyword', }, - 'rsa.misc.audit_object': { - category: 'rsa', - name: 'rsa.misc.audit_object', - type: 'keyword', + 'fortinet.firewall.chassisid': { + category: 'fortinet', + description: 'Chassis ID ', + name: 'fortinet.firewall.chassisid', + type: 'integer', }, - 'rsa.misc.auditdata': { - category: 'rsa', - name: 'rsa.misc.auditdata', + 'fortinet.firewall.checksum': { + category: 'fortinet', + description: 'The checksum of the scanned file ', + name: 'fortinet.firewall.checksum', type: 'keyword', }, - 'rsa.misc.benchmark': { - category: 'rsa', - name: 'rsa.misc.benchmark', + 'fortinet.firewall.chgheaders': { + category: 'fortinet', + description: 'HTTP Headers ', + name: 'fortinet.firewall.chgheaders', type: 'keyword', }, - 'rsa.misc.bypass': { - category: 'rsa', - name: 'rsa.misc.bypass', + 'fortinet.firewall.cldobjid': { + category: 'fortinet', + description: 'Connector object ID ', + name: 'fortinet.firewall.cldobjid', type: 'keyword', }, - 'rsa.misc.cache': { - category: 'rsa', - name: 'rsa.misc.cache', + 'fortinet.firewall.client_addr': { + category: 'fortinet', + description: 'Wifi client address ', + name: 'fortinet.firewall.client_addr', type: 'keyword', }, - 'rsa.misc.cache_hit': { - category: 'rsa', - name: 'rsa.misc.cache_hit', + 'fortinet.firewall.cloudaction': { + category: 'fortinet', + description: 'Cloud Action ', + name: 'fortinet.firewall.cloudaction', type: 'keyword', }, - 'rsa.misc.cefversion': { - category: 'rsa', - name: 'rsa.misc.cefversion', + 'fortinet.firewall.clouduser': { + category: 'fortinet', + description: 'Cloud User ', + name: 'fortinet.firewall.clouduser', type: 'keyword', }, - 'rsa.misc.cfg_attr': { - category: 'rsa', - name: 'rsa.misc.cfg_attr', - type: 'keyword', + 'fortinet.firewall.column': { + category: 'fortinet', + description: 'VOIP Column ', + name: 'fortinet.firewall.column', + type: 'integer', }, - 'rsa.misc.cfg_obj': { - category: 'rsa', - name: 'rsa.misc.cfg_obj', + 'fortinet.firewall.command': { + category: 'fortinet', + description: 'CLI Command ', + name: 'fortinet.firewall.command', type: 'keyword', }, - 'rsa.misc.cfg_path': { - category: 'rsa', - name: 'rsa.misc.cfg_path', + 'fortinet.firewall.community': { + category: 'fortinet', + description: 'SNMP Community ', + name: 'fortinet.firewall.community', type: 'keyword', }, - 'rsa.misc.changes': { - category: 'rsa', - name: 'rsa.misc.changes', + 'fortinet.firewall.configcountry': { + category: 'fortinet', + description: 'Configuration country ', + name: 'fortinet.firewall.configcountry', type: 'keyword', }, - 'rsa.misc.client_ip': { - category: 'rsa', - name: 'rsa.misc.client_ip', + 'fortinet.firewall.connection_type': { + category: 'fortinet', + description: 'FortiClient Connection Type ', + name: 'fortinet.firewall.connection_type', type: 'keyword', }, - 'rsa.misc.clustermembers': { - category: 'rsa', - name: 'rsa.misc.clustermembers', + 'fortinet.firewall.conserve': { + category: 'fortinet', + description: 'Flag for conserve mode ', + name: 'fortinet.firewall.conserve', type: 'keyword', }, - 'rsa.misc.cn_acttimeout': { - category: 'rsa', - name: 'rsa.misc.cn_acttimeout', + 'fortinet.firewall.constraint': { + category: 'fortinet', + description: 'WAF http protocol restrictions ', + name: 'fortinet.firewall.constraint', type: 'keyword', }, - 'rsa.misc.cn_asn_src': { - category: 'rsa', - name: 'rsa.misc.cn_asn_src', + 'fortinet.firewall.contentdisarmed': { + category: 'fortinet', + description: 'Email scanned content ', + name: 'fortinet.firewall.contentdisarmed', type: 'keyword', }, - 'rsa.misc.cn_bgpv4nxthop': { - category: 'rsa', - name: 'rsa.misc.cn_bgpv4nxthop', + 'fortinet.firewall.contenttype': { + category: 'fortinet', + description: 'Content Type from HTTP header ', + name: 'fortinet.firewall.contenttype', type: 'keyword', }, - 'rsa.misc.cn_ctr_dst_code': { - category: 'rsa', - name: 'rsa.misc.cn_ctr_dst_code', + 'fortinet.firewall.cookies': { + category: 'fortinet', + description: 'VPN Cookie ', + name: 'fortinet.firewall.cookies', type: 'keyword', }, - 'rsa.misc.cn_dst_tos': { - category: 'rsa', - name: 'rsa.misc.cn_dst_tos', - type: 'keyword', + 'fortinet.firewall.count': { + category: 'fortinet', + description: 'Counts of action type ', + name: 'fortinet.firewall.count', + type: 'integer', }, - 'rsa.misc.cn_dst_vlan': { - category: 'rsa', - name: 'rsa.misc.cn_dst_vlan', - type: 'keyword', + 'fortinet.firewall.countapp': { + category: 'fortinet', + description: 'Number of App Ctrl logs associated with the session ', + name: 'fortinet.firewall.countapp', + type: 'integer', }, - 'rsa.misc.cn_engine_id': { - category: 'rsa', - name: 'rsa.misc.cn_engine_id', - type: 'keyword', + 'fortinet.firewall.countav': { + category: 'fortinet', + description: 'Number of AV logs associated with the session ', + name: 'fortinet.firewall.countav', + type: 'integer', }, - 'rsa.misc.cn_engine_type': { - category: 'rsa', - name: 'rsa.misc.cn_engine_type', - type: 'keyword', + 'fortinet.firewall.countcifs': { + category: 'fortinet', + description: 'Number of CIFS logs associated with the session ', + name: 'fortinet.firewall.countcifs', + type: 'integer', }, - 'rsa.misc.cn_f_switch': { - category: 'rsa', - name: 'rsa.misc.cn_f_switch', - type: 'keyword', + 'fortinet.firewall.countdlp': { + category: 'fortinet', + description: 'Number of DLP logs associated with the session ', + name: 'fortinet.firewall.countdlp', + type: 'integer', }, - 'rsa.misc.cn_flowsampid': { - category: 'rsa', - name: 'rsa.misc.cn_flowsampid', - type: 'keyword', + 'fortinet.firewall.countdns': { + category: 'fortinet', + description: 'Number of DNS logs associated with the session ', + name: 'fortinet.firewall.countdns', + type: 'integer', }, - 'rsa.misc.cn_flowsampintv': { - category: 'rsa', - name: 'rsa.misc.cn_flowsampintv', - type: 'keyword', + 'fortinet.firewall.countemail': { + category: 'fortinet', + description: 'Number of email logs associated with the session ', + name: 'fortinet.firewall.countemail', + type: 'integer', }, - 'rsa.misc.cn_flowsampmode': { - category: 'rsa', - name: 'rsa.misc.cn_flowsampmode', - type: 'keyword', + 'fortinet.firewall.countff': { + category: 'fortinet', + description: 'Number of ff logs associated with the session ', + name: 'fortinet.firewall.countff', + type: 'integer', }, - 'rsa.misc.cn_inacttimeout': { - category: 'rsa', - name: 'rsa.misc.cn_inacttimeout', - type: 'keyword', + 'fortinet.firewall.countips': { + category: 'fortinet', + description: 'Number of IPS logs associated with the session ', + name: 'fortinet.firewall.countips', + type: 'integer', }, - 'rsa.misc.cn_inpermbyts': { - category: 'rsa', - name: 'rsa.misc.cn_inpermbyts', - type: 'keyword', + 'fortinet.firewall.countssh': { + category: 'fortinet', + description: 'Number of SSH logs associated with the session ', + name: 'fortinet.firewall.countssh', + type: 'integer', }, - 'rsa.misc.cn_inpermpckts': { - category: 'rsa', - name: 'rsa.misc.cn_inpermpckts', - type: 'keyword', + 'fortinet.firewall.countssl': { + category: 'fortinet', + description: 'Number of SSL logs associated with the session ', + name: 'fortinet.firewall.countssl', + type: 'integer', }, - 'rsa.misc.cn_invalid': { - category: 'rsa', - name: 'rsa.misc.cn_invalid', - type: 'keyword', + 'fortinet.firewall.countwaf': { + category: 'fortinet', + description: 'Number of WAF logs associated with the session ', + name: 'fortinet.firewall.countwaf', + type: 'integer', }, - 'rsa.misc.cn_ip_proto_ver': { - category: 'rsa', - name: 'rsa.misc.cn_ip_proto_ver', - type: 'keyword', + 'fortinet.firewall.countweb': { + category: 'fortinet', + description: 'Number of Web filter logs associated with the session ', + name: 'fortinet.firewall.countweb', + type: 'integer', }, - 'rsa.misc.cn_ipv4_ident': { - category: 'rsa', - name: 'rsa.misc.cn_ipv4_ident', - type: 'keyword', + 'fortinet.firewall.cpu': { + category: 'fortinet', + description: 'CPU Usage ', + name: 'fortinet.firewall.cpu', + type: 'integer', }, - 'rsa.misc.cn_l_switch': { - category: 'rsa', - name: 'rsa.misc.cn_l_switch', - type: 'keyword', + 'fortinet.firewall.craction': { + category: 'fortinet', + description: 'Client Reputation Action ', + name: 'fortinet.firewall.craction', + type: 'integer', }, - 'rsa.misc.cn_log_did': { - category: 'rsa', - name: 'rsa.misc.cn_log_did', - type: 'keyword', + 'fortinet.firewall.criticalcount': { + category: 'fortinet', + description: 'Number of critical ratings ', + name: 'fortinet.firewall.criticalcount', + type: 'integer', }, - 'rsa.misc.cn_log_rid': { - category: 'rsa', - name: 'rsa.misc.cn_log_rid', + 'fortinet.firewall.crl': { + category: 'fortinet', + description: 'Client Reputation Level ', + name: 'fortinet.firewall.crl', type: 'keyword', }, - 'rsa.misc.cn_max_ttl': { - category: 'rsa', - name: 'rsa.misc.cn_max_ttl', + 'fortinet.firewall.crlevel': { + category: 'fortinet', + description: 'Client Reputation Level ', + name: 'fortinet.firewall.crlevel', type: 'keyword', }, - 'rsa.misc.cn_maxpcktlen': { - category: 'rsa', - name: 'rsa.misc.cn_maxpcktlen', - type: 'keyword', + 'fortinet.firewall.crscore': { + category: 'fortinet', + description: 'Some description ', + name: 'fortinet.firewall.crscore', + type: 'integer', }, - 'rsa.misc.cn_min_ttl': { - category: 'rsa', - name: 'rsa.misc.cn_min_ttl', + 'fortinet.firewall.cveid': { + category: 'fortinet', + description: 'CVE ID ', + name: 'fortinet.firewall.cveid', type: 'keyword', }, - 'rsa.misc.cn_minpcktlen': { - category: 'rsa', - name: 'rsa.misc.cn_minpcktlen', + 'fortinet.firewall.daemon': { + category: 'fortinet', + description: 'Daemon name ', + name: 'fortinet.firewall.daemon', type: 'keyword', }, - 'rsa.misc.cn_mpls_lbl_1': { - category: 'rsa', - name: 'rsa.misc.cn_mpls_lbl_1', + 'fortinet.firewall.datarange': { + category: 'fortinet', + description: 'Data range for reports ', + name: 'fortinet.firewall.datarange', type: 'keyword', }, - 'rsa.misc.cn_mpls_lbl_10': { - category: 'rsa', - name: 'rsa.misc.cn_mpls_lbl_10', + 'fortinet.firewall.date': { + category: 'fortinet', + description: 'Date ', + name: 'fortinet.firewall.date', type: 'keyword', }, - 'rsa.misc.cn_mpls_lbl_2': { - category: 'rsa', - name: 'rsa.misc.cn_mpls_lbl_2', - type: 'keyword', + 'fortinet.firewall.ddnsserver': { + category: 'fortinet', + description: 'DDNS server ', + name: 'fortinet.firewall.ddnsserver', + type: 'ip', }, - 'rsa.misc.cn_mpls_lbl_3': { - category: 'rsa', - name: 'rsa.misc.cn_mpls_lbl_3', + 'fortinet.firewall.desc': { + category: 'fortinet', + description: 'Description ', + name: 'fortinet.firewall.desc', type: 'keyword', }, - 'rsa.misc.cn_mpls_lbl_4': { - category: 'rsa', - name: 'rsa.misc.cn_mpls_lbl_4', + 'fortinet.firewall.detectionmethod': { + category: 'fortinet', + description: 'Detection method ', + name: 'fortinet.firewall.detectionmethod', type: 'keyword', }, - 'rsa.misc.cn_mpls_lbl_5': { - category: 'rsa', - name: 'rsa.misc.cn_mpls_lbl_5', + 'fortinet.firewall.devcategory': { + category: 'fortinet', + description: 'Device category ', + name: 'fortinet.firewall.devcategory', type: 'keyword', }, - 'rsa.misc.cn_mpls_lbl_6': { - category: 'rsa', - name: 'rsa.misc.cn_mpls_lbl_6', + 'fortinet.firewall.devintfname': { + category: 'fortinet', + description: 'HA device Interface Name ', + name: 'fortinet.firewall.devintfname', type: 'keyword', }, - 'rsa.misc.cn_mpls_lbl_7': { - category: 'rsa', - name: 'rsa.misc.cn_mpls_lbl_7', + 'fortinet.firewall.devtype': { + category: 'fortinet', + description: 'Device type ', + name: 'fortinet.firewall.devtype', type: 'keyword', }, - 'rsa.misc.cn_mpls_lbl_8': { - category: 'rsa', - name: 'rsa.misc.cn_mpls_lbl_8', + 'fortinet.firewall.dhcp_msg': { + category: 'fortinet', + description: 'DHCP Message ', + name: 'fortinet.firewall.dhcp_msg', type: 'keyword', }, - 'rsa.misc.cn_mpls_lbl_9': { - category: 'rsa', - name: 'rsa.misc.cn_mpls_lbl_9', + 'fortinet.firewall.dintf': { + category: 'fortinet', + description: 'Destination interface ', + name: 'fortinet.firewall.dintf', type: 'keyword', }, - 'rsa.misc.cn_mplstoplabel': { - category: 'rsa', - name: 'rsa.misc.cn_mplstoplabel', + 'fortinet.firewall.disk': { + category: 'fortinet', + description: 'Assosciated disk ', + name: 'fortinet.firewall.disk', type: 'keyword', }, - 'rsa.misc.cn_mplstoplabip': { - category: 'rsa', - name: 'rsa.misc.cn_mplstoplabip', - type: 'keyword', + 'fortinet.firewall.disklograte': { + category: 'fortinet', + description: 'Disk logging rate ', + name: 'fortinet.firewall.disklograte', + type: 'long', }, - 'rsa.misc.cn_mul_dst_byt': { - category: 'rsa', - name: 'rsa.misc.cn_mul_dst_byt', + 'fortinet.firewall.dlpextra': { + category: 'fortinet', + description: 'DLP extra information ', + name: 'fortinet.firewall.dlpextra', type: 'keyword', }, - 'rsa.misc.cn_mul_dst_pks': { - category: 'rsa', - name: 'rsa.misc.cn_mul_dst_pks', + 'fortinet.firewall.docsource': { + category: 'fortinet', + description: 'DLP fingerprint document source ', + name: 'fortinet.firewall.docsource', type: 'keyword', }, - 'rsa.misc.cn_muligmptype': { - category: 'rsa', - name: 'rsa.misc.cn_muligmptype', - type: 'keyword', + 'fortinet.firewall.domainctrlauthstate': { + category: 'fortinet', + description: 'CIFS domain auth state ', + name: 'fortinet.firewall.domainctrlauthstate', + type: 'integer', }, - 'rsa.misc.cn_sampalgo': { - category: 'rsa', - name: 'rsa.misc.cn_sampalgo', - type: 'keyword', + 'fortinet.firewall.domainctrlauthtype': { + category: 'fortinet', + description: 'CIFS domain auth type ', + name: 'fortinet.firewall.domainctrlauthtype', + type: 'integer', }, - 'rsa.misc.cn_sampint': { - category: 'rsa', - name: 'rsa.misc.cn_sampint', + 'fortinet.firewall.domainctrldomain': { + category: 'fortinet', + description: 'CIFS domain auth domain ', + name: 'fortinet.firewall.domainctrldomain', type: 'keyword', }, - 'rsa.misc.cn_seqctr': { - category: 'rsa', - name: 'rsa.misc.cn_seqctr', - type: 'keyword', + 'fortinet.firewall.domainctrlip': { + category: 'fortinet', + description: 'CIFS Domain IP ', + name: 'fortinet.firewall.domainctrlip', + type: 'ip', }, - 'rsa.misc.cn_spackets': { - category: 'rsa', - name: 'rsa.misc.cn_spackets', + 'fortinet.firewall.domainctrlname': { + category: 'fortinet', + description: 'CIFS Domain name ', + name: 'fortinet.firewall.domainctrlname', type: 'keyword', }, - 'rsa.misc.cn_src_tos': { - category: 'rsa', - name: 'rsa.misc.cn_src_tos', + 'fortinet.firewall.domainctrlprotocoltype': { + category: 'fortinet', + description: 'CIFS Domain connection protocol ', + name: 'fortinet.firewall.domainctrlprotocoltype', + type: 'integer', + }, + 'fortinet.firewall.domainctrlusername': { + category: 'fortinet', + description: 'CIFS Domain username ', + name: 'fortinet.firewall.domainctrlusername', type: 'keyword', }, - 'rsa.misc.cn_src_vlan': { - category: 'rsa', - name: 'rsa.misc.cn_src_vlan', - type: 'keyword', + 'fortinet.firewall.domainfilteridx': { + category: 'fortinet', + description: 'Domain filter ID ', + name: 'fortinet.firewall.domainfilteridx', + type: 'integer', }, - 'rsa.misc.cn_sysuptime': { - category: 'rsa', - name: 'rsa.misc.cn_sysuptime', + 'fortinet.firewall.domainfilterlist': { + category: 'fortinet', + description: 'Domain filter name ', + name: 'fortinet.firewall.domainfilterlist', type: 'keyword', }, - 'rsa.misc.cn_template_id': { - category: 'rsa', - name: 'rsa.misc.cn_template_id', + 'fortinet.firewall.ds': { + category: 'fortinet', + description: 'Direction with distribution system ', + name: 'fortinet.firewall.ds', type: 'keyword', }, - 'rsa.misc.cn_totbytsexp': { - category: 'rsa', - name: 'rsa.misc.cn_totbytsexp', + 'fortinet.firewall.dst_int': { + category: 'fortinet', + description: 'Destination interface ', + name: 'fortinet.firewall.dst_int', type: 'keyword', }, - 'rsa.misc.cn_totflowexp': { - category: 'rsa', - name: 'rsa.misc.cn_totflowexp', + 'fortinet.firewall.dstintfrole': { + category: 'fortinet', + description: 'Destination interface role ', + name: 'fortinet.firewall.dstintfrole', type: 'keyword', }, - 'rsa.misc.cn_totpcktsexp': { - category: 'rsa', - name: 'rsa.misc.cn_totpcktsexp', + 'fortinet.firewall.dstcountry': { + category: 'fortinet', + description: 'Destination country ', + name: 'fortinet.firewall.dstcountry', type: 'keyword', }, - 'rsa.misc.cn_unixnanosecs': { - category: 'rsa', - name: 'rsa.misc.cn_unixnanosecs', + 'fortinet.firewall.dstdevcategory': { + category: 'fortinet', + description: 'Destination device category ', + name: 'fortinet.firewall.dstdevcategory', type: 'keyword', }, - 'rsa.misc.cn_v6flowlabel': { - category: 'rsa', - name: 'rsa.misc.cn_v6flowlabel', + 'fortinet.firewall.dstdevtype': { + category: 'fortinet', + description: 'Destination device type ', + name: 'fortinet.firewall.dstdevtype', type: 'keyword', }, - 'rsa.misc.cn_v6optheaders': { - category: 'rsa', - name: 'rsa.misc.cn_v6optheaders', + 'fortinet.firewall.dstfamily': { + category: 'fortinet', + description: 'Destination OS family ', + name: 'fortinet.firewall.dstfamily', type: 'keyword', }, - 'rsa.misc.comp_class': { - category: 'rsa', - name: 'rsa.misc.comp_class', + 'fortinet.firewall.dsthwvendor': { + category: 'fortinet', + description: 'Destination HW vendor ', + name: 'fortinet.firewall.dsthwvendor', type: 'keyword', }, - 'rsa.misc.comp_name': { - category: 'rsa', - name: 'rsa.misc.comp_name', + 'fortinet.firewall.dsthwversion': { + category: 'fortinet', + description: 'Destination HW version ', + name: 'fortinet.firewall.dsthwversion', type: 'keyword', }, - 'rsa.misc.comp_rbytes': { - category: 'rsa', - name: 'rsa.misc.comp_rbytes', + 'fortinet.firewall.dstinetsvc': { + category: 'fortinet', + description: 'Destination interface service ', + name: 'fortinet.firewall.dstinetsvc', type: 'keyword', }, - 'rsa.misc.comp_sbytes': { - category: 'rsa', - name: 'rsa.misc.comp_sbytes', + 'fortinet.firewall.dstosname': { + category: 'fortinet', + description: 'Destination OS name ', + name: 'fortinet.firewall.dstosname', type: 'keyword', }, - 'rsa.misc.cpu_data': { - category: 'rsa', - name: 'rsa.misc.cpu_data', + 'fortinet.firewall.dstosversion': { + category: 'fortinet', + description: 'Destination OS version ', + name: 'fortinet.firewall.dstosversion', type: 'keyword', }, - 'rsa.misc.criticality': { - category: 'rsa', - name: 'rsa.misc.criticality', - type: 'keyword', + 'fortinet.firewall.dstserver': { + category: 'fortinet', + description: 'Destination server ', + name: 'fortinet.firewall.dstserver', + type: 'integer', }, - 'rsa.misc.cs_agency_dst': { - category: 'rsa', - name: 'rsa.misc.cs_agency_dst', + 'fortinet.firewall.dstssid': { + category: 'fortinet', + description: 'Destination SSID ', + name: 'fortinet.firewall.dstssid', type: 'keyword', }, - 'rsa.misc.cs_analyzedby': { - category: 'rsa', - name: 'rsa.misc.cs_analyzedby', + 'fortinet.firewall.dstswversion': { + category: 'fortinet', + description: 'Destination software version ', + name: 'fortinet.firewall.dstswversion', type: 'keyword', }, - 'rsa.misc.cs_av_other': { - category: 'rsa', - name: 'rsa.misc.cs_av_other', + 'fortinet.firewall.dstunauthusersource': { + category: 'fortinet', + description: 'Destination unauthenticated source ', + name: 'fortinet.firewall.dstunauthusersource', type: 'keyword', }, - 'rsa.misc.cs_av_primary': { - category: 'rsa', - name: 'rsa.misc.cs_av_primary', + 'fortinet.firewall.dstuuid': { + category: 'fortinet', + description: 'UUID of the Destination IP address ', + name: 'fortinet.firewall.dstuuid', type: 'keyword', }, - 'rsa.misc.cs_av_secondary': { - category: 'rsa', - name: 'rsa.misc.cs_av_secondary', + 'fortinet.firewall.duid': { + category: 'fortinet', + description: 'DHCP UID ', + name: 'fortinet.firewall.duid', type: 'keyword', }, - 'rsa.misc.cs_bgpv6nxthop': { - category: 'rsa', - name: 'rsa.misc.cs_bgpv6nxthop', - type: 'keyword', + 'fortinet.firewall.eapolcnt': { + category: 'fortinet', + description: 'EAPOL packet count ', + name: 'fortinet.firewall.eapolcnt', + type: 'integer', }, - 'rsa.misc.cs_bit9status': { - category: 'rsa', - name: 'rsa.misc.cs_bit9status', + 'fortinet.firewall.eapoltype': { + category: 'fortinet', + description: 'EAPOL packet type ', + name: 'fortinet.firewall.eapoltype', type: 'keyword', }, - 'rsa.misc.cs_context': { - category: 'rsa', - name: 'rsa.misc.cs_context', - type: 'keyword', + 'fortinet.firewall.encrypt': { + category: 'fortinet', + description: 'Whether the packet is encrypted or not ', + name: 'fortinet.firewall.encrypt', + type: 'integer', }, - 'rsa.misc.cs_control': { - category: 'rsa', - name: 'rsa.misc.cs_control', + 'fortinet.firewall.encryption': { + category: 'fortinet', + description: 'Encryption method ', + name: 'fortinet.firewall.encryption', type: 'keyword', }, - 'rsa.misc.cs_data': { - category: 'rsa', - name: 'rsa.misc.cs_data', - type: 'keyword', + 'fortinet.firewall.epoch': { + category: 'fortinet', + description: 'Epoch used for locating file ', + name: 'fortinet.firewall.epoch', + type: 'integer', }, - 'rsa.misc.cs_datecret': { - category: 'rsa', - name: 'rsa.misc.cs_datecret', + 'fortinet.firewall.espauth': { + category: 'fortinet', + description: 'ESP Authentication ', + name: 'fortinet.firewall.espauth', type: 'keyword', }, - 'rsa.misc.cs_dst_tld': { - category: 'rsa', - name: 'rsa.misc.cs_dst_tld', + 'fortinet.firewall.esptransform': { + category: 'fortinet', + description: 'ESP Transform ', + name: 'fortinet.firewall.esptransform', type: 'keyword', }, - 'rsa.misc.cs_eth_dst_ven': { - category: 'rsa', - name: 'rsa.misc.cs_eth_dst_ven', + 'fortinet.firewall.eventtype': { + category: 'fortinet', + description: 'UTM Event Type ', + name: 'fortinet.firewall.eventtype', type: 'keyword', }, - 'rsa.misc.cs_eth_src_ven': { - category: 'rsa', - name: 'rsa.misc.cs_eth_src_ven', + 'fortinet.firewall.exch': { + category: 'fortinet', + description: 'Mail Exchanges from DNS response answer section ', + name: 'fortinet.firewall.exch', type: 'keyword', }, - 'rsa.misc.cs_event_uuid': { - category: 'rsa', - name: 'rsa.misc.cs_event_uuid', + 'fortinet.firewall.exchange': { + category: 'fortinet', + description: 'Mail Exchanges from DNS response answer section ', + name: 'fortinet.firewall.exchange', type: 'keyword', }, - 'rsa.misc.cs_filetype': { - category: 'rsa', - name: 'rsa.misc.cs_filetype', + 'fortinet.firewall.expectedsignature': { + category: 'fortinet', + description: 'Expected SSL signature ', + name: 'fortinet.firewall.expectedsignature', type: 'keyword', }, - 'rsa.misc.cs_fld': { - category: 'rsa', - name: 'rsa.misc.cs_fld', + 'fortinet.firewall.expiry': { + category: 'fortinet', + description: 'FortiGuard override expiry timestamp ', + name: 'fortinet.firewall.expiry', type: 'keyword', }, - 'rsa.misc.cs_if_desc': { - category: 'rsa', - name: 'rsa.misc.cs_if_desc', - type: 'keyword', + 'fortinet.firewall.fams_pause': { + category: 'fortinet', + description: 'Fortinet Analysis and Management Service Pause ', + name: 'fortinet.firewall.fams_pause', + type: 'integer', }, - 'rsa.misc.cs_if_name': { - category: 'rsa', - name: 'rsa.misc.cs_if_name', - type: 'keyword', + 'fortinet.firewall.fazlograte': { + category: 'fortinet', + description: 'FortiAnalyzer Logging Rate ', + name: 'fortinet.firewall.fazlograte', + type: 'long', }, - 'rsa.misc.cs_ip_next_hop': { - category: 'rsa', - name: 'rsa.misc.cs_ip_next_hop', + 'fortinet.firewall.fctemssn': { + category: 'fortinet', + description: 'FortiClient Endpoint SSN ', + name: 'fortinet.firewall.fctemssn', type: 'keyword', }, - 'rsa.misc.cs_ipv4dstpre': { - category: 'rsa', - name: 'rsa.misc.cs_ipv4dstpre', + 'fortinet.firewall.fctuid': { + category: 'fortinet', + description: 'FortiClient UID ', + name: 'fortinet.firewall.fctuid', type: 'keyword', }, - 'rsa.misc.cs_ipv4srcpre': { - category: 'rsa', - name: 'rsa.misc.cs_ipv4srcpre', + 'fortinet.firewall.field': { + category: 'fortinet', + description: 'NTP status field ', + name: 'fortinet.firewall.field', type: 'keyword', }, - 'rsa.misc.cs_lifetime': { - category: 'rsa', - name: 'rsa.misc.cs_lifetime', + 'fortinet.firewall.filefilter': { + category: 'fortinet', + description: 'The filter used to identify the affected file ', + name: 'fortinet.firewall.filefilter', type: 'keyword', }, - 'rsa.misc.cs_log_medium': { - category: 'rsa', - name: 'rsa.misc.cs_log_medium', + 'fortinet.firewall.filehashsrc': { + category: 'fortinet', + description: 'Filehash source ', + name: 'fortinet.firewall.filehashsrc', type: 'keyword', }, - 'rsa.misc.cs_loginname': { - category: 'rsa', - name: 'rsa.misc.cs_loginname', + 'fortinet.firewall.filtercat': { + category: 'fortinet', + description: 'DLP filter category ', + name: 'fortinet.firewall.filtercat', type: 'keyword', }, - 'rsa.misc.cs_modulescore': { - category: 'rsa', - name: 'rsa.misc.cs_modulescore', - type: 'keyword', + 'fortinet.firewall.filteridx': { + category: 'fortinet', + description: 'DLP filter ID ', + name: 'fortinet.firewall.filteridx', + type: 'integer', }, - 'rsa.misc.cs_modulesign': { - category: 'rsa', - name: 'rsa.misc.cs_modulesign', + 'fortinet.firewall.filtername': { + category: 'fortinet', + description: 'DLP rule name ', + name: 'fortinet.firewall.filtername', type: 'keyword', }, - 'rsa.misc.cs_opswatresult': { - category: 'rsa', - name: 'rsa.misc.cs_opswatresult', + 'fortinet.firewall.filtertype': { + category: 'fortinet', + description: 'DLP filter type ', + name: 'fortinet.firewall.filtertype', type: 'keyword', }, - 'rsa.misc.cs_payload': { - category: 'rsa', - name: 'rsa.misc.cs_payload', + 'fortinet.firewall.fortiguardresp': { + category: 'fortinet', + description: 'Antispam ESP value ', + name: 'fortinet.firewall.fortiguardresp', type: 'keyword', }, - 'rsa.misc.cs_registrant': { - category: 'rsa', - name: 'rsa.misc.cs_registrant', + 'fortinet.firewall.forwardedfor': { + category: 'fortinet', + description: 'Email address forwarded ', + name: 'fortinet.firewall.forwardedfor', type: 'keyword', }, - 'rsa.misc.cs_registrar': { - category: 'rsa', - name: 'rsa.misc.cs_registrar', + 'fortinet.firewall.fqdn': { + category: 'fortinet', + description: 'FQDN ', + name: 'fortinet.firewall.fqdn', type: 'keyword', }, - 'rsa.misc.cs_represult': { - category: 'rsa', - name: 'rsa.misc.cs_represult', + 'fortinet.firewall.frametype': { + category: 'fortinet', + description: 'Wireless frametype ', + name: 'fortinet.firewall.frametype', type: 'keyword', }, - 'rsa.misc.cs_rpayload': { - category: 'rsa', - name: 'rsa.misc.cs_rpayload', - type: 'keyword', + 'fortinet.firewall.freediskstorage': { + category: 'fortinet', + description: 'Free disk integer ', + name: 'fortinet.firewall.freediskstorage', + type: 'integer', }, - 'rsa.misc.cs_sampler_name': { - category: 'rsa', - name: 'rsa.misc.cs_sampler_name', + 'fortinet.firewall.from': { + category: 'fortinet', + description: 'From email address ', + name: 'fortinet.firewall.from', type: 'keyword', }, - 'rsa.misc.cs_sourcemodule': { - category: 'rsa', - name: 'rsa.misc.cs_sourcemodule', - type: 'keyword', + 'fortinet.firewall.from_vcluster': { + category: 'fortinet', + description: 'Source virtual cluster number ', + name: 'fortinet.firewall.from_vcluster', + type: 'integer', }, - 'rsa.misc.cs_streams': { - category: 'rsa', - name: 'rsa.misc.cs_streams', + 'fortinet.firewall.fsaverdict': { + category: 'fortinet', + description: 'FSA verdict ', + name: 'fortinet.firewall.fsaverdict', type: 'keyword', }, - 'rsa.misc.cs_targetmodule': { - category: 'rsa', - name: 'rsa.misc.cs_targetmodule', + 'fortinet.firewall.fwserver_name': { + category: 'fortinet', + description: 'Web proxy server name ', + name: 'fortinet.firewall.fwserver_name', type: 'keyword', }, - 'rsa.misc.cs_v6nxthop': { - category: 'rsa', - name: 'rsa.misc.cs_v6nxthop', - type: 'keyword', + 'fortinet.firewall.gateway': { + category: 'fortinet', + description: 'Gateway ip address for PPPoE status report ', + name: 'fortinet.firewall.gateway', + type: 'ip', }, - 'rsa.misc.cs_whois_server': { - category: 'rsa', - name: 'rsa.misc.cs_whois_server', + 'fortinet.firewall.green': { + category: 'fortinet', + description: 'Memory status ', + name: 'fortinet.firewall.green', type: 'keyword', }, - 'rsa.misc.cs_yararesult': { - category: 'rsa', - name: 'rsa.misc.cs_yararesult', - type: 'keyword', + 'fortinet.firewall.groupid': { + category: 'fortinet', + description: 'User Group ID ', + name: 'fortinet.firewall.groupid', + type: 'integer', }, - 'rsa.misc.description': { - category: 'rsa', - name: 'rsa.misc.description', - type: 'keyword', + 'fortinet.firewall.ha-prio': { + category: 'fortinet', + description: 'HA Priority ', + name: 'fortinet.firewall.ha-prio', + type: 'integer', }, - 'rsa.misc.devvendor': { - category: 'rsa', - name: 'rsa.misc.devvendor', + 'fortinet.firewall.ha_group': { + category: 'fortinet', + description: 'HA Group ', + name: 'fortinet.firewall.ha_group', type: 'keyword', }, - 'rsa.misc.distance': { - category: 'rsa', - name: 'rsa.misc.distance', + 'fortinet.firewall.ha_role': { + category: 'fortinet', + description: 'HA Role ', + name: 'fortinet.firewall.ha_role', type: 'keyword', }, - 'rsa.misc.dstburb': { - category: 'rsa', - name: 'rsa.misc.dstburb', + 'fortinet.firewall.handshake': { + category: 'fortinet', + description: 'SSL Handshake ', + name: 'fortinet.firewall.handshake', type: 'keyword', }, - 'rsa.misc.edomain': { - category: 'rsa', - name: 'rsa.misc.edomain', + 'fortinet.firewall.hash': { + category: 'fortinet', + description: 'Hash value of downloaded file ', + name: 'fortinet.firewall.hash', type: 'keyword', }, - 'rsa.misc.edomaub': { - category: 'rsa', - name: 'rsa.misc.edomaub', + 'fortinet.firewall.hbdn_reason': { + category: 'fortinet', + description: 'Heartbeat down reason ', + name: 'fortinet.firewall.hbdn_reason', type: 'keyword', }, - 'rsa.misc.euid': { - category: 'rsa', - name: 'rsa.misc.euid', - type: 'keyword', + 'fortinet.firewall.highcount': { + category: 'fortinet', + description: 'Highcount fabric summary ', + name: 'fortinet.firewall.highcount', + type: 'integer', }, - 'rsa.misc.facility': { - category: 'rsa', - name: 'rsa.misc.facility', + 'fortinet.firewall.host': { + category: 'fortinet', + description: 'Hostname ', + name: 'fortinet.firewall.host', type: 'keyword', }, - 'rsa.misc.finterface': { - category: 'rsa', - name: 'rsa.misc.finterface', + 'fortinet.firewall.iaid': { + category: 'fortinet', + description: 'DHCPv6 id ', + name: 'fortinet.firewall.iaid', type: 'keyword', }, - 'rsa.misc.flags': { - category: 'rsa', - name: 'rsa.misc.flags', + 'fortinet.firewall.icmpcode': { + category: 'fortinet', + description: 'Destination Port of the ICMP message ', + name: 'fortinet.firewall.icmpcode', type: 'keyword', }, - 'rsa.misc.gaddr': { - category: 'rsa', - name: 'rsa.misc.gaddr', + 'fortinet.firewall.icmpid': { + category: 'fortinet', + description: 'Source port of the ICMP message ', + name: 'fortinet.firewall.icmpid', type: 'keyword', }, - 'rsa.misc.id3': { - category: 'rsa', - name: 'rsa.misc.id3', + 'fortinet.firewall.icmptype': { + category: 'fortinet', + description: 'The type of ICMP message ', + name: 'fortinet.firewall.icmptype', type: 'keyword', }, - 'rsa.misc.im_buddyname': { - category: 'rsa', - name: 'rsa.misc.im_buddyname', + 'fortinet.firewall.identifier': { + category: 'fortinet', + description: 'Network traffic identifier ', + name: 'fortinet.firewall.identifier', + type: 'integer', + }, + 'fortinet.firewall.in_spi': { + category: 'fortinet', + description: 'IPSEC inbound SPI ', + name: 'fortinet.firewall.in_spi', type: 'keyword', }, - 'rsa.misc.im_croomid': { - category: 'rsa', - name: 'rsa.misc.im_croomid', - type: 'keyword', + 'fortinet.firewall.incidentserialno': { + category: 'fortinet', + description: 'Incident serial number ', + name: 'fortinet.firewall.incidentserialno', + type: 'integer', + }, + 'fortinet.firewall.infected': { + category: 'fortinet', + description: 'Infected MMS ', + name: 'fortinet.firewall.infected', + type: 'integer', }, - 'rsa.misc.im_croomtype': { - category: 'rsa', - name: 'rsa.misc.im_croomtype', - type: 'keyword', + 'fortinet.firewall.infectedfilelevel': { + category: 'fortinet', + description: 'DLP infected file level ', + name: 'fortinet.firewall.infectedfilelevel', + type: 'integer', }, - 'rsa.misc.im_members': { - category: 'rsa', - name: 'rsa.misc.im_members', + 'fortinet.firewall.informationsource': { + category: 'fortinet', + description: 'Information source ', + name: 'fortinet.firewall.informationsource', type: 'keyword', }, - 'rsa.misc.im_username': { - category: 'rsa', - name: 'rsa.misc.im_username', + 'fortinet.firewall.init': { + category: 'fortinet', + description: 'IPSEC init stage ', + name: 'fortinet.firewall.init', type: 'keyword', }, - 'rsa.misc.ipkt': { - category: 'rsa', - name: 'rsa.misc.ipkt', + 'fortinet.firewall.initiator': { + category: 'fortinet', + description: 'Original login user name for Fortiguard override ', + name: 'fortinet.firewall.initiator', type: 'keyword', }, - 'rsa.misc.ipscat': { - category: 'rsa', - name: 'rsa.misc.ipscat', + 'fortinet.firewall.interface': { + category: 'fortinet', + description: 'Related interface ', + name: 'fortinet.firewall.interface', type: 'keyword', }, - 'rsa.misc.ipspri': { - category: 'rsa', - name: 'rsa.misc.ipspri', + 'fortinet.firewall.intf': { + category: 'fortinet', + description: 'Related interface ', + name: 'fortinet.firewall.intf', type: 'keyword', }, - 'rsa.misc.latitude': { - category: 'rsa', - name: 'rsa.misc.latitude', + 'fortinet.firewall.invalidmac': { + category: 'fortinet', + description: 'The MAC address with invalid OUI ', + name: 'fortinet.firewall.invalidmac', type: 'keyword', }, - 'rsa.misc.linenum': { - category: 'rsa', - name: 'rsa.misc.linenum', - type: 'keyword', + 'fortinet.firewall.ip': { + category: 'fortinet', + description: 'Related IP ', + name: 'fortinet.firewall.ip', + type: 'ip', }, - 'rsa.misc.list_name': { - category: 'rsa', - name: 'rsa.misc.list_name', + 'fortinet.firewall.iptype': { + category: 'fortinet', + description: 'Related IP type ', + name: 'fortinet.firewall.iptype', type: 'keyword', }, - 'rsa.misc.load_data': { - category: 'rsa', - name: 'rsa.misc.load_data', + 'fortinet.firewall.keyword': { + category: 'fortinet', + description: 'Keyword used for search ', + name: 'fortinet.firewall.keyword', type: 'keyword', }, - 'rsa.misc.location_floor': { - category: 'rsa', - name: 'rsa.misc.location_floor', + 'fortinet.firewall.kind': { + category: 'fortinet', + description: 'VOIP kind ', + name: 'fortinet.firewall.kind', type: 'keyword', }, - 'rsa.misc.location_mark': { - category: 'rsa', - name: 'rsa.misc.location_mark', - type: 'keyword', + 'fortinet.firewall.lanin': { + category: 'fortinet', + description: 'LAN incoming traffic in bytes ', + name: 'fortinet.firewall.lanin', + type: 'long', }, - 'rsa.misc.log_id': { - category: 'rsa', - name: 'rsa.misc.log_id', - type: 'keyword', + 'fortinet.firewall.lanout': { + category: 'fortinet', + description: 'LAN outbound traffic in bytes ', + name: 'fortinet.firewall.lanout', + type: 'long', }, - 'rsa.misc.log_type': { - category: 'rsa', - name: 'rsa.misc.log_type', - type: 'keyword', + 'fortinet.firewall.lease': { + category: 'fortinet', + description: 'DHCP lease ', + name: 'fortinet.firewall.lease', + type: 'integer', }, - 'rsa.misc.logid': { - category: 'rsa', - name: 'rsa.misc.logid', + 'fortinet.firewall.license_limit': { + category: 'fortinet', + description: 'Maximum Number of FortiClients for the License ', + name: 'fortinet.firewall.license_limit', type: 'keyword', }, - 'rsa.misc.logip': { - category: 'rsa', - name: 'rsa.misc.logip', - type: 'keyword', + 'fortinet.firewall.limit': { + category: 'fortinet', + description: 'Virtual Domain Resource Limit ', + name: 'fortinet.firewall.limit', + type: 'integer', }, - 'rsa.misc.logname': { - category: 'rsa', - name: 'rsa.misc.logname', + 'fortinet.firewall.line': { + category: 'fortinet', + description: 'VOIP line ', + name: 'fortinet.firewall.line', type: 'keyword', }, - 'rsa.misc.longitude': { - category: 'rsa', - name: 'rsa.misc.longitude', - type: 'keyword', + 'fortinet.firewall.live': { + category: 'fortinet', + description: 'Time in seconds ', + name: 'fortinet.firewall.live', + type: 'integer', }, - 'rsa.misc.lport': { - category: 'rsa', - name: 'rsa.misc.lport', - type: 'keyword', + 'fortinet.firewall.local': { + category: 'fortinet', + description: 'Local IP for a PPPD Connection ', + name: 'fortinet.firewall.local', + type: 'ip', }, - 'rsa.misc.mbug_data': { - category: 'rsa', - name: 'rsa.misc.mbug_data', + 'fortinet.firewall.log': { + category: 'fortinet', + description: 'Log message ', + name: 'fortinet.firewall.log', type: 'keyword', }, - 'rsa.misc.misc_name': { - category: 'rsa', - name: 'rsa.misc.misc_name', + 'fortinet.firewall.login': { + category: 'fortinet', + description: 'SSH login ', + name: 'fortinet.firewall.login', type: 'keyword', }, - 'rsa.misc.msg_type': { - category: 'rsa', - name: 'rsa.misc.msg_type', - type: 'keyword', + 'fortinet.firewall.lowcount': { + category: 'fortinet', + description: 'Fabric lowcount ', + name: 'fortinet.firewall.lowcount', + type: 'integer', }, - 'rsa.misc.msgid': { - category: 'rsa', - name: 'rsa.misc.msgid', + 'fortinet.firewall.mac': { + category: 'fortinet', + description: 'DHCP mac address ', + name: 'fortinet.firewall.mac', type: 'keyword', }, - 'rsa.misc.netsessid': { - category: 'rsa', - name: 'rsa.misc.netsessid', - type: 'keyword', + 'fortinet.firewall.malform_data': { + category: 'fortinet', + description: 'VOIP malformed data ', + name: 'fortinet.firewall.malform_data', + type: 'integer', }, - 'rsa.misc.num': { - category: 'rsa', - name: 'rsa.misc.num', + 'fortinet.firewall.malform_desc': { + category: 'fortinet', + description: 'VOIP malformed data description ', + name: 'fortinet.firewall.malform_desc', type: 'keyword', }, - 'rsa.misc.number1': { - category: 'rsa', - name: 'rsa.misc.number1', + 'fortinet.firewall.manuf': { + category: 'fortinet', + description: 'Manufacturer name ', + name: 'fortinet.firewall.manuf', type: 'keyword', }, - 'rsa.misc.number2': { - category: 'rsa', - name: 'rsa.misc.number2', + 'fortinet.firewall.masterdstmac': { + category: 'fortinet', + description: 'Master mac address for a host with multiple network interfaces ', + name: 'fortinet.firewall.masterdstmac', type: 'keyword', }, - 'rsa.misc.nwwn': { - category: 'rsa', - name: 'rsa.misc.nwwn', + 'fortinet.firewall.mastersrcmac': { + category: 'fortinet', + description: 'The master MAC address for a host that has multiple network interfaces ', + name: 'fortinet.firewall.mastersrcmac', type: 'keyword', }, - 'rsa.misc.object': { - category: 'rsa', - name: 'rsa.misc.object', - type: 'keyword', + 'fortinet.firewall.mediumcount': { + category: 'fortinet', + description: 'Fabric medium count ', + name: 'fortinet.firewall.mediumcount', + type: 'integer', }, - 'rsa.misc.operation': { - category: 'rsa', - name: 'rsa.misc.operation', - type: 'keyword', + 'fortinet.firewall.mem': { + category: 'fortinet', + description: 'Memory usage system statistics ', + name: 'fortinet.firewall.mem', + type: 'integer', }, - 'rsa.misc.opkt': { - category: 'rsa', - name: 'rsa.misc.opkt', + 'fortinet.firewall.meshmode': { + category: 'fortinet', + description: 'Wireless mesh mode ', + name: 'fortinet.firewall.meshmode', type: 'keyword', }, - 'rsa.misc.orig_from': { - category: 'rsa', - name: 'rsa.misc.orig_from', + 'fortinet.firewall.message_type': { + category: 'fortinet', + description: 'VOIP message type ', + name: 'fortinet.firewall.message_type', type: 'keyword', }, - 'rsa.misc.owner_id': { - category: 'rsa', - name: 'rsa.misc.owner_id', + 'fortinet.firewall.method': { + category: 'fortinet', + description: 'HTTP method ', + name: 'fortinet.firewall.method', type: 'keyword', }, - 'rsa.misc.p_action': { - category: 'rsa', - name: 'rsa.misc.p_action', - type: 'keyword', + 'fortinet.firewall.mgmtcnt': { + category: 'fortinet', + description: 'The number of unauthorized client flooding managemet frames ', + name: 'fortinet.firewall.mgmtcnt', + type: 'integer', }, - 'rsa.misc.p_filter': { - category: 'rsa', - name: 'rsa.misc.p_filter', + 'fortinet.firewall.mode': { + category: 'fortinet', + description: 'IPSEC mode ', + name: 'fortinet.firewall.mode', type: 'keyword', }, - 'rsa.misc.p_group_object': { - category: 'rsa', - name: 'rsa.misc.p_group_object', + 'fortinet.firewall.module': { + category: 'fortinet', + description: 'PCI-DSS module ', + name: 'fortinet.firewall.module', type: 'keyword', }, - 'rsa.misc.p_id': { - category: 'rsa', - name: 'rsa.misc.p_id', + 'fortinet.firewall.monitor-name': { + category: 'fortinet', + description: 'Health Monitor Name ', + name: 'fortinet.firewall.monitor-name', type: 'keyword', }, - 'rsa.misc.p_msgid1': { - category: 'rsa', - name: 'rsa.misc.p_msgid1', + 'fortinet.firewall.monitor-type': { + category: 'fortinet', + description: 'Health Monitor Type ', + name: 'fortinet.firewall.monitor-type', type: 'keyword', }, - 'rsa.misc.p_msgid2': { - category: 'rsa', - name: 'rsa.misc.p_msgid2', + 'fortinet.firewall.mpsk': { + category: 'fortinet', + description: 'Wireless MPSK ', + name: 'fortinet.firewall.mpsk', type: 'keyword', }, - 'rsa.misc.p_result1': { - category: 'rsa', - name: 'rsa.misc.p_result1', + 'fortinet.firewall.msgproto': { + category: 'fortinet', + description: 'Message Protocol Number ', + name: 'fortinet.firewall.msgproto', type: 'keyword', }, - 'rsa.misc.password_chg': { - category: 'rsa', - name: 'rsa.misc.password_chg', - type: 'keyword', + 'fortinet.firewall.mtu': { + category: 'fortinet', + description: 'Max Transmission Unit Value ', + name: 'fortinet.firewall.mtu', + type: 'integer', }, - 'rsa.misc.password_expire': { - category: 'rsa', - name: 'rsa.misc.password_expire', + 'fortinet.firewall.name': { + category: 'fortinet', + description: 'Name ', + name: 'fortinet.firewall.name', type: 'keyword', }, - 'rsa.misc.permgranted': { - category: 'rsa', - name: 'rsa.misc.permgranted', + 'fortinet.firewall.nat': { + category: 'fortinet', + description: 'NAT IP Address ', + name: 'fortinet.firewall.nat', type: 'keyword', }, - 'rsa.misc.permwanted': { - category: 'rsa', - name: 'rsa.misc.permwanted', + 'fortinet.firewall.netid': { + category: 'fortinet', + description: 'Connector NetID ', + name: 'fortinet.firewall.netid', type: 'keyword', }, - 'rsa.misc.pgid': { - category: 'rsa', - name: 'rsa.misc.pgid', + 'fortinet.firewall.new_status': { + category: 'fortinet', + description: 'New status on user change ', + name: 'fortinet.firewall.new_status', type: 'keyword', }, - 'rsa.misc.policyUUID': { - category: 'rsa', - name: 'rsa.misc.policyUUID', + 'fortinet.firewall.new_value': { + category: 'fortinet', + description: 'New Virtual Domain Name ', + name: 'fortinet.firewall.new_value', type: 'keyword', }, - 'rsa.misc.prog_asp_num': { - category: 'rsa', - name: 'rsa.misc.prog_asp_num', - type: 'keyword', + 'fortinet.firewall.newchannel': { + category: 'fortinet', + description: 'New Channel Number ', + name: 'fortinet.firewall.newchannel', + type: 'integer', }, - 'rsa.misc.program': { - category: 'rsa', - name: 'rsa.misc.program', - type: 'keyword', + 'fortinet.firewall.newchassisid': { + category: 'fortinet', + description: 'New Chassis ID ', + name: 'fortinet.firewall.newchassisid', + type: 'integer', }, - 'rsa.misc.real_data': { - category: 'rsa', - name: 'rsa.misc.real_data', - type: 'keyword', + 'fortinet.firewall.newslot': { + category: 'fortinet', + description: 'New Slot Number ', + name: 'fortinet.firewall.newslot', + type: 'integer', }, - 'rsa.misc.rec_asp_device': { - category: 'rsa', - name: 'rsa.misc.rec_asp_device', - type: 'keyword', + 'fortinet.firewall.nextstat': { + category: 'fortinet', + description: 'Time interval in seconds for the next statistics. ', + name: 'fortinet.firewall.nextstat', + type: 'integer', }, - 'rsa.misc.rec_asp_num': { - category: 'rsa', - name: 'rsa.misc.rec_asp_num', + 'fortinet.firewall.nf_type': { + category: 'fortinet', + description: 'Notification Type ', + name: 'fortinet.firewall.nf_type', type: 'keyword', }, - 'rsa.misc.rec_library': { - category: 'rsa', - name: 'rsa.misc.rec_library', - type: 'keyword', + 'fortinet.firewall.noise': { + category: 'fortinet', + description: 'Wifi Noise ', + name: 'fortinet.firewall.noise', + type: 'integer', }, - 'rsa.misc.recordnum': { - category: 'rsa', - name: 'rsa.misc.recordnum', + 'fortinet.firewall.old_status': { + category: 'fortinet', + description: 'Original Status ', + name: 'fortinet.firewall.old_status', type: 'keyword', }, - 'rsa.misc.ruid': { - category: 'rsa', - name: 'rsa.misc.ruid', + 'fortinet.firewall.old_value': { + category: 'fortinet', + description: 'Original Virtual Domain name ', + name: 'fortinet.firewall.old_value', type: 'keyword', }, - 'rsa.misc.sburb': { - category: 'rsa', - name: 'rsa.misc.sburb', - type: 'keyword', + 'fortinet.firewall.oldchannel': { + category: 'fortinet', + description: 'Original channel ', + name: 'fortinet.firewall.oldchannel', + type: 'integer', }, - 'rsa.misc.sdomain_fld': { - category: 'rsa', - name: 'rsa.misc.sdomain_fld', - type: 'keyword', + 'fortinet.firewall.oldchassisid': { + category: 'fortinet', + description: 'Original Chassis Number ', + name: 'fortinet.firewall.oldchassisid', + type: 'integer', }, - 'rsa.misc.sec': { - category: 'rsa', - name: 'rsa.misc.sec', - type: 'keyword', + 'fortinet.firewall.oldslot': { + category: 'fortinet', + description: 'Original Slot Number ', + name: 'fortinet.firewall.oldslot', + type: 'integer', }, - 'rsa.misc.sensorname': { - category: 'rsa', - name: 'rsa.misc.sensorname', + 'fortinet.firewall.oldsn': { + category: 'fortinet', + description: 'Old Serial number ', + name: 'fortinet.firewall.oldsn', type: 'keyword', }, - 'rsa.misc.seqnum': { - category: 'rsa', - name: 'rsa.misc.seqnum', + 'fortinet.firewall.oldwprof': { + category: 'fortinet', + description: 'Old Web Filter Profile ', + name: 'fortinet.firewall.oldwprof', type: 'keyword', }, - 'rsa.misc.session': { - category: 'rsa', - name: 'rsa.misc.session', + 'fortinet.firewall.onwire': { + category: 'fortinet', + description: 'A flag to indicate if the AP is onwire or not ', + name: 'fortinet.firewall.onwire', type: 'keyword', }, - 'rsa.misc.sessiontype': { - category: 'rsa', - name: 'rsa.misc.sessiontype', + 'fortinet.firewall.opercountry': { + category: 'fortinet', + description: 'Operating Country ', + name: 'fortinet.firewall.opercountry', type: 'keyword', }, - 'rsa.misc.sigUUID': { - category: 'rsa', - name: 'rsa.misc.sigUUID', - type: 'keyword', + 'fortinet.firewall.opertxpower': { + category: 'fortinet', + description: 'Operating TX power ', + name: 'fortinet.firewall.opertxpower', + type: 'integer', }, - 'rsa.misc.spi': { - category: 'rsa', - name: 'rsa.misc.spi', + 'fortinet.firewall.osname': { + category: 'fortinet', + description: 'Operating System name ', + name: 'fortinet.firewall.osname', type: 'keyword', }, - 'rsa.misc.srcburb': { - category: 'rsa', - name: 'rsa.misc.srcburb', + 'fortinet.firewall.osversion': { + category: 'fortinet', + description: 'Operating System version ', + name: 'fortinet.firewall.osversion', type: 'keyword', }, - 'rsa.misc.srcdom': { - category: 'rsa', - name: 'rsa.misc.srcdom', + 'fortinet.firewall.out_spi': { + category: 'fortinet', + description: 'Out SPI ', + name: 'fortinet.firewall.out_spi', type: 'keyword', }, - 'rsa.misc.srcservice': { - category: 'rsa', - name: 'rsa.misc.srcservice', + 'fortinet.firewall.outintf': { + category: 'fortinet', + description: 'Out interface ', + name: 'fortinet.firewall.outintf', type: 'keyword', }, - 'rsa.misc.state': { - category: 'rsa', - name: 'rsa.misc.state', - type: 'keyword', + 'fortinet.firewall.passedcount': { + category: 'fortinet', + description: 'Fabric passed count ', + name: 'fortinet.firewall.passedcount', + type: 'integer', }, - 'rsa.misc.status1': { - category: 'rsa', - name: 'rsa.misc.status1', + 'fortinet.firewall.passwd': { + category: 'fortinet', + description: 'Changed user password information ', + name: 'fortinet.firewall.passwd', type: 'keyword', }, - 'rsa.misc.svcno': { - category: 'rsa', - name: 'rsa.misc.svcno', + 'fortinet.firewall.path': { + category: 'fortinet', + description: 'Path of looped configuration for security fabric ', + name: 'fortinet.firewall.path', type: 'keyword', }, - 'rsa.misc.system': { - category: 'rsa', - name: 'rsa.misc.system', + 'fortinet.firewall.peer': { + category: 'fortinet', + description: 'WAN optimization peer ', + name: 'fortinet.firewall.peer', type: 'keyword', }, - 'rsa.misc.tbdstr1': { - category: 'rsa', - name: 'rsa.misc.tbdstr1', + 'fortinet.firewall.peer_notif': { + category: 'fortinet', + description: 'VPN peer notification ', + name: 'fortinet.firewall.peer_notif', type: 'keyword', }, - 'rsa.misc.tgtdom': { - category: 'rsa', - name: 'rsa.misc.tgtdom', + 'fortinet.firewall.phase2_name': { + category: 'fortinet', + description: 'VPN phase2 name ', + name: 'fortinet.firewall.phase2_name', type: 'keyword', }, - 'rsa.misc.tgtdomain': { - category: 'rsa', - name: 'rsa.misc.tgtdomain', + 'fortinet.firewall.phone': { + category: 'fortinet', + description: 'VOIP Phone ', + name: 'fortinet.firewall.phone', type: 'keyword', }, - 'rsa.misc.threshold': { - category: 'rsa', - name: 'rsa.misc.threshold', - type: 'keyword', + 'fortinet.firewall.pid': { + category: 'fortinet', + description: 'Process ID ', + name: 'fortinet.firewall.pid', + type: 'integer', }, - 'rsa.misc.type1': { - category: 'rsa', - name: 'rsa.misc.type1', + 'fortinet.firewall.policytype': { + category: 'fortinet', + description: 'Policy Type ', + name: 'fortinet.firewall.policytype', type: 'keyword', }, - 'rsa.misc.udb_class': { - category: 'rsa', - name: 'rsa.misc.udb_class', + 'fortinet.firewall.poolname': { + category: 'fortinet', + description: 'IP Pool name ', + name: 'fortinet.firewall.poolname', type: 'keyword', }, - 'rsa.misc.url_fld': { - category: 'rsa', - name: 'rsa.misc.url_fld', - type: 'keyword', + 'fortinet.firewall.port': { + category: 'fortinet', + description: 'Log upload error port ', + name: 'fortinet.firewall.port', + type: 'integer', }, - 'rsa.misc.user_div': { - category: 'rsa', - name: 'rsa.misc.user_div', + 'fortinet.firewall.portbegin': { + category: 'fortinet', + description: 'IP Pool port number to begin ', + name: 'fortinet.firewall.portbegin', + type: 'integer', + }, + 'fortinet.firewall.portend': { + category: 'fortinet', + description: 'IP Pool port number to end ', + name: 'fortinet.firewall.portend', + type: 'integer', + }, + 'fortinet.firewall.probeproto': { + category: 'fortinet', + description: 'Link Monitor Probe Protocol ', + name: 'fortinet.firewall.probeproto', type: 'keyword', }, - 'rsa.misc.userid': { - category: 'rsa', - name: 'rsa.misc.userid', + 'fortinet.firewall.process': { + category: 'fortinet', + description: 'URL Filter process ', + name: 'fortinet.firewall.process', type: 'keyword', }, - 'rsa.misc.username_fld': { - category: 'rsa', - name: 'rsa.misc.username_fld', + 'fortinet.firewall.processtime': { + category: 'fortinet', + description: 'Process time for reports ', + name: 'fortinet.firewall.processtime', + type: 'integer', + }, + 'fortinet.firewall.profile': { + category: 'fortinet', + description: 'Profile Name ', + name: 'fortinet.firewall.profile', type: 'keyword', }, - 'rsa.misc.utcstamp': { - category: 'rsa', - name: 'rsa.misc.utcstamp', + 'fortinet.firewall.profile_vd': { + category: 'fortinet', + description: 'Virtual Domain Name ', + name: 'fortinet.firewall.profile_vd', type: 'keyword', }, - 'rsa.misc.v_instafname': { - category: 'rsa', - name: 'rsa.misc.v_instafname', + 'fortinet.firewall.profilegroup': { + category: 'fortinet', + description: 'Profile Group Name ', + name: 'fortinet.firewall.profilegroup', type: 'keyword', }, - 'rsa.misc.virt_data': { - category: 'rsa', - name: 'rsa.misc.virt_data', + 'fortinet.firewall.profiletype': { + category: 'fortinet', + description: 'Profile Type ', + name: 'fortinet.firewall.profiletype', type: 'keyword', }, - 'rsa.misc.vpnid': { - category: 'rsa', - name: 'rsa.misc.vpnid', + 'fortinet.firewall.qtypeval': { + category: 'fortinet', + description: 'DNS question type value ', + name: 'fortinet.firewall.qtypeval', + type: 'integer', + }, + 'fortinet.firewall.quarskip': { + category: 'fortinet', + description: 'Quarantine skip explanation ', + name: 'fortinet.firewall.quarskip', type: 'keyword', }, - 'rsa.misc.autorun_type': { - category: 'rsa', - description: 'This is used to capture Auto Run type', - name: 'rsa.misc.autorun_type', + 'fortinet.firewall.quotaexceeded': { + category: 'fortinet', + description: 'If quota has been exceeded ', + name: 'fortinet.firewall.quotaexceeded', type: 'keyword', }, - 'rsa.misc.cc_number': { - category: 'rsa', - description: 'Valid Credit Card Numbers only', - name: 'rsa.misc.cc_number', + 'fortinet.firewall.quotamax': { + category: 'fortinet', + description: 'Maximum quota allowed - in seconds if time-based - in bytes if traffic-based ', + name: 'fortinet.firewall.quotamax', type: 'long', }, - 'rsa.misc.content': { - category: 'rsa', - description: 'This key captures the content type from protocol headers', - name: 'rsa.misc.content', + 'fortinet.firewall.quotatype': { + category: 'fortinet', + description: 'Quota type ', + name: 'fortinet.firewall.quotatype', type: 'keyword', }, - 'rsa.misc.ein_number': { - category: 'rsa', - description: 'Employee Identification Numbers only', - name: 'rsa.misc.ein_number', + 'fortinet.firewall.quotaused': { + category: 'fortinet', + description: 'Quota used - in seconds if time-based - in bytes if trafficbased) ', + name: 'fortinet.firewall.quotaused', type: 'long', }, - 'rsa.misc.found': { - category: 'rsa', - description: 'This is used to capture the results of regex match', - name: 'rsa.misc.found', + 'fortinet.firewall.radioband': { + category: 'fortinet', + description: 'Radio band ', + name: 'fortinet.firewall.radioband', type: 'keyword', }, - 'rsa.misc.language': { - category: 'rsa', - description: 'This is used to capture list of languages the client support and what it prefers', - name: 'rsa.misc.language', + 'fortinet.firewall.radioid': { + category: 'fortinet', + description: 'Radio ID ', + name: 'fortinet.firewall.radioid', + type: 'integer', + }, + 'fortinet.firewall.radioidclosest': { + category: 'fortinet', + description: 'Radio ID on the AP closest the rogue AP ', + name: 'fortinet.firewall.radioidclosest', + type: 'integer', + }, + 'fortinet.firewall.radioiddetected': { + category: 'fortinet', + description: 'Radio ID on the AP which detected the rogue AP ', + name: 'fortinet.firewall.radioiddetected', + type: 'integer', + }, + 'fortinet.firewall.rate': { + category: 'fortinet', + description: 'Wireless rogue rate value ', + name: 'fortinet.firewall.rate', type: 'keyword', }, - 'rsa.misc.lifetime': { - category: 'rsa', - description: 'This key is used to capture the session lifetime in seconds.', - name: 'rsa.misc.lifetime', - type: 'long', + 'fortinet.firewall.rawdata': { + category: 'fortinet', + description: 'Raw data value ', + name: 'fortinet.firewall.rawdata', + type: 'keyword', }, - 'rsa.misc.link': { - category: 'rsa', - description: - 'This key is used to link the sessions together. This key should never be used to parse Meta data from a session (Logs/Packets) Directly, this is a Reserved key in NetWitness', - name: 'rsa.misc.link', + 'fortinet.firewall.rawdataid': { + category: 'fortinet', + description: 'Raw data ID ', + name: 'fortinet.firewall.rawdataid', type: 'keyword', }, - 'rsa.misc.match': { - category: 'rsa', - description: 'This key is for regex match name from search.ini', - name: 'rsa.misc.match', + 'fortinet.firewall.rcvddelta': { + category: 'fortinet', + description: 'Received bytes delta ', + name: 'fortinet.firewall.rcvddelta', type: 'keyword', }, - 'rsa.misc.param_dst': { - category: 'rsa', - description: 'This key captures the command line/launch argument of the target process or file', - name: 'rsa.misc.param_dst', + 'fortinet.firewall.reason': { + category: 'fortinet', + description: 'Alert reason ', + name: 'fortinet.firewall.reason', type: 'keyword', }, - 'rsa.misc.param_src': { - category: 'rsa', - description: 'This key captures source parameter', - name: 'rsa.misc.param_src', + 'fortinet.firewall.received': { + category: 'fortinet', + description: 'Server key exchange received ', + name: 'fortinet.firewall.received', + type: 'integer', + }, + 'fortinet.firewall.receivedsignature': { + category: 'fortinet', + description: 'Server key exchange received signature ', + name: 'fortinet.firewall.receivedsignature', type: 'keyword', }, - 'rsa.misc.search_text': { - category: 'rsa', - description: 'This key captures the Search Text used', - name: 'rsa.misc.search_text', + 'fortinet.firewall.red': { + category: 'fortinet', + description: 'Memory information in red ', + name: 'fortinet.firewall.red', type: 'keyword', }, - 'rsa.misc.sig_name': { - category: 'rsa', - description: 'This key is used to capture the Signature Name only.', - name: 'rsa.misc.sig_name', + 'fortinet.firewall.referralurl': { + category: 'fortinet', + description: 'Web filter referralurl ', + name: 'fortinet.firewall.referralurl', type: 'keyword', }, - 'rsa.misc.snmp_value': { - category: 'rsa', - description: 'SNMP set request value', - name: 'rsa.misc.snmp_value', + 'fortinet.firewall.remote': { + category: 'fortinet', + description: 'Remote PPP IP address ', + name: 'fortinet.firewall.remote', + type: 'ip', + }, + 'fortinet.firewall.remotewtptime': { + category: 'fortinet', + description: 'Remote Wifi Radius authentication time ', + name: 'fortinet.firewall.remotewtptime', type: 'keyword', }, - 'rsa.misc.streams': { - category: 'rsa', - description: 'This key captures number of streams in session', - name: 'rsa.misc.streams', - type: 'long', + 'fortinet.firewall.reporttype': { + category: 'fortinet', + description: 'Report type ', + name: 'fortinet.firewall.reporttype', + type: 'keyword', }, - 'rsa.db.index': { - category: 'rsa', - description: 'This key captures IndexID of the index.', - name: 'rsa.db.index', + 'fortinet.firewall.reqtype': { + category: 'fortinet', + description: 'Request type ', + name: 'fortinet.firewall.reqtype', type: 'keyword', }, - 'rsa.db.instance': { - category: 'rsa', - description: 'This key is used to capture the database server instance name', - name: 'rsa.db.instance', + 'fortinet.firewall.request_name': { + category: 'fortinet', + description: 'VOIP request name ', + name: 'fortinet.firewall.request_name', type: 'keyword', }, - 'rsa.db.database': { - category: 'rsa', - description: - 'This key is used to capture the name of a database or an instance as seen in a session', - name: 'rsa.db.database', + 'fortinet.firewall.result': { + category: 'fortinet', + description: 'VPN phase result ', + name: 'fortinet.firewall.result', type: 'keyword', }, - 'rsa.db.transact_id': { - category: 'rsa', - description: 'This key captures the SQL transantion ID of the current session', - name: 'rsa.db.transact_id', + 'fortinet.firewall.role': { + category: 'fortinet', + description: 'VPN Phase 2 role ', + name: 'fortinet.firewall.role', type: 'keyword', }, - 'rsa.db.permissions': { - category: 'rsa', - description: 'This key captures permission or privilege level assigned to a resource.', - name: 'rsa.db.permissions', + 'fortinet.firewall.rssi': { + category: 'fortinet', + description: 'Received signal strength indicator ', + name: 'fortinet.firewall.rssi', + type: 'integer', + }, + 'fortinet.firewall.rsso_key': { + category: 'fortinet', + description: 'RADIUS SSO attribute value ', + name: 'fortinet.firewall.rsso_key', type: 'keyword', }, - 'rsa.db.table_name': { - category: 'rsa', - description: 'This key is used to capture the table name', - name: 'rsa.db.table_name', + 'fortinet.firewall.ruledata': { + category: 'fortinet', + description: 'Rule data ', + name: 'fortinet.firewall.ruledata', type: 'keyword', }, - 'rsa.db.db_id': { - category: 'rsa', - description: 'This key is used to capture the unique identifier for a database', - name: 'rsa.db.db_id', + 'fortinet.firewall.ruletype': { + category: 'fortinet', + description: 'Rule type ', + name: 'fortinet.firewall.ruletype', type: 'keyword', }, - 'rsa.db.db_pid': { - category: 'rsa', - description: 'This key captures the process id of a connection with database server', - name: 'rsa.db.db_pid', - type: 'long', + 'fortinet.firewall.scanned': { + category: 'fortinet', + description: 'Number of Scanned MMSs ', + name: 'fortinet.firewall.scanned', + type: 'integer', }, - 'rsa.db.lread': { - category: 'rsa', - description: 'This key is used for the number of logical reads', - name: 'rsa.db.lread', + 'fortinet.firewall.scantime': { + category: 'fortinet', + description: 'Scanned time ', + name: 'fortinet.firewall.scantime', type: 'long', }, - 'rsa.db.lwrite': { - category: 'rsa', - description: 'This key is used for the number of logical writes', - name: 'rsa.db.lwrite', - type: 'long', + 'fortinet.firewall.scope': { + category: 'fortinet', + description: 'FortiGuard Override Scope ', + name: 'fortinet.firewall.scope', + type: 'keyword', }, - 'rsa.db.pread': { - category: 'rsa', - description: 'This key is used for the number of physical writes', - name: 'rsa.db.pread', - type: 'long', + 'fortinet.firewall.security': { + category: 'fortinet', + description: 'Wireless rogue security ', + name: 'fortinet.firewall.security', + type: 'keyword', }, - 'rsa.network.alias_host': { - category: 'rsa', - description: - 'This key should be used when the source or destination context of a hostname is not clear.Also it captures the Device Hostname. Any Hostname that isnt ad.computer.', - name: 'rsa.network.alias_host', + 'fortinet.firewall.sensitivity': { + category: 'fortinet', + description: 'Sensitivity for document fingerprint ', + name: 'fortinet.firewall.sensitivity', type: 'keyword', }, - 'rsa.network.domain': { - category: 'rsa', - name: 'rsa.network.domain', + 'fortinet.firewall.sensor': { + category: 'fortinet', + description: 'NAC Sensor Name ', + name: 'fortinet.firewall.sensor', type: 'keyword', }, - 'rsa.network.host_dst': { - category: 'rsa', - description: 'This key should only be used when it’s a Destination Hostname', - name: 'rsa.network.host_dst', + 'fortinet.firewall.sentdelta': { + category: 'fortinet', + description: 'Sent bytes delta ', + name: 'fortinet.firewall.sentdelta', type: 'keyword', }, - 'rsa.network.network_service': { - category: 'rsa', - description: 'This is used to capture layer 7 protocols/service names', - name: 'rsa.network.network_service', + 'fortinet.firewall.seq': { + category: 'fortinet', + description: 'Sequence number ', + name: 'fortinet.firewall.seq', type: 'keyword', }, - 'rsa.network.interface': { - category: 'rsa', - description: - 'This key should be used when the source or destination context of an interface is not clear', - name: 'rsa.network.interface', + 'fortinet.firewall.serial': { + category: 'fortinet', + description: 'WAN optimisation serial ', + name: 'fortinet.firewall.serial', type: 'keyword', }, - 'rsa.network.network_port': { - category: 'rsa', - description: - 'Deprecated, use port. NOTE: There is a type discrepancy as currently used, TM: Int32, INDEX: UInt64 (why neither chose the correct UInt16?!)', - name: 'rsa.network.network_port', - type: 'long', + 'fortinet.firewall.serialno': { + category: 'fortinet', + description: 'Serial number ', + name: 'fortinet.firewall.serialno', + type: 'keyword', }, - 'rsa.network.eth_host': { - category: 'rsa', - description: 'Deprecated, use alias.mac', - name: 'rsa.network.eth_host', + 'fortinet.firewall.server': { + category: 'fortinet', + description: 'AD server FQDN or IP ', + name: 'fortinet.firewall.server', type: 'keyword', }, - 'rsa.network.sinterface': { - category: 'rsa', - description: 'This key should only be used when it’s a Source Interface', - name: 'rsa.network.sinterface', + 'fortinet.firewall.session_id': { + category: 'fortinet', + description: 'Session ID ', + name: 'fortinet.firewall.session_id', type: 'keyword', }, - 'rsa.network.dinterface': { - category: 'rsa', - description: 'This key should only be used when it’s a Destination Interface', - name: 'rsa.network.dinterface', + 'fortinet.firewall.sessionid': { + category: 'fortinet', + description: 'WAD Session ID ', + name: 'fortinet.firewall.sessionid', + type: 'integer', + }, + 'fortinet.firewall.setuprate': { + category: 'fortinet', + description: 'Session Setup Rate ', + name: 'fortinet.firewall.setuprate', + type: 'long', + }, + 'fortinet.firewall.severity': { + category: 'fortinet', + description: 'Severity ', + name: 'fortinet.firewall.severity', type: 'keyword', }, - 'rsa.network.vlan': { - category: 'rsa', - description: 'This key should only be used to capture the ID of the Virtual LAN', - name: 'rsa.network.vlan', - type: 'long', + 'fortinet.firewall.shaperdroprcvdbyte': { + category: 'fortinet', + description: 'Received bytes dropped by shaper ', + name: 'fortinet.firewall.shaperdroprcvdbyte', + type: 'integer', + }, + 'fortinet.firewall.shaperdropsentbyte': { + category: 'fortinet', + description: 'Sent bytes dropped by shaper ', + name: 'fortinet.firewall.shaperdropsentbyte', + type: 'integer', }, - 'rsa.network.zone_src': { - category: 'rsa', - description: 'This key should only be used when it’s a Source Zone.', - name: 'rsa.network.zone_src', - type: 'keyword', + 'fortinet.firewall.shaperperipdropbyte': { + category: 'fortinet', + description: 'Dropped bytes per IP by shaper ', + name: 'fortinet.firewall.shaperperipdropbyte', + type: 'integer', }, - 'rsa.network.zone': { - category: 'rsa', - description: - 'This key should be used when the source or destination context of a Zone is not clear', - name: 'rsa.network.zone', + 'fortinet.firewall.shaperperipname': { + category: 'fortinet', + description: 'Traffic shaper name (per IP) ', + name: 'fortinet.firewall.shaperperipname', type: 'keyword', }, - 'rsa.network.zone_dst': { - category: 'rsa', - description: 'This key should only be used when it’s a Destination Zone.', - name: 'rsa.network.zone_dst', + 'fortinet.firewall.shaperrcvdname': { + category: 'fortinet', + description: 'Traffic shaper name for received traffic ', + name: 'fortinet.firewall.shaperrcvdname', type: 'keyword', }, - 'rsa.network.gateway': { - category: 'rsa', - description: 'This key is used to capture the IP Address of the gateway', - name: 'rsa.network.gateway', + 'fortinet.firewall.shapersentname': { + category: 'fortinet', + description: 'Traffic shaper name for sent traffic ', + name: 'fortinet.firewall.shapersentname', type: 'keyword', }, - 'rsa.network.icmp_type': { - category: 'rsa', - description: 'This key is used to capture the ICMP type only', - name: 'rsa.network.icmp_type', - type: 'long', + 'fortinet.firewall.shapingpolicyid': { + category: 'fortinet', + description: 'Traffic shaper policy ID ', + name: 'fortinet.firewall.shapingpolicyid', + type: 'integer', }, - 'rsa.network.mask': { - category: 'rsa', - description: 'This key is used to capture the device network IPmask.', - name: 'rsa.network.mask', - type: 'keyword', + 'fortinet.firewall.signal': { + category: 'fortinet', + description: 'Wireless rogue API signal ', + name: 'fortinet.firewall.signal', + type: 'integer', }, - 'rsa.network.icmp_code': { - category: 'rsa', - description: 'This key is used to capture the ICMP code only', - name: 'rsa.network.icmp_code', + 'fortinet.firewall.size': { + category: 'fortinet', + description: 'Email size in bytes ', + name: 'fortinet.firewall.size', type: 'long', }, - 'rsa.network.protocol_detail': { - category: 'rsa', - description: 'This key should be used to capture additional protocol information', - name: 'rsa.network.protocol_detail', - type: 'keyword', + 'fortinet.firewall.slot': { + category: 'fortinet', + description: 'Slot number ', + name: 'fortinet.firewall.slot', + type: 'integer', }, - 'rsa.network.dmask': { - category: 'rsa', - description: 'This key is used for Destionation Device network mask', - name: 'rsa.network.dmask', + 'fortinet.firewall.sn': { + category: 'fortinet', + description: 'Security fabric serial number ', + name: 'fortinet.firewall.sn', type: 'keyword', }, - 'rsa.network.port': { - category: 'rsa', - description: - 'This key should only be used to capture a Network Port when the directionality is not clear', - name: 'rsa.network.port', - type: 'long', - }, - 'rsa.network.smask': { - category: 'rsa', - description: 'This key is used for capturing source Network Mask', - name: 'rsa.network.smask', + 'fortinet.firewall.snclosest': { + category: 'fortinet', + description: 'SN of the AP closest to the rogue AP ', + name: 'fortinet.firewall.snclosest', type: 'keyword', }, - 'rsa.network.netname': { - category: 'rsa', - description: - 'This key is used to capture the network name associated with an IP range. This is configured by the end user.', - name: 'rsa.network.netname', + 'fortinet.firewall.sndetected': { + category: 'fortinet', + description: 'SN of the AP which detected the rogue AP ', + name: 'fortinet.firewall.sndetected', type: 'keyword', }, - 'rsa.network.paddr': { - category: 'rsa', - description: 'Deprecated', - name: 'rsa.network.paddr', - type: 'ip', - }, - 'rsa.network.faddr': { - category: 'rsa', - name: 'rsa.network.faddr', + 'fortinet.firewall.snmeshparent': { + category: 'fortinet', + description: 'SN of the mesh parent ', + name: 'fortinet.firewall.snmeshparent', type: 'keyword', }, - 'rsa.network.lhost': { - category: 'rsa', - name: 'rsa.network.lhost', + 'fortinet.firewall.spi': { + category: 'fortinet', + description: 'IPSEC SPI ', + name: 'fortinet.firewall.spi', type: 'keyword', }, - 'rsa.network.origin': { - category: 'rsa', - name: 'rsa.network.origin', + 'fortinet.firewall.src_int': { + category: 'fortinet', + description: 'Source interface ', + name: 'fortinet.firewall.src_int', type: 'keyword', }, - 'rsa.network.remote_domain_id': { - category: 'rsa', - name: 'rsa.network.remote_domain_id', + 'fortinet.firewall.srcintfrole': { + category: 'fortinet', + description: 'Source interface role ', + name: 'fortinet.firewall.srcintfrole', type: 'keyword', }, - 'rsa.network.addr': { - category: 'rsa', - name: 'rsa.network.addr', + 'fortinet.firewall.srccountry': { + category: 'fortinet', + description: 'Source country ', + name: 'fortinet.firewall.srccountry', type: 'keyword', }, - 'rsa.network.dns_a_record': { - category: 'rsa', - name: 'rsa.network.dns_a_record', + 'fortinet.firewall.srcfamily': { + category: 'fortinet', + description: 'Source family ', + name: 'fortinet.firewall.srcfamily', type: 'keyword', }, - 'rsa.network.dns_ptr_record': { - category: 'rsa', - name: 'rsa.network.dns_ptr_record', + 'fortinet.firewall.srchwvendor': { + category: 'fortinet', + description: 'Source hardware vendor ', + name: 'fortinet.firewall.srchwvendor', type: 'keyword', }, - 'rsa.network.fhost': { - category: 'rsa', - name: 'rsa.network.fhost', + 'fortinet.firewall.srchwversion': { + category: 'fortinet', + description: 'Source hardware version ', + name: 'fortinet.firewall.srchwversion', type: 'keyword', }, - 'rsa.network.fport': { - category: 'rsa', - name: 'rsa.network.fport', + 'fortinet.firewall.srcinetsvc': { + category: 'fortinet', + description: 'Source interface service ', + name: 'fortinet.firewall.srcinetsvc', type: 'keyword', }, - 'rsa.network.laddr': { - category: 'rsa', - name: 'rsa.network.laddr', + 'fortinet.firewall.srcname': { + category: 'fortinet', + description: 'Source name ', + name: 'fortinet.firewall.srcname', type: 'keyword', }, - 'rsa.network.linterface': { - category: 'rsa', - name: 'rsa.network.linterface', - type: 'keyword', + 'fortinet.firewall.srcserver': { + category: 'fortinet', + description: 'Source server ', + name: 'fortinet.firewall.srcserver', + type: 'integer', }, - 'rsa.network.phost': { - category: 'rsa', - name: 'rsa.network.phost', + 'fortinet.firewall.srcssid': { + category: 'fortinet', + description: 'Source SSID ', + name: 'fortinet.firewall.srcssid', type: 'keyword', }, - 'rsa.network.ad_computer_dst': { - category: 'rsa', - description: 'Deprecated, use host.dst', - name: 'rsa.network.ad_computer_dst', + 'fortinet.firewall.srcswversion': { + category: 'fortinet', + description: 'Source software version ', + name: 'fortinet.firewall.srcswversion', type: 'keyword', }, - 'rsa.network.eth_type': { - category: 'rsa', - description: 'This key is used to capture Ethernet Type, Used for Layer 3 Protocols Only', - name: 'rsa.network.eth_type', - type: 'long', - }, - 'rsa.network.ip_proto': { - category: 'rsa', - description: - 'This key should be used to capture the Protocol number, all the protocol nubers are converted into string in UI', - name: 'rsa.network.ip_proto', - type: 'long', - }, - 'rsa.network.dns_cname_record': { - category: 'rsa', - name: 'rsa.network.dns_cname_record', + 'fortinet.firewall.srcuuid': { + category: 'fortinet', + description: 'Source UUID ', + name: 'fortinet.firewall.srcuuid', type: 'keyword', }, - 'rsa.network.dns_id': { - category: 'rsa', - name: 'rsa.network.dns_id', + 'fortinet.firewall.sscname': { + category: 'fortinet', + description: 'SSC name ', + name: 'fortinet.firewall.sscname', type: 'keyword', }, - 'rsa.network.dns_opcode': { - category: 'rsa', - name: 'rsa.network.dns_opcode', + 'fortinet.firewall.ssid': { + category: 'fortinet', + description: 'Base Service Set ID ', + name: 'fortinet.firewall.ssid', type: 'keyword', }, - 'rsa.network.dns_resp': { - category: 'rsa', - name: 'rsa.network.dns_resp', + 'fortinet.firewall.sslaction': { + category: 'fortinet', + description: 'SSL Action ', + name: 'fortinet.firewall.sslaction', type: 'keyword', }, - 'rsa.network.dns_type': { - category: 'rsa', - name: 'rsa.network.dns_type', + 'fortinet.firewall.ssllocal': { + category: 'fortinet', + description: 'WAD SSL local ', + name: 'fortinet.firewall.ssllocal', type: 'keyword', }, - 'rsa.network.domain1': { - category: 'rsa', - name: 'rsa.network.domain1', + 'fortinet.firewall.sslremote': { + category: 'fortinet', + description: 'WAD SSL remote ', + name: 'fortinet.firewall.sslremote', type: 'keyword', }, - 'rsa.network.host_type': { - category: 'rsa', - name: 'rsa.network.host_type', + 'fortinet.firewall.stacount': { + category: 'fortinet', + description: 'Number of stations/clients ', + name: 'fortinet.firewall.stacount', + type: 'integer', + }, + 'fortinet.firewall.stage': { + category: 'fortinet', + description: 'IPSEC stage ', + name: 'fortinet.firewall.stage', type: 'keyword', }, - 'rsa.network.packet_length': { - category: 'rsa', - name: 'rsa.network.packet_length', + 'fortinet.firewall.stamac': { + category: 'fortinet', + description: '802.1x station mac ', + name: 'fortinet.firewall.stamac', type: 'keyword', }, - 'rsa.network.host_orig': { - category: 'rsa', - description: - 'This is used to capture the original hostname in case of a Forwarding Agent or a Proxy in between.', - name: 'rsa.network.host_orig', + 'fortinet.firewall.state': { + category: 'fortinet', + description: 'Admin login state ', + name: 'fortinet.firewall.state', type: 'keyword', }, - 'rsa.network.rpayload': { - category: 'rsa', - description: - 'This key is used to capture the total number of payload bytes seen in the retransmitted packets.', - name: 'rsa.network.rpayload', + 'fortinet.firewall.status': { + category: 'fortinet', + description: 'Status ', + name: 'fortinet.firewall.status', type: 'keyword', }, - 'rsa.network.vlan_name': { - category: 'rsa', - description: 'This key should only be used to capture the name of the Virtual LAN', - name: 'rsa.network.vlan_name', + 'fortinet.firewall.stitch': { + category: 'fortinet', + description: 'Automation stitch triggered ', + name: 'fortinet.firewall.stitch', type: 'keyword', }, - 'rsa.investigations.ec_activity': { - category: 'rsa', - description: 'This key captures the particular event activity(Ex:Logoff)', - name: 'rsa.investigations.ec_activity', + 'fortinet.firewall.subject': { + category: 'fortinet', + description: 'Email subject ', + name: 'fortinet.firewall.subject', type: 'keyword', }, - 'rsa.investigations.ec_theme': { - category: 'rsa', - description: 'This key captures the Theme of a particular Event(Ex:Authentication)', - name: 'rsa.investigations.ec_theme', + 'fortinet.firewall.submodule': { + category: 'fortinet', + description: 'Configuration Sub-Module Name ', + name: 'fortinet.firewall.submodule', type: 'keyword', }, - 'rsa.investigations.ec_subject': { - category: 'rsa', - description: 'This key captures the Subject of a particular Event(Ex:User)', - name: 'rsa.investigations.ec_subject', + 'fortinet.firewall.subservice': { + category: 'fortinet', + description: 'AV subservice ', + name: 'fortinet.firewall.subservice', type: 'keyword', }, - 'rsa.investigations.ec_outcome': { - category: 'rsa', - description: 'This key captures the outcome of a particular Event(Ex:Success)', - name: 'rsa.investigations.ec_outcome', + 'fortinet.firewall.subtype': { + category: 'fortinet', + description: 'Log subtype ', + name: 'fortinet.firewall.subtype', type: 'keyword', }, - 'rsa.investigations.event_cat': { - category: 'rsa', - description: 'This key captures the Event category number', - name: 'rsa.investigations.event_cat', - type: 'long', + 'fortinet.firewall.suspicious': { + category: 'fortinet', + description: 'Number of Suspicious MMSs ', + name: 'fortinet.firewall.suspicious', + type: 'integer', }, - 'rsa.investigations.event_cat_name': { - category: 'rsa', - description: 'This key captures the event category name corresponding to the event cat code', - name: 'rsa.investigations.event_cat_name', + 'fortinet.firewall.switchproto': { + category: 'fortinet', + description: 'Protocol change information ', + name: 'fortinet.firewall.switchproto', type: 'keyword', }, - 'rsa.investigations.event_vcat': { - category: 'rsa', - description: - 'This is a vendor supplied category. This should be used in situations where the vendor has adopted their own event_category taxonomy.', - name: 'rsa.investigations.event_vcat', + 'fortinet.firewall.sync_status': { + category: 'fortinet', + description: 'The sync status with the master ', + name: 'fortinet.firewall.sync_status', type: 'keyword', }, - 'rsa.investigations.analysis_file': { - category: 'rsa', - description: - 'This is used to capture all indicators used in a File Analysis. This key should be used to capture an analysis of a file', - name: 'rsa.investigations.analysis_file', + 'fortinet.firewall.sync_type': { + category: 'fortinet', + description: 'The sync type with the master ', + name: 'fortinet.firewall.sync_type', type: 'keyword', }, - 'rsa.investigations.analysis_service': { - category: 'rsa', - description: - 'This is used to capture all indicators used in a Service Analysis. This key should be used to capture an analysis of a service', - name: 'rsa.investigations.analysis_service', + 'fortinet.firewall.sysuptime': { + category: 'fortinet', + description: 'System uptime ', + name: 'fortinet.firewall.sysuptime', type: 'keyword', }, - 'rsa.investigations.analysis_session': { - category: 'rsa', - description: - 'This is used to capture all indicators used for a Session Analysis. This key should be used to capture an analysis of a session', - name: 'rsa.investigations.analysis_session', + 'fortinet.firewall.tamac': { + category: 'fortinet', + description: 'the MAC address of Transmitter, if none, then Receiver ', + name: 'fortinet.firewall.tamac', type: 'keyword', }, - 'rsa.investigations.boc': { - category: 'rsa', - description: 'This is used to capture behaviour of compromise', - name: 'rsa.investigations.boc', + 'fortinet.firewall.threattype': { + category: 'fortinet', + description: 'WIDS threat type ', + name: 'fortinet.firewall.threattype', type: 'keyword', }, - 'rsa.investigations.eoc': { - category: 'rsa', - description: 'This is used to capture Enablers of Compromise', - name: 'rsa.investigations.eoc', + 'fortinet.firewall.time': { + category: 'fortinet', + description: 'Time of the event ', + name: 'fortinet.firewall.time', type: 'keyword', }, - 'rsa.investigations.inv_category': { - category: 'rsa', - description: 'This used to capture investigation category', - name: 'rsa.investigations.inv_category', + 'fortinet.firewall.to': { + category: 'fortinet', + description: 'Email to field ', + name: 'fortinet.firewall.to', type: 'keyword', }, - 'rsa.investigations.inv_context': { - category: 'rsa', - description: 'This used to capture investigation context', - name: 'rsa.investigations.inv_context', - type: 'keyword', + 'fortinet.firewall.to_vcluster': { + category: 'fortinet', + description: 'destination virtual cluster number ', + name: 'fortinet.firewall.to_vcluster', + type: 'integer', }, - 'rsa.investigations.ioc': { - category: 'rsa', - description: 'This is key capture indicator of compromise', - name: 'rsa.investigations.ioc', + 'fortinet.firewall.total': { + category: 'fortinet', + description: 'Total memory ', + name: 'fortinet.firewall.total', + type: 'integer', + }, + 'fortinet.firewall.totalsession': { + category: 'fortinet', + description: 'Total Number of Sessions ', + name: 'fortinet.firewall.totalsession', + type: 'integer', + }, + 'fortinet.firewall.trace_id': { + category: 'fortinet', + description: 'Session clash trace ID ', + name: 'fortinet.firewall.trace_id', type: 'keyword', }, - 'rsa.counters.dclass_c1': { - category: 'rsa', - description: - 'This is a generic counter key that should be used with the label dclass.c1.str only', - name: 'rsa.counters.dclass_c1', - type: 'long', + 'fortinet.firewall.trandisp': { + category: 'fortinet', + description: 'NAT translation type ', + name: 'fortinet.firewall.trandisp', + type: 'keyword', }, - 'rsa.counters.dclass_c2': { - category: 'rsa', - description: - 'This is a generic counter key that should be used with the label dclass.c2.str only', - name: 'rsa.counters.dclass_c2', - type: 'long', + 'fortinet.firewall.transid': { + category: 'fortinet', + description: 'HTTP transaction ID ', + name: 'fortinet.firewall.transid', + type: 'integer', }, - 'rsa.counters.event_counter': { - category: 'rsa', - description: 'This is used to capture the number of times an event repeated', - name: 'rsa.counters.event_counter', - type: 'long', + 'fortinet.firewall.translationid': { + category: 'fortinet', + description: 'DNS filter transaltion ID ', + name: 'fortinet.firewall.translationid', + type: 'keyword', }, - 'rsa.counters.dclass_r1': { - category: 'rsa', - description: - 'This is a generic ratio key that should be used with the label dclass.r1.str only', - name: 'rsa.counters.dclass_r1', + 'fortinet.firewall.trigger': { + category: 'fortinet', + description: 'Automation stitch trigger ', + name: 'fortinet.firewall.trigger', type: 'keyword', }, - 'rsa.counters.dclass_c3': { - category: 'rsa', - description: - 'This is a generic counter key that should be used with the label dclass.c3.str only', - name: 'rsa.counters.dclass_c3', - type: 'long', + 'fortinet.firewall.trueclntip': { + category: 'fortinet', + description: 'File filter true client IP ', + name: 'fortinet.firewall.trueclntip', + type: 'ip', + }, + 'fortinet.firewall.tunnelid': { + category: 'fortinet', + description: 'IPSEC tunnel ID ', + name: 'fortinet.firewall.tunnelid', + type: 'integer', }, - 'rsa.counters.dclass_c1_str': { - category: 'rsa', - description: - 'This is a generic counter string key that should be used with the label dclass.c1 only', - name: 'rsa.counters.dclass_c1_str', - type: 'keyword', + 'fortinet.firewall.tunnelip': { + category: 'fortinet', + description: 'IPSEC tunnel IP ', + name: 'fortinet.firewall.tunnelip', + type: 'ip', }, - 'rsa.counters.dclass_c2_str': { - category: 'rsa', - description: - 'This is a generic counter string key that should be used with the label dclass.c2 only', - name: 'rsa.counters.dclass_c2_str', + 'fortinet.firewall.tunneltype': { + category: 'fortinet', + description: 'IPSEC tunnel type ', + name: 'fortinet.firewall.tunneltype', type: 'keyword', }, - 'rsa.counters.dclass_r1_str': { - category: 'rsa', - description: - 'This is a generic ratio string key that should be used with the label dclass.r1 only', - name: 'rsa.counters.dclass_r1_str', + 'fortinet.firewall.type': { + category: 'fortinet', + description: 'Module type ', + name: 'fortinet.firewall.type', type: 'keyword', }, - 'rsa.counters.dclass_r2': { - category: 'rsa', - description: - 'This is a generic ratio key that should be used with the label dclass.r2.str only', - name: 'rsa.counters.dclass_r2', + 'fortinet.firewall.ui': { + category: 'fortinet', + description: 'Admin authentication UI type ', + name: 'fortinet.firewall.ui', type: 'keyword', }, - 'rsa.counters.dclass_c3_str': { - category: 'rsa', - description: - 'This is a generic counter string key that should be used with the label dclass.c3 only', - name: 'rsa.counters.dclass_c3_str', + 'fortinet.firewall.unauthusersource': { + category: 'fortinet', + description: 'Unauthenticated user source ', + name: 'fortinet.firewall.unauthusersource', type: 'keyword', }, - 'rsa.counters.dclass_r3': { - category: 'rsa', - description: - 'This is a generic ratio key that should be used with the label dclass.r3.str only', - name: 'rsa.counters.dclass_r3', - type: 'keyword', + 'fortinet.firewall.unit': { + category: 'fortinet', + description: 'Power supply unit ', + name: 'fortinet.firewall.unit', + type: 'integer', }, - 'rsa.counters.dclass_r2_str': { - category: 'rsa', - description: - 'This is a generic ratio string key that should be used with the label dclass.r2 only', - name: 'rsa.counters.dclass_r2_str', - type: 'keyword', + 'fortinet.firewall.urlfilteridx': { + category: 'fortinet', + description: 'URL filter ID ', + name: 'fortinet.firewall.urlfilteridx', + type: 'integer', }, - 'rsa.counters.dclass_r3_str': { - category: 'rsa', - description: - 'This is a generic ratio string key that should be used with the label dclass.r3 only', - name: 'rsa.counters.dclass_r3_str', + 'fortinet.firewall.urlfilterlist': { + category: 'fortinet', + description: 'URL filter list ', + name: 'fortinet.firewall.urlfilterlist', type: 'keyword', }, - 'rsa.identity.auth_method': { - category: 'rsa', - description: 'This key is used to capture authentication methods used only', - name: 'rsa.identity.auth_method', + 'fortinet.firewall.urlsource': { + category: 'fortinet', + description: 'URL filter source ', + name: 'fortinet.firewall.urlsource', type: 'keyword', }, - 'rsa.identity.user_role': { - category: 'rsa', - description: 'This key is used to capture the Role of a user only', - name: 'rsa.identity.user_role', + 'fortinet.firewall.urltype': { + category: 'fortinet', + description: 'URL filter type ', + name: 'fortinet.firewall.urltype', type: 'keyword', }, - 'rsa.identity.dn': { - category: 'rsa', - description: 'X.500 (LDAP) Distinguished Name', - name: 'rsa.identity.dn', - type: 'keyword', + 'fortinet.firewall.used': { + category: 'fortinet', + description: 'Number of Used IPs ', + name: 'fortinet.firewall.used', + type: 'integer', }, - 'rsa.identity.logon_type': { - category: 'rsa', - description: 'This key is used to capture the type of logon method used.', - name: 'rsa.identity.logon_type', - type: 'keyword', + 'fortinet.firewall.used_for_type': { + category: 'fortinet', + description: 'Connection for the type ', + name: 'fortinet.firewall.used_for_type', + type: 'integer', }, - 'rsa.identity.profile': { - category: 'rsa', - description: 'This key is used to capture the user profile', - name: 'rsa.identity.profile', + 'fortinet.firewall.utmaction': { + category: 'fortinet', + description: 'Security action performed by UTM ', + name: 'fortinet.firewall.utmaction', type: 'keyword', }, - 'rsa.identity.accesses': { - category: 'rsa', - description: 'This key is used to capture actual privileges used in accessing an object', - name: 'rsa.identity.accesses', + 'fortinet.firewall.utmref': { + category: 'fortinet', + description: 'Reference to UTM ', + name: 'fortinet.firewall.utmref', type: 'keyword', }, - 'rsa.identity.realm': { - category: 'rsa', - description: 'Radius realm or similar grouping of accounts', - name: 'rsa.identity.realm', + 'fortinet.firewall.vap': { + category: 'fortinet', + description: 'Virtual AP ', + name: 'fortinet.firewall.vap', type: 'keyword', }, - 'rsa.identity.user_sid_dst': { - category: 'rsa', - description: 'This key captures Destination User Session ID', - name: 'rsa.identity.user_sid_dst', + 'fortinet.firewall.vapmode': { + category: 'fortinet', + description: 'Virtual AP mode ', + name: 'fortinet.firewall.vapmode', type: 'keyword', }, - 'rsa.identity.dn_src': { - category: 'rsa', - description: - 'An X.500 (LDAP) Distinguished name that is used in a context that indicates a Source dn', - name: 'rsa.identity.dn_src', - type: 'keyword', + 'fortinet.firewall.vcluster': { + category: 'fortinet', + description: 'virtual cluster id ', + name: 'fortinet.firewall.vcluster', + type: 'integer', }, - 'rsa.identity.org': { - category: 'rsa', - description: 'This key captures the User organization', - name: 'rsa.identity.org', - type: 'keyword', + 'fortinet.firewall.vcluster_member': { + category: 'fortinet', + description: 'Virtual cluster member ', + name: 'fortinet.firewall.vcluster_member', + type: 'integer', }, - 'rsa.identity.dn_dst': { - category: 'rsa', - description: - 'An X.500 (LDAP) Distinguished name that used in a context that indicates a Destination dn', - name: 'rsa.identity.dn_dst', + 'fortinet.firewall.vcluster_state': { + category: 'fortinet', + description: 'Virtual cluster state ', + name: 'fortinet.firewall.vcluster_state', type: 'keyword', }, - 'rsa.identity.firstname': { - category: 'rsa', - description: - 'This key is for First Names only, this is used for Healthcare predominantly to capture Patients information', - name: 'rsa.identity.firstname', + 'fortinet.firewall.vd': { + category: 'fortinet', + description: 'Virtual Domain Name ', + name: 'fortinet.firewall.vd', type: 'keyword', }, - 'rsa.identity.lastname': { - category: 'rsa', - description: - 'This key is for Last Names only, this is used for Healthcare predominantly to capture Patients information', - name: 'rsa.identity.lastname', + 'fortinet.firewall.vdname': { + category: 'fortinet', + description: 'Virtual Domain Name ', + name: 'fortinet.firewall.vdname', type: 'keyword', }, - 'rsa.identity.user_dept': { - category: 'rsa', - description: "User's Department Names only", - name: 'rsa.identity.user_dept', + 'fortinet.firewall.vendorurl': { + category: 'fortinet', + description: 'Vulnerability scan vendor name ', + name: 'fortinet.firewall.vendorurl', type: 'keyword', }, - 'rsa.identity.user_sid_src': { - category: 'rsa', - description: 'This key captures Source User Session ID', - name: 'rsa.identity.user_sid_src', + 'fortinet.firewall.version': { + category: 'fortinet', + description: 'Version ', + name: 'fortinet.firewall.version', type: 'keyword', }, - 'rsa.identity.federated_sp': { - category: 'rsa', - description: - 'This key is the Federated Service Provider. This is the application requesting authentication.', - name: 'rsa.identity.federated_sp', + 'fortinet.firewall.vip': { + category: 'fortinet', + description: 'Virtual IP ', + name: 'fortinet.firewall.vip', type: 'keyword', }, - 'rsa.identity.federated_idp': { - category: 'rsa', - description: - 'This key is the federated Identity Provider. This is the server providing the authentication.', - name: 'rsa.identity.federated_idp', + 'fortinet.firewall.virus': { + category: 'fortinet', + description: 'Virus name ', + name: 'fortinet.firewall.virus', type: 'keyword', }, - 'rsa.identity.logon_type_desc': { - category: 'rsa', - description: - "This key is used to capture the textual description of an integer logon type as stored in the meta key 'logon.type'.", - name: 'rsa.identity.logon_type_desc', - type: 'keyword', + 'fortinet.firewall.virusid': { + category: 'fortinet', + description: 'Virus ID (unique virus identifier) ', + name: 'fortinet.firewall.virusid', + type: 'integer', }, - 'rsa.identity.middlename': { - category: 'rsa', - description: - 'This key is for Middle Names only, this is used for Healthcare predominantly to capture Patients information', - name: 'rsa.identity.middlename', + 'fortinet.firewall.voip_proto': { + category: 'fortinet', + description: 'VOIP protocol ', + name: 'fortinet.firewall.voip_proto', type: 'keyword', }, - 'rsa.identity.password': { - category: 'rsa', - description: 'This key is for Passwords seen in any session, plain text or encrypted', - name: 'rsa.identity.password', + 'fortinet.firewall.vpn': { + category: 'fortinet', + description: 'VPN description ', + name: 'fortinet.firewall.vpn', type: 'keyword', }, - 'rsa.identity.host_role': { - category: 'rsa', - description: 'This key should only be used to capture the role of a Host Machine', - name: 'rsa.identity.host_role', + 'fortinet.firewall.vpntunnel': { + category: 'fortinet', + description: 'IPsec Vpn Tunnel Name ', + name: 'fortinet.firewall.vpntunnel', type: 'keyword', }, - 'rsa.identity.ldap': { - category: 'rsa', - description: - 'This key is for Uninterpreted LDAP values. Ldap Values that don’t have a clear query or response context', - name: 'rsa.identity.ldap', + 'fortinet.firewall.vpntype': { + category: 'fortinet', + description: 'The type of the VPN tunnel ', + name: 'fortinet.firewall.vpntype', type: 'keyword', }, - 'rsa.identity.ldap_query': { - category: 'rsa', - description: 'This key is the Search criteria from an LDAP search', - name: 'rsa.identity.ldap_query', - type: 'keyword', + 'fortinet.firewall.vrf': { + category: 'fortinet', + description: 'VRF number ', + name: 'fortinet.firewall.vrf', + type: 'integer', }, - 'rsa.identity.ldap_response': { - category: 'rsa', - description: 'This key is to capture Results from an LDAP search', - name: 'rsa.identity.ldap_response', + 'fortinet.firewall.vulncat': { + category: 'fortinet', + description: 'Vulnerability Category ', + name: 'fortinet.firewall.vulncat', type: 'keyword', }, - 'rsa.identity.owner': { - category: 'rsa', - description: - 'This is used to capture username the process or service is running as, the author of the task', - name: 'rsa.identity.owner', + 'fortinet.firewall.vulnid': { + category: 'fortinet', + description: 'Vulnerability ID ', + name: 'fortinet.firewall.vulnid', + type: 'integer', + }, + 'fortinet.firewall.vulnname': { + category: 'fortinet', + description: 'Vulnerability name ', + name: 'fortinet.firewall.vulnname', type: 'keyword', }, - 'rsa.identity.service_account': { - category: 'rsa', - description: - 'This key is a windows specific key, used for capturing name of the account a service (referenced in the event) is running under. Legacy Usage', - name: 'rsa.identity.service_account', + 'fortinet.firewall.vwlid': { + category: 'fortinet', + description: 'VWL ID ', + name: 'fortinet.firewall.vwlid', + type: 'integer', + }, + 'fortinet.firewall.vwlquality': { + category: 'fortinet', + description: 'VWL quality ', + name: 'fortinet.firewall.vwlquality', type: 'keyword', }, - 'rsa.email.email_dst': { - category: 'rsa', - description: - 'This key is used to capture the Destination email address only, when the destination context is not clear use email', - name: 'rsa.email.email_dst', + 'fortinet.firewall.vwlservice': { + category: 'fortinet', + description: 'VWL service ', + name: 'fortinet.firewall.vwlservice', type: 'keyword', }, - 'rsa.email.email_src': { - category: 'rsa', - description: - 'This key is used to capture the source email address only, when the source context is not clear use email', - name: 'rsa.email.email_src', + 'fortinet.firewall.vwpvlanid': { + category: 'fortinet', + description: 'VWP VLAN ID ', + name: 'fortinet.firewall.vwpvlanid', + type: 'integer', + }, + 'fortinet.firewall.wanin': { + category: 'fortinet', + description: 'WAN incoming traffic in bytes ', + name: 'fortinet.firewall.wanin', + type: 'long', + }, + 'fortinet.firewall.wanoptapptype': { + category: 'fortinet', + description: 'WAN Optimization Application type ', + name: 'fortinet.firewall.wanoptapptype', type: 'keyword', }, - 'rsa.email.subject': { - category: 'rsa', - description: 'This key is used to capture the subject string from an Email only.', - name: 'rsa.email.subject', + 'fortinet.firewall.wanout': { + category: 'fortinet', + description: 'WAN outgoing traffic in bytes ', + name: 'fortinet.firewall.wanout', + type: 'long', + }, + 'fortinet.firewall.weakwepiv': { + category: 'fortinet', + description: 'Weak Wep Initiation Vector ', + name: 'fortinet.firewall.weakwepiv', type: 'keyword', }, - 'rsa.email.email': { - category: 'rsa', - description: - 'This key is used to capture a generic email address where the source or destination context is not clear', - name: 'rsa.email.email', + 'fortinet.firewall.xauthgroup': { + category: 'fortinet', + description: 'XAuth Group Name ', + name: 'fortinet.firewall.xauthgroup', type: 'keyword', }, - 'rsa.email.trans_from': { - category: 'rsa', - description: 'Deprecated key defined only in table map.', - name: 'rsa.email.trans_from', + 'fortinet.firewall.xauthuser': { + category: 'fortinet', + description: 'XAuth User Name ', + name: 'fortinet.firewall.xauthuser', type: 'keyword', }, - 'rsa.email.trans_to': { - category: 'rsa', - description: 'Deprecated key defined only in table map.', - name: 'rsa.email.trans_to', + 'fortinet.firewall.xid': { + category: 'fortinet', + description: 'Wireless X ID ', + name: 'fortinet.firewall.xid', + type: 'integer', + }, + 'gcp.destination.instance.project_id': { + category: 'gcp', + description: 'ID of the project containing the VM. ', + name: 'gcp.destination.instance.project_id', type: 'keyword', }, - 'rsa.file.privilege': { - category: 'rsa', - description: 'Deprecated, use permissions', - name: 'rsa.file.privilege', + 'gcp.destination.instance.region': { + category: 'gcp', + description: 'Region of the VM. ', + name: 'gcp.destination.instance.region', type: 'keyword', }, - 'rsa.file.attachment': { - category: 'rsa', - description: 'This key captures the attachment file name', - name: 'rsa.file.attachment', + 'gcp.destination.instance.zone': { + category: 'gcp', + description: 'Zone of the VM. ', + name: 'gcp.destination.instance.zone', type: 'keyword', }, - 'rsa.file.filesystem': { - category: 'rsa', - name: 'rsa.file.filesystem', + 'gcp.destination.vpc.project_id': { + category: 'gcp', + description: 'ID of the project containing the VM. ', + name: 'gcp.destination.vpc.project_id', type: 'keyword', }, - 'rsa.file.binary': { - category: 'rsa', - description: 'Deprecated key defined only in table map.', - name: 'rsa.file.binary', + 'gcp.destination.vpc.vpc_name': { + category: 'gcp', + description: 'VPC on which the VM is operating. ', + name: 'gcp.destination.vpc.vpc_name', type: 'keyword', }, - 'rsa.file.filename_dst': { - category: 'rsa', - description: 'This is used to capture name of the file targeted by the action', - name: 'rsa.file.filename_dst', + 'gcp.destination.vpc.subnetwork_name': { + category: 'gcp', + description: 'Subnetwork on which the VM is operating. ', + name: 'gcp.destination.vpc.subnetwork_name', type: 'keyword', }, - 'rsa.file.filename_src': { - category: 'rsa', - description: - 'This is used to capture name of the parent filename, the file which performed the action', - name: 'rsa.file.filename_src', + 'gcp.source.instance.project_id': { + category: 'gcp', + description: 'ID of the project containing the VM. ', + name: 'gcp.source.instance.project_id', type: 'keyword', }, - 'rsa.file.filename_tmp': { - category: 'rsa', - name: 'rsa.file.filename_tmp', + 'gcp.source.instance.region': { + category: 'gcp', + description: 'Region of the VM. ', + name: 'gcp.source.instance.region', type: 'keyword', }, - 'rsa.file.directory_dst': { - category: 'rsa', - description: - 'This key is used to capture the directory of the target process or file', - name: 'rsa.file.directory_dst', + 'gcp.source.instance.zone': { + category: 'gcp', + description: 'Zone of the VM. ', + name: 'gcp.source.instance.zone', type: 'keyword', }, - 'rsa.file.directory_src': { - category: 'rsa', - description: 'This key is used to capture the directory of the source process or file', - name: 'rsa.file.directory_src', + 'gcp.source.vpc.project_id': { + category: 'gcp', + description: 'ID of the project containing the VM. ', + name: 'gcp.source.vpc.project_id', type: 'keyword', }, - 'rsa.file.file_entropy': { - category: 'rsa', - description: 'This is used to capture entropy vale of a file', - name: 'rsa.file.file_entropy', - type: 'double', + 'gcp.source.vpc.vpc_name': { + category: 'gcp', + description: 'VPC on which the VM is operating. ', + name: 'gcp.source.vpc.vpc_name', + type: 'keyword', }, - 'rsa.file.file_vendor': { - category: 'rsa', - description: 'This is used to capture Company name of file located in version_info', - name: 'rsa.file.file_vendor', + 'gcp.source.vpc.subnetwork_name': { + category: 'gcp', + description: 'Subnetwork on which the VM is operating. ', + name: 'gcp.source.vpc.subnetwork_name', type: 'keyword', }, - 'rsa.file.task_name': { - category: 'rsa', - description: 'This is used to capture name of the task', - name: 'rsa.file.task_name', + 'gcp.audit.type': { + category: 'gcp', + description: 'Type property. ', + name: 'gcp.audit.type', type: 'keyword', }, - 'rsa.web.fqdn': { - category: 'rsa', - description: 'Fully Qualified Domain Names', - name: 'rsa.web.fqdn', + 'gcp.audit.authentication_info.principal_email': { + category: 'gcp', + description: 'The email address of the authenticated user making the request. ', + name: 'gcp.audit.authentication_info.principal_email', type: 'keyword', }, - 'rsa.web.web_cookie': { - category: 'rsa', - description: 'This key is used to capture the Web cookies specifically.', - name: 'rsa.web.web_cookie', + 'gcp.audit.authentication_info.authority_selector': { + category: 'gcp', + description: + 'The authority selector specified by the requestor, if any. It is not guaranteed that the principal was allowed to use this authority. ', + name: 'gcp.audit.authentication_info.authority_selector', type: 'keyword', }, - 'rsa.web.alias_host': { - category: 'rsa', - name: 'rsa.web.alias_host', + 'gcp.audit.authorization_info.permission': { + category: 'gcp', + description: 'The required IAM permission. ', + name: 'gcp.audit.authorization_info.permission', type: 'keyword', }, - 'rsa.web.reputation_num': { - category: 'rsa', - description: 'Reputation Number of an entity. Typically used for Web Domains', - name: 'rsa.web.reputation_num', - type: 'double', + 'gcp.audit.authorization_info.granted': { + category: 'gcp', + description: 'Whether or not authorization for resource and permission was granted. ', + name: 'gcp.audit.authorization_info.granted', + type: 'boolean', }, - 'rsa.web.web_ref_domain': { - category: 'rsa', - description: "Web referer's domain", - name: 'rsa.web.web_ref_domain', + 'gcp.audit.authorization_info.resource_attributes.service': { + category: 'gcp', + description: 'The name of the service. ', + name: 'gcp.audit.authorization_info.resource_attributes.service', type: 'keyword', }, - 'rsa.web.web_ref_query': { - category: 'rsa', - description: "This key captures Web referer's query portion of the URL", - name: 'rsa.web.web_ref_query', + 'gcp.audit.authorization_info.resource_attributes.name': { + category: 'gcp', + description: 'The name of the resource. ', + name: 'gcp.audit.authorization_info.resource_attributes.name', type: 'keyword', }, - 'rsa.web.remote_domain': { - category: 'rsa', - name: 'rsa.web.remote_domain', + 'gcp.audit.authorization_info.resource_attributes.type': { + category: 'gcp', + description: 'The type of the resource. ', + name: 'gcp.audit.authorization_info.resource_attributes.type', type: 'keyword', }, - 'rsa.web.web_ref_page': { - category: 'rsa', - description: "This key captures Web referer's page information", - name: 'rsa.web.web_ref_page', + 'gcp.audit.method_name': { + category: 'gcp', + description: + "The name of the service method or operation. For API calls, this should be the name of the API method. For example, 'google.datastore.v1.Datastore.RunQuery'. ", + name: 'gcp.audit.method_name', type: 'keyword', }, - 'rsa.web.web_ref_root': { - category: 'rsa', - description: "Web referer's root URL path", - name: 'rsa.web.web_ref_root', - type: 'keyword', + 'gcp.audit.num_response_items': { + category: 'gcp', + description: 'The number of items returned from a List or Query API method, if applicable. ', + name: 'gcp.audit.num_response_items', + type: 'long', }, - 'rsa.web.cn_asn_dst': { - category: 'rsa', - name: 'rsa.web.cn_asn_dst', + 'gcp.audit.request.proto_name': { + category: 'gcp', + description: 'Type property of the request. ', + name: 'gcp.audit.request.proto_name', type: 'keyword', }, - 'rsa.web.cn_rpackets': { - category: 'rsa', - name: 'rsa.web.cn_rpackets', + 'gcp.audit.request.filter': { + category: 'gcp', + description: 'Filter of the request. ', + name: 'gcp.audit.request.filter', type: 'keyword', }, - 'rsa.web.urlpage': { - category: 'rsa', - name: 'rsa.web.urlpage', + 'gcp.audit.request.name': { + category: 'gcp', + description: 'Name of the request. ', + name: 'gcp.audit.request.name', type: 'keyword', }, - 'rsa.web.urlroot': { - category: 'rsa', - name: 'rsa.web.urlroot', + 'gcp.audit.request.resource_name': { + category: 'gcp', + description: 'Name of the request resource. ', + name: 'gcp.audit.request.resource_name', type: 'keyword', }, - 'rsa.web.p_url': { - category: 'rsa', - name: 'rsa.web.p_url', - type: 'keyword', + 'gcp.audit.request_metadata.caller_ip': { + category: 'gcp', + description: 'The IP address of the caller. ', + name: 'gcp.audit.request_metadata.caller_ip', + type: 'ip', }, - 'rsa.web.p_user_agent': { - category: 'rsa', - name: 'rsa.web.p_user_agent', + 'gcp.audit.request_metadata.caller_supplied_user_agent': { + category: 'gcp', + description: + 'The user agent of the caller. This information is not authenticated and should be treated accordingly. ', + name: 'gcp.audit.request_metadata.caller_supplied_user_agent', type: 'keyword', }, - 'rsa.web.p_web_cookie': { - category: 'rsa', - name: 'rsa.web.p_web_cookie', + 'gcp.audit.response.proto_name': { + category: 'gcp', + description: 'Type property of the response. ', + name: 'gcp.audit.response.proto_name', type: 'keyword', }, - 'rsa.web.p_web_method': { - category: 'rsa', - name: 'rsa.web.p_web_method', + 'gcp.audit.response.details.group': { + category: 'gcp', + description: 'The name of the group. ', + name: 'gcp.audit.response.details.group', type: 'keyword', }, - 'rsa.web.p_web_referer': { - category: 'rsa', - name: 'rsa.web.p_web_referer', + 'gcp.audit.response.details.kind': { + category: 'gcp', + description: 'The kind of the response details. ', + name: 'gcp.audit.response.details.kind', type: 'keyword', }, - 'rsa.web.web_extension_tmp': { - category: 'rsa', - name: 'rsa.web.web_extension_tmp', + 'gcp.audit.response.details.name': { + category: 'gcp', + description: 'The name of the response details. ', + name: 'gcp.audit.response.details.name', type: 'keyword', }, - 'rsa.web.web_page': { - category: 'rsa', - name: 'rsa.web.web_page', + 'gcp.audit.response.details.uid': { + category: 'gcp', + description: 'The uid of the response details. ', + name: 'gcp.audit.response.details.uid', type: 'keyword', }, - 'rsa.threat.threat_category': { - category: 'rsa', - description: 'This key captures Threat Name/Threat Category/Categorization of alert', - name: 'rsa.threat.threat_category', + 'gcp.audit.response.status': { + category: 'gcp', + description: 'Status of the response. ', + name: 'gcp.audit.response.status', type: 'keyword', }, - 'rsa.threat.threat_desc': { - category: 'rsa', + 'gcp.audit.resource_name': { + category: 'gcp', description: - 'This key is used to capture the threat description from the session directly or inferred', - name: 'rsa.threat.threat_desc', + "The resource or collection that is the target of the operation. The name is a scheme-less URI, not including the API service name. For example, 'shelves/SHELF_ID/books'. ", + name: 'gcp.audit.resource_name', type: 'keyword', }, - 'rsa.threat.alert': { - category: 'rsa', - description: 'This key is used to capture name of the alert', - name: 'rsa.threat.alert', + 'gcp.audit.resource_location.current_locations': { + category: 'gcp', + description: 'Current locations of the resource. ', + name: 'gcp.audit.resource_location.current_locations', type: 'keyword', }, - 'rsa.threat.threat_source': { - category: 'rsa', - description: 'This key is used to capture source of the threat', - name: 'rsa.threat.threat_source', + 'gcp.audit.service_name': { + category: 'gcp', + description: + 'The name of the API service performing the operation. For example, datastore.googleapis.com. ', + name: 'gcp.audit.service_name', type: 'keyword', }, - 'rsa.crypto.crypto': { - category: 'rsa', - description: 'This key is used to capture the Encryption Type or Encryption Key only', - name: 'rsa.crypto.crypto', - type: 'keyword', + 'gcp.audit.status.code': { + category: 'gcp', + description: 'The status code, which should be an enum value of google.rpc.Code. ', + name: 'gcp.audit.status.code', + type: 'integer', }, - 'rsa.crypto.cipher_src': { - category: 'rsa', - description: 'This key is for Source (Client) Cipher', - name: 'rsa.crypto.cipher_src', + 'gcp.audit.status.message': { + category: 'gcp', + description: + 'A developer-facing error message, which should be in English. Any user-facing error message should be localized and sent in the google.rpc.Status.details field, or localized by the client. ', + name: 'gcp.audit.status.message', type: 'keyword', }, - 'rsa.crypto.cert_subject': { - category: 'rsa', - description: 'This key is used to capture the Certificate organization only', - name: 'rsa.crypto.cert_subject', - type: 'keyword', + 'gcp.firewall.rule_details.priority': { + category: 'gcp', + description: 'The priority for the firewall rule.', + name: 'gcp.firewall.rule_details.priority', + type: 'long', }, - 'rsa.crypto.peer': { - category: 'rsa', - description: "This key is for Encryption peer's IP Address", - name: 'rsa.crypto.peer', + 'gcp.firewall.rule_details.action': { + category: 'gcp', + description: 'Action that the rule performs on match.', + name: 'gcp.firewall.rule_details.action', type: 'keyword', }, - 'rsa.crypto.cipher_size_src': { - category: 'rsa', - description: 'This key captures Source (Client) Cipher Size', - name: 'rsa.crypto.cipher_size_src', - type: 'long', + 'gcp.firewall.rule_details.direction': { + category: 'gcp', + description: 'Direction of traffic that matches this rule.', + name: 'gcp.firewall.rule_details.direction', + type: 'keyword', }, - 'rsa.crypto.ike': { - category: 'rsa', - description: 'IKE negotiation phase.', - name: 'rsa.crypto.ike', + 'gcp.firewall.rule_details.reference': { + category: 'gcp', + description: 'Reference to the firewall rule.', + name: 'gcp.firewall.rule_details.reference', type: 'keyword', }, - 'rsa.crypto.scheme': { - category: 'rsa', - description: 'This key captures the Encryption scheme used', - name: 'rsa.crypto.scheme', + 'gcp.firewall.rule_details.source_range': { + category: 'gcp', + description: 'List of source ranges that the firewall rule applies to.', + name: 'gcp.firewall.rule_details.source_range', type: 'keyword', }, - 'rsa.crypto.peer_id': { - category: 'rsa', - description: 'This key is for Encryption peer’s identity', - name: 'rsa.crypto.peer_id', + 'gcp.firewall.rule_details.destination_range': { + category: 'gcp', + description: 'List of destination ranges that the firewall applies to.', + name: 'gcp.firewall.rule_details.destination_range', type: 'keyword', }, - 'rsa.crypto.sig_type': { - category: 'rsa', - description: 'This key captures the Signature Type', - name: 'rsa.crypto.sig_type', + 'gcp.firewall.rule_details.source_tag': { + category: 'gcp', + description: 'List of all the source tags that the firewall rule applies to. ', + name: 'gcp.firewall.rule_details.source_tag', type: 'keyword', }, - 'rsa.crypto.cert_issuer': { - category: 'rsa', - name: 'rsa.crypto.cert_issuer', + 'gcp.firewall.rule_details.target_tag': { + category: 'gcp', + description: 'List of all the target tags that the firewall rule applies to. ', + name: 'gcp.firewall.rule_details.target_tag', type: 'keyword', }, - 'rsa.crypto.cert_host_name': { - category: 'rsa', - description: 'Deprecated key defined only in table map.', - name: 'rsa.crypto.cert_host_name', + 'gcp.firewall.rule_details.ip_port_info': { + category: 'gcp', + description: 'List of ip protocols and applicable port ranges for rules. ', + name: 'gcp.firewall.rule_details.ip_port_info', + type: 'array', + }, + 'gcp.firewall.rule_details.source_service_account': { + category: 'gcp', + description: 'List of all the source service accounts that the firewall rule applies to. ', + name: 'gcp.firewall.rule_details.source_service_account', type: 'keyword', }, - 'rsa.crypto.cert_error': { - category: 'rsa', - description: 'This key captures the Certificate Error String', - name: 'rsa.crypto.cert_error', + 'gcp.firewall.rule_details.target_service_account': { + category: 'gcp', + description: 'List of all the target service accounts that the firewall rule applies to. ', + name: 'gcp.firewall.rule_details.target_service_account', type: 'keyword', }, - 'rsa.crypto.cipher_dst': { - category: 'rsa', - description: 'This key is for Destination (Server) Cipher', - name: 'rsa.crypto.cipher_dst', + 'gcp.vpcflow.reporter': { + category: 'gcp', + description: "The side which reported the flow. Can be either 'SRC' or 'DEST'. ", + name: 'gcp.vpcflow.reporter', type: 'keyword', }, - 'rsa.crypto.cipher_size_dst': { - category: 'rsa', - description: 'This key captures Destination (Server) Cipher Size', - name: 'rsa.crypto.cipher_size_dst', + 'gcp.vpcflow.rtt.ms': { + category: 'gcp', + description: + 'Latency as measured (for TCP flows only) during the time interval. This is the time elapsed between sending a SEQ and receiving a corresponding ACK and it contains the network RTT as well as the application related delay. ', + name: 'gcp.vpcflow.rtt.ms', type: 'long', }, - 'rsa.crypto.ssl_ver_src': { - category: 'rsa', - description: 'Deprecated, use version', - name: 'rsa.crypto.ssl_ver_src', + 'google_workspace.actor.type': { + category: 'google_workspace', + description: + 'The type of actor. Values can be: *USER*: Another user in the same domain. *EXTERNAL_USER*: A user outside the domain. *KEY*: A non-human actor. ', + name: 'google_workspace.actor.type', type: 'keyword', }, - 'rsa.crypto.d_certauth': { - category: 'rsa', - name: 'rsa.crypto.d_certauth', + 'google_workspace.actor.key': { + category: 'google_workspace', + description: + 'Only present when `actor.type` is `KEY`. Can be the `consumer_key` of the requestor for OAuth 2LO API requests or an identifier for robot accounts. ', + name: 'google_workspace.actor.key', type: 'keyword', }, - 'rsa.crypto.s_certauth': { - category: 'rsa', - name: 'rsa.crypto.s_certauth', + 'google_workspace.event.type': { + category: 'google_workspace', + description: + 'The type of Google Workspace event, mapped from `items[].events[].type` in the original payload. Each fileset can have a different set of values for it, more details can be found at https://developers.google.com/admin-sdk/reports/v1/reference/activities/list ', + example: 'audit#activity', + name: 'google_workspace.event.type', type: 'keyword', }, - 'rsa.crypto.ike_cookie1': { - category: 'rsa', - description: 'ID of the negotiation — sent for ISAKMP Phase One', - name: 'rsa.crypto.ike_cookie1', + 'google_workspace.kind': { + category: 'google_workspace', + description: + 'The type of API resource, mapped from `kind` in the original payload. More details can be found at https://developers.google.com/admin-sdk/reports/v1/reference/activities/list ', + example: 'audit#activity', + name: 'google_workspace.kind', type: 'keyword', }, - 'rsa.crypto.ike_cookie2': { - category: 'rsa', - description: 'ID of the negotiation — sent for ISAKMP Phase Two', - name: 'rsa.crypto.ike_cookie2', + 'google_workspace.organization.domain': { + category: 'google_workspace', + description: "The domain that is affected by the report's event. ", + name: 'google_workspace.organization.domain', type: 'keyword', }, - 'rsa.crypto.cert_checksum': { - category: 'rsa', - name: 'rsa.crypto.cert_checksum', + 'google_workspace.admin.application.edition': { + category: 'google_workspace', + description: 'The Google Workspace edition.', + name: 'google_workspace.admin.application.edition', type: 'keyword', }, - 'rsa.crypto.cert_host_cat': { - category: 'rsa', - description: 'This key is used for the hostname category value of a certificate', - name: 'rsa.crypto.cert_host_cat', + 'google_workspace.admin.application.name': { + category: 'google_workspace', + description: "The application's name.", + name: 'google_workspace.admin.application.name', type: 'keyword', }, - 'rsa.crypto.cert_serial': { - category: 'rsa', - description: 'This key is used to capture the Certificate serial number only', - name: 'rsa.crypto.cert_serial', + 'google_workspace.admin.application.enabled': { + category: 'google_workspace', + description: 'The enabled application.', + name: 'google_workspace.admin.application.enabled', type: 'keyword', }, - 'rsa.crypto.cert_status': { - category: 'rsa', - description: 'This key captures Certificate validation status', - name: 'rsa.crypto.cert_status', + 'google_workspace.admin.application.licences_order_number': { + category: 'google_workspace', + description: 'Order number used to redeem licenses.', + name: 'google_workspace.admin.application.licences_order_number', type: 'keyword', }, - 'rsa.crypto.ssl_ver_dst': { - category: 'rsa', - description: 'Deprecated, use version', - name: 'rsa.crypto.ssl_ver_dst', + 'google_workspace.admin.application.licences_purchased': { + category: 'google_workspace', + description: 'Number of licences purchased.', + name: 'google_workspace.admin.application.licences_purchased', type: 'keyword', }, - 'rsa.crypto.cert_keysize': { - category: 'rsa', - name: 'rsa.crypto.cert_keysize', + 'google_workspace.admin.application.id': { + category: 'google_workspace', + description: 'The application ID.', + name: 'google_workspace.admin.application.id', type: 'keyword', }, - 'rsa.crypto.cert_username': { - category: 'rsa', - name: 'rsa.crypto.cert_username', + 'google_workspace.admin.application.asp_id': { + category: 'google_workspace', + description: 'The application specific password ID.', + name: 'google_workspace.admin.application.asp_id', type: 'keyword', }, - 'rsa.crypto.https_insact': { - category: 'rsa', - name: 'rsa.crypto.https_insact', + 'google_workspace.admin.application.package_id': { + category: 'google_workspace', + description: 'The mobile application package ID.', + name: 'google_workspace.admin.application.package_id', type: 'keyword', }, - 'rsa.crypto.https_valid': { - category: 'rsa', - name: 'rsa.crypto.https_valid', + 'google_workspace.admin.group.email': { + category: 'google_workspace', + description: "The group's primary email address.", + name: 'google_workspace.admin.group.email', type: 'keyword', }, - 'rsa.crypto.cert_ca': { - category: 'rsa', - description: 'This key is used to capture the Certificate signing authority only', - name: 'rsa.crypto.cert_ca', + 'google_workspace.admin.new_value': { + category: 'google_workspace', + description: 'The new value for the setting.', + name: 'google_workspace.admin.new_value', type: 'keyword', }, - 'rsa.crypto.cert_common': { - category: 'rsa', - description: 'This key is used to capture the Certificate common name only', - name: 'rsa.crypto.cert_common', + 'google_workspace.admin.old_value': { + category: 'google_workspace', + description: 'The old value for the setting.', + name: 'google_workspace.admin.old_value', type: 'keyword', }, - 'rsa.wireless.wlan_ssid': { - category: 'rsa', - description: 'This key is used to capture the ssid of a Wireless Session', - name: 'rsa.wireless.wlan_ssid', + 'google_workspace.admin.org_unit.name': { + category: 'google_workspace', + description: 'The organizational unit name.', + name: 'google_workspace.admin.org_unit.name', type: 'keyword', }, - 'rsa.wireless.access_point': { - category: 'rsa', - description: 'This key is used to capture the access point name.', - name: 'rsa.wireless.access_point', + 'google_workspace.admin.org_unit.full': { + category: 'google_workspace', + description: 'The org unit full path including the root org unit name.', + name: 'google_workspace.admin.org_unit.full', type: 'keyword', }, - 'rsa.wireless.wlan_channel': { - category: 'rsa', - description: 'This is used to capture the channel names', - name: 'rsa.wireless.wlan_channel', - type: 'long', - }, - 'rsa.wireless.wlan_name': { - category: 'rsa', - description: 'This key captures either WLAN number/name', - name: 'rsa.wireless.wlan_name', + 'google_workspace.admin.setting.name': { + category: 'google_workspace', + description: 'The setting name.', + name: 'google_workspace.admin.setting.name', type: 'keyword', }, - 'rsa.storage.disk_volume': { - category: 'rsa', - description: 'A unique name assigned to logical units (volumes) within a physical disk', - name: 'rsa.storage.disk_volume', + 'google_workspace.admin.user_defined_setting.name': { + category: 'google_workspace', + description: 'The name of the user-defined setting.', + name: 'google_workspace.admin.user_defined_setting.name', type: 'keyword', }, - 'rsa.storage.lun': { - category: 'rsa', - description: 'Logical Unit Number.This key is a very useful concept in Storage.', - name: 'rsa.storage.lun', + 'google_workspace.admin.setting.description': { + category: 'google_workspace', + description: 'The setting name.', + name: 'google_workspace.admin.setting.description', type: 'keyword', }, - 'rsa.storage.pwwn': { - category: 'rsa', - description: 'This uniquely identifies a port on a HBA.', - name: 'rsa.storage.pwwn', + 'google_workspace.admin.group.priorities': { + category: 'google_workspace', + description: 'Group priorities.', + name: 'google_workspace.admin.group.priorities', type: 'keyword', }, - 'rsa.physical.org_dst': { - category: 'rsa', - description: - 'This is used to capture the destination organization based on the GEOPIP Maxmind database.', - name: 'rsa.physical.org_dst', + 'google_workspace.admin.domain.alias': { + category: 'google_workspace', + description: 'The domain alias.', + name: 'google_workspace.admin.domain.alias', type: 'keyword', }, - 'rsa.physical.org_src': { - category: 'rsa', - description: - 'This is used to capture the source organization based on the GEOPIP Maxmind database.', - name: 'rsa.physical.org_src', + 'google_workspace.admin.domain.name': { + category: 'google_workspace', + description: 'The primary domain name.', + name: 'google_workspace.admin.domain.name', type: 'keyword', }, - 'rsa.healthcare.patient_fname': { - category: 'rsa', - description: - 'This key is for First Names only, this is used for Healthcare predominantly to capture Patients information', - name: 'rsa.healthcare.patient_fname', + 'google_workspace.admin.domain.secondary_name': { + category: 'google_workspace', + description: 'The secondary domain name.', + name: 'google_workspace.admin.domain.secondary_name', type: 'keyword', }, - 'rsa.healthcare.patient_id': { - category: 'rsa', - description: 'This key captures the unique ID for a patient', - name: 'rsa.healthcare.patient_id', + 'google_workspace.admin.managed_configuration': { + category: 'google_workspace', + description: 'The name of the managed configuration.', + name: 'google_workspace.admin.managed_configuration', type: 'keyword', }, - 'rsa.healthcare.patient_lname': { - category: 'rsa', + 'google_workspace.admin.non_featured_services_selection': { + category: 'google_workspace', description: - 'This key is for Last Names only, this is used for Healthcare predominantly to capture Patients information', - name: 'rsa.healthcare.patient_lname', + 'Non-featured services selection. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/admin-application-settings#FLASHLIGHT_EDU_NON_FEATURED_SERVICES_SELECTED ', + name: 'google_workspace.admin.non_featured_services_selection', type: 'keyword', }, - 'rsa.healthcare.patient_mname': { - category: 'rsa', - description: - 'This key is for Middle Names only, this is used for Healthcare predominantly to capture Patients information', - name: 'rsa.healthcare.patient_mname', + 'google_workspace.admin.field': { + category: 'google_workspace', + description: 'The name of the field.', + name: 'google_workspace.admin.field', type: 'keyword', }, - 'rsa.endpoint.host_state': { - category: 'rsa', - description: - 'This key is used to capture the current state of the machine, such as blacklisted, infected, firewall disabled and so on', - name: 'rsa.endpoint.host_state', + 'google_workspace.admin.resource.id': { + category: 'google_workspace', + description: 'The name of the resource identifier.', + name: 'google_workspace.admin.resource.id', type: 'keyword', }, - 'rsa.endpoint.registry_key': { - category: 'rsa', - description: 'This key captures the path to the registry key', - name: 'rsa.endpoint.registry_key', + 'google_workspace.admin.user.email': { + category: 'google_workspace', + description: "The user's primary email address.", + name: 'google_workspace.admin.user.email', type: 'keyword', }, - 'rsa.endpoint.registry_value': { - category: 'rsa', - description: 'This key captures values or decorators used within a registry entry', - name: 'rsa.endpoint.registry_value', + 'google_workspace.admin.user.nickname': { + category: 'google_workspace', + description: "The user's nickname.", + name: 'google_workspace.admin.user.nickname', type: 'keyword', }, - 'forcepoint.virus_id': { - category: 'forcepoint', - description: 'Virus ID ', - name: 'forcepoint.virus_id', - type: 'keyword', + 'google_workspace.admin.user.birthdate': { + category: 'google_workspace', + description: "The user's birth date.", + name: 'google_workspace.admin.user.birthdate', + type: 'date', }, - 'checkpoint.app_risk': { - category: 'checkpoint', - description: 'Application risk.', - name: 'checkpoint.app_risk', + 'google_workspace.admin.gateway.name': { + category: 'google_workspace', + description: 'Gateway name. Present on some chat settings.', + name: 'google_workspace.admin.gateway.name', type: 'keyword', }, - 'checkpoint.app_severity': { - category: 'checkpoint', - description: 'Application threat severity.', - name: 'checkpoint.app_severity', + 'google_workspace.admin.chrome_os.session_type': { + category: 'google_workspace', + description: 'Chrome OS session type.', + name: 'google_workspace.admin.chrome_os.session_type', type: 'keyword', }, - 'checkpoint.app_sig_id': { - category: 'checkpoint', - description: 'The signature ID which the application was detected by.', - name: 'checkpoint.app_sig_id', + 'google_workspace.admin.device.serial_number': { + category: 'google_workspace', + description: 'Device serial number.', + name: 'google_workspace.admin.device.serial_number', type: 'keyword', }, - 'checkpoint.auth_method': { - category: 'checkpoint', - description: 'Password authentication protocol used.', - name: 'checkpoint.auth_method', + 'google_workspace.admin.device.id': { + category: 'google_workspace', + name: 'google_workspace.admin.device.id', type: 'keyword', }, - 'checkpoint.category': { - category: 'checkpoint', - description: 'Category.', - name: 'checkpoint.category', + 'google_workspace.admin.device.type': { + category: 'google_workspace', + description: 'Device type.', + name: 'google_workspace.admin.device.type', type: 'keyword', }, - 'checkpoint.confidence_level': { - category: 'checkpoint', - description: 'Confidence level determined.', - name: 'checkpoint.confidence_level', - type: 'integer', - }, - 'checkpoint.connectivity_state': { - category: 'checkpoint', - description: 'Connectivity state.', - name: 'checkpoint.connectivity_state', + 'google_workspace.admin.print_server.name': { + category: 'google_workspace', + description: 'The name of the print server.', + name: 'google_workspace.admin.print_server.name', type: 'keyword', }, - 'checkpoint.cookie': { - category: 'checkpoint', - description: 'IKE cookie.', - name: 'checkpoint.cookie', + 'google_workspace.admin.printer.name': { + category: 'google_workspace', + description: 'The name of the printer.', + name: 'google_workspace.admin.printer.name', type: 'keyword', }, - 'checkpoint.dst_phone_number': { - category: 'checkpoint', - description: 'Destination IP-Phone.', - name: 'checkpoint.dst_phone_number', + 'google_workspace.admin.device.command_details': { + category: 'google_workspace', + description: 'Command details.', + name: 'google_workspace.admin.device.command_details', type: 'keyword', }, - 'checkpoint.email_control': { - category: 'checkpoint', - description: 'Engine name.', - name: 'checkpoint.email_control', + 'google_workspace.admin.role.id': { + category: 'google_workspace', + description: 'Unique identifier for this role privilege.', + name: 'google_workspace.admin.role.id', type: 'keyword', }, - 'checkpoint.email_id': { - category: 'checkpoint', - description: 'Internal email ID.', - name: 'checkpoint.email_id', + 'google_workspace.admin.role.name': { + category: 'google_workspace', + description: + 'The role name. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/admin-delegated-admin-settings ', + name: 'google_workspace.admin.role.name', type: 'keyword', }, - 'checkpoint.email_recipients_num': { - category: 'checkpoint', - description: 'Number of recipients.', - name: 'checkpoint.email_recipients_num', - type: 'long', - }, - 'checkpoint.email_session_id': { - category: 'checkpoint', - description: 'Internal email session ID.', - name: 'checkpoint.email_session_id', + 'google_workspace.admin.privilege.name': { + category: 'google_workspace', + description: 'Privilege name.', + name: 'google_workspace.admin.privilege.name', type: 'keyword', }, - 'checkpoint.email_spool_id': { - category: 'checkpoint', - description: 'Internal email spool ID.', - name: 'checkpoint.email_spool_id', + 'google_workspace.admin.service.name': { + category: 'google_workspace', + description: 'The service name.', + name: 'google_workspace.admin.service.name', type: 'keyword', }, - 'checkpoint.email_subject': { - category: 'checkpoint', - description: 'Email subject.', - name: 'checkpoint.email_subject', + 'google_workspace.admin.url.name': { + category: 'google_workspace', + description: 'The website name.', + name: 'google_workspace.admin.url.name', type: 'keyword', }, - 'checkpoint.event_count': { - category: 'checkpoint', - description: 'Number of events associated with the log.', - name: 'checkpoint.event_count', - type: 'long', + 'google_workspace.admin.product.name': { + category: 'google_workspace', + description: 'The product name.', + name: 'google_workspace.admin.product.name', + type: 'keyword', }, - 'checkpoint.frequency': { - category: 'checkpoint', - description: 'Scan frequency.', - name: 'checkpoint.frequency', + 'google_workspace.admin.product.sku': { + category: 'google_workspace', + description: 'The product SKU.', + name: 'google_workspace.admin.product.sku', type: 'keyword', }, - 'checkpoint.icmp_type': { - category: 'checkpoint', - description: 'ICMP type.', - name: 'checkpoint.icmp_type', + 'google_workspace.admin.bulk_upload.failed': { + category: 'google_workspace', + description: 'Number of failed records in bulk upload operation.', + name: 'google_workspace.admin.bulk_upload.failed', type: 'long', }, - 'checkpoint.icmp_code': { - category: 'checkpoint', - description: 'ICMP code.', - name: 'checkpoint.icmp_code', + 'google_workspace.admin.bulk_upload.total': { + category: 'google_workspace', + description: 'Number of total records in bulk upload operation.', + name: 'google_workspace.admin.bulk_upload.total', type: 'long', }, - 'checkpoint.identity_type': { - category: 'checkpoint', - description: 'Identity type.', - name: 'checkpoint.identity_type', - type: 'keyword', - }, - 'checkpoint.incident_extension': { - category: 'checkpoint', - description: 'Format of original data.', - name: 'checkpoint.incident_extension', + 'google_workspace.admin.group.allowed_list': { + category: 'google_workspace', + description: 'Names of allow-listed groups.', + name: 'google_workspace.admin.group.allowed_list', type: 'keyword', }, - 'checkpoint.integrity_av_invoke_type': { - category: 'checkpoint', - description: 'Scan invoke type.', - name: 'checkpoint.integrity_av_invoke_type', + 'google_workspace.admin.email.quarantine_name': { + category: 'google_workspace', + description: 'The name of the quarantine.', + name: 'google_workspace.admin.email.quarantine_name', type: 'keyword', }, - 'checkpoint.malware_family': { - category: 'checkpoint', - description: 'Malware family.', - name: 'checkpoint.malware_family', + 'google_workspace.admin.email.log_search_filter.message_id': { + category: 'google_workspace', + description: "The log search filter's email message ID.", + name: 'google_workspace.admin.email.log_search_filter.message_id', type: 'keyword', }, - 'checkpoint.peer_gateway': { - category: 'checkpoint', - description: 'Main IP of the peer Security Gateway.', - name: 'checkpoint.peer_gateway', - type: 'ip', + 'google_workspace.admin.email.log_search_filter.start_date': { + category: 'google_workspace', + description: "The log search filter's start date.", + name: 'google_workspace.admin.email.log_search_filter.start_date', + type: 'date', }, - 'checkpoint.performance_impact': { - category: 'checkpoint', - description: 'Protection performance impact.', - name: 'checkpoint.performance_impact', - type: 'integer', + 'google_workspace.admin.email.log_search_filter.end_date': { + category: 'google_workspace', + description: "The log search filter's ending date.", + name: 'google_workspace.admin.email.log_search_filter.end_date', + type: 'date', }, - 'checkpoint.protection_id': { - category: 'checkpoint', - description: 'Protection malware ID.', - name: 'checkpoint.protection_id', + 'google_workspace.admin.email.log_search_filter.recipient.value': { + category: 'google_workspace', + description: "The log search filter's email recipient.", + name: 'google_workspace.admin.email.log_search_filter.recipient.value', type: 'keyword', }, - 'checkpoint.protection_name': { - category: 'checkpoint', - description: 'Specific signature name of the attack.', - name: 'checkpoint.protection_name', + 'google_workspace.admin.email.log_search_filter.sender.value': { + category: 'google_workspace', + description: "The log search filter's email sender.", + name: 'google_workspace.admin.email.log_search_filter.sender.value', type: 'keyword', }, - 'checkpoint.protection_type': { - category: 'checkpoint', - description: 'Type of protection used to detect the attack.', - name: 'checkpoint.protection_type', + 'google_workspace.admin.email.log_search_filter.recipient.ip': { + category: 'google_workspace', + description: "The log search filter's email recipient's IP address.", + name: 'google_workspace.admin.email.log_search_filter.recipient.ip', + type: 'ip', + }, + 'google_workspace.admin.email.log_search_filter.sender.ip': { + category: 'google_workspace', + description: "The log search filter's email sender's IP address.", + name: 'google_workspace.admin.email.log_search_filter.sender.ip', + type: 'ip', + }, + 'google_workspace.admin.chrome_licenses.enabled': { + category: 'google_workspace', + description: + 'Licences enabled. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/admin-org-settings ', + name: 'google_workspace.admin.chrome_licenses.enabled', type: 'keyword', }, - 'checkpoint.scan_result': { - category: 'checkpoint', - description: 'Scan result.', - name: 'checkpoint.scan_result', + 'google_workspace.admin.chrome_licenses.allowed': { + category: 'google_workspace', + description: + 'Licences enabled. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/admin-org-settings ', + name: 'google_workspace.admin.chrome_licenses.allowed', type: 'keyword', }, - 'checkpoint.sensor_mode': { - category: 'checkpoint', - description: 'Sensor mode.', - name: 'checkpoint.sensor_mode', + 'google_workspace.admin.oauth2.service.name': { + category: 'google_workspace', + description: + 'OAuth2 service name. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/admin-security-settings ', + name: 'google_workspace.admin.oauth2.service.name', type: 'keyword', }, - 'checkpoint.severity': { - category: 'checkpoint', - description: 'Threat severity.', - name: 'checkpoint.severity', + 'google_workspace.admin.oauth2.application.id': { + category: 'google_workspace', + description: 'OAuth2 application ID.', + name: 'google_workspace.admin.oauth2.application.id', type: 'keyword', }, - 'checkpoint.spyware_name': { - category: 'checkpoint', - description: 'Spyware name.', - name: 'checkpoint.spyware_name', + 'google_workspace.admin.oauth2.application.name': { + category: 'google_workspace', + description: 'OAuth2 application name.', + name: 'google_workspace.admin.oauth2.application.name', type: 'keyword', }, - 'checkpoint.spyware_status': { - category: 'checkpoint', - description: 'Spyware status.', - name: 'checkpoint.spyware_status', + 'google_workspace.admin.oauth2.application.type': { + category: 'google_workspace', + description: + 'OAuth2 application type. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/admin-security-settings ', + name: 'google_workspace.admin.oauth2.application.type', type: 'keyword', }, - 'checkpoint.subs_exp': { - category: 'checkpoint', - description: 'The expiration date of the subscription.', - name: 'checkpoint.subs_exp', - type: 'date', + 'google_workspace.admin.verification_method': { + category: 'google_workspace', + description: + 'Related verification method. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/admin-security-settings and https://developers.google.com/admin-sdk/reports/v1/appendix/activity/admin-domain-settings ', + name: 'google_workspace.admin.verification_method', + type: 'keyword', }, - 'checkpoint.tcp_flags': { - category: 'checkpoint', - description: 'TCP packet flags.', - name: 'checkpoint.tcp_flags', + 'google_workspace.admin.alert.name': { + category: 'google_workspace', + description: 'The alert name.', + name: 'google_workspace.admin.alert.name', type: 'keyword', }, - 'checkpoint.termination_reason': { - category: 'checkpoint', - description: 'Termination reason.', - name: 'checkpoint.termination_reason', + 'google_workspace.admin.rule.name': { + category: 'google_workspace', + description: 'The rule name.', + name: 'google_workspace.admin.rule.name', type: 'keyword', }, - 'checkpoint.update_status': { - category: 'checkpoint', - description: 'Update status.', - name: 'checkpoint.update_status', + 'google_workspace.admin.api.client.name': { + category: 'google_workspace', + description: 'The API client name.', + name: 'google_workspace.admin.api.client.name', type: 'keyword', }, - 'checkpoint.user_status': { - category: 'checkpoint', - description: 'User response.', - name: 'checkpoint.user_status', + 'google_workspace.admin.api.scopes': { + category: 'google_workspace', + description: 'The API scopes.', + name: 'google_workspace.admin.api.scopes', type: 'keyword', }, - 'checkpoint.uuid': { - category: 'checkpoint', - description: 'External ID.', - name: 'checkpoint.uuid', + 'google_workspace.admin.mdm.token': { + category: 'google_workspace', + description: 'The MDM vendor enrollment token.', + name: 'google_workspace.admin.mdm.token', type: 'keyword', }, - 'checkpoint.virus_name': { - category: 'checkpoint', - description: 'Virus name.', - name: 'checkpoint.virus_name', + 'google_workspace.admin.mdm.vendor': { + category: 'google_workspace', + description: "The MDM vendor's name.", + name: 'google_workspace.admin.mdm.vendor', type: 'keyword', }, - 'checkpoint.voip_log_type': { - category: 'checkpoint', - description: 'VoIP log types.', - name: 'checkpoint.voip_log_type', + 'google_workspace.admin.info_type': { + category: 'google_workspace', + description: + 'This will be used to state what kind of information was changed. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/admin-domain-settings ', + name: 'google_workspace.admin.info_type', type: 'keyword', }, - 'cef.extensions.cp_app_risk': { - category: 'cef', - name: 'cef.extensions.cp_app_risk', + 'google_workspace.admin.email_monitor.dest_email': { + category: 'google_workspace', + description: 'The destination address of the email monitor.', + name: 'google_workspace.admin.email_monitor.dest_email', type: 'keyword', }, - 'cef.extensions.cp_severity': { - category: 'cef', - name: 'cef.extensions.cp_severity', + 'google_workspace.admin.email_monitor.level.chat': { + category: 'google_workspace', + description: 'The chat email monitor level.', + name: 'google_workspace.admin.email_monitor.level.chat', type: 'keyword', }, - 'cef.extensions.ifname': { - category: 'cef', - name: 'cef.extensions.ifname', + 'google_workspace.admin.email_monitor.level.draft': { + category: 'google_workspace', + description: 'The draft email monitor level.', + name: 'google_workspace.admin.email_monitor.level.draft', type: 'keyword', }, - 'cef.extensions.inzone': { - category: 'cef', - name: 'cef.extensions.inzone', + 'google_workspace.admin.email_monitor.level.incoming': { + category: 'google_workspace', + description: 'The incoming email monitor level.', + name: 'google_workspace.admin.email_monitor.level.incoming', type: 'keyword', }, - 'cef.extensions.layer_uuid': { - category: 'cef', - name: 'cef.extensions.layer_uuid', + 'google_workspace.admin.email_monitor.level.outgoing': { + category: 'google_workspace', + description: 'The outgoing email monitor level.', + name: 'google_workspace.admin.email_monitor.level.outgoing', type: 'keyword', }, - 'cef.extensions.layer_name': { - category: 'cef', - name: 'cef.extensions.layer_name', + 'google_workspace.admin.email_dump.include_deleted': { + category: 'google_workspace', + description: 'Indicates if deleted emails are included in the export.', + name: 'google_workspace.admin.email_dump.include_deleted', + type: 'boolean', + }, + 'google_workspace.admin.email_dump.package_content': { + category: 'google_workspace', + description: 'The contents of the mailbox package.', + name: 'google_workspace.admin.email_dump.package_content', type: 'keyword', }, - 'cef.extensions.logid': { - category: 'cef', - name: 'cef.extensions.logid', + 'google_workspace.admin.email_dump.query': { + category: 'google_workspace', + description: 'The search query used for the dump.', + name: 'google_workspace.admin.email_dump.query', type: 'keyword', }, - 'cef.extensions.loguid': { - category: 'cef', - name: 'cef.extensions.loguid', + 'google_workspace.admin.request.id': { + category: 'google_workspace', + description: 'The request ID.', + name: 'google_workspace.admin.request.id', type: 'keyword', }, - 'cef.extensions.match_id': { - category: 'cef', - name: 'cef.extensions.match_id', + 'google_workspace.admin.mobile.action.id': { + category: 'google_workspace', + description: "The mobile device action's ID.", + name: 'google_workspace.admin.mobile.action.id', type: 'keyword', }, - 'cef.extensions.nat_addtnl_rulenum': { - category: 'cef', - name: 'cef.extensions.nat_addtnl_rulenum', + 'google_workspace.admin.mobile.action.type': { + category: 'google_workspace', + description: + "The mobile device action's type. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/admin-mobile-settings ", + name: 'google_workspace.admin.mobile.action.type', type: 'keyword', }, - 'cef.extensions.nat_rulenum': { - category: 'cef', - name: 'cef.extensions.nat_rulenum', + 'google_workspace.admin.mobile.certificate.name': { + category: 'google_workspace', + description: 'The mobile certificate common name.', + name: 'google_workspace.admin.mobile.certificate.name', type: 'keyword', }, - 'cef.extensions.origin': { - category: 'cef', - name: 'cef.extensions.origin', + 'google_workspace.admin.mobile.company_owned_devices': { + category: 'google_workspace', + description: 'The number of devices a company owns.', + name: 'google_workspace.admin.mobile.company_owned_devices', + type: 'long', + }, + 'google_workspace.admin.distribution.entity.name': { + category: 'google_workspace', + description: + 'The distribution entity value, which can be a group name or an org-unit name. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/admin-mobile-settings ', + name: 'google_workspace.admin.distribution.entity.name', type: 'keyword', }, - 'cef.extensions.originsicname': { - category: 'cef', - name: 'cef.extensions.originsicname', + 'google_workspace.admin.distribution.entity.type': { + category: 'google_workspace', + description: + 'The distribution entity type, which can be a group or an org-unit. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/admin-mobile-settings ', + name: 'google_workspace.admin.distribution.entity.type', type: 'keyword', }, - 'cef.extensions.outzone': { - category: 'cef', - name: 'cef.extensions.outzone', + 'google_workspace.drive.billable': { + category: 'google_workspace', + description: 'Whether this activity is billable.', + name: 'google_workspace.drive.billable', + type: 'boolean', + }, + 'google_workspace.drive.source_folder_id': { + category: 'google_workspace', + name: 'google_workspace.drive.source_folder_id', type: 'keyword', }, - 'cef.extensions.parent_rule': { - category: 'cef', - name: 'cef.extensions.parent_rule', + 'google_workspace.drive.source_folder_title': { + category: 'google_workspace', + name: 'google_workspace.drive.source_folder_title', type: 'keyword', }, - 'cef.extensions.product': { - category: 'cef', - name: 'cef.extensions.product', + 'google_workspace.drive.destination_folder_id': { + category: 'google_workspace', + name: 'google_workspace.drive.destination_folder_id', type: 'keyword', }, - 'cef.extensions.rule_action': { - category: 'cef', - name: 'cef.extensions.rule_action', + 'google_workspace.drive.destination_folder_title': { + category: 'google_workspace', + name: 'google_workspace.drive.destination_folder_title', type: 'keyword', }, - 'cef.extensions.rule_uid': { - category: 'cef', - name: 'cef.extensions.rule_uid', + 'google_workspace.drive.file.id': { + category: 'google_workspace', + name: 'google_workspace.drive.file.id', type: 'keyword', }, - 'cef.extensions.sequencenum': { - category: 'cef', - name: 'cef.extensions.sequencenum', + 'google_workspace.drive.file.type': { + category: 'google_workspace', + description: + 'Document Drive type. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/drive ', + name: 'google_workspace.drive.file.type', type: 'keyword', }, - 'cef.extensions.service_id': { - category: 'cef', - name: 'cef.extensions.service_id', + 'google_workspace.drive.originating_app_id': { + category: 'google_workspace', + description: 'The Google Cloud Project ID of the application that performed the action. ', + name: 'google_workspace.drive.originating_app_id', type: 'keyword', }, - 'cef.extensions.version': { - category: 'cef', - name: 'cef.extensions.version', + 'google_workspace.drive.file.owner.email': { + category: 'google_workspace', + name: 'google_workspace.drive.file.owner.email', type: 'keyword', }, - 'checkpoint.calc_desc': { - category: 'checkpoint', - description: 'Log description. ', - name: 'checkpoint.calc_desc', + 'google_workspace.drive.file.owner.is_shared_drive': { + category: 'google_workspace', + description: 'Boolean flag denoting whether owner is a shared drive. ', + name: 'google_workspace.drive.file.owner.is_shared_drive', + type: 'boolean', + }, + 'google_workspace.drive.primary_event': { + category: 'google_workspace', + description: + 'Whether this is a primary event. A single user action in Drive may generate several events. ', + name: 'google_workspace.drive.primary_event', + type: 'boolean', + }, + 'google_workspace.drive.shared_drive_id': { + category: 'google_workspace', + description: + 'The unique identifier of the Team Drive. Only populated for for events relating to a Team Drive or item contained inside a Team Drive. ', + name: 'google_workspace.drive.shared_drive_id', type: 'keyword', }, - 'checkpoint.dst_country': { - category: 'checkpoint', - description: 'Destination country. ', - name: 'checkpoint.dst_country', + 'google_workspace.drive.visibility': { + category: 'google_workspace', + description: + 'Visibility of target file. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/drive ', + name: 'google_workspace.drive.visibility', type: 'keyword', }, - 'checkpoint.dst_user_name': { - category: 'checkpoint', - description: 'Connected user name on the destination IP. ', - name: 'checkpoint.dst_user_name', + 'google_workspace.drive.new_value': { + category: 'google_workspace', + description: + 'When a setting or property of the file changes, the new value for it will appear here. ', + name: 'google_workspace.drive.new_value', type: 'keyword', }, - 'checkpoint.sys_message': { - category: 'checkpoint', - description: 'System messages ', - name: 'checkpoint.sys_message', + 'google_workspace.drive.old_value': { + category: 'google_workspace', + description: + 'When a setting or property of the file changes, the old value for it will appear here. ', + name: 'google_workspace.drive.old_value', type: 'keyword', }, - 'checkpoint.logid': { - category: 'checkpoint', - description: 'System messages ', - name: 'checkpoint.logid', + 'google_workspace.drive.sheets_import_range_recipient_doc': { + category: 'google_workspace', + description: 'Doc ID of the recipient of a sheets import range.', + name: 'google_workspace.drive.sheets_import_range_recipient_doc', type: 'keyword', }, - 'checkpoint.failure_impact': { - category: 'checkpoint', - description: 'The impact of update service failure. ', - name: 'checkpoint.failure_impact', + 'google_workspace.drive.old_visibility': { + category: 'google_workspace', + description: 'When visibility changes, this holds the old value. ', + name: 'google_workspace.drive.old_visibility', type: 'keyword', }, - 'checkpoint.id': { - category: 'checkpoint', - description: 'Override application ID. ', - name: 'checkpoint.id', - type: 'integer', + 'google_workspace.drive.visibility_change': { + category: 'google_workspace', + description: 'When visibility changes, this holds the new overall visibility of the file. ', + name: 'google_workspace.drive.visibility_change', + type: 'keyword', }, - 'checkpoint.information': { - category: 'checkpoint', - description: 'Policy installation status for a specific blade. ', - name: 'checkpoint.information', + 'google_workspace.drive.target_domain': { + category: 'google_workspace', + description: + 'The domain for which the acccess scope was changed. This can also be the alias all to indicate the access scope was changed for all domains that have visibility for this document. ', + name: 'google_workspace.drive.target_domain', type: 'keyword', }, - 'checkpoint.layer_name': { - category: 'checkpoint', - description: 'Layer name. ', - name: 'checkpoint.layer_name', + 'google_workspace.drive.added_role': { + category: 'google_workspace', + description: + 'Added membership role of a user/group in a Team Drive. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/drive ', + name: 'google_workspace.drive.added_role', type: 'keyword', }, - 'checkpoint.layer_uuid': { - category: 'checkpoint', - description: 'Layer UUID. ', - name: 'checkpoint.layer_uuid', + 'google_workspace.drive.membership_change_type': { + category: 'google_workspace', + description: + 'Type of change in Team Drive membership of a user/group. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/drive ', + name: 'google_workspace.drive.membership_change_type', type: 'keyword', }, - 'checkpoint.log_id': { - category: 'checkpoint', - description: 'Unique identity for logs. ', - name: 'checkpoint.log_id', - type: 'integer', + 'google_workspace.drive.shared_drive_settings_change_type': { + category: 'google_workspace', + description: + 'Type of change in Team Drive settings. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/drive ', + name: 'google_workspace.drive.shared_drive_settings_change_type', + type: 'keyword', }, - 'checkpoint.origin_sic_name': { - category: 'checkpoint', - description: 'Machine SIC. ', - name: 'checkpoint.origin_sic_name', + 'google_workspace.drive.removed_role': { + category: 'google_workspace', + description: + 'Removed membership role of a user/group in a Team Drive. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/drive ', + name: 'google_workspace.drive.removed_role', type: 'keyword', }, - 'checkpoint.policy_mgmt': { - category: 'checkpoint', - description: 'Name of the Management Server that manages this Security Gateway. ', - name: 'checkpoint.policy_mgmt', + 'google_workspace.drive.target': { + category: 'google_workspace', + description: 'Target user or group.', + name: 'google_workspace.drive.target', type: 'keyword', }, - 'checkpoint.policy_name': { - category: 'checkpoint', - description: 'Name of the last policy that this Security Gateway fetched. ', - name: 'checkpoint.policy_name', + 'google_workspace.groups.acl_permission': { + category: 'google_workspace', + description: + 'Group permission setting updated. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/groups ', + name: 'google_workspace.groups.acl_permission', type: 'keyword', }, - 'checkpoint.protocol': { - category: 'checkpoint', - description: 'Protocol detected on the connection. ', - name: 'checkpoint.protocol', + 'google_workspace.groups.email': { + category: 'google_workspace', + description: 'Group email. ', + name: 'google_workspace.groups.email', type: 'keyword', }, - 'checkpoint.proxy_src_ip': { - category: 'checkpoint', - description: 'Sender source IP (even when using proxy). ', - name: 'checkpoint.proxy_src_ip', - type: 'ip', + 'google_workspace.groups.member.email': { + category: 'google_workspace', + description: 'Member email. ', + name: 'google_workspace.groups.member.email', + type: 'keyword', }, - 'checkpoint.rule': { - category: 'checkpoint', - description: 'Matched rule number. ', - name: 'checkpoint.rule', - type: 'integer', + 'google_workspace.groups.member.role': { + category: 'google_workspace', + description: + 'Member role. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/groups ', + name: 'google_workspace.groups.member.role', + type: 'keyword', }, - 'checkpoint.rule_action': { - category: 'checkpoint', - description: 'Action of the matched rule in the access policy. ', - name: 'checkpoint.rule_action', + 'google_workspace.groups.setting': { + category: 'google_workspace', + description: + 'Group setting updated. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/groups ', + name: 'google_workspace.groups.setting', type: 'keyword', }, - 'checkpoint.scan_direction': { - category: 'checkpoint', - description: 'Scan direction. ', - name: 'checkpoint.scan_direction', + 'google_workspace.groups.new_value': { + category: 'google_workspace', + description: + 'New value(s) of the group setting. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/groups ', + name: 'google_workspace.groups.new_value', type: 'keyword', }, - 'checkpoint.session_id': { - category: 'checkpoint', - description: 'Log uuid. ', - name: 'checkpoint.session_id', + 'google_workspace.groups.old_value': { + category: 'google_workspace', + description: + 'Old value(s) of the group setting. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/groups', + name: 'google_workspace.groups.old_value', type: 'keyword', }, - 'checkpoint.source_os': { - category: 'checkpoint', - description: 'OS which generated the attack. ', - name: 'checkpoint.source_os', + 'google_workspace.groups.value': { + category: 'google_workspace', + description: + 'Value of the group setting. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/groups ', + name: 'google_workspace.groups.value', type: 'keyword', }, - 'checkpoint.src_country': { - category: 'checkpoint', - description: 'Country name, derived from connection source IP address. ', - name: 'checkpoint.src_country', + 'google_workspace.groups.message.id': { + category: 'google_workspace', + description: 'SMTP message Id of an email message. Present for moderation events. ', + name: 'google_workspace.groups.message.id', type: 'keyword', }, - 'checkpoint.src_user_name': { - category: 'checkpoint', - description: 'User name connected to source IP ', - name: 'checkpoint.src_user_name', + 'google_workspace.groups.message.moderation_action': { + category: 'google_workspace', + description: 'Message moderation action. Possible values are `approved` and `rejected`. ', + name: 'google_workspace.groups.message.moderation_action', type: 'keyword', }, - 'checkpoint.ticket_id': { - category: 'checkpoint', - description: 'Unique ID per file. ', - name: 'checkpoint.ticket_id', + 'google_workspace.groups.status': { + category: 'google_workspace', + description: + 'A status describing the output of an operation. Possible values are `failed` and `succeeded`. ', + name: 'google_workspace.groups.status', type: 'keyword', }, - 'checkpoint.tls_server_host_name': { - category: 'checkpoint', - description: 'SNI/CN from encrypted TLS connection used by URLF for categorization. ', - name: 'checkpoint.tls_server_host_name', + 'google_workspace.login.affected_email_address': { + category: 'google_workspace', + name: 'google_workspace.login.affected_email_address', type: 'keyword', }, - 'checkpoint.verdict': { - category: 'checkpoint', - description: 'TE engine verdict Possible values: Malicious/Benign/Error. ', - name: 'checkpoint.verdict', + 'google_workspace.login.challenge_method': { + category: 'google_workspace', + description: + 'Login challenge method. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/login. ', + name: 'google_workspace.login.challenge_method', type: 'keyword', }, - 'checkpoint.user': { - category: 'checkpoint', - description: 'Source user name. ', - name: 'checkpoint.user', + 'google_workspace.login.failure_type': { + category: 'google_workspace', + description: + 'Login failure type. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/login. ', + name: 'google_workspace.login.failure_type', type: 'keyword', }, - 'checkpoint.vendor_list': { - category: 'checkpoint', - description: 'The vendor name that provided the verdict for a malicious URL. ', - name: 'checkpoint.vendor_list', + 'google_workspace.login.type': { + category: 'google_workspace', + description: + 'Login credentials type. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/login. ', + name: 'google_workspace.login.type', type: 'keyword', }, - 'checkpoint.web_server_type': { - category: 'checkpoint', - description: 'Web server detected in the HTTP response. ', - name: 'checkpoint.web_server_type', + 'google_workspace.login.is_second_factor': { + category: 'google_workspace', + name: 'google_workspace.login.is_second_factor', + type: 'boolean', + }, + 'google_workspace.login.is_suspicious': { + category: 'google_workspace', + name: 'google_workspace.login.is_suspicious', + type: 'boolean', + }, + 'google_workspace.saml.application_name': { + category: 'google_workspace', + description: 'Saml SP application name. ', + name: 'google_workspace.saml.application_name', type: 'keyword', }, - 'checkpoint.client_name': { - category: 'checkpoint', - description: 'Client Application or Software Blade that detected the event. ', - name: 'checkpoint.client_name', + 'google_workspace.saml.failure_type': { + category: 'google_workspace', + description: + 'Login failure type. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/saml. ', + name: 'google_workspace.saml.failure_type', type: 'keyword', }, - 'checkpoint.client_version': { - category: 'checkpoint', - description: 'Build version of SandBlast Agent client installed on the computer. ', - name: 'checkpoint.client_version', + 'google_workspace.saml.initiated_by': { + category: 'google_workspace', + description: 'Requester of SAML authentication. ', + name: 'google_workspace.saml.initiated_by', type: 'keyword', }, - 'checkpoint.extension_version': { - category: 'checkpoint', - description: 'Build version of the SandBlast Agent browser extension. ', - name: 'checkpoint.extension_version', + 'google_workspace.saml.orgunit_path': { + category: 'google_workspace', + description: 'User orgunit. ', + name: 'google_workspace.saml.orgunit_path', type: 'keyword', }, - 'checkpoint.host_time': { - category: 'checkpoint', - description: 'Local time on the endpoint computer. ', - name: 'checkpoint.host_time', + 'google_workspace.saml.status_code': { + category: 'google_workspace', + description: 'SAML status code. ', + name: 'google_workspace.saml.status_code', type: 'keyword', }, - 'checkpoint.installed_products': { - category: 'checkpoint', - description: 'List of installed Endpoint Software Blades. ', - name: 'checkpoint.installed_products', + 'google_workspace.saml.second_level_status_code': { + category: 'google_workspace', + description: 'SAML second level status code. ', + name: 'google_workspace.saml.second_level_status_code', type: 'keyword', }, - 'checkpoint.cc': { - category: 'checkpoint', - description: 'The Carbon Copy address of the email. ', - name: 'checkpoint.cc', + 'ibmmq.errorlog.installation': { + category: 'ibmmq', + description: + 'This is the installation name which can be given at installation time. Each installation of IBM MQ on UNIX, Linux, and Windows, has a unique identifier known as an installation name. The installation name is used to associate things such as queue managers and configuration files with an installation. ', + name: 'ibmmq.errorlog.installation', type: 'keyword', }, - 'checkpoint.parent_process_username': { - category: 'checkpoint', - description: 'Owner username of the parent process of the process that triggered the attack. ', - name: 'checkpoint.parent_process_username', + 'ibmmq.errorlog.qmgr': { + category: 'ibmmq', + description: + 'Name of the queue manager. Queue managers provide queuing services to applications, and manages the queues that belong to them. ', + name: 'ibmmq.errorlog.qmgr', type: 'keyword', }, - 'checkpoint.process_username': { - category: 'checkpoint', - description: 'Owner username of the process that triggered the attack. ', - name: 'checkpoint.process_username', + 'ibmmq.errorlog.arithinsert': { + category: 'ibmmq', + description: 'Changing content based on error.id', + name: 'ibmmq.errorlog.arithinsert', type: 'keyword', }, - 'checkpoint.audit_status': { - category: 'checkpoint', - description: 'Audit Status. Can be Success or Failure. ', - name: 'checkpoint.audit_status', + 'ibmmq.errorlog.commentinsert': { + category: 'ibmmq', + description: 'Changing content based on error.id', + name: 'ibmmq.errorlog.commentinsert', type: 'keyword', }, - 'checkpoint.objecttable': { - category: 'checkpoint', - description: 'Table of affected objects. ', - name: 'checkpoint.objecttable', + 'ibmmq.errorlog.errordescription': { + category: 'ibmmq', + description: 'Please add description', + example: 'Please add example', + name: 'ibmmq.errorlog.errordescription', + type: 'text', + }, + 'ibmmq.errorlog.explanation': { + category: 'ibmmq', + description: 'Explaines the error in more detail', + name: 'ibmmq.errorlog.explanation', type: 'keyword', }, - 'checkpoint.objecttype': { - category: 'checkpoint', - description: 'The type of the affected object. ', - name: 'checkpoint.objecttype', + 'ibmmq.errorlog.action': { + category: 'ibmmq', + description: 'Defines what to do when the error occurs', + name: 'ibmmq.errorlog.action', type: 'keyword', }, - 'checkpoint.operation_number': { - category: 'checkpoint', - description: 'The operation nuber. ', - name: 'checkpoint.operation_number', + 'ibmmq.errorlog.code': { + category: 'ibmmq', + description: 'Error code.', + name: 'ibmmq.errorlog.code', type: 'keyword', }, - 'checkpoint.suppressed_logs': { - category: 'checkpoint', - description: - 'Aggregated connections for five minutes on the same source, destination and port. ', - name: 'checkpoint.suppressed_logs', + 'iptables.ether_type': { + category: 'iptables', + description: 'Value of the ethernet type field identifying the network layer protocol. ', + name: 'iptables.ether_type', + type: 'long', + }, + 'iptables.flow_label': { + category: 'iptables', + description: 'IPv6 flow label. ', + name: 'iptables.flow_label', type: 'integer', }, - 'checkpoint.blade_name': { - category: 'checkpoint', - description: 'Blade name. ', - name: 'checkpoint.blade_name', + 'iptables.fragment_flags': { + category: 'iptables', + description: 'IP fragment flags. A combination of CE, DF and MF. ', + name: 'iptables.fragment_flags', type: 'keyword', }, - 'checkpoint.status': { - category: 'checkpoint', - description: 'Ok/Warning/Error. ', - name: 'checkpoint.status', - type: 'keyword', + 'iptables.fragment_offset': { + category: 'iptables', + description: 'Offset of the current IP fragment. ', + name: 'iptables.fragment_offset', + type: 'long', }, - 'checkpoint.short_desc': { - category: 'checkpoint', - description: 'Short description of the process that was executed. ', - name: 'checkpoint.short_desc', - type: 'keyword', + 'iptables.icmp.code': { + category: 'iptables', + description: 'ICMP code. ', + name: 'iptables.icmp.code', + type: 'long', }, - 'checkpoint.long_desc': { - category: 'checkpoint', - description: 'More information on the process (usually describing error reason in failure). ', - name: 'checkpoint.long_desc', + 'iptables.icmp.id': { + category: 'iptables', + description: 'ICMP ID. ', + name: 'iptables.icmp.id', + type: 'long', + }, + 'iptables.icmp.parameter': { + category: 'iptables', + description: 'ICMP parameter. ', + name: 'iptables.icmp.parameter', + type: 'long', + }, + 'iptables.icmp.redirect': { + category: 'iptables', + description: 'ICMP redirect address. ', + name: 'iptables.icmp.redirect', + type: 'ip', + }, + 'iptables.icmp.seq': { + category: 'iptables', + description: 'ICMP sequence number. ', + name: 'iptables.icmp.seq', + type: 'long', + }, + 'iptables.icmp.type': { + category: 'iptables', + description: 'ICMP type. ', + name: 'iptables.icmp.type', + type: 'long', + }, + 'iptables.id': { + category: 'iptables', + description: 'Packet identifier. ', + name: 'iptables.id', + type: 'long', + }, + 'iptables.incomplete_bytes': { + category: 'iptables', + description: 'Number of incomplete bytes. ', + name: 'iptables.incomplete_bytes', + type: 'long', + }, + 'iptables.input_device': { + category: 'iptables', + description: 'Device that received the packet. ', + name: 'iptables.input_device', type: 'keyword', }, - 'checkpoint.scan_hosts_hour': { - category: 'checkpoint', - description: 'Number of unique hosts during the last hour. ', - name: 'checkpoint.scan_hosts_hour', - type: 'integer', + 'iptables.precedence_bits': { + category: 'iptables', + description: 'IP precedence bits. ', + name: 'iptables.precedence_bits', + type: 'short', }, - 'checkpoint.scan_hosts_day': { - category: 'checkpoint', - description: 'Number of unique hosts during the last day. ', - name: 'checkpoint.scan_hosts_day', - type: 'integer', + 'iptables.tos': { + category: 'iptables', + description: 'IP Type of Service field. ', + name: 'iptables.tos', + type: 'long', + }, + 'iptables.length': { + category: 'iptables', + description: 'Packet length. ', + name: 'iptables.length', + type: 'long', + }, + 'iptables.output_device': { + category: 'iptables', + description: 'Device that output the packet. ', + name: 'iptables.output_device', + type: 'keyword', }, - 'checkpoint.scan_hosts_week': { - category: 'checkpoint', - description: 'Number of unique hosts during the last week. ', - name: 'checkpoint.scan_hosts_week', - type: 'integer', + 'iptables.tcp.flags': { + category: 'iptables', + description: 'TCP flags. ', + name: 'iptables.tcp.flags', + type: 'keyword', }, - 'checkpoint.unique_detected_hour': { - category: 'checkpoint', - description: 'Detected virus for a specific host during the last hour. ', - name: 'checkpoint.unique_detected_hour', - type: 'integer', + 'iptables.tcp.reserved_bits': { + category: 'iptables', + description: 'TCP reserved bits. ', + name: 'iptables.tcp.reserved_bits', + type: 'short', }, - 'checkpoint.unique_detected_day': { - category: 'checkpoint', - description: 'Detected virus for a specific host during the last day. ', - name: 'checkpoint.unique_detected_day', - type: 'integer', + 'iptables.tcp.seq': { + category: 'iptables', + description: 'TCP sequence number. ', + name: 'iptables.tcp.seq', + type: 'long', }, - 'checkpoint.unique_detected_week': { - category: 'checkpoint', - description: 'Detected virus for a specific host during the last week. ', - name: 'checkpoint.unique_detected_week', - type: 'integer', + 'iptables.tcp.ack': { + category: 'iptables', + description: 'TCP Acknowledgment number. ', + name: 'iptables.tcp.ack', + type: 'long', }, - 'checkpoint.scan_mail': { - category: 'checkpoint', - description: 'Number of emails that were scanned by "AB malicious activity" engine. ', - name: 'checkpoint.scan_mail', + 'iptables.tcp.window': { + category: 'iptables', + description: 'Advertised TCP window size. ', + name: 'iptables.tcp.window', + type: 'long', + }, + 'iptables.ttl': { + category: 'iptables', + description: 'Time To Live field. ', + name: 'iptables.ttl', type: 'integer', }, - 'checkpoint.additional_ip': { - category: 'checkpoint', - description: 'DNS host name. ', - name: 'checkpoint.additional_ip', - type: 'keyword', + 'iptables.udp.length': { + category: 'iptables', + description: 'Length of the UDP header and payload. ', + name: 'iptables.udp.length', + type: 'long', }, - 'checkpoint.description': { - category: 'checkpoint', - description: 'Additional explanation how the security gateway enforced the connection. ', - name: 'checkpoint.description', + 'iptables.ubiquiti.input_zone': { + category: 'iptables', + description: 'Input zone. ', + name: 'iptables.ubiquiti.input_zone', type: 'keyword', }, - 'checkpoint.email_spam_category': { - category: 'checkpoint', - description: 'Email categories. Possible values: spam/not spam/phishing. ', - name: 'checkpoint.email_spam_category', + 'iptables.ubiquiti.output_zone': { + category: 'iptables', + description: 'Output zone. ', + name: 'iptables.ubiquiti.output_zone', type: 'keyword', }, - 'checkpoint.email_control_analysis': { - category: 'checkpoint', - description: 'Message classification, received from spam vendor engine. ', - name: 'checkpoint.email_control_analysis', + 'iptables.ubiquiti.rule_number': { + category: 'iptables', + description: 'The rule number within the rule set.', + name: 'iptables.ubiquiti.rule_number', type: 'keyword', }, - 'checkpoint.scan_results': { - category: 'checkpoint', - description: '"Infected"/description of a failure. ', - name: 'checkpoint.scan_results', + 'iptables.ubiquiti.rule_set': { + category: 'iptables', + description: 'The rule set name.', + name: 'iptables.ubiquiti.rule_set', type: 'keyword', }, - 'checkpoint.original_queue_id': { - category: 'checkpoint', - description: 'Original postfix email queue id. ', - name: 'checkpoint.original_queue_id', + 'juniper.srx.reason': { + category: 'juniper', + description: 'reason ', + name: 'juniper.srx.reason', type: 'keyword', }, - 'checkpoint.risk': { - category: 'checkpoint', - description: 'Risk level we got from the engine. ', - name: 'checkpoint.risk', + 'juniper.srx.connection_tag': { + category: 'juniper', + description: 'connection tag ', + name: 'juniper.srx.connection_tag', type: 'keyword', }, - 'checkpoint.observable_name': { - category: 'checkpoint', - description: 'IOC observable signature name. ', - name: 'checkpoint.observable_name', + 'juniper.srx.service_name': { + category: 'juniper', + description: 'service name ', + name: 'juniper.srx.service_name', type: 'keyword', }, - 'checkpoint.observable_id': { - category: 'checkpoint', - description: 'IOC observable signature id. ', - name: 'checkpoint.observable_id', + 'juniper.srx.nat_connection_tag': { + category: 'juniper', + description: 'nat connection tag ', + name: 'juniper.srx.nat_connection_tag', type: 'keyword', }, - 'checkpoint.observable_comment': { - category: 'checkpoint', - description: 'IOC observable signature description. ', - name: 'checkpoint.observable_comment', + 'juniper.srx.src_nat_rule_type': { + category: 'juniper', + description: 'src nat rule type ', + name: 'juniper.srx.src_nat_rule_type', type: 'keyword', }, - 'checkpoint.indicator_name': { - category: 'checkpoint', - description: 'IOC indicator name. ', - name: 'checkpoint.indicator_name', + 'juniper.srx.src_nat_rule_name': { + category: 'juniper', + description: 'src nat rule name ', + name: 'juniper.srx.src_nat_rule_name', type: 'keyword', }, - 'checkpoint.indicator_description': { - category: 'checkpoint', - description: 'IOC indicator description. ', - name: 'checkpoint.indicator_description', + 'juniper.srx.dst_nat_rule_type': { + category: 'juniper', + description: 'dst nat rule type ', + name: 'juniper.srx.dst_nat_rule_type', type: 'keyword', }, - 'checkpoint.indicator_reference': { - category: 'checkpoint', - description: 'IOC indicator reference. ', - name: 'checkpoint.indicator_reference', + 'juniper.srx.dst_nat_rule_name': { + category: 'juniper', + description: 'dst nat rule name ', + name: 'juniper.srx.dst_nat_rule_name', type: 'keyword', }, - 'checkpoint.indicator_uuid': { - category: 'checkpoint', - description: 'IOC indicator uuid. ', - name: 'checkpoint.indicator_uuid', + 'juniper.srx.protocol_id': { + category: 'juniper', + description: 'protocol id ', + name: 'juniper.srx.protocol_id', type: 'keyword', }, - 'checkpoint.app_desc': { - category: 'checkpoint', - description: 'Application description. ', - name: 'checkpoint.app_desc', + 'juniper.srx.policy_name': { + category: 'juniper', + description: 'policy name ', + name: 'juniper.srx.policy_name', type: 'keyword', }, - 'checkpoint.app_id': { - category: 'checkpoint', - description: 'Application ID. ', - name: 'checkpoint.app_id', - type: 'integer', - }, - 'checkpoint.certificate_resource': { - category: 'checkpoint', - description: 'HTTPS resource Possible values: SNI or domain name (DN). ', - name: 'checkpoint.certificate_resource', + 'juniper.srx.session_id_32': { + category: 'juniper', + description: 'session id 32 ', + name: 'juniper.srx.session_id_32', type: 'keyword', }, - 'checkpoint.certificate_validation': { - category: 'checkpoint', - description: - 'Precise error, describing HTTPS certificate failure under "HTTPS categorize websites" feature. ', - name: 'checkpoint.certificate_validation', + 'juniper.srx.session_id': { + category: 'juniper', + description: 'session id ', + name: 'juniper.srx.session_id', type: 'keyword', }, - 'checkpoint.browse_time': { - category: 'checkpoint', - description: 'Application session browse time. ', - name: 'checkpoint.browse_time', - type: 'keyword', + 'juniper.srx.outbound_packets': { + category: 'juniper', + description: 'packets from client ', + name: 'juniper.srx.outbound_packets', + type: 'integer', }, - 'checkpoint.limit_requested': { - category: 'checkpoint', - description: 'Indicates whether data limit was requested for the session. ', - name: 'checkpoint.limit_requested', + 'juniper.srx.outbound_bytes': { + category: 'juniper', + description: 'bytes from client ', + name: 'juniper.srx.outbound_bytes', type: 'integer', }, - 'checkpoint.limit_applied': { - category: 'checkpoint', - description: 'Indicates whether the session was actually date limited. ', - name: 'checkpoint.limit_applied', + 'juniper.srx.inbound_packets': { + category: 'juniper', + description: 'packets from server ', + name: 'juniper.srx.inbound_packets', type: 'integer', }, - 'checkpoint.dropped_total': { - category: 'checkpoint', - description: 'Amount of dropped packets (both incoming and outgoing). ', - name: 'checkpoint.dropped_total', + 'juniper.srx.inbound_bytes': { + category: 'juniper', + description: 'bytes from server ', + name: 'juniper.srx.inbound_bytes', type: 'integer', }, - 'checkpoint.client_type_os': { - category: 'checkpoint', - description: 'Client OS detected in the HTTP request. ', - name: 'checkpoint.client_type_os', - type: 'keyword', + 'juniper.srx.elapsed_time': { + category: 'juniper', + description: 'elapsed time ', + name: 'juniper.srx.elapsed_time', + type: 'date', }, - 'checkpoint.name': { - category: 'checkpoint', - description: 'Application name. ', - name: 'checkpoint.name', + 'juniper.srx.application': { + category: 'juniper', + description: 'application ', + name: 'juniper.srx.application', type: 'keyword', }, - 'checkpoint.properties': { - category: 'checkpoint', - description: 'Application categories. ', - name: 'checkpoint.properties', + 'juniper.srx.nested_application': { + category: 'juniper', + description: 'nested application ', + name: 'juniper.srx.nested_application', type: 'keyword', }, - 'checkpoint.sig_id': { - category: 'checkpoint', - description: "Application's signature ID which how it was detected by. ", - name: 'checkpoint.sig_id', + 'juniper.srx.username': { + category: 'juniper', + description: 'username ', + name: 'juniper.srx.username', type: 'keyword', }, - 'checkpoint.desc': { - category: 'checkpoint', - description: 'Override application description. ', - name: 'checkpoint.desc', + 'juniper.srx.roles': { + category: 'juniper', + description: 'roles ', + name: 'juniper.srx.roles', type: 'keyword', }, - 'checkpoint.referrer_self_uid': { - category: 'checkpoint', - description: 'UUID of the current log. ', - name: 'checkpoint.referrer_self_uid', + 'juniper.srx.encrypted': { + category: 'juniper', + description: 'encrypted ', + name: 'juniper.srx.encrypted', type: 'keyword', }, - 'checkpoint.referrer_parent_uid': { - category: 'checkpoint', - description: 'Log UUID of the referring application. ', - name: 'checkpoint.referrer_parent_uid', + 'juniper.srx.application_category': { + category: 'juniper', + description: 'application category ', + name: 'juniper.srx.application_category', type: 'keyword', }, - 'checkpoint.needs_browse_time': { - category: 'checkpoint', - description: 'Browse time required for the connection. ', - name: 'checkpoint.needs_browse_time', - type: 'integer', - }, - 'checkpoint.cluster_info': { - category: 'checkpoint', - description: - 'Cluster information. Possible options: Failover reason/cluster state changes/CP cluster or 3rd party. ', - name: 'checkpoint.cluster_info', + 'juniper.srx.application_sub_category': { + category: 'juniper', + description: 'application sub category ', + name: 'juniper.srx.application_sub_category', type: 'keyword', }, - 'checkpoint.sync': { - category: 'checkpoint', - description: 'Sync status and the reason (stable, at risk). ', - name: 'checkpoint.sync', + 'juniper.srx.application_characteristics': { + category: 'juniper', + description: 'application characteristics ', + name: 'juniper.srx.application_characteristics', type: 'keyword', }, - 'checkpoint.file_direction': { - category: 'checkpoint', - description: 'File direction. Possible options: upload/download. ', - name: 'checkpoint.file_direction', + 'juniper.srx.secure_web_proxy_session_type': { + category: 'juniper', + description: 'secure web proxy session type ', + name: 'juniper.srx.secure_web_proxy_session_type', type: 'keyword', }, - 'checkpoint.invalid_file_size': { - category: 'checkpoint', - description: 'File_size field is valid only if this field is set to 0. ', - name: 'checkpoint.invalid_file_size', - type: 'integer', - }, - 'checkpoint.top_archive_file_name': { - category: 'checkpoint', - description: 'In case of archive file: the file that was sent/received. ', - name: 'checkpoint.top_archive_file_name', + 'juniper.srx.peer_session_id': { + category: 'juniper', + description: 'peer session id ', + name: 'juniper.srx.peer_session_id', type: 'keyword', }, - 'checkpoint.data_type_name': { - category: 'checkpoint', - description: 'Data type in rulebase that was matched. ', - name: 'checkpoint.data_type_name', - type: 'keyword', + 'juniper.srx.peer_source_address': { + category: 'juniper', + description: 'peer source address ', + name: 'juniper.srx.peer_source_address', + type: 'ip', }, - 'checkpoint.specific_data_type_name': { - category: 'checkpoint', - description: 'Compound/Group scenario, data type that was matched. ', - name: 'checkpoint.specific_data_type_name', - type: 'keyword', + 'juniper.srx.peer_source_port': { + category: 'juniper', + description: 'peer source port ', + name: 'juniper.srx.peer_source_port', + type: 'integer', }, - 'checkpoint.word_list': { - category: 'checkpoint', - description: 'Words matched by data type. ', - name: 'checkpoint.word_list', - type: 'keyword', + 'juniper.srx.peer_destination_address': { + category: 'juniper', + description: 'peer destination address ', + name: 'juniper.srx.peer_destination_address', + type: 'ip', }, - 'checkpoint.info': { - category: 'checkpoint', - description: 'Special log message. ', - name: 'checkpoint.info', - type: 'keyword', + 'juniper.srx.peer_destination_port': { + category: 'juniper', + description: 'peer destination port ', + name: 'juniper.srx.peer_destination_port', + type: 'integer', }, - 'checkpoint.outgoing_url': { - category: 'checkpoint', - description: 'URL related to this log (for HTTP). ', - name: 'checkpoint.outgoing_url', + 'juniper.srx.hostname': { + category: 'juniper', + description: 'hostname ', + name: 'juniper.srx.hostname', type: 'keyword', }, - 'checkpoint.dlp_rule_name': { - category: 'checkpoint', - description: 'Matched rule name. ', - name: 'checkpoint.dlp_rule_name', + 'juniper.srx.src_vrf_grp': { + category: 'juniper', + description: 'src_vrf_grp ', + name: 'juniper.srx.src_vrf_grp', type: 'keyword', }, - 'checkpoint.dlp_recipients': { - category: 'checkpoint', - description: 'Mail recipients. ', - name: 'checkpoint.dlp_recipients', + 'juniper.srx.dst_vrf_grp': { + category: 'juniper', + description: 'dst_vrf_grp ', + name: 'juniper.srx.dst_vrf_grp', type: 'keyword', }, - 'checkpoint.dlp_subject': { - category: 'checkpoint', - description: 'Mail subject. ', - name: 'checkpoint.dlp_subject', - type: 'keyword', + 'juniper.srx.icmp_type': { + category: 'juniper', + description: 'icmp type ', + name: 'juniper.srx.icmp_type', + type: 'integer', }, - 'checkpoint.dlp_word_list': { - category: 'checkpoint', - description: 'Phrases matched by data type. ', - name: 'checkpoint.dlp_word_list', + 'juniper.srx.process': { + category: 'juniper', + description: 'process that generated the message ', + name: 'juniper.srx.process', type: 'keyword', }, - 'checkpoint.dlp_template_score': { - category: 'checkpoint', - description: 'Template data type match score. ', - name: 'checkpoint.dlp_template_score', + 'juniper.srx.apbr_rule_type': { + category: 'juniper', + description: 'apbr rule type ', + name: 'juniper.srx.apbr_rule_type', type: 'keyword', }, - 'checkpoint.message_size': { - category: 'checkpoint', - description: 'Mail/post size. ', - name: 'checkpoint.message_size', + 'juniper.srx.dscp_value': { + category: 'juniper', + description: 'apbr rule type ', + name: 'juniper.srx.dscp_value', type: 'integer', }, - 'checkpoint.dlp_incident_uid': { - category: 'checkpoint', - description: 'Unique ID of the matched rule. ', - name: 'checkpoint.dlp_incident_uid', + 'juniper.srx.logical_system_name': { + category: 'juniper', + description: 'logical system name ', + name: 'juniper.srx.logical_system_name', type: 'keyword', }, - 'checkpoint.dlp_related_incident_uid': { - category: 'checkpoint', - description: 'Other ID related to this one. ', - name: 'checkpoint.dlp_related_incident_uid', + 'juniper.srx.profile_name': { + category: 'juniper', + description: 'profile name ', + name: 'juniper.srx.profile_name', type: 'keyword', }, - 'checkpoint.dlp_data_type_name': { - category: 'checkpoint', - description: 'Matched data type. ', - name: 'checkpoint.dlp_data_type_name', + 'juniper.srx.routing_instance': { + category: 'juniper', + description: 'routing instance ', + name: 'juniper.srx.routing_instance', type: 'keyword', }, - 'checkpoint.dlp_data_type_uid': { - category: 'checkpoint', - description: 'Unique ID of the matched data type. ', - name: 'checkpoint.dlp_data_type_uid', + 'juniper.srx.rule_name': { + category: 'juniper', + description: 'rule name ', + name: 'juniper.srx.rule_name', type: 'keyword', }, - 'checkpoint.dlp_violation_description': { - category: 'checkpoint', - description: 'Violation descriptions described in the rulebase. ', - name: 'checkpoint.dlp_violation_description', - type: 'keyword', + 'juniper.srx.uplink_tx_bytes': { + category: 'juniper', + description: 'uplink tx bytes ', + name: 'juniper.srx.uplink_tx_bytes', + type: 'integer', }, - 'checkpoint.dlp_relevant_data_types': { - category: 'checkpoint', - description: 'In case of Compound/Group: the inner data types that were matched. ', - name: 'checkpoint.dlp_relevant_data_types', + 'juniper.srx.uplink_rx_bytes': { + category: 'juniper', + description: 'uplink rx bytes ', + name: 'juniper.srx.uplink_rx_bytes', + type: 'integer', + }, + 'juniper.srx.obj': { + category: 'juniper', + description: 'url path ', + name: 'juniper.srx.obj', type: 'keyword', }, - 'checkpoint.dlp_action_reason': { - category: 'checkpoint', - description: 'Action chosen reason. ', - name: 'checkpoint.dlp_action_reason', + 'juniper.srx.url': { + category: 'juniper', + description: 'url domain ', + name: 'juniper.srx.url', type: 'keyword', }, - 'checkpoint.dlp_categories': { - category: 'checkpoint', - description: 'Data type category. ', - name: 'checkpoint.dlp_categories', + 'juniper.srx.profile': { + category: 'juniper', + description: 'filter profile ', + name: 'juniper.srx.profile', type: 'keyword', }, - 'checkpoint.dlp_transint': { - category: 'checkpoint', - description: 'HTTP/SMTP/FTP. ', - name: 'checkpoint.dlp_transint', + 'juniper.srx.category': { + category: 'juniper', + description: 'filter category ', + name: 'juniper.srx.category', type: 'keyword', }, - 'checkpoint.duplicate': { - category: 'checkpoint', - description: - 'Log marked as duplicated, when mail is split and the Security Gateway sees it twice. ', - name: 'checkpoint.duplicate', + 'juniper.srx.filename': { + category: 'juniper', + description: 'filename ', + name: 'juniper.srx.filename', type: 'keyword', }, - 'checkpoint.matched_file': { - category: 'checkpoint', - description: 'Unique ID of the matched data type. ', - name: 'checkpoint.matched_file', + 'juniper.srx.temporary_filename': { + category: 'juniper', + description: 'temporary_filename ', + name: 'juniper.srx.temporary_filename', type: 'keyword', }, - 'checkpoint.matched_file_text_segments': { - category: 'checkpoint', - description: 'Fingerprint: number of text segments matched by this traffic. ', - name: 'checkpoint.matched_file_text_segments', - type: 'integer', + 'juniper.srx.name': { + category: 'juniper', + description: 'name ', + name: 'juniper.srx.name', + type: 'keyword', }, - 'checkpoint.matched_file_percentage': { - category: 'checkpoint', - description: 'Fingerprint: match percentage of the traffic. ', - name: 'checkpoint.matched_file_percentage', - type: 'integer', + 'juniper.srx.error_message': { + category: 'juniper', + description: 'error_message ', + name: 'juniper.srx.error_message', + type: 'keyword', }, - 'checkpoint.dlp_additional_action': { - category: 'checkpoint', - description: 'Watermark/None. ', - name: 'checkpoint.dlp_additional_action', + 'juniper.srx.error_code': { + category: 'juniper', + description: 'error_code ', + name: 'juniper.srx.error_code', type: 'keyword', }, - 'checkpoint.dlp_watermark_profile': { - category: 'checkpoint', - description: 'Watermark which was applied. ', - name: 'checkpoint.dlp_watermark_profile', + 'juniper.srx.action': { + category: 'juniper', + description: 'action ', + name: 'juniper.srx.action', type: 'keyword', }, - 'checkpoint.dlp_repository_id': { - category: 'checkpoint', - description: 'ID of scanned repository. ', - name: 'checkpoint.dlp_repository_id', + 'juniper.srx.protocol': { + category: 'juniper', + description: 'protocol ', + name: 'juniper.srx.protocol', type: 'keyword', }, - 'checkpoint.dlp_repository_root_path': { - category: 'checkpoint', - description: 'Repository path. ', - name: 'checkpoint.dlp_repository_root_path', + 'juniper.srx.protocol_name': { + category: 'juniper', + description: 'protocol name ', + name: 'juniper.srx.protocol_name', type: 'keyword', }, - 'checkpoint.scan_id': { - category: 'checkpoint', - description: 'Sequential number of scan. ', - name: 'checkpoint.scan_id', + 'juniper.srx.type': { + category: 'juniper', + description: 'type ', + name: 'juniper.srx.type', type: 'keyword', }, - 'checkpoint.special_properties': { - category: 'checkpoint', - description: - "If this field is set to '1' the log will not be shown (in use for monitoring scan progress). ", - name: 'checkpoint.special_properties', + 'juniper.srx.repeat_count': { + category: 'juniper', + description: 'repeat count ', + name: 'juniper.srx.repeat_count', type: 'integer', }, - 'checkpoint.dlp_repository_total_size': { - category: 'checkpoint', - description: 'Repository size. ', - name: 'checkpoint.dlp_repository_total_size', - type: 'integer', + 'juniper.srx.alert': { + category: 'juniper', + description: 'repeat alert ', + name: 'juniper.srx.alert', + type: 'keyword', }, - 'checkpoint.dlp_repository_files_number': { - category: 'checkpoint', - description: 'Number of files in repository. ', - name: 'checkpoint.dlp_repository_files_number', - type: 'integer', + 'juniper.srx.message_type': { + category: 'juniper', + description: 'message type ', + name: 'juniper.srx.message_type', + type: 'keyword', }, - 'checkpoint.dlp_repository_scanned_files_number': { - category: 'checkpoint', - description: 'Number of scanned files in repository. ', - name: 'checkpoint.dlp_repository_scanned_files_number', - type: 'integer', + 'juniper.srx.threat_severity': { + category: 'juniper', + description: 'threat severity ', + name: 'juniper.srx.threat_severity', + type: 'keyword', }, - 'checkpoint.duration': { - category: 'checkpoint', - description: 'Scan duration. ', - name: 'checkpoint.duration', + 'juniper.srx.application_name': { + category: 'juniper', + description: 'application name ', + name: 'juniper.srx.application_name', type: 'keyword', }, - 'checkpoint.dlp_fingerprint_long_status': { - category: 'checkpoint', - description: 'Scan status - long format. ', - name: 'checkpoint.dlp_fingerprint_long_status', + 'juniper.srx.attack_name': { + category: 'juniper', + description: 'attack name ', + name: 'juniper.srx.attack_name', type: 'keyword', }, - 'checkpoint.dlp_fingerprint_short_status': { - category: 'checkpoint', - description: 'Scan status - short format. ', - name: 'checkpoint.dlp_fingerprint_short_status', + 'juniper.srx.index': { + category: 'juniper', + description: 'index ', + name: 'juniper.srx.index', type: 'keyword', }, - 'checkpoint.dlp_repository_directories_number': { - category: 'checkpoint', - description: 'Number of directories in repository. ', - name: 'checkpoint.dlp_repository_directories_number', - type: 'integer', + 'juniper.srx.message': { + category: 'juniper', + description: 'mesagge ', + name: 'juniper.srx.message', + type: 'keyword', }, - 'checkpoint.dlp_repository_unreachable_directories_number': { - category: 'checkpoint', - description: 'Number of directories the Security Gateway was unable to read. ', - name: 'checkpoint.dlp_repository_unreachable_directories_number', - type: 'integer', + 'juniper.srx.epoch_time': { + category: 'juniper', + description: 'epoch time ', + name: 'juniper.srx.epoch_time', + type: 'date', }, - 'checkpoint.dlp_fingerprint_files_number': { - category: 'checkpoint', - description: 'Number of successfully scanned files in repository. ', - name: 'checkpoint.dlp_fingerprint_files_number', + 'juniper.srx.packet_log_id': { + category: 'juniper', + description: 'packet log id ', + name: 'juniper.srx.packet_log_id', type: 'integer', }, - 'checkpoint.dlp_repository_skipped_files_number': { - category: 'checkpoint', - description: 'Skipped number of files because of configuration. ', - name: 'checkpoint.dlp_repository_skipped_files_number', + 'juniper.srx.export_id': { + category: 'juniper', + description: 'packet log id ', + name: 'juniper.srx.export_id', type: 'integer', }, - 'checkpoint.dlp_repository_scanned_directories_number': { - category: 'checkpoint', - description: 'Amount of directories scanned. ', - name: 'checkpoint.dlp_repository_scanned_directories_number', - type: 'integer', + 'juniper.srx.ddos_application_name': { + category: 'juniper', + description: 'ddos application name ', + name: 'juniper.srx.ddos_application_name', + type: 'keyword', }, - 'checkpoint.number_of_errors': { - category: 'checkpoint', - description: 'Number of files that were not scanned due to an error. ', - name: 'checkpoint.number_of_errors', + 'juniper.srx.connection_hit_rate': { + category: 'juniper', + description: 'connection hit rate ', + name: 'juniper.srx.connection_hit_rate', type: 'integer', }, - 'checkpoint.next_scheduled_scan_date': { - category: 'checkpoint', - description: 'Next scan scheduled time according to time object. ', - name: 'checkpoint.next_scheduled_scan_date', + 'juniper.srx.time_scope': { + category: 'juniper', + description: 'time scope ', + name: 'juniper.srx.time_scope', type: 'keyword', }, - 'checkpoint.dlp_repository_scanned_total_size': { - category: 'checkpoint', - description: 'Size scanned. ', - name: 'checkpoint.dlp_repository_scanned_total_size', - type: 'integer', - }, - 'checkpoint.dlp_repository_reached_directories_number': { - category: 'checkpoint', - description: 'Number of scanned directories in repository. ', - name: 'checkpoint.dlp_repository_reached_directories_number', + 'juniper.srx.context_hit_rate': { + category: 'juniper', + description: 'context hit rate ', + name: 'juniper.srx.context_hit_rate', type: 'integer', }, - 'checkpoint.dlp_repository_not_scanned_directories_percentage': { - category: 'checkpoint', - description: 'Percentage of directories the Security Gateway was unable to read. ', - name: 'checkpoint.dlp_repository_not_scanned_directories_percentage', + 'juniper.srx.context_value_hit_rate': { + category: 'juniper', + description: 'context value hit rate ', + name: 'juniper.srx.context_value_hit_rate', type: 'integer', }, - 'checkpoint.speed': { - category: 'checkpoint', - description: 'Current scan speed. ', - name: 'checkpoint.speed', + 'juniper.srx.time_count': { + category: 'juniper', + description: 'time count ', + name: 'juniper.srx.time_count', type: 'integer', }, - 'checkpoint.dlp_repository_scan_progress': { - category: 'checkpoint', - description: 'Scan percentage. ', - name: 'checkpoint.dlp_repository_scan_progress', + 'juniper.srx.time_period': { + category: 'juniper', + description: 'time period ', + name: 'juniper.srx.time_period', type: 'integer', }, - 'checkpoint.sub_policy_name': { - category: 'checkpoint', - description: 'Layer name. ', - name: 'checkpoint.sub_policy_name', - type: 'keyword', - }, - 'checkpoint.sub_policy_uid': { - category: 'checkpoint', - description: 'Layer uid. ', - name: 'checkpoint.sub_policy_uid', + 'juniper.srx.context_value': { + category: 'juniper', + description: 'context value ', + name: 'juniper.srx.context_value', type: 'keyword', }, - 'checkpoint.fw_message': { - category: 'checkpoint', - description: 'Used for various firewall errors. ', - name: 'checkpoint.fw_message', + 'juniper.srx.context_name': { + category: 'juniper', + description: 'context name ', + name: 'juniper.srx.context_name', type: 'keyword', }, - 'checkpoint.message': { - category: 'checkpoint', - description: 'ISP link has failed. ', - name: 'checkpoint.message', + 'juniper.srx.ruleebase_name': { + category: 'juniper', + description: 'ruleebase name ', + name: 'juniper.srx.ruleebase_name', type: 'keyword', }, - 'checkpoint.isp_link': { - category: 'checkpoint', - description: 'Name of ISP link. ', - name: 'checkpoint.isp_link', + 'juniper.srx.verdict_source': { + category: 'juniper', + description: 'verdict source ', + name: 'juniper.srx.verdict_source', type: 'keyword', }, - 'checkpoint.fw_subproduct': { - category: 'checkpoint', - description: 'Can be vpn/non vpn. ', - name: 'checkpoint.fw_subproduct', - type: 'keyword', + 'juniper.srx.verdict_number': { + category: 'juniper', + description: 'verdict number ', + name: 'juniper.srx.verdict_number', + type: 'integer', }, - 'checkpoint.sctp_error': { - category: 'checkpoint', - description: 'Error information, what caused sctp to fail on out_of_state. ', - name: 'checkpoint.sctp_error', + 'juniper.srx.file_category': { + category: 'juniper', + description: 'file category ', + name: 'juniper.srx.file_category', type: 'keyword', }, - 'checkpoint.chunk_type': { - category: 'checkpoint', - description: 'Chunck of the sctp stream. ', - name: 'checkpoint.chunk_type', + 'juniper.srx.sample_sha256': { + category: 'juniper', + description: 'sample sha256 ', + name: 'juniper.srx.sample_sha256', type: 'keyword', }, - 'checkpoint.sctp_association_state': { - category: 'checkpoint', - description: 'The bad state you were trying to update to. ', - name: 'checkpoint.sctp_association_state', + 'juniper.srx.malware_info': { + category: 'juniper', + description: 'malware info ', + name: 'juniper.srx.malware_info', type: 'keyword', }, - 'checkpoint.tcp_packet_out_of_state': { - category: 'checkpoint', - description: 'State violation. ', - name: 'checkpoint.tcp_packet_out_of_state', - type: 'keyword', + 'juniper.srx.client_ip': { + category: 'juniper', + description: 'client ip ', + name: 'juniper.srx.client_ip', + type: 'ip', }, - 'checkpoint.connectivity_level': { - category: 'checkpoint', - description: 'Log for a new connection in wire mode. ', - name: 'checkpoint.connectivity_level', + 'juniper.srx.tenant_id': { + category: 'juniper', + description: 'tenant id ', + name: 'juniper.srx.tenant_id', type: 'keyword', }, - 'checkpoint.ip_option': { - category: 'checkpoint', - description: 'IP option that was dropped. ', - name: 'checkpoint.ip_option', - type: 'integer', + 'juniper.srx.timestamp': { + category: 'juniper', + description: 'timestamp ', + name: 'juniper.srx.timestamp', + type: 'date', }, - 'checkpoint.tcp_state': { - category: 'checkpoint', - description: 'Log reinting a tcp state change. ', - name: 'checkpoint.tcp_state', + 'juniper.srx.th': { + category: 'juniper', + description: 'th ', + name: 'juniper.srx.th', type: 'keyword', }, - 'checkpoint.expire_time': { - category: 'checkpoint', - description: 'Connection closing time. ', - name: 'checkpoint.expire_time', + 'juniper.srx.status': { + category: 'juniper', + description: 'status ', + name: 'juniper.srx.status', type: 'keyword', }, - 'checkpoint.rpc_prog': { - category: 'checkpoint', - description: 'Log for new RPC state - prog values. ', - name: 'checkpoint.rpc_prog', - type: 'integer', + 'juniper.srx.state': { + category: 'juniper', + description: 'state ', + name: 'juniper.srx.state', + type: 'keyword', }, - 'checkpoint.dce-rpc_interface_uuid': { - category: 'checkpoint', - description: 'Log for new RPC state - UUID values ', - name: 'checkpoint.dce-rpc_interface_uuid', + 'juniper.srx.file_hash_lookup': { + category: 'juniper', + description: 'file hash lookup ', + name: 'juniper.srx.file_hash_lookup', type: 'keyword', }, - 'checkpoint.elapsed': { - category: 'checkpoint', - description: 'Time passed since start time. ', - name: 'checkpoint.elapsed', + 'juniper.srx.file_name': { + category: 'juniper', + description: 'file name ', + name: 'juniper.srx.file_name', type: 'keyword', }, - 'checkpoint.icmp': { - category: 'checkpoint', - description: 'Number of packets, received by the client. ', - name: 'checkpoint.icmp', + 'juniper.srx.action_detail': { + category: 'juniper', + description: 'action detail ', + name: 'juniper.srx.action_detail', type: 'keyword', }, - 'checkpoint.capture_uuid': { - category: 'checkpoint', - description: 'UUID generated for the capture. Used when enabling the capture when logging. ', - name: 'checkpoint.capture_uuid', + 'juniper.srx.sub_category': { + category: 'juniper', + description: 'sub category ', + name: 'juniper.srx.sub_category', type: 'keyword', }, - 'checkpoint.diameter_app_ID': { - category: 'checkpoint', - description: 'The ID of diameter application. ', - name: 'checkpoint.diameter_app_ID', - type: 'integer', + 'juniper.srx.feed_name': { + category: 'juniper', + description: 'feed name ', + name: 'juniper.srx.feed_name', + type: 'keyword', }, - 'checkpoint.diameter_cmd_code': { - category: 'checkpoint', - description: 'Diameter not allowed application command id. ', - name: 'checkpoint.diameter_cmd_code', + 'juniper.srx.occur_count': { + category: 'juniper', + description: 'occur count ', + name: 'juniper.srx.occur_count', type: 'integer', }, - 'checkpoint.diameter_msg_type': { - category: 'checkpoint', - description: 'Diameter message type. ', - name: 'checkpoint.diameter_msg_type', + 'juniper.srx.tag': { + category: 'juniper', + description: 'system log message tag, which uniquely identifies the message. ', + name: 'juniper.srx.tag', type: 'keyword', }, - 'checkpoint.cp_message': { - category: 'checkpoint', - description: 'Used to log a general message. ', - name: 'checkpoint.cp_message', - type: 'integer', + 'microsoft.defender_atp.lastUpdateTime': { + category: 'microsoft', + description: 'The date and time (in UTC) the alert was last updated. ', + name: 'microsoft.defender_atp.lastUpdateTime', + type: 'date', }, - 'checkpoint.log_delay': { - category: 'checkpoint', - description: 'Time left before deleting template. ', - name: 'checkpoint.log_delay', - type: 'integer', + 'microsoft.defender_atp.resolvedTime': { + category: 'microsoft', + description: "The date and time in which the status of the alert was changed to 'Resolved'. ", + name: 'microsoft.defender_atp.resolvedTime', + type: 'date', }, - 'checkpoint.attack_status': { - category: 'checkpoint', - description: 'In case of a malicious event on an endpoint computer, the status of the attack. ', - name: 'checkpoint.attack_status', + 'microsoft.defender_atp.incidentId': { + category: 'microsoft', + description: 'The Incident ID of the Alert. ', + name: 'microsoft.defender_atp.incidentId', type: 'keyword', }, - 'checkpoint.impacted_files': { - category: 'checkpoint', - description: - 'In case of an infection on an endpoint computer, the list of files that the malware impacted. ', - name: 'checkpoint.impacted_files', + 'microsoft.defender_atp.investigationId': { + category: 'microsoft', + description: 'The Investigation ID related to the Alert. ', + name: 'microsoft.defender_atp.investigationId', type: 'keyword', }, - 'checkpoint.remediated_files': { - category: 'checkpoint', - description: - 'In case of an infection and a successful cleaning of that infection, this is a list of remediated files on the computer. ', - name: 'checkpoint.remediated_files', + 'microsoft.defender_atp.investigationState': { + category: 'microsoft', + description: 'The current state of the Investigation. ', + name: 'microsoft.defender_atp.investigationState', type: 'keyword', }, - 'checkpoint.triggered_by': { - category: 'checkpoint', + 'microsoft.defender_atp.assignedTo': { + category: 'microsoft', + description: 'Owner of the alert. ', + name: 'microsoft.defender_atp.assignedTo', + type: 'keyword', + }, + 'microsoft.defender_atp.status': { + category: 'microsoft', description: - 'The name of the mechanism that triggered the Software Blade to enforce a protection. ', - name: 'checkpoint.triggered_by', + "Specifies the current status of the alert. Possible values are: 'Unknown', 'New', 'InProgress' and 'Resolved'. ", + name: 'microsoft.defender_atp.status', type: 'keyword', }, - 'checkpoint.https_inspection_rule_id': { - category: 'checkpoint', - description: 'ID of the matched rule. ', - name: 'checkpoint.https_inspection_rule_id', + 'microsoft.defender_atp.classification': { + category: 'microsoft', + description: + "Specification of the alert. Possible values are: 'Unknown', 'FalsePositive', 'TruePositive'. ", + name: 'microsoft.defender_atp.classification', type: 'keyword', }, - 'checkpoint.https_inspection_rule_name': { - category: 'checkpoint', - description: 'Name of the matched rule. ', - name: 'checkpoint.https_inspection_rule_name', + 'microsoft.defender_atp.determination': { + category: 'microsoft', + description: + "Specifies the determination of the alert. Possible values are: 'NotAvailable', 'Apt', 'Malware', 'SecurityPersonnel', 'SecurityTesting', 'UnwantedSoftware', 'Other'. ", + name: 'microsoft.defender_atp.determination', type: 'keyword', }, - 'checkpoint.app_properties': { - category: 'checkpoint', - description: 'List of all found categories. ', - name: 'checkpoint.app_properties', + 'microsoft.defender_atp.threatFamilyName': { + category: 'microsoft', + description: 'Threat family. ', + name: 'microsoft.defender_atp.threatFamilyName', type: 'keyword', }, - 'checkpoint.https_validation': { - category: 'checkpoint', - description: 'Precise error, describing HTTPS inspection failure. ', - name: 'checkpoint.https_validation', + 'microsoft.defender_atp.rbacGroupName': { + category: 'microsoft', + description: 'User group related to the alert ', + name: 'microsoft.defender_atp.rbacGroupName', type: 'keyword', }, - 'checkpoint.https_inspection_action': { - category: 'checkpoint', - description: 'HTTPS inspection action (Inspect/Bypass/Error). ', - name: 'checkpoint.https_inspection_action', + 'microsoft.defender_atp.evidence.domainName': { + category: 'microsoft', + description: 'Domain name related to the alert ', + name: 'microsoft.defender_atp.evidence.domainName', type: 'keyword', }, - 'checkpoint.icap_service_id': { - category: 'checkpoint', - description: 'Service ID, can work with multiple servers, treated as services. ', - name: 'checkpoint.icap_service_id', - type: 'integer', + 'microsoft.defender_atp.evidence.ipAddress': { + category: 'microsoft', + description: 'IP address involved in the alert ', + name: 'microsoft.defender_atp.evidence.ipAddress', + type: 'ip', }, - 'checkpoint.icap_server_name': { - category: 'checkpoint', - description: 'Server name. ', - name: 'checkpoint.icap_server_name', + 'microsoft.defender_atp.evidence.aadUserId': { + category: 'microsoft', + description: 'ID of the user involved in the alert ', + name: 'microsoft.defender_atp.evidence.aadUserId', type: 'keyword', }, - 'checkpoint.internal_error': { - category: 'checkpoint', - description: 'Internal error, for troubleshooting ', - name: 'checkpoint.internal_error', + 'microsoft.defender_atp.evidence.accountName': { + category: 'microsoft', + description: 'Username of the user involved in the alert ', + name: 'microsoft.defender_atp.evidence.accountName', type: 'keyword', }, - 'checkpoint.icap_more_info': { - category: 'checkpoint', - description: 'Free text for verdict. ', - name: 'checkpoint.icap_more_info', - type: 'integer', + 'microsoft.defender_atp.evidence.entityType': { + category: 'microsoft', + description: 'The type of evidence ', + name: 'microsoft.defender_atp.evidence.entityType', + type: 'keyword', }, - 'checkpoint.reply_status': { - category: 'checkpoint', - description: 'ICAP reply status code, e.g. 200 or 204. ', - name: 'checkpoint.reply_status', - type: 'integer', + 'microsoft.defender_atp.evidence.userPrincipalName': { + category: 'microsoft', + description: 'Principal name of the user involved in the alert ', + name: 'microsoft.defender_atp.evidence.userPrincipalName', + type: 'keyword', }, - 'checkpoint.icap_server_service': { - category: 'checkpoint', - description: 'Service name, as given in the ICAP URI ', - name: 'checkpoint.icap_server_service', + 'microsoft.m365_defender.incidentId': { + category: 'microsoft', + description: 'Unique identifier to represent the incident. ', + name: 'microsoft.m365_defender.incidentId', type: 'keyword', }, - 'checkpoint.mirror_and_decrypt_type': { - category: 'checkpoint', + 'microsoft.m365_defender.redirectIncidentId': { + category: 'microsoft', description: - 'Information about decrypt and forward. Possible values: Mirror only, Decrypt and mirror, Partial mirroring (HTTPS inspection Bypass). ', - name: 'checkpoint.mirror_and_decrypt_type', + 'Only populated in case an incident is being grouped together with another incident, as part of the incident processing logic. ', + name: 'microsoft.m365_defender.redirectIncidentId', type: 'keyword', }, - 'checkpoint.interface_name': { - category: 'checkpoint', - description: 'Designated interface for mirror And decrypt. ', - name: 'checkpoint.interface_name', + 'microsoft.m365_defender.incidentName': { + category: 'microsoft', + description: 'Name of the Incident. ', + name: 'microsoft.m365_defender.incidentName', type: 'keyword', }, - 'checkpoint.session_uid': { - category: 'checkpoint', - description: 'HTTP session-id. ', - name: 'checkpoint.session_uid', + 'microsoft.m365_defender.determination': { + category: 'microsoft', + description: + 'Specifies the determination of the incident. The property values are: NotAvailable, Apt, Malware, SecurityPersonnel, SecurityTesting, UnwantedSoftware, Other. ', + name: 'microsoft.m365_defender.determination', type: 'keyword', }, - 'checkpoint.broker_publisher': { - category: 'checkpoint', - description: 'IP address of the broker publisher who shared the session information. ', - name: 'checkpoint.broker_publisher', - type: 'ip', - }, - 'checkpoint.src_user_dn': { - category: 'checkpoint', - description: 'User distinguished name connected to source IP. ', - name: 'checkpoint.src_user_dn', + 'microsoft.m365_defender.investigationState': { + category: 'microsoft', + description: 'The current state of the Investigation. ', + name: 'microsoft.m365_defender.investigationState', type: 'keyword', }, - 'checkpoint.proxy_user_name': { - category: 'checkpoint', - description: 'User name connected to proxy IP. ', - name: 'checkpoint.proxy_user_name', + 'microsoft.m365_defender.assignedTo': { + category: 'microsoft', + description: 'Owner of the alert. ', + name: 'microsoft.m365_defender.assignedTo', type: 'keyword', }, - 'checkpoint.proxy_machine_name': { - category: 'checkpoint', - description: 'Machine name connected to proxy IP. ', - name: 'checkpoint.proxy_machine_name', - type: 'integer', - }, - 'checkpoint.proxy_user_dn': { - category: 'checkpoint', - description: 'User distinguished name connected to proxy IP. ', - name: 'checkpoint.proxy_user_dn', + 'microsoft.m365_defender.tags': { + category: 'microsoft', + description: + 'Array of custom tags associated with an incident, for example to flag a group of incidents with a common characteristic. ', + name: 'microsoft.m365_defender.tags', type: 'keyword', }, - 'checkpoint.query': { - category: 'checkpoint', - description: 'DNS query. ', - name: 'checkpoint.query', + 'microsoft.m365_defender.status': { + category: 'microsoft', + description: + "Specifies the current status of the alert. Possible values are: 'Unknown', 'New', 'InProgress' and 'Resolved'. ", + name: 'microsoft.m365_defender.status', type: 'keyword', }, - 'checkpoint.dns_query': { - category: 'checkpoint', - description: 'DNS query. ', - name: 'checkpoint.dns_query', + 'microsoft.m365_defender.classification': { + category: 'microsoft', + description: + "Specification of the alert. Possible values are: 'Unknown', 'FalsePositive', 'TruePositive'. ", + name: 'microsoft.m365_defender.classification', type: 'keyword', }, - 'checkpoint.inspection_item': { - category: 'checkpoint', - description: 'Blade element performed inspection. ', - name: 'checkpoint.inspection_item', + 'microsoft.m365_defender.alerts.incidentId': { + category: 'microsoft', + description: 'Unique identifier to represent the incident this alert is associated with. ', + name: 'microsoft.m365_defender.alerts.incidentId', type: 'keyword', }, - 'checkpoint.inspection_category': { - category: 'checkpoint', - description: 'Inspection category: protocol anomaly, signature etc. ', - name: 'checkpoint.inspection_category', + 'microsoft.m365_defender.alerts.resolvedTime': { + category: 'microsoft', + description: 'Time when alert was resolved. ', + name: 'microsoft.m365_defender.alerts.resolvedTime', + type: 'date', + }, + 'microsoft.m365_defender.alerts.status': { + category: 'microsoft', + description: 'Categorize alerts (as New, Active, or Resolved). ', + name: 'microsoft.m365_defender.alerts.status', type: 'keyword', }, - 'checkpoint.inspection_profile': { - category: 'checkpoint', - description: 'Profile which the activated protection belongs to. ', - name: 'checkpoint.inspection_profile', + 'microsoft.m365_defender.alerts.severity': { + category: 'microsoft', + description: 'The severity of the related alert. ', + name: 'microsoft.m365_defender.alerts.severity', type: 'keyword', }, - 'checkpoint.summary': { - category: 'checkpoint', - description: 'Summary message of a non-compliant DNS traffic drops or detects. ', - name: 'checkpoint.summary', + 'microsoft.m365_defender.alerts.creationTime': { + category: 'microsoft', + description: 'Time when alert was first created. ', + name: 'microsoft.m365_defender.alerts.creationTime', + type: 'date', + }, + 'microsoft.m365_defender.alerts.lastUpdatedTime': { + category: 'microsoft', + description: 'Time when alert was last updated. ', + name: 'microsoft.m365_defender.alerts.lastUpdatedTime', + type: 'date', + }, + 'microsoft.m365_defender.alerts.investigationId': { + category: 'microsoft', + description: 'The automated investigation id triggered by this alert. ', + name: 'microsoft.m365_defender.alerts.investigationId', type: 'keyword', }, - 'checkpoint.question_rdata': { - category: 'checkpoint', - description: 'List of question records domains. ', - name: 'checkpoint.question_rdata', + 'microsoft.m365_defender.alerts.userSid': { + category: 'microsoft', + description: 'The SID of the related user ', + name: 'microsoft.m365_defender.alerts.userSid', type: 'keyword', }, - 'checkpoint.answer_rdata': { - category: 'checkpoint', - description: 'List of answer resource records to the questioned domains. ', - name: 'checkpoint.answer_rdata', + 'microsoft.m365_defender.alerts.detectionSource': { + category: 'microsoft', + description: 'The service that initially detected the threat. ', + name: 'microsoft.m365_defender.alerts.detectionSource', type: 'keyword', }, - 'checkpoint.authority_rdata': { - category: 'checkpoint', - description: 'List of authoritative servers. ', - name: 'checkpoint.authority_rdata', + 'microsoft.m365_defender.alerts.classification': { + category: 'microsoft', + description: + 'The specification for the incident. The property values are: Unknown, FalsePositive, TruePositive or null. ', + name: 'microsoft.m365_defender.alerts.classification', type: 'keyword', }, - 'checkpoint.additional_rdata': { - category: 'checkpoint', - description: 'List of additional resource records. ', - name: 'checkpoint.additional_rdata', + 'microsoft.m365_defender.alerts.investigationState': { + category: 'microsoft', + description: "Information on the investigation's current status. ", + name: 'microsoft.m365_defender.alerts.investigationState', type: 'keyword', }, - 'checkpoint.files_names': { - category: 'checkpoint', - description: 'List of files requested by FTP. ', - name: 'checkpoint.files_names', + 'microsoft.m365_defender.alerts.determination': { + category: 'microsoft', + description: + 'Specifies the determination of the incident. The property values are: NotAvailable, Apt, Malware, SecurityPersonnel, SecurityTesting, UnwantedSoftware, Other or null ', + name: 'microsoft.m365_defender.alerts.determination', type: 'keyword', }, - 'checkpoint.ftp_user': { - category: 'checkpoint', - description: 'FTP username. ', - name: 'checkpoint.ftp_user', + 'microsoft.m365_defender.alerts.assignedTo': { + category: 'microsoft', + description: 'Owner of the incident, or null if no owner is assigned. ', + name: 'microsoft.m365_defender.alerts.assignedTo', type: 'keyword', }, - 'checkpoint.mime_from': { - category: 'checkpoint', - description: "Sender's address. ", - name: 'checkpoint.mime_from', + 'microsoft.m365_defender.alerts.actorName': { + category: 'microsoft', + description: 'The activity group, if any, the associated with this alert. ', + name: 'microsoft.m365_defender.alerts.actorName', type: 'keyword', }, - 'checkpoint.mime_to': { - category: 'checkpoint', - description: 'List of receiver address. ', - name: 'checkpoint.mime_to', + 'microsoft.m365_defender.alerts.threatFamilyName': { + category: 'microsoft', + description: 'Threat family associated with this alert. ', + name: 'microsoft.m365_defender.alerts.threatFamilyName', type: 'keyword', }, - 'checkpoint.bcc': { - category: 'checkpoint', - description: 'List of BCC addresses. ', - name: 'checkpoint.bcc', + 'microsoft.m365_defender.alerts.mitreTechniques': { + category: 'microsoft', + description: 'The attack techniques, as aligned with the MITRE ATT&CK™ framework. ', + name: 'microsoft.m365_defender.alerts.mitreTechniques', type: 'keyword', }, - 'checkpoint.content_type': { - category: 'checkpoint', + 'microsoft.m365_defender.alerts.entities.entityType': { + category: 'microsoft', description: - 'Mail content type. Possible values: application/msword, text/html, image/gif etc. ', - name: 'checkpoint.content_type', + 'Entities that have been identified to be part of, or related to, a given alert. The properties values are: User, Ip, Url, File, Process, MailBox, MailMessage, MailCluster, Registry. ', + name: 'microsoft.m365_defender.alerts.entities.entityType', type: 'keyword', }, - 'checkpoint.user_agent': { - category: 'checkpoint', - description: 'String identifying requesting software user agent. ', - name: 'checkpoint.user_agent', + 'microsoft.m365_defender.alerts.entities.accountName': { + category: 'microsoft', + description: 'Account name of the related user. ', + name: 'microsoft.m365_defender.alerts.entities.accountName', type: 'keyword', }, - 'checkpoint.referrer': { - category: 'checkpoint', - description: 'Referrer HTTP request header, previous web page address. ', - name: 'checkpoint.referrer', + 'microsoft.m365_defender.alerts.entities.mailboxDisplayName': { + category: 'microsoft', + description: 'The display name of the related mailbox. ', + name: 'microsoft.m365_defender.alerts.entities.mailboxDisplayName', type: 'keyword', }, - 'checkpoint.http_location': { - category: 'checkpoint', - description: 'Response header, indicates the URL to redirect a page to. ', - name: 'checkpoint.http_location', + 'microsoft.m365_defender.alerts.entities.mailboxAddress': { + category: 'microsoft', + description: 'The mail address of the related mailbox. ', + name: 'microsoft.m365_defender.alerts.entities.mailboxAddress', type: 'keyword', }, - 'checkpoint.content_disposition': { - category: 'checkpoint', - description: 'Indicates how the content is expected to be displayed inline in the browser. ', - name: 'checkpoint.content_disposition', + 'microsoft.m365_defender.alerts.entities.clusterBy': { + category: 'microsoft', + description: 'A list of metadata if the entityType is MailCluster. ', + name: 'microsoft.m365_defender.alerts.entities.clusterBy', type: 'keyword', }, - 'checkpoint.via': { - category: 'checkpoint', - description: - 'Via header is added by proxies for tracking purposes to avoid sending reqests in loop. ', - name: 'checkpoint.via', + 'microsoft.m365_defender.alerts.entities.sender': { + category: 'microsoft', + description: 'The sender for the related email message. ', + name: 'microsoft.m365_defender.alerts.entities.sender', type: 'keyword', }, - 'checkpoint.http_server': { - category: 'checkpoint', - description: - 'Server HTTP header value, contains information about the software used by the origin server, which handles the request. ', - name: 'checkpoint.http_server', + 'microsoft.m365_defender.alerts.entities.recipient': { + category: 'microsoft', + description: 'The recipient for the related email message. ', + name: 'microsoft.m365_defender.alerts.entities.recipient', type: 'keyword', }, - 'checkpoint.content_length': { - category: 'checkpoint', - description: 'Indicates the size of the entity-body of the HTTP header. ', - name: 'checkpoint.content_length', + 'microsoft.m365_defender.alerts.entities.subject': { + category: 'microsoft', + description: 'The subject for the related email message. ', + name: 'microsoft.m365_defender.alerts.entities.subject', type: 'keyword', }, - 'checkpoint.authorization': { - category: 'checkpoint', - description: 'Authorization HTTP header value. ', - name: 'checkpoint.authorization', + 'microsoft.m365_defender.alerts.entities.deliveryAction': { + category: 'microsoft', + description: 'The delivery status for the related email message. ', + name: 'microsoft.m365_defender.alerts.entities.deliveryAction', type: 'keyword', }, - 'checkpoint.http_host': { - category: 'checkpoint', - description: 'Domain name of the server that the HTTP request is sent to. ', - name: 'checkpoint.http_host', + 'microsoft.m365_defender.alerts.entities.securityGroupId': { + category: 'microsoft', + description: 'The Security Group ID for the user related to the email message. ', + name: 'microsoft.m365_defender.alerts.entities.securityGroupId', type: 'keyword', }, - 'checkpoint.inspection_settings_log': { - category: 'checkpoint', - description: 'Indicats that the log was released by inspection settings. ', - name: 'checkpoint.inspection_settings_log', + 'microsoft.m365_defender.alerts.entities.securityGroupName': { + category: 'microsoft', + description: 'The Security Group Name for the user related to the email message. ', + name: 'microsoft.m365_defender.alerts.entities.securityGroupName', type: 'keyword', }, - 'checkpoint.cvpn_resource': { - category: 'checkpoint', - description: 'Mobile Access application. ', - name: 'checkpoint.cvpn_resource', + 'microsoft.m365_defender.alerts.entities.registryHive': { + category: 'microsoft', + description: + 'Reference to which Hive in registry the event is related to, if eventType is registry. Example: HKEY_LOCAL_MACHINE. ', + name: 'microsoft.m365_defender.alerts.entities.registryHive', type: 'keyword', }, - 'checkpoint.cvpn_category': { - category: 'checkpoint', - description: 'Mobile Access application type. ', - name: 'checkpoint.cvpn_category', + 'microsoft.m365_defender.alerts.entities.registryKey': { + category: 'microsoft', + description: 'Reference to the related registry key to the event. ', + name: 'microsoft.m365_defender.alerts.entities.registryKey', type: 'keyword', }, - 'checkpoint.url': { - category: 'checkpoint', - description: 'Translated URL. ', - name: 'checkpoint.url', + 'microsoft.m365_defender.alerts.entities.registryValueType': { + category: 'microsoft', + description: 'Value type of the registry key/value pair related to the event. ', + name: 'microsoft.m365_defender.alerts.entities.registryValueType', type: 'keyword', }, - 'checkpoint.reject_id': { - category: 'checkpoint', - description: - 'A reject ID that corresponds to the one presented in the Mobile Access error page. ', - name: 'checkpoint.reject_id', + 'microsoft.m365_defender.alerts.entities.deviceId': { + category: 'microsoft', + description: 'The unique ID of the device related to the event. ', + name: 'microsoft.m365_defender.alerts.entities.deviceId', type: 'keyword', }, - 'checkpoint.fs-proto': { - category: 'checkpoint', - description: 'The file share protocol used in mobile acess file share application. ', - name: 'checkpoint.fs-proto', + 'microsoft.m365_defender.alerts.entities.ipAddress': { + category: 'microsoft', + description: 'The related IP address to the event. ', + name: 'microsoft.m365_defender.alerts.entities.ipAddress', type: 'keyword', }, - 'checkpoint.app_package': { - category: 'checkpoint', - description: 'Unique identifier of the application on the protected mobile device. ', - name: 'checkpoint.app_package', + 'microsoft.m365_defender.alerts.devices': { + category: 'microsoft', + description: 'The devices related to the investigation. ', + name: 'microsoft.m365_defender.alerts.devices', + type: 'flattened', + }, + 'misp.attack_pattern.id': { + category: 'misp', + description: 'Identifier of the threat indicator. ', + name: 'misp.attack_pattern.id', type: 'keyword', }, - 'checkpoint.appi_name': { - category: 'checkpoint', - description: 'Name of application downloaded on the protected mobile device. ', - name: 'checkpoint.appi_name', + 'misp.attack_pattern.name': { + category: 'misp', + description: 'Name of the attack pattern. ', + name: 'misp.attack_pattern.name', type: 'keyword', }, - 'checkpoint.app_repackaged': { - category: 'checkpoint', - description: - 'Indicates whether the original application was repackage not by the official developer. ', - name: 'checkpoint.app_repackaged', + 'misp.attack_pattern.description': { + category: 'misp', + description: 'Description of the attack pattern. ', + name: 'misp.attack_pattern.description', + type: 'text', + }, + 'misp.attack_pattern.kill_chain_phases': { + category: 'misp', + description: 'The kill chain phase(s) to which this attack pattern corresponds. ', + name: 'misp.attack_pattern.kill_chain_phases', type: 'keyword', }, - 'checkpoint.app_sid_id': { - category: 'checkpoint', - description: 'Unique SHA identifier of a mobile application. ', - name: 'checkpoint.app_sid_id', + 'misp.campaign.id': { + category: 'misp', + description: 'Identifier of the campaign. ', + name: 'misp.campaign.id', type: 'keyword', }, - 'checkpoint.app_version': { - category: 'checkpoint', - description: 'Version of the application downloaded on the protected mobile device. ', - name: 'checkpoint.app_version', + 'misp.campaign.name': { + category: 'misp', + description: 'Name of the campaign. ', + name: 'misp.campaign.name', type: 'keyword', }, - 'checkpoint.developer_certificate_name': { - category: 'checkpoint', + 'misp.campaign.description': { + category: 'misp', + description: 'Description of the campaign. ', + name: 'misp.campaign.description', + type: 'text', + }, + 'misp.campaign.aliases': { + category: 'misp', + description: 'Alternative names used to identify this campaign. ', + name: 'misp.campaign.aliases', + type: 'text', + }, + 'misp.campaign.first_seen': { + category: 'misp', + description: 'The time that this Campaign was first seen, in RFC3339 format. ', + name: 'misp.campaign.first_seen', + type: 'date', + }, + 'misp.campaign.last_seen': { + category: 'misp', + description: 'The time that this Campaign was last seen, in RFC3339 format. ', + name: 'misp.campaign.last_seen', + type: 'date', + }, + 'misp.campaign.objective': { + category: 'misp', description: - "Name of the developer's certificate that was used to sign the mobile application. ", - name: 'checkpoint.developer_certificate_name', + "This field defines the Campaign's primary goal, objective, desired outcome, or intended effect. ", + name: 'misp.campaign.objective', type: 'keyword', }, - 'checkpoint.email_message_id': { - category: 'checkpoint', - description: 'Email session id (uniqe ID of the mail). ', - name: 'checkpoint.email_message_id', + 'misp.course_of_action.id': { + category: 'misp', + description: 'Identifier of the Course of Action. ', + name: 'misp.course_of_action.id', type: 'keyword', }, - 'checkpoint.email_queue_id': { - category: 'checkpoint', - description: 'Postfix email queue id. ', - name: 'checkpoint.email_queue_id', + 'misp.course_of_action.name': { + category: 'misp', + description: 'The name used to identify the Course of Action. ', + name: 'misp.course_of_action.name', type: 'keyword', }, - 'checkpoint.email_queue_name': { - category: 'checkpoint', - description: 'Postfix email queue name. ', - name: 'checkpoint.email_queue_name', - type: 'keyword', + 'misp.course_of_action.description': { + category: 'misp', + description: 'Description of the Course of Action. ', + name: 'misp.course_of_action.description', + type: 'text', }, - 'checkpoint.file_name': { - category: 'checkpoint', - description: 'Malicious file name. ', - name: 'checkpoint.file_name', + 'misp.identity.id': { + category: 'misp', + description: 'Identifier of the Identity. ', + name: 'misp.identity.id', type: 'keyword', }, - 'checkpoint.failure_reason': { - category: 'checkpoint', - description: 'MTA failure description. ', - name: 'checkpoint.failure_reason', + 'misp.identity.name': { + category: 'misp', + description: 'The name used to identify the Identity. ', + name: 'misp.identity.name', type: 'keyword', }, - 'checkpoint.email_headers': { - category: 'checkpoint', - description: 'String containing all the email headers. ', - name: 'checkpoint.email_headers', + 'misp.identity.description': { + category: 'misp', + description: 'Description of the Identity. ', + name: 'misp.identity.description', + type: 'text', + }, + 'misp.identity.identity_class': { + category: 'misp', + description: + 'The type of entity that this Identity describes, e.g., an individual or organization. Open Vocab - identity-class-ov ', + name: 'misp.identity.identity_class', type: 'keyword', }, - 'checkpoint.arrival_time': { - category: 'checkpoint', - description: 'Email arrival timestamp. ', - name: 'checkpoint.arrival_time', + 'misp.identity.labels': { + category: 'misp', + description: 'The list of roles that this Identity performs. ', + example: 'CEO\n', + name: 'misp.identity.labels', type: 'keyword', }, - 'checkpoint.email_status': { - category: 'checkpoint', + 'misp.identity.sectors': { + category: 'misp', description: - "Describes the email's state. Possible options: delivered, deferred, skipped, bounced, hold, new, scan_started, scan_ended ", - name: 'checkpoint.email_status', + 'The list of sectors that this Identity belongs to. Open Vocab - industry-sector-ov ', + name: 'misp.identity.sectors', type: 'keyword', }, - 'checkpoint.status_update': { - category: 'checkpoint', - description: 'Last time log was updated. ', - name: 'checkpoint.status_update', + 'misp.identity.contact_information': { + category: 'misp', + description: 'The contact information (e-mail, phone number, etc.) for this Identity. ', + name: 'misp.identity.contact_information', + type: 'text', + }, + 'misp.intrusion_set.id': { + category: 'misp', + description: 'Identifier of the Intrusion Set. ', + name: 'misp.intrusion_set.id', type: 'keyword', }, - 'checkpoint.delivery_time': { - category: 'checkpoint', - description: 'Timestamp of when email was delivered (MTA finished handling the email. ', - name: 'checkpoint.delivery_time', + 'misp.intrusion_set.name': { + category: 'misp', + description: 'The name used to identify the Intrusion Set. ', + name: 'misp.intrusion_set.name', type: 'keyword', }, - 'checkpoint.links_num': { - category: 'checkpoint', - description: 'Number of links in the mail. ', - name: 'checkpoint.links_num', - type: 'integer', + 'misp.intrusion_set.description': { + category: 'misp', + description: 'Description of the Intrusion Set. ', + name: 'misp.intrusion_set.description', + type: 'text', }, - 'checkpoint.attachments_num': { - category: 'checkpoint', - description: 'Number of attachments in the mail. ', - name: 'checkpoint.attachments_num', - type: 'integer', + 'misp.intrusion_set.aliases': { + category: 'misp', + description: 'Alternative names used to identify the Intrusion Set. ', + name: 'misp.intrusion_set.aliases', + type: 'text', }, - 'checkpoint.email_content': { - category: 'checkpoint', + 'misp.intrusion_set.first_seen': { + category: 'misp', + description: 'The time that this Intrusion Set was first seen, in RFC3339 format. ', + name: 'misp.intrusion_set.first_seen', + type: 'date', + }, + 'misp.intrusion_set.last_seen': { + category: 'misp', + description: 'The time that this Intrusion Set was last seen, in RFC3339 format. ', + name: 'misp.intrusion_set.last_seen', + type: 'date', + }, + 'misp.intrusion_set.goals': { + category: 'misp', + description: 'The high level goals of this Intrusion Set, namely, what are they trying to do. ', + name: 'misp.intrusion_set.goals', + type: 'text', + }, + 'misp.intrusion_set.resource_level': { + category: 'misp', description: - 'Mail contents. Possible options: attachments/links & attachments/links/text only. ', - name: 'checkpoint.email_content', - type: 'keyword', + 'This defines the organizational level at which this Intrusion Set typically works. Open Vocab - attack-resource-level-ov ', + name: 'misp.intrusion_set.resource_level', + type: 'text', }, - 'checkpoint.allocated_ports': { - category: 'checkpoint', - description: 'Amount of allocated ports. ', - name: 'checkpoint.allocated_ports', - type: 'integer', + 'misp.intrusion_set.primary_motivation': { + category: 'misp', + description: + 'The primary reason, motivation, or purpose behind this Intrusion Set. Open Vocab - attack-motivation-ov ', + name: 'misp.intrusion_set.primary_motivation', + type: 'text', }, - 'checkpoint.capacity': { - category: 'checkpoint', - description: 'Capacity of the ports. ', - name: 'checkpoint.capacity', - type: 'integer', + 'misp.intrusion_set.secondary_motivations': { + category: 'misp', + description: + 'The secondary reasons, motivations, or purposes behind this Intrusion Set. Open Vocab - attack-motivation-ov ', + name: 'misp.intrusion_set.secondary_motivations', + type: 'text', }, - 'checkpoint.ports_usage': { - category: 'checkpoint', - description: 'Percentage of allocated ports. ', - name: 'checkpoint.ports_usage', - type: 'integer', + 'misp.malware.id': { + category: 'misp', + description: 'Identifier of the Malware. ', + name: 'misp.malware.id', + type: 'keyword', }, - 'checkpoint.nat_exhausted_pool': { - category: 'checkpoint', - description: '4-tuple of an exhausted pool. ', - name: 'checkpoint.nat_exhausted_pool', + 'misp.malware.name': { + category: 'misp', + description: 'The name used to identify the Malware. ', + name: 'misp.malware.name', type: 'keyword', }, - 'checkpoint.nat_rulenum': { - category: 'checkpoint', - description: 'NAT rulebase first matched rule. ', - name: 'checkpoint.nat_rulenum', - type: 'integer', + 'misp.malware.description': { + category: 'misp', + description: 'Description of the Malware. ', + name: 'misp.malware.description', + type: 'text', }, - 'checkpoint.nat_addtnl_rulenum': { - category: 'checkpoint', + 'misp.malware.labels': { + category: 'misp', description: - 'When matching 2 automatic rules , second rule match will be shown otherwise field will be 0. ', - name: 'checkpoint.nat_addtnl_rulenum', - type: 'integer', - }, - 'checkpoint.message_info': { - category: 'checkpoint', - description: 'Used for information messages, for example:NAT connection has ended. ', - name: 'checkpoint.message_info', + 'The type of malware being described. Open Vocab - malware-label-ov. adware,backdoor,bot,ddos,dropper,exploit-kit,keylogger,ransomware, remote-access-trojan,resource-exploitation,rogue-security-software,rootkit, screen-capture,spyware,trojan,virus,worm ', + name: 'misp.malware.labels', type: 'keyword', }, - 'checkpoint.nat46': { - category: 'checkpoint', - description: 'NAT 46 status, in most cases "enabled". ', - name: 'checkpoint.nat46', + 'misp.malware.kill_chain_phases': { + category: 'misp', + description: 'The list of kill chain phases for which this Malware instance can be used. ', + name: 'misp.malware.kill_chain_phases', type: 'keyword', + format: 'string', }, - 'checkpoint.end_time': { - category: 'checkpoint', - description: 'TCP connection end time. ', - name: 'checkpoint.end_time', + 'misp.note.id': { + category: 'misp', + description: 'Identifier of the Note. ', + name: 'misp.note.id', type: 'keyword', }, - 'checkpoint.tcp_end_reason': { - category: 'checkpoint', - description: 'Reason for TCP connection closure. ', - name: 'checkpoint.tcp_end_reason', + 'misp.note.summary': { + category: 'misp', + description: 'A brief description used as a summary of the Note. ', + name: 'misp.note.summary', type: 'keyword', }, - 'checkpoint.cgnet': { - category: 'checkpoint', - description: 'Describes NAT allocation for specific subscriber. ', - name: 'checkpoint.cgnet', - type: 'keyword', + 'misp.note.description': { + category: 'misp', + description: 'The content of the Note. ', + name: 'misp.note.description', + type: 'text', }, - 'checkpoint.subscriber': { - category: 'checkpoint', - description: 'Source IP before CGNAT. ', - name: 'checkpoint.subscriber', - type: 'ip', + 'misp.note.authors': { + category: 'misp', + description: 'The name of the author(s) of this Note. ', + name: 'misp.note.authors', + type: 'keyword', }, - 'checkpoint.hide_ip': { - category: 'checkpoint', - description: 'Source IP which will be used after CGNAT. ', - name: 'checkpoint.hide_ip', - type: 'ip', + 'misp.note.object_refs': { + category: 'misp', + description: 'The STIX Objects (SDOs and SROs) that the note is being applied to. ', + name: 'misp.note.object_refs', + type: 'keyword', }, - 'checkpoint.int_start': { - category: 'checkpoint', - description: 'Subscriber start int which will be used for NAT. ', - name: 'checkpoint.int_start', - type: 'integer', + 'misp.threat_indicator.labels': { + category: 'misp', + description: 'list of type open-vocab that specifies the type of indicator. ', + example: 'Domain Watchlist\n', + name: 'misp.threat_indicator.labels', + type: 'keyword', }, - 'checkpoint.int_end': { - category: 'checkpoint', - description: 'Subscriber end int which will be used for NAT. ', - name: 'checkpoint.int_end', - type: 'integer', + 'misp.threat_indicator.id': { + category: 'misp', + description: 'Identifier of the threat indicator. ', + name: 'misp.threat_indicator.id', + type: 'keyword', }, - 'checkpoint.packet_amount': { - category: 'checkpoint', - description: 'Amount of packets dropped. ', - name: 'checkpoint.packet_amount', - type: 'integer', + 'misp.threat_indicator.version': { + category: 'misp', + description: 'Version of the threat indicator. ', + name: 'misp.threat_indicator.version', + type: 'keyword', }, - 'checkpoint.monitor_reason': { - category: 'checkpoint', - description: 'Aggregated logs of monitored packets. ', - name: 'checkpoint.monitor_reason', + 'misp.threat_indicator.type': { + category: 'misp', + description: 'Type of the threat indicator. ', + name: 'misp.threat_indicator.type', type: 'keyword', }, - 'checkpoint.drops_amount': { - category: 'checkpoint', - description: 'Amount of multicast packets dropped. ', - name: 'checkpoint.drops_amount', - type: 'integer', + 'misp.threat_indicator.description': { + category: 'misp', + description: 'Description of the threat indicator. ', + name: 'misp.threat_indicator.description', + type: 'text', }, - 'checkpoint.securexl_message': { - category: 'checkpoint', + 'misp.threat_indicator.feed': { + category: 'misp', + description: 'Name of the threat feed. ', + name: 'misp.threat_indicator.feed', + type: 'text', + }, + 'misp.threat_indicator.valid_from': { + category: 'misp', description: - 'Two options for a SecureXL message: 1. Missed accounting records after heavy load on logging system. 2. FW log message regarding a packet drop. ', - name: 'checkpoint.securexl_message', - type: 'keyword', + 'The time from which this Indicator should be considered valuable intelligence, in RFC3339 format. ', + name: 'misp.threat_indicator.valid_from', + type: 'date', }, - 'checkpoint.conns_amount': { - category: 'checkpoint', - description: 'Connections amount of aggregated log info. ', - name: 'checkpoint.conns_amount', - type: 'integer', + 'misp.threat_indicator.valid_until': { + category: 'misp', + description: + 'The time at which this Indicator should no longer be considered valuable intelligence. If the valid_until property is omitted, then there is no constraint on the latest time for which the indicator should be used, in RFC3339 format. ', + name: 'misp.threat_indicator.valid_until', + type: 'date', }, - 'checkpoint.scope': { - category: 'checkpoint', - description: 'IP related to the attack. ', - name: 'checkpoint.scope', + 'misp.threat_indicator.severity': { + category: 'misp', + description: 'Threat severity to which this indicator corresponds. ', + example: 'high', + name: 'misp.threat_indicator.severity', type: 'keyword', + format: 'string', }, - 'checkpoint.analyzed_on': { - category: 'checkpoint', - description: 'Check Point ThreatCloud / emulator name. ', - name: 'checkpoint.analyzed_on', + 'misp.threat_indicator.confidence': { + category: 'misp', + description: 'Confidence level to which this indicator corresponds. ', + example: 'high', + name: 'misp.threat_indicator.confidence', type: 'keyword', }, - 'checkpoint.detected_on': { - category: 'checkpoint', - description: 'System and applications version the file was emulated on. ', - name: 'checkpoint.detected_on', + 'misp.threat_indicator.kill_chain_phases': { + category: 'misp', + description: 'The kill chain phase(s) to which this indicator corresponds. ', + name: 'misp.threat_indicator.kill_chain_phases', type: 'keyword', + format: 'string', }, - 'checkpoint.dropped_file_name': { - category: 'checkpoint', - description: 'List of names dropped from the original file. ', - name: 'checkpoint.dropped_file_name', + 'misp.threat_indicator.mitre_tactic': { + category: 'misp', + description: 'MITRE tactics to which this indicator corresponds. ', + example: 'Initial Access', + name: 'misp.threat_indicator.mitre_tactic', type: 'keyword', + format: 'string', }, - 'checkpoint.dropped_file_type': { - category: 'checkpoint', - description: 'List of file types dropped from the original file. ', - name: 'checkpoint.dropped_file_type', + 'misp.threat_indicator.mitre_technique': { + category: 'misp', + description: 'MITRE techniques to which this indicator corresponds. ', + example: 'Drive-by Compromise', + name: 'misp.threat_indicator.mitre_technique', type: 'keyword', + format: 'string', }, - 'checkpoint.dropped_file_hash': { - category: 'checkpoint', - description: 'List of file hashes dropped from the original file. ', - name: 'checkpoint.dropped_file_hash', + 'misp.threat_indicator.attack_pattern': { + category: 'misp', + description: + 'The attack_pattern for this indicator is a STIX Pattern as specified in STIX Version 2.0 Part 5 - STIX Patterning. ', + example: "[destination:ip = '91.219.29.188/32']\n", + name: 'misp.threat_indicator.attack_pattern', type: 'keyword', }, - 'checkpoint.dropped_file_verdict': { - category: 'checkpoint', - description: 'List of file verdics dropped from the original file. ', - name: 'checkpoint.dropped_file_verdict', + 'misp.threat_indicator.attack_pattern_kql': { + category: 'misp', + description: + 'The attack_pattern for this indicator is KQL query that matches the attack_pattern specified in the STIX Pattern format. ', + example: 'destination.ip: "91.219.29.188/32"\n', + name: 'misp.threat_indicator.attack_pattern_kql', type: 'keyword', }, - 'checkpoint.emulated_on': { - category: 'checkpoint', - description: 'Images the files were emulated on. ', - name: 'checkpoint.emulated_on', + 'misp.threat_indicator.negate': { + category: 'misp', + description: 'When set to true, it specifies the absence of the attack_pattern. ', + name: 'misp.threat_indicator.negate', + type: 'boolean', + }, + 'misp.threat_indicator.intrusion_set': { + category: 'misp', + description: 'Name of the intrusion set if known. ', + name: 'misp.threat_indicator.intrusion_set', type: 'keyword', }, - 'checkpoint.extracted_file_type': { - category: 'checkpoint', - description: 'Types of extracted files in case of an archive. ', - name: 'checkpoint.extracted_file_type', + 'misp.threat_indicator.campaign': { + category: 'misp', + description: 'Name of the attack campaign if known. ', + name: 'misp.threat_indicator.campaign', type: 'keyword', }, - 'checkpoint.extracted_file_names': { - category: 'checkpoint', - description: 'Names of extracted files in case of an archive. ', - name: 'checkpoint.extracted_file_names', + 'misp.threat_indicator.threat_actor': { + category: 'misp', + description: 'Name of the threat actor if known. ', + name: 'misp.threat_indicator.threat_actor', type: 'keyword', }, - 'checkpoint.extracted_file_hash': { - category: 'checkpoint', - description: 'Archive hash in case of extracted files. ', - name: 'checkpoint.extracted_file_hash', + 'misp.observed_data.id': { + category: 'misp', + description: 'Identifier of the Observed Data. ', + name: 'misp.observed_data.id', type: 'keyword', }, - 'checkpoint.extracted_file_verdict': { - category: 'checkpoint', - description: 'Verdict of extracted files in case of an archive. ', - name: 'checkpoint.extracted_file_verdict', + 'misp.observed_data.first_observed': { + category: 'misp', + description: 'The beginning of the time window that the data was observed, in RFC3339 format. ', + name: 'misp.observed_data.first_observed', + type: 'date', + }, + 'misp.observed_data.last_observed': { + category: 'misp', + description: 'The end of the time window that the data was observed, in RFC3339 format. ', + name: 'misp.observed_data.last_observed', + type: 'date', + }, + 'misp.observed_data.number_observed': { + category: 'misp', + description: + 'The number of times the data represented in the objects property was observed. This MUST be an integer between 1 and 999,999,999 inclusive. ', + name: 'misp.observed_data.number_observed', + type: 'integer', + }, + 'misp.observed_data.objects': { + category: 'misp', + description: + 'A dictionary of Cyber Observable Objects that describes the single fact that was observed. ', + name: 'misp.observed_data.objects', type: 'keyword', }, - 'checkpoint.extracted_file_uid': { - category: 'checkpoint', - description: 'UID of extracted files in case of an archive. ', - name: 'checkpoint.extracted_file_uid', + 'misp.report.id': { + category: 'misp', + description: 'Identifier of the Report. ', + name: 'misp.report.id', type: 'keyword', }, - 'checkpoint.mitre_initial_access': { - category: 'checkpoint', - description: 'The adversary is trying to break into your network. ', - name: 'checkpoint.mitre_initial_access', + 'misp.report.labels': { + category: 'misp', + description: + 'This field is an Open Vocabulary that specifies the primary subject of this report. Open Vocab - report-label-ov. threat-report,attack-pattern,campaign,identity,indicator,malware,observed-data,threat-actor,tool,vulnerability ', + name: 'misp.report.labels', type: 'keyword', }, - 'checkpoint.mitre_execution': { - category: 'checkpoint', - description: 'The adversary is trying to run malicious code. ', - name: 'checkpoint.mitre_execution', + 'misp.report.name': { + category: 'misp', + description: 'The name used to identify the Report. ', + name: 'misp.report.name', type: 'keyword', }, - 'checkpoint.mitre_persistence': { - category: 'checkpoint', - description: 'The adversary is trying to maintain his foothold. ', - name: 'checkpoint.mitre_persistence', + 'misp.report.description': { + category: 'misp', + description: 'A description that provides more details and context about Report. ', + name: 'misp.report.description', + type: 'text', + }, + 'misp.report.published': { + category: 'misp', + description: + 'The date that this report object was officially published by the creator of this report, in RFC3339 format. ', + name: 'misp.report.published', + type: 'date', + }, + 'misp.report.object_refs': { + category: 'misp', + description: 'Specifies the STIX Objects that are referred to by this Report. ', + name: 'misp.report.object_refs', + type: 'text', + }, + 'misp.threat_actor.id': { + category: 'misp', + description: 'Identifier of the Threat Actor. ', + name: 'misp.threat_actor.id', type: 'keyword', }, - 'checkpoint.mitre_privilege_escalation': { - category: 'checkpoint', - description: 'The adversary is trying to gain higher-level permissions. ', - name: 'checkpoint.mitre_privilege_escalation', + 'misp.threat_actor.labels': { + category: 'misp', + description: + 'This field specifies the type of threat actor. Open Vocab - threat-actor-label-ov. activist,competitor,crime-syndicate,criminal,hacker,insider-accidental,insider-disgruntled,nation-state,sensationalist,spy,terrorist ', + name: 'misp.threat_actor.labels', type: 'keyword', }, - 'checkpoint.mitre_defense_evasion': { - category: 'checkpoint', - description: 'The adversary is trying to avoid being detected. ', - name: 'checkpoint.mitre_defense_evasion', + 'misp.threat_actor.name': { + category: 'misp', + description: 'The name used to identify this Threat Actor or Threat Actor group. ', + name: 'misp.threat_actor.name', type: 'keyword', }, - 'checkpoint.mitre_credential_access': { - category: 'checkpoint', - description: 'The adversary is trying to steal account names and passwords. ', - name: 'checkpoint.mitre_credential_access', - type: 'keyword', + 'misp.threat_actor.description': { + category: 'misp', + description: 'A description that provides more details and context about the Threat Actor. ', + name: 'misp.threat_actor.description', + type: 'text', }, - 'checkpoint.mitre_discovery': { - category: 'checkpoint', - description: 'The adversary is trying to expose information about your environment. ', - name: 'checkpoint.mitre_discovery', - type: 'keyword', + 'misp.threat_actor.aliases': { + category: 'misp', + description: 'A list of other names that this Threat Actor is believed to use. ', + name: 'misp.threat_actor.aliases', + type: 'text', }, - 'checkpoint.mitre_lateral_movement': { - category: 'checkpoint', - description: 'The adversary is trying to explore your environment. ', - name: 'checkpoint.mitre_lateral_movement', - type: 'keyword', + 'misp.threat_actor.roles': { + category: 'misp', + description: + 'This is a list of roles the Threat Actor plays. Open Vocab - threat-actor-role-ov. agent,director,independent,sponsor,infrastructure-operator,infrastructure-architect,malware-author ', + name: 'misp.threat_actor.roles', + type: 'text', }, - 'checkpoint.mitre_collection': { - category: 'checkpoint', - description: 'The adversary is trying to collect data of interest to achieve his goal. ', - name: 'checkpoint.mitre_collection', - type: 'keyword', + 'misp.threat_actor.goals': { + category: 'misp', + description: 'The high level goals of this Threat Actor, namely, what are they trying to do. ', + name: 'misp.threat_actor.goals', + type: 'text', }, - 'checkpoint.mitre_command_and_control': { - category: 'checkpoint', + 'misp.threat_actor.sophistication': { + category: 'misp', description: - 'The adversary is trying to communicate with compromised systems in order to control them. ', - name: 'checkpoint.mitre_command_and_control', - type: 'keyword', + 'The skill, specific knowledge, special training, or expertise a Threat Actor must have to perform the attack. Open Vocab - threat-actor-sophistication-ov. none,minimal,intermediate,advanced,strategic,expert,innovator ', + name: 'misp.threat_actor.sophistication', + type: 'text', }, - 'checkpoint.mitre_exfiltration': { - category: 'checkpoint', - description: 'The adversary is trying to steal data. ', - name: 'checkpoint.mitre_exfiltration', - type: 'keyword', + 'misp.threat_actor.resource_level': { + category: 'misp', + description: + 'This defines the organizational level at which this Threat Actor typically works. Open Vocab - attack-resource-level-ov. individual,club,contest,team,organization,government ', + name: 'misp.threat_actor.resource_level', + type: 'text', }, - 'checkpoint.mitre_impact': { - category: 'checkpoint', + 'misp.threat_actor.primary_motivation': { + category: 'misp', description: - 'The adversary is trying to manipulate, interrupt, or destroy your systems and data. ', - name: 'checkpoint.mitre_impact', - type: 'keyword', + 'The primary reason, motivation, or purpose behind this Threat Actor. Open Vocab - attack-motivation-ov. accidental,coercion,dominance,ideology,notoriety,organizational-gain,personal-gain,personal-satisfaction,revenge,unpredictable ', + name: 'misp.threat_actor.primary_motivation', + type: 'text', }, - 'checkpoint.parent_file_hash': { - category: 'checkpoint', - description: "Archive's hash in case of extracted files. ", - name: 'checkpoint.parent_file_hash', - type: 'keyword', + 'misp.threat_actor.secondary_motivations': { + category: 'misp', + description: + 'The secondary reasons, motivations, or purposes behind this Threat Actor. Open Vocab - attack-motivation-ov. accidental,coercion,dominance,ideology,notoriety,organizational-gain,personal-gain,personal-satisfaction,revenge,unpredictable ', + name: 'misp.threat_actor.secondary_motivations', + type: 'text', }, - 'checkpoint.parent_file_name': { - category: 'checkpoint', - description: "Archive's name in case of extracted files. ", - name: 'checkpoint.parent_file_name', - type: 'keyword', + 'misp.threat_actor.personal_motivations': { + category: 'misp', + description: + 'The personal reasons, motivations, or purposes of the Threat Actor regardless of organizational goals. Open Vocab - attack-motivation-ov. accidental,coercion,dominance,ideology,notoriety,organizational-gain,personal-gain,personal-satisfaction,revenge,unpredictable ', + name: 'misp.threat_actor.personal_motivations', + type: 'text', }, - 'checkpoint.parent_file_uid': { - category: 'checkpoint', - description: "Archive's UID in case of extracted files. ", - name: 'checkpoint.parent_file_uid', + 'misp.tool.id': { + category: 'misp', + description: 'Identifier of the Tool. ', + name: 'misp.tool.id', type: 'keyword', }, - 'checkpoint.similiar_iocs': { - category: 'checkpoint', - description: 'Other IoCs similar to the ones found, related to the malicious file. ', - name: 'checkpoint.similiar_iocs', + 'misp.tool.labels': { + category: 'misp', + description: + 'The kind(s) of tool(s) being described. Open Vocab - tool-label-ov. denial-of-service,exploitation,information-gathering,network-capture,credential-exploitation,remote-access,vulnerability-scanning ', + name: 'misp.tool.labels', type: 'keyword', }, - 'checkpoint.similar_hashes': { - category: 'checkpoint', - description: 'Hashes found similar to the malicious file. ', - name: 'checkpoint.similar_hashes', + 'misp.tool.name': { + category: 'misp', + description: 'The name used to identify the Tool. ', + name: 'misp.tool.name', type: 'keyword', }, - 'checkpoint.similar_strings': { - category: 'checkpoint', - description: 'Strings found similar to the malicious file. ', - name: 'checkpoint.similar_strings', - type: 'keyword', + 'misp.tool.description': { + category: 'misp', + description: 'A description that provides more details and context about the Tool. ', + name: 'misp.tool.description', + type: 'text', }, - 'checkpoint.similar_communication': { - category: 'checkpoint', - description: 'Network action found similar to the malicious file. ', - name: 'checkpoint.similar_communication', + 'misp.tool.tool_version': { + category: 'misp', + description: 'The version identifier associated with the Tool. ', + name: 'misp.tool.tool_version', type: 'keyword', }, - 'checkpoint.te_verdict_determined_by': { - category: 'checkpoint', - description: 'Emulators determined file verdict. ', - name: 'checkpoint.te_verdict_determined_by', - type: 'keyword', + 'misp.tool.kill_chain_phases': { + category: 'misp', + description: 'The list of kill chain phases for which this Tool instance can be used. ', + name: 'misp.tool.kill_chain_phases', + type: 'text', }, - 'checkpoint.packet_capture_unique_id': { - category: 'checkpoint', - description: 'Identifier of the packet capture files. ', - name: 'checkpoint.packet_capture_unique_id', + 'misp.vulnerability.id': { + category: 'misp', + description: 'Identifier of the Vulnerability. ', + name: 'misp.vulnerability.id', type: 'keyword', }, - 'checkpoint.total_attachments': { - category: 'checkpoint', - description: 'The number of attachments in an email. ', - name: 'checkpoint.total_attachments', - type: 'integer', - }, - 'checkpoint.additional_info': { - category: 'checkpoint', - description: 'ID of original file/mail which are sent by admin. ', - name: 'checkpoint.additional_info', + 'misp.vulnerability.name': { + category: 'misp', + description: 'The name used to identify the Vulnerability. ', + name: 'misp.vulnerability.name', type: 'keyword', }, - 'checkpoint.content_risk': { - category: 'checkpoint', - description: 'File risk. ', - name: 'checkpoint.content_risk', - type: 'integer', + 'misp.vulnerability.description': { + category: 'misp', + description: 'A description that provides more details and context about the Vulnerability. ', + name: 'misp.vulnerability.description', + type: 'text', }, - 'checkpoint.operation': { - category: 'checkpoint', - description: 'Operation made by Threat Extraction. ', - name: 'checkpoint.operation', + 'mssql.log.origin': { + category: 'mssql', + description: 'Origin of the message, usually the server but it can also be a recovery process', + name: 'mssql.log.origin', type: 'keyword', }, - 'checkpoint.scrubbed_content': { - category: 'checkpoint', - description: 'Active content that was found. ', - name: 'checkpoint.scrubbed_content', + 'mysqlenterprise.audit.class': { + category: 'mysqlenterprise', + description: + 'A string representing the event class. The class defines the type of event, when taken together with the event item that specifies the event subclass. ', + name: 'mysqlenterprise.audit.class', type: 'keyword', }, - 'checkpoint.scrub_time': { - category: 'checkpoint', - description: 'Extraction process duration. ', - name: 'checkpoint.scrub_time', + 'mysqlenterprise.audit.connection_id': { + category: 'mysqlenterprise', + description: + 'An integer representing the client connection identifier. This is the same as the value returned by the CONNECTION_ID() function within the session. ', + name: 'mysqlenterprise.audit.connection_id', type: 'keyword', }, - 'checkpoint.scrub_download_time': { - category: 'checkpoint', - description: 'File download time from resource. ', - name: 'checkpoint.scrub_download_time', + 'mysqlenterprise.audit.id': { + category: 'mysqlenterprise', + description: 'An unsigned integer representing an event ID. ', + name: 'mysqlenterprise.audit.id', type: 'keyword', }, - 'checkpoint.scrub_total_time': { - category: 'checkpoint', - description: 'Threat extraction total file handling time. ', - name: 'checkpoint.scrub_total_time', + 'mysqlenterprise.audit.connection_data.connection_type': { + category: 'mysqlenterprise', + description: + 'The security state of the connection to the server. Permitted values are tcp/ip (TCP/IP connection established without encryption), ssl (TCP/IP connection established with encryption), socket (Unix socket file connection), named_pipe (Windows named pipe connection), and shared_memory (Windows shared memory connection). ', + name: 'mysqlenterprise.audit.connection_data.connection_type', type: 'keyword', }, - 'checkpoint.scrub_activity': { - category: 'checkpoint', - description: 'The result of the extraction ', - name: 'checkpoint.scrub_activity', - type: 'keyword', + 'mysqlenterprise.audit.connection_data.status': { + category: 'mysqlenterprise', + description: + 'An integer representing the command status: 0 for success, nonzero if an error occurred. ', + name: 'mysqlenterprise.audit.connection_data.status', + type: 'long', }, - 'checkpoint.watermark': { - category: 'checkpoint', - description: 'Reports whether watermark is added to the cleaned file. ', - name: 'checkpoint.watermark', + 'mysqlenterprise.audit.connection_data.db': { + category: 'mysqlenterprise', + description: + 'A string representing a database name. For connection_data, it is the default database. For table_access_data, it is the table database. ', + name: 'mysqlenterprise.audit.connection_data.db', type: 'keyword', }, - 'checkpoint.source_object': { - category: 'checkpoint', - description: 'Matched object name on source column. ', - name: 'checkpoint.source_object', - type: 'integer', + 'mysqlenterprise.audit.connection_data.connection_attributes': { + category: 'mysqlenterprise', + description: 'Connection attributes that might be passed by different MySQL Clients. ', + name: 'mysqlenterprise.audit.connection_data.connection_attributes', + type: 'flattened', }, - 'checkpoint.destination_object': { - category: 'checkpoint', - description: 'Matched object name on destination column. ', - name: 'checkpoint.destination_object', + 'mysqlenterprise.audit.general_data.command': { + category: 'mysqlenterprise', + description: + 'A string representing the type of instruction that generated the audit event, such as a command that the server received from a client. ', + name: 'mysqlenterprise.audit.general_data.command', type: 'keyword', }, - 'checkpoint.drop_reason': { - category: 'checkpoint', - description: 'Drop reason description. ', - name: 'checkpoint.drop_reason', + 'mysqlenterprise.audit.general_data.sql_command': { + category: 'mysqlenterprise', + description: 'A string that indicates the SQL statement type. ', + name: 'mysqlenterprise.audit.general_data.sql_command', type: 'keyword', }, - 'checkpoint.hit': { - category: 'checkpoint', - description: 'Number of hits on a rule. ', - name: 'checkpoint.hit', - type: 'integer', - }, - 'checkpoint.rulebase_id': { - category: 'checkpoint', - description: 'Layer number. ', - name: 'checkpoint.rulebase_id', - type: 'integer', - }, - 'checkpoint.first_hit_time': { - category: 'checkpoint', - description: 'First hit time in current interval. ', - name: 'checkpoint.first_hit_time', - type: 'integer', + 'mysqlenterprise.audit.general_data.query': { + category: 'mysqlenterprise', + description: + 'A string representing the text of an SQL statement. The value can be empty. Long values may be truncated. The string, like the audit log file itself, is written using UTF-8 (up to 4 bytes per character), so the value may be the result of conversion. ', + name: 'mysqlenterprise.audit.general_data.query', + type: 'keyword', }, - 'checkpoint.last_hit_time': { - category: 'checkpoint', - description: 'Last hit time in current interval. ', - name: 'checkpoint.last_hit_time', - type: 'integer', + 'mysqlenterprise.audit.general_data.status': { + category: 'mysqlenterprise', + description: + 'An integer representing the command status: 0 for success, nonzero if an error occurred. This is the same as the value of the mysql_errno() C API function. ', + name: 'mysqlenterprise.audit.general_data.status', + type: 'long', }, - 'checkpoint.rematch_info': { - category: 'checkpoint', + 'mysqlenterprise.audit.login.user': { + category: 'mysqlenterprise', description: - 'Information sent when old connections cannot be matched during policy installation. ', - name: 'checkpoint.rematch_info', + 'A string representing the information indicating how a client connected to the server. ', + name: 'mysqlenterprise.audit.login.user', type: 'keyword', }, - 'checkpoint.last_rematch_time': { - category: 'checkpoint', - description: 'Connection rematched time. ', - name: 'checkpoint.last_rematch_time', + 'mysqlenterprise.audit.login.proxy': { + category: 'mysqlenterprise', + description: + 'A string representing the proxy user. The value is empty if user proxying is not in effect. ', + name: 'mysqlenterprise.audit.login.proxy', type: 'keyword', }, - 'checkpoint.action_reason': { - category: 'checkpoint', - description: 'Connection drop reason. ', - name: 'checkpoint.action_reason', - type: 'integer', - }, - 'checkpoint.c_bytes': { - category: 'checkpoint', - description: 'Boolean value indicates whether bytes sent from the client side are used. ', - name: 'checkpoint.c_bytes', - type: 'integer', - }, - 'checkpoint.context_num': { - category: 'checkpoint', - description: 'Serial number of the log for a specific connection. ', - name: 'checkpoint.context_num', - type: 'integer', - }, - 'checkpoint.match_id': { - category: 'checkpoint', - description: 'Private key of the rule ', - name: 'checkpoint.match_id', - type: 'integer', - }, - 'checkpoint.alert': { - category: 'checkpoint', - description: 'Alert level of matched rule (for connection logs). ', - name: 'checkpoint.alert', + 'mysqlenterprise.audit.shutdown_data.server_id': { + category: 'mysqlenterprise', + description: + 'An integer representing the server ID. This is the same as the value of the server_id system variable. ', + name: 'mysqlenterprise.audit.shutdown_data.server_id', type: 'keyword', }, - 'checkpoint.parent_rule': { - category: 'checkpoint', - description: 'Parent rule number, in case of inline layer. ', - name: 'checkpoint.parent_rule', - type: 'integer', - }, - 'checkpoint.match_fk': { - category: 'checkpoint', - description: 'Rule number. ', - name: 'checkpoint.match_fk', - type: 'integer', - }, - 'checkpoint.dropped_outgoing': { - category: 'checkpoint', - description: 'Number of outgoing bytes dropped when using UP-limit feature. ', - name: 'checkpoint.dropped_outgoing', - type: 'integer', - }, - 'checkpoint.dropped_incoming': { - category: 'checkpoint', - description: 'Number of incoming bytes dropped when using UP-limit feature. ', - name: 'checkpoint.dropped_incoming', - type: 'integer', - }, - 'checkpoint.media_type': { - category: 'checkpoint', - description: 'Media used (audio, video, etc.) ', - name: 'checkpoint.media_type', + 'mysqlenterprise.audit.startup_data.server_id': { + category: 'mysqlenterprise', + description: + 'An integer representing the server ID. This is the same as the value of the server_id system variable. ', + name: 'mysqlenterprise.audit.startup_data.server_id', type: 'keyword', }, - 'checkpoint.sip_reason': { - category: 'checkpoint', - description: "Explains why 'source_ip' isn't allowed to redirect (handover). ", - name: 'checkpoint.sip_reason', + 'mysqlenterprise.audit.startup_data.mysql_version': { + category: 'mysqlenterprise', + description: + 'An integer representing the server ID. This is the same as the value of the server_id system variable. ', + name: 'mysqlenterprise.audit.startup_data.mysql_version', type: 'keyword', }, - 'checkpoint.voip_method': { - category: 'checkpoint', - description: 'Registration request. ', - name: 'checkpoint.voip_method', + 'mysqlenterprise.audit.table_access_data.db': { + category: 'mysqlenterprise', + description: + 'A string representing a database name. For connection_data, it is the default database. For table_access_data, it is the table database. ', + name: 'mysqlenterprise.audit.table_access_data.db', type: 'keyword', }, - 'checkpoint.registered_ip-phones': { - category: 'checkpoint', - description: 'Registered IP-Phones. ', - name: 'checkpoint.registered_ip-phones', + 'mysqlenterprise.audit.table_access_data.table': { + category: 'mysqlenterprise', + description: 'A string representing a table name. ', + name: 'mysqlenterprise.audit.table_access_data.table', type: 'keyword', }, - 'checkpoint.voip_reg_user_type': { - category: 'checkpoint', - description: 'Registered IP-Phone type. ', - name: 'checkpoint.voip_reg_user_type', + 'mysqlenterprise.audit.table_access_data.query': { + category: 'mysqlenterprise', + description: + 'A string representing the text of an SQL statement. The value can be empty. Long values may be truncated. The string, like the audit log file itself, is written using UTF-8 (up to 4 bytes per character), so the value may be the result of conversion. ', + name: 'mysqlenterprise.audit.table_access_data.query', type: 'keyword', }, - 'checkpoint.voip_call_id': { - category: 'checkpoint', - description: 'Call-ID. ', - name: 'checkpoint.voip_call_id', + 'mysqlenterprise.audit.table_access_data.sql_command': { + category: 'mysqlenterprise', + description: 'A string that indicates the SQL statement type. ', + name: 'mysqlenterprise.audit.table_access_data.sql_command', type: 'keyword', }, - 'checkpoint.voip_reg_int': { - category: 'checkpoint', - description: 'Registration port. ', - name: 'checkpoint.voip_reg_int', - type: 'integer', - }, - 'checkpoint.voip_reg_ipp': { - category: 'checkpoint', - description: 'Registration IP protocol. ', - name: 'checkpoint.voip_reg_ipp', - type: 'integer', - }, - 'checkpoint.voip_reg_period': { - category: 'checkpoint', - description: 'Registration period. ', - name: 'checkpoint.voip_reg_period', - type: 'integer', - }, - 'checkpoint.src_phone_number': { - category: 'checkpoint', - description: 'Source IP-Phone. ', - name: 'checkpoint.src_phone_number', + 'mysqlenterprise.audit.account.user': { + category: 'mysqlenterprise', + description: + 'A string representing the user that the server authenticated the client as. This is the user name that the server uses for privilege checking. ', + name: 'mysqlenterprise.audit.account.user', type: 'keyword', }, - 'checkpoint.voip_from_user_type': { - category: 'checkpoint', - description: 'Source IP-Phone type. ', - name: 'checkpoint.voip_from_user_type', + 'mysqlenterprise.audit.account.host': { + category: 'mysqlenterprise', + description: 'A string representing the client host name. ', + name: 'mysqlenterprise.audit.account.host', type: 'keyword', }, - 'checkpoint.voip_to_user_type': { - category: 'checkpoint', - description: 'Destination IP-Phone type. ', - name: 'checkpoint.voip_to_user_type', + 'mysqlenterprise.audit.login.os': { + category: 'mysqlenterprise', + description: + 'A string representing the external user name used during the authentication process, as set by the plugin used to authenticate the client. ', + name: 'mysqlenterprise.audit.login.os', type: 'keyword', }, - 'checkpoint.voip_call_dir': { - category: 'checkpoint', - description: 'Call direction: in/out. ', - name: 'checkpoint.voip_call_dir', + 'o365.audit.AADGroupId': { + category: 'o365', + name: 'o365.audit.AADGroupId', type: 'keyword', }, - 'checkpoint.voip_call_state': { - category: 'checkpoint', - description: 'Call state. Possible values: in/out. ', - name: 'checkpoint.voip_call_state', + 'o365.audit.Actor.ID': { + category: 'o365', + name: 'o365.audit.Actor.ID', type: 'keyword', }, - 'checkpoint.voip_call_term_time': { - category: 'checkpoint', - description: 'Call termination time stamp. ', - name: 'checkpoint.voip_call_term_time', + 'o365.audit.Actor.Type': { + category: 'o365', + name: 'o365.audit.Actor.Type', type: 'keyword', }, - 'checkpoint.voip_duration': { - category: 'checkpoint', - description: 'Call duration (seconds). ', - name: 'checkpoint.voip_duration', + 'o365.audit.ActorContextId': { + category: 'o365', + name: 'o365.audit.ActorContextId', type: 'keyword', }, - 'checkpoint.voip_media_port': { - category: 'checkpoint', - description: 'Media int. ', - name: 'checkpoint.voip_media_port', + 'o365.audit.ActorIpAddress': { + category: 'o365', + name: 'o365.audit.ActorIpAddress', type: 'keyword', }, - 'checkpoint.voip_media_ipp': { - category: 'checkpoint', - description: 'Media IP protocol. ', - name: 'checkpoint.voip_media_ipp', + 'o365.audit.ActorUserId': { + category: 'o365', + name: 'o365.audit.ActorUserId', type: 'keyword', }, - 'checkpoint.voip_est_codec': { - category: 'checkpoint', - description: 'Estimated codec. ', - name: 'checkpoint.voip_est_codec', + 'o365.audit.ActorYammerUserId': { + category: 'o365', + name: 'o365.audit.ActorYammerUserId', type: 'keyword', }, - 'checkpoint.voip_exp': { - category: 'checkpoint', - description: 'Expiration. ', - name: 'checkpoint.voip_exp', - type: 'integer', - }, - 'checkpoint.voip_attach_sz': { - category: 'checkpoint', - description: 'Attachment size. ', - name: 'checkpoint.voip_attach_sz', - type: 'integer', - }, - 'checkpoint.voip_attach_action_info': { - category: 'checkpoint', - description: 'Attachment action Info. ', - name: 'checkpoint.voip_attach_action_info', + 'o365.audit.AlertEntityId': { + category: 'o365', + name: 'o365.audit.AlertEntityId', type: 'keyword', }, - 'checkpoint.voip_media_codec': { - category: 'checkpoint', - description: 'Estimated codec. ', - name: 'checkpoint.voip_media_codec', + 'o365.audit.AlertId': { + category: 'o365', + name: 'o365.audit.AlertId', type: 'keyword', }, - 'checkpoint.voip_reject_reason': { - category: 'checkpoint', - description: 'Reject reason. ', - name: 'checkpoint.voip_reject_reason', + 'o365.audit.AlertLinks': { + category: 'o365', + name: 'o365.audit.AlertLinks', + type: 'array', + }, + 'o365.audit.AlertType': { + category: 'o365', + name: 'o365.audit.AlertType', type: 'keyword', }, - 'checkpoint.voip_reason_info': { - category: 'checkpoint', - description: 'Information. ', - name: 'checkpoint.voip_reason_info', + 'o365.audit.AppId': { + category: 'o365', + name: 'o365.audit.AppId', type: 'keyword', }, - 'checkpoint.voip_config': { - category: 'checkpoint', - description: 'Configuration. ', - name: 'checkpoint.voip_config', + 'o365.audit.ApplicationDisplayName': { + category: 'o365', + name: 'o365.audit.ApplicationDisplayName', type: 'keyword', }, - 'checkpoint.voip_reg_server': { - category: 'checkpoint', - description: 'Registrar server IP address. ', - name: 'checkpoint.voip_reg_server', - type: 'ip', + 'o365.audit.ApplicationId': { + category: 'o365', + name: 'o365.audit.ApplicationId', + type: 'keyword', }, - 'checkpoint.scv_user': { - category: 'checkpoint', - description: 'Username whose packets are dropped on SCV. ', - name: 'checkpoint.scv_user', + 'o365.audit.AzureActiveDirectoryEventType': { + category: 'o365', + name: 'o365.audit.AzureActiveDirectoryEventType', type: 'keyword', }, - 'checkpoint.scv_message_info': { - category: 'checkpoint', - description: 'Drop reason. ', - name: 'checkpoint.scv_message_info', - type: 'keyword', + 'o365.audit.ExchangeMetaData.*': { + category: 'o365', + name: 'o365.audit.ExchangeMetaData.*', + type: 'object', }, - 'checkpoint.ppp': { - category: 'checkpoint', - description: 'Authentication status. ', - name: 'checkpoint.ppp', + 'o365.audit.Category': { + category: 'o365', + name: 'o365.audit.Category', type: 'keyword', }, - 'checkpoint.scheme': { - category: 'checkpoint', - description: 'Describes the scheme used for the log. ', - name: 'checkpoint.scheme', + 'o365.audit.ClientAppId': { + category: 'o365', + name: 'o365.audit.ClientAppId', type: 'keyword', }, - 'checkpoint.machine': { - category: 'checkpoint', - description: 'L2TP machine which triggered the log and the log refers to it. ', - name: 'checkpoint.machine', + 'o365.audit.ClientInfoString': { + category: 'o365', + name: 'o365.audit.ClientInfoString', type: 'keyword', }, - 'checkpoint.vpn_feature_name': { - category: 'checkpoint', - description: 'L2TP /IKE / Link Selection. ', - name: 'checkpoint.vpn_feature_name', + 'o365.audit.ClientIP': { + category: 'o365', + name: 'o365.audit.ClientIP', type: 'keyword', }, - 'checkpoint.reject_category': { - category: 'checkpoint', - description: 'Authentication failure reason. ', - name: 'checkpoint.reject_category', + 'o365.audit.ClientIPAddress': { + category: 'o365', + name: 'o365.audit.ClientIPAddress', type: 'keyword', }, - 'checkpoint.peer_ip_probing_status_update': { - category: 'checkpoint', - description: 'IP address response status. ', - name: 'checkpoint.peer_ip_probing_status_update', + 'o365.audit.Comments': { + category: 'o365', + name: 'o365.audit.Comments', + type: 'text', + }, + 'o365.audit.CommunicationType': { + category: 'o365', + name: 'o365.audit.CommunicationType', type: 'keyword', }, - 'checkpoint.peer_ip': { - category: 'checkpoint', - description: 'IP address which the client connects to. ', - name: 'checkpoint.peer_ip', + 'o365.audit.CorrelationId': { + category: 'o365', + name: 'o365.audit.CorrelationId', type: 'keyword', }, - 'checkpoint.link_probing_status_update': { - category: 'checkpoint', - description: 'IP address response status. ', - name: 'checkpoint.link_probing_status_update', + 'o365.audit.CreationTime': { + category: 'o365', + name: 'o365.audit.CreationTime', type: 'keyword', }, - 'checkpoint.source_interface': { - category: 'checkpoint', - description: 'External Interface name for source interface or Null if not found. ', - name: 'checkpoint.source_interface', + 'o365.audit.CustomUniqueId': { + category: 'o365', + name: 'o365.audit.CustomUniqueId', type: 'keyword', }, - 'checkpoint.next_hop_ip': { - category: 'checkpoint', - description: 'Next hop IP address. ', - name: 'checkpoint.next_hop_ip', + 'o365.audit.Data': { + category: 'o365', + name: 'o365.audit.Data', type: 'keyword', }, - 'checkpoint.srckeyid': { - category: 'checkpoint', - description: 'Initiator Spi ID. ', - name: 'checkpoint.srckeyid', + 'o365.audit.DataType': { + category: 'o365', + name: 'o365.audit.DataType', type: 'keyword', }, - 'checkpoint.dstkeyid': { - category: 'checkpoint', - description: 'Responder Spi ID. ', - name: 'checkpoint.dstkeyid', + 'o365.audit.DoNotDistributeEvent': { + category: 'o365', + name: 'o365.audit.DoNotDistributeEvent', + type: 'boolean', + }, + 'o365.audit.EntityType': { + category: 'o365', + name: 'o365.audit.EntityType', type: 'keyword', }, - 'checkpoint.encryption_failure': { - category: 'checkpoint', - description: 'Message indicating why the encryption failed. ', - name: 'checkpoint.encryption_failure', + 'o365.audit.ErrorNumber': { + category: 'o365', + name: 'o365.audit.ErrorNumber', type: 'keyword', }, - 'checkpoint.ike_ids': { - category: 'checkpoint', - description: 'All QM ids. ', - name: 'checkpoint.ike_ids', + 'o365.audit.EventData': { + category: 'o365', + name: 'o365.audit.EventData', type: 'keyword', }, - 'checkpoint.community': { - category: 'checkpoint', - description: 'Community name for the IPSec key and the use of the IKEv. ', - name: 'checkpoint.community', + 'o365.audit.EventSource': { + category: 'o365', + name: 'o365.audit.EventSource', type: 'keyword', }, - 'checkpoint.ike': { - category: 'checkpoint', - description: 'IKEMode (PHASE1, PHASE2, etc..). ', - name: 'checkpoint.ike', + 'o365.audit.ExceptionInfo.*': { + category: 'o365', + name: 'o365.audit.ExceptionInfo.*', + type: 'object', + }, + 'o365.audit.ExtendedProperties.*': { + category: 'o365', + name: 'o365.audit.ExtendedProperties.*', + type: 'object', + }, + 'o365.audit.ExternalAccess': { + category: 'o365', + name: 'o365.audit.ExternalAccess', type: 'keyword', }, - 'checkpoint.cookieI': { - category: 'checkpoint', - description: 'Initiator cookie. ', - name: 'checkpoint.cookieI', + 'o365.audit.FromApp': { + category: 'o365', + name: 'o365.audit.FromApp', + type: 'boolean', + }, + 'o365.audit.GroupName': { + category: 'o365', + name: 'o365.audit.GroupName', type: 'keyword', }, - 'checkpoint.cookieR': { - category: 'checkpoint', - description: 'Responder cookie. ', - name: 'checkpoint.cookieR', + 'o365.audit.Id': { + category: 'o365', + name: 'o365.audit.Id', type: 'keyword', }, - 'checkpoint.msgid': { - category: 'checkpoint', - description: 'Message ID. ', - name: 'checkpoint.msgid', + 'o365.audit.ImplicitShare': { + category: 'o365', + name: 'o365.audit.ImplicitShare', type: 'keyword', }, - 'checkpoint.methods': { - category: 'checkpoint', - description: 'IPSEc methods. ', - name: 'checkpoint.methods', + 'o365.audit.IncidentId': { + category: 'o365', + name: 'o365.audit.IncidentId', type: 'keyword', }, - 'checkpoint.connection_uid': { - category: 'checkpoint', - description: 'Calculation of md5 of the IP and user name as UID. ', - name: 'checkpoint.connection_uid', + 'o365.audit.InternalLogonType': { + category: 'o365', + name: 'o365.audit.InternalLogonType', type: 'keyword', }, - 'checkpoint.site_name': { - category: 'checkpoint', - description: 'Site name. ', - name: 'checkpoint.site_name', + 'o365.audit.InterSystemsId': { + category: 'o365', + name: 'o365.audit.InterSystemsId', type: 'keyword', }, - 'checkpoint.esod_rule_name': { - category: 'checkpoint', - description: 'Unknown rule name. ', - name: 'checkpoint.esod_rule_name', + 'o365.audit.IntraSystemId': { + category: 'o365', + name: 'o365.audit.IntraSystemId', type: 'keyword', }, - 'checkpoint.esod_rule_action': { - category: 'checkpoint', - description: 'Unknown rule action. ', - name: 'checkpoint.esod_rule_action', + 'o365.audit.IsDocLib': { + category: 'o365', + name: 'o365.audit.IsDocLib', + type: 'boolean', + }, + 'o365.audit.Item.*': { + category: 'o365', + name: 'o365.audit.Item.*', + type: 'object', + }, + 'o365.audit.Item.*.*': { + category: 'o365', + name: 'o365.audit.Item.*.*', + type: 'object', + }, + 'o365.audit.ItemCount': { + category: 'o365', + name: 'o365.audit.ItemCount', + type: 'long', + }, + 'o365.audit.ItemName': { + category: 'o365', + name: 'o365.audit.ItemName', type: 'keyword', }, - 'checkpoint.esod_rule_type': { - category: 'checkpoint', - description: 'Unknown rule type. ', - name: 'checkpoint.esod_rule_type', + 'o365.audit.ItemType': { + category: 'o365', + name: 'o365.audit.ItemType', type: 'keyword', }, - 'checkpoint.esod_noncompliance_reason': { - category: 'checkpoint', - description: 'Non-compliance reason. ', - name: 'checkpoint.esod_noncompliance_reason', + 'o365.audit.ListBaseTemplateType': { + category: 'o365', + name: 'o365.audit.ListBaseTemplateType', type: 'keyword', }, - 'checkpoint.esod_associated_policies': { - category: 'checkpoint', - description: 'Associated policies. ', - name: 'checkpoint.esod_associated_policies', + 'o365.audit.ListBaseType': { + category: 'o365', + name: 'o365.audit.ListBaseType', type: 'keyword', }, - 'checkpoint.spyware_type': { - category: 'checkpoint', - description: 'Spyware type. ', - name: 'checkpoint.spyware_type', + 'o365.audit.ListColor': { + category: 'o365', + name: 'o365.audit.ListColor', type: 'keyword', }, - 'checkpoint.anti_virus_type': { - category: 'checkpoint', - description: 'Anti virus type. ', - name: 'checkpoint.anti_virus_type', + 'o365.audit.ListIcon': { + category: 'o365', + name: 'o365.audit.ListIcon', type: 'keyword', }, - 'checkpoint.end_user_firewall_type': { - category: 'checkpoint', - description: 'End user firewall type. ', - name: 'checkpoint.end_user_firewall_type', + 'o365.audit.ListId': { + category: 'o365', + name: 'o365.audit.ListId', type: 'keyword', }, - 'checkpoint.esod_scan_status': { - category: 'checkpoint', - description: 'Scan failed. ', - name: 'checkpoint.esod_scan_status', + 'o365.audit.ListTitle': { + category: 'o365', + name: 'o365.audit.ListTitle', type: 'keyword', }, - 'checkpoint.esod_access_status': { - category: 'checkpoint', - description: 'Access denied. ', - name: 'checkpoint.esod_access_status', + 'o365.audit.ListItemUniqueId': { + category: 'o365', + name: 'o365.audit.ListItemUniqueId', type: 'keyword', }, - 'checkpoint.client_type': { - category: 'checkpoint', - description: 'Endpoint Connect. ', - name: 'checkpoint.client_type', + 'o365.audit.LogonError': { + category: 'o365', + name: 'o365.audit.LogonError', type: 'keyword', }, - 'checkpoint.precise_error': { - category: 'checkpoint', - description: 'HTTP parser error. ', - name: 'checkpoint.precise_error', + 'o365.audit.LogonType': { + category: 'o365', + name: 'o365.audit.LogonType', type: 'keyword', }, - 'checkpoint.method': { - category: 'checkpoint', - description: 'HTTP method. ', - name: 'checkpoint.method', + 'o365.audit.LogonUserSid': { + category: 'o365', + name: 'o365.audit.LogonUserSid', type: 'keyword', }, - 'checkpoint.trusted_domain': { - category: 'checkpoint', - description: 'In case of phishing event, the domain, which the attacker was impersonating. ', - name: 'checkpoint.trusted_domain', + 'o365.audit.MailboxGuid': { + category: 'o365', + name: 'o365.audit.MailboxGuid', type: 'keyword', }, - 'cisco.asa.message_id': { - category: 'cisco', - description: 'The Cisco ASA message identifier. ', - name: 'cisco.asa.message_id', + 'o365.audit.MailboxOwnerMasterAccountSid': { + category: 'o365', + name: 'o365.audit.MailboxOwnerMasterAccountSid', type: 'keyword', }, - 'cisco.asa.suffix': { - category: 'cisco', - description: 'Optional suffix after %ASA identifier. ', - example: 'session', - name: 'cisco.asa.suffix', + 'o365.audit.MailboxOwnerSid': { + category: 'o365', + name: 'o365.audit.MailboxOwnerSid', type: 'keyword', }, - 'cisco.asa.source_interface': { - category: 'cisco', - description: 'Source interface for the flow or event. ', - name: 'cisco.asa.source_interface', + 'o365.audit.MailboxOwnerUPN': { + category: 'o365', + name: 'o365.audit.MailboxOwnerUPN', type: 'keyword', }, - 'cisco.asa.destination_interface': { - category: 'cisco', - description: 'Destination interface for the flow or event. ', - name: 'cisco.asa.destination_interface', + 'o365.audit.Members': { + category: 'o365', + name: 'o365.audit.Members', + type: 'array', + }, + 'o365.audit.Members.*': { + category: 'o365', + name: 'o365.audit.Members.*', + type: 'object', + }, + 'o365.audit.ModifiedProperties.*.*': { + category: 'o365', + name: 'o365.audit.ModifiedProperties.*.*', + type: 'object', + }, + 'o365.audit.Name': { + category: 'o365', + name: 'o365.audit.Name', type: 'keyword', }, - 'cisco.asa.rule_name': { - category: 'cisco', - description: 'Name of the Access Control List rule that matched this event. ', - name: 'cisco.asa.rule_name', + 'o365.audit.ObjectId': { + category: 'o365', + name: 'o365.audit.ObjectId', type: 'keyword', }, - 'cisco.asa.source_username': { - category: 'cisco', - description: 'Name of the user that is the source for this event. ', - name: 'cisco.asa.source_username', + 'o365.audit.Operation': { + category: 'o365', + name: 'o365.audit.Operation', type: 'keyword', }, - 'cisco.asa.destination_username': { - category: 'cisco', - description: 'Name of the user that is the destination for this event. ', - name: 'cisco.asa.destination_username', + 'o365.audit.OrganizationId': { + category: 'o365', + name: 'o365.audit.OrganizationId', type: 'keyword', }, - 'cisco.asa.mapped_source_ip': { - category: 'cisco', - description: 'The translated source IP address. ', - name: 'cisco.asa.mapped_source_ip', - type: 'ip', + 'o365.audit.OrganizationName': { + category: 'o365', + name: 'o365.audit.OrganizationName', + type: 'keyword', }, - 'cisco.asa.mapped_source_host': { - category: 'cisco', - description: 'The translated source host. ', - name: 'cisco.asa.mapped_source_host', + 'o365.audit.OriginatingServer': { + category: 'o365', + name: 'o365.audit.OriginatingServer', type: 'keyword', }, - 'cisco.asa.mapped_source_port': { - category: 'cisco', - description: 'The translated source port. ', - name: 'cisco.asa.mapped_source_port', - type: 'long', + 'o365.audit.Parameters.*': { + category: 'o365', + name: 'o365.audit.Parameters.*', + type: 'object', }, - 'cisco.asa.mapped_destination_ip': { - category: 'cisco', - description: 'The translated destination IP address. ', - name: 'cisco.asa.mapped_destination_ip', - type: 'ip', + 'o365.audit.PolicyDetails': { + category: 'o365', + name: 'o365.audit.PolicyDetails', + type: 'array', }, - 'cisco.asa.mapped_destination_host': { - category: 'cisco', - description: 'The translated destination host. ', - name: 'cisco.asa.mapped_destination_host', + 'o365.audit.PolicyId': { + category: 'o365', + name: 'o365.audit.PolicyId', type: 'keyword', }, - 'cisco.asa.mapped_destination_port': { - category: 'cisco', - description: 'The translated destination port. ', - name: 'cisco.asa.mapped_destination_port', - type: 'long', - }, - 'cisco.asa.threat_level': { - category: 'cisco', - description: - 'Threat level for malware / botnet traffic. One of very-low, low, moderate, high or very-high. ', - name: 'cisco.asa.threat_level', + 'o365.audit.RecordType': { + category: 'o365', + name: 'o365.audit.RecordType', type: 'keyword', }, - 'cisco.asa.threat_category': { - category: 'cisco', - description: - 'Category for the malware / botnet traffic. For example: virus, botnet, trojan, etc. ', - name: 'cisco.asa.threat_category', + 'o365.audit.ResultStatus': { + category: 'o365', + name: 'o365.audit.ResultStatus', type: 'keyword', }, - 'cisco.asa.connection_id': { - category: 'cisco', - description: 'Unique identifier for a flow. ', - name: 'cisco.asa.connection_id', + 'o365.audit.SensitiveInfoDetectionIsIncluded': { + category: 'o365', + name: 'o365.audit.SensitiveInfoDetectionIsIncluded', type: 'keyword', }, - 'cisco.asa.icmp_type': { - category: 'cisco', - description: 'ICMP type. ', - name: 'cisco.asa.icmp_type', - type: 'short', - }, - 'cisco.asa.icmp_code': { - category: 'cisco', - description: 'ICMP code. ', - name: 'cisco.asa.icmp_code', - type: 'short', + 'o365.audit.SharePointMetaData.*': { + category: 'o365', + name: 'o365.audit.SharePointMetaData.*', + type: 'object', }, - 'cisco.asa.connection_type': { - category: 'cisco', - description: 'The VPN connection type ', - name: 'cisco.asa.connection_type', + 'o365.audit.SessionId': { + category: 'o365', + name: 'o365.audit.SessionId', type: 'keyword', }, - 'cisco.asa.dap_records': { - category: 'cisco', - description: 'The assigned DAP records ', - name: 'cisco.asa.dap_records', + 'o365.audit.Severity': { + category: 'o365', + name: 'o365.audit.Severity', type: 'keyword', }, - 'cisco.ftd.message_id': { - category: 'cisco', - description: 'The Cisco FTD message identifier. ', - name: 'cisco.ftd.message_id', + 'o365.audit.Site': { + category: 'o365', + name: 'o365.audit.Site', type: 'keyword', }, - 'cisco.ftd.suffix': { - category: 'cisco', - description: 'Optional suffix after %FTD identifier. ', - example: 'session', - name: 'cisco.ftd.suffix', + 'o365.audit.SiteUrl': { + category: 'o365', + name: 'o365.audit.SiteUrl', type: 'keyword', }, - 'cisco.ftd.source_interface': { - category: 'cisco', - description: 'Source interface for the flow or event. ', - name: 'cisco.ftd.source_interface', + 'o365.audit.Source': { + category: 'o365', + name: 'o365.audit.Source', type: 'keyword', }, - 'cisco.ftd.destination_interface': { - category: 'cisco', - description: 'Destination interface for the flow or event. ', - name: 'cisco.ftd.destination_interface', + 'o365.audit.SourceFileExtension': { + category: 'o365', + name: 'o365.audit.SourceFileExtension', type: 'keyword', }, - 'cisco.ftd.rule_name': { - category: 'cisco', - description: 'Name of the Access Control List rule that matched this event. ', - name: 'cisco.ftd.rule_name', + 'o365.audit.SourceFileName': { + category: 'o365', + name: 'o365.audit.SourceFileName', type: 'keyword', }, - 'cisco.ftd.source_username': { - category: 'cisco', - description: 'Name of the user that is the source for this event. ', - name: 'cisco.ftd.source_username', + 'o365.audit.SourceRelativeUrl': { + category: 'o365', + name: 'o365.audit.SourceRelativeUrl', type: 'keyword', }, - 'cisco.ftd.destination_username': { - category: 'cisco', - description: 'Name of the user that is the destination for this event. ', - name: 'cisco.ftd.destination_username', + 'o365.audit.Status': { + category: 'o365', + name: 'o365.audit.Status', type: 'keyword', }, - 'cisco.ftd.mapped_source_ip': { - category: 'cisco', - description: 'The translated source IP address. Use ECS source.nat.ip. ', - name: 'cisco.ftd.mapped_source_ip', - type: 'ip', - }, - 'cisco.ftd.mapped_source_host': { - category: 'cisco', - description: 'The translated source host. ', - name: 'cisco.ftd.mapped_source_host', + 'o365.audit.SupportTicketId': { + category: 'o365', + name: 'o365.audit.SupportTicketId', type: 'keyword', }, - 'cisco.ftd.mapped_source_port': { - category: 'cisco', - description: 'The translated source port. Use ECS source.nat.port. ', - name: 'cisco.ftd.mapped_source_port', - type: 'long', + 'o365.audit.Target.ID': { + category: 'o365', + name: 'o365.audit.Target.ID', + type: 'keyword', }, - 'cisco.ftd.mapped_destination_ip': { - category: 'cisco', - description: 'The translated destination IP address. Use ECS destination.nat.ip. ', - name: 'cisco.ftd.mapped_destination_ip', - type: 'ip', + 'o365.audit.Target.Type': { + category: 'o365', + name: 'o365.audit.Target.Type', + type: 'keyword', }, - 'cisco.ftd.mapped_destination_host': { - category: 'cisco', - description: 'The translated destination host. ', - name: 'cisco.ftd.mapped_destination_host', + 'o365.audit.TargetContextId': { + category: 'o365', + name: 'o365.audit.TargetContextId', type: 'keyword', }, - 'cisco.ftd.mapped_destination_port': { - category: 'cisco', - description: 'The translated destination port. Use ECS destination.nat.port. ', - name: 'cisco.ftd.mapped_destination_port', - type: 'long', + 'o365.audit.TargetUserOrGroupName': { + category: 'o365', + name: 'o365.audit.TargetUserOrGroupName', + type: 'keyword', }, - 'cisco.ftd.threat_level': { - category: 'cisco', - description: - 'Threat level for malware / botnet traffic. One of very-low, low, moderate, high or very-high. ', - name: 'cisco.ftd.threat_level', + 'o365.audit.TargetUserOrGroupType': { + category: 'o365', + name: 'o365.audit.TargetUserOrGroupType', type: 'keyword', }, - 'cisco.ftd.threat_category': { - category: 'cisco', - description: - 'Category for the malware / botnet traffic. For example: virus, botnet, trojan, etc. ', - name: 'cisco.ftd.threat_category', + 'o365.audit.TeamName': { + category: 'o365', + name: 'o365.audit.TeamName', type: 'keyword', }, - 'cisco.ftd.connection_id': { - category: 'cisco', - description: 'Unique identifier for a flow. ', - name: 'cisco.ftd.connection_id', + 'o365.audit.TeamGuid': { + category: 'o365', + name: 'o365.audit.TeamGuid', type: 'keyword', }, - 'cisco.ftd.icmp_type': { - category: 'cisco', - description: 'ICMP type. ', - name: 'cisco.ftd.icmp_type', - type: 'short', + 'o365.audit.TemplateTypeId': { + category: 'o365', + name: 'o365.audit.TemplateTypeId', + type: 'keyword', }, - 'cisco.ftd.icmp_code': { - category: 'cisco', - description: 'ICMP code. ', - name: 'cisco.ftd.icmp_code', - type: 'short', + 'o365.audit.UniqueSharingId': { + category: 'o365', + name: 'o365.audit.UniqueSharingId', + type: 'keyword', }, - 'cisco.ftd.security': { - category: 'cisco', - description: 'Raw fields for Security Events.', - name: 'cisco.ftd.security', - type: 'object', + 'o365.audit.UserAgent': { + category: 'o365', + name: 'o365.audit.UserAgent', + type: 'keyword', }, - 'cisco.ftd.connection_type': { - category: 'cisco', - description: 'The VPN connection type ', - name: 'cisco.ftd.connection_type', + 'o365.audit.UserId': { + category: 'o365', + name: 'o365.audit.UserId', type: 'keyword', }, - 'cisco.ftd.dap_records': { - category: 'cisco', - description: 'The assigned DAP records ', - name: 'cisco.ftd.dap_records', + 'o365.audit.UserKey': { + category: 'o365', + name: 'o365.audit.UserKey', type: 'keyword', }, - 'cisco.ios.access_list': { - category: 'cisco', - description: 'Name of the IP access list. ', - name: 'cisco.ios.access_list', + 'o365.audit.UserType': { + category: 'o365', + name: 'o365.audit.UserType', type: 'keyword', }, - 'cisco.ios.facility': { - category: 'cisco', - description: - 'The facility to which the message refers (for example, SNMP, SYS, and so forth). A facility can be a hardware device, a protocol, or a module of the system software. It denotes the source or the cause of the system message. ', - example: 'SEC', - name: 'cisco.ios.facility', + 'o365.audit.Version': { + category: 'o365', + name: 'o365.audit.Version', type: 'keyword', }, - 'coredns.id': { - category: 'coredns', - description: 'id of the DNS transaction ', - name: 'coredns.id', + 'o365.audit.WebId': { + category: 'o365', + name: 'o365.audit.WebId', type: 'keyword', }, - 'coredns.query.size': { - category: 'coredns', - description: 'size of the DNS query ', - name: 'coredns.query.size', - type: 'integer', - format: 'bytes', + 'o365.audit.Workload': { + category: 'o365', + name: 'o365.audit.Workload', + type: 'keyword', }, - 'coredns.query.class': { - category: 'coredns', - description: 'DNS query class ', - name: 'coredns.query.class', + 'o365.audit.YammerNetworkId': { + category: 'o365', + name: 'o365.audit.YammerNetworkId', type: 'keyword', }, - 'coredns.query.name': { - category: 'coredns', - description: 'DNS query name ', - name: 'coredns.query.name', + 'okta.uuid': { + category: 'okta', + description: 'The unique identifier of the Okta LogEvent. ', + name: 'okta.uuid', type: 'keyword', }, - 'coredns.query.type': { - category: 'coredns', - description: 'DNS query type ', - name: 'coredns.query.type', + 'okta.event_type': { + category: 'okta', + description: 'The type of the LogEvent. ', + name: 'okta.event_type', type: 'keyword', }, - 'coredns.response.code': { - category: 'coredns', - description: 'DNS response code ', - name: 'coredns.response.code', + 'okta.version': { + category: 'okta', + description: 'The version of the LogEvent. ', + name: 'okta.version', type: 'keyword', }, - 'coredns.response.flags': { - category: 'coredns', - description: 'DNS response flags ', - name: 'coredns.response.flags', + 'okta.severity': { + category: 'okta', + description: 'The severity of the LogEvent. Must be one of DEBUG, INFO, WARN, or ERROR. ', + name: 'okta.severity', type: 'keyword', }, - 'coredns.response.size': { - category: 'coredns', - description: 'size of the DNS response ', - name: 'coredns.response.size', - type: 'integer', - format: 'bytes', + 'okta.display_message': { + category: 'okta', + description: 'The display message of the LogEvent. ', + name: 'okta.display_message', + type: 'keyword', }, - 'coredns.dnssec_ok': { - category: 'coredns', - description: 'dnssec flag ', - name: 'coredns.dnssec_ok', - type: 'boolean', + 'okta.actor.id': { + category: 'okta', + description: 'Identifier of the actor. ', + name: 'okta.actor.id', + type: 'keyword', }, - 'crowdstrike.metadata.eventType': { - category: 'crowdstrike', - description: - 'DetectionSummaryEvent, FirewallMatchEvent, IncidentSummaryEvent, RemoteResponseSessionStartEvent, RemoteResponseSessionEndEvent, AuthActivityAuditEvent, or UserActivityAuditEvent ', - name: 'crowdstrike.metadata.eventType', + 'okta.actor.type': { + category: 'okta', + description: 'Type of the actor. ', + name: 'okta.actor.type', type: 'keyword', }, - 'crowdstrike.metadata.eventCreationTime': { - category: 'crowdstrike', - description: 'The time this event occurred on the endpoint in UTC UNIX_MS format. ', - name: 'crowdstrike.metadata.eventCreationTime', - type: 'date', + 'okta.actor.alternate_id': { + category: 'okta', + description: 'Alternate identifier of the actor. ', + name: 'okta.actor.alternate_id', + type: 'keyword', }, - 'crowdstrike.metadata.offset': { - category: 'crowdstrike', - description: - 'Offset number that tracks the location of the event in stream. This is used to identify unique detection events. ', - name: 'crowdstrike.metadata.offset', - type: 'integer', + 'okta.actor.display_name': { + category: 'okta', + description: 'Display name of the actor. ', + name: 'okta.actor.display_name', + type: 'keyword', }, - 'crowdstrike.metadata.customerIDString': { - category: 'crowdstrike', - description: 'Customer identifier ', - name: 'crowdstrike.metadata.customerIDString', + 'okta.client.ip': { + category: 'okta', + description: 'The IP address of the client. ', + name: 'okta.client.ip', + type: 'ip', + }, + 'okta.client.user_agent.raw_user_agent': { + category: 'okta', + description: 'The raw informaton of the user agent. ', + name: 'okta.client.user_agent.raw_user_agent', type: 'keyword', }, - 'crowdstrike.metadata.version': { - category: 'crowdstrike', - description: 'Schema version ', - name: 'crowdstrike.metadata.version', + 'okta.client.user_agent.os': { + category: 'okta', + description: 'The OS informaton. ', + name: 'okta.client.user_agent.os', type: 'keyword', }, - 'crowdstrike.event.ProcessStartTime': { - category: 'crowdstrike', - description: 'The process start time in UTC UNIX_MS format. ', - name: 'crowdstrike.event.ProcessStartTime', - type: 'date', + 'okta.client.user_agent.browser': { + category: 'okta', + description: 'The browser informaton of the client. ', + name: 'okta.client.user_agent.browser', + type: 'keyword', }, - 'crowdstrike.event.ProcessEndTime': { - category: 'crowdstrike', - description: 'The process termination time in UTC UNIX_MS format. ', - name: 'crowdstrike.event.ProcessEndTime', - type: 'date', + 'okta.client.zone': { + category: 'okta', + description: 'The zone information of the client. ', + name: 'okta.client.zone', + type: 'keyword', }, - 'crowdstrike.event.ProcessId': { - category: 'crowdstrike', - description: 'Process ID related to the detection. ', - name: 'crowdstrike.event.ProcessId', - type: 'integer', + 'okta.client.device': { + category: 'okta', + description: 'The information of the client device. ', + name: 'okta.client.device', + type: 'keyword', }, - 'crowdstrike.event.ParentProcessId': { - category: 'crowdstrike', - description: 'Parent process ID related to the detection. ', - name: 'crowdstrike.event.ParentProcessId', - type: 'integer', + 'okta.client.id': { + category: 'okta', + description: 'The identifier of the client. ', + name: 'okta.client.id', + type: 'keyword', }, - 'crowdstrike.event.ComputerName': { - category: 'crowdstrike', - description: 'Name of the computer where the detection occurred. ', - name: 'crowdstrike.event.ComputerName', + 'okta.outcome.reason': { + category: 'okta', + description: 'The reason of the outcome. ', + name: 'okta.outcome.reason', type: 'keyword', }, - 'crowdstrike.event.UserName': { - category: 'crowdstrike', - description: 'User name associated with the detection. ', - name: 'crowdstrike.event.UserName', + 'okta.outcome.result': { + category: 'okta', + description: + 'The result of the outcome. Must be one of: SUCCESS, FAILURE, SKIPPED, ALLOW, DENY, CHALLENGE, UNKNOWN. ', + name: 'okta.outcome.result', type: 'keyword', }, - 'crowdstrike.event.DetectName': { - category: 'crowdstrike', - description: 'Name of the detection. ', - name: 'crowdstrike.event.DetectName', + 'okta.target.id': { + category: 'okta', + description: 'Identifier of the actor. ', + name: 'okta.target.id', type: 'keyword', }, - 'crowdstrike.event.DetectDescription': { - category: 'crowdstrike', - description: 'Description of the detection. ', - name: 'crowdstrike.event.DetectDescription', + 'okta.target.type': { + category: 'okta', + description: 'Type of the actor. ', + name: 'okta.target.type', type: 'keyword', }, - 'crowdstrike.event.Severity': { - category: 'crowdstrike', - description: 'Severity score of the detection. ', - name: 'crowdstrike.event.Severity', - type: 'integer', + 'okta.target.alternate_id': { + category: 'okta', + description: 'Alternate identifier of the actor. ', + name: 'okta.target.alternate_id', + type: 'keyword', }, - 'crowdstrike.event.SeverityName': { - category: 'crowdstrike', - description: 'Severity score text. ', - name: 'crowdstrike.event.SeverityName', + 'okta.target.display_name': { + category: 'okta', + description: 'Display name of the actor. ', + name: 'okta.target.display_name', type: 'keyword', }, - 'crowdstrike.event.FileName': { - category: 'crowdstrike', - description: 'File name of the associated process for the detection. ', - name: 'crowdstrike.event.FileName', + 'okta.transaction.id': { + category: 'okta', + description: 'Identifier of the transaction. ', + name: 'okta.transaction.id', type: 'keyword', }, - 'crowdstrike.event.FilePath': { - category: 'crowdstrike', - description: 'Path of the executable associated with the detection. ', - name: 'crowdstrike.event.FilePath', + 'okta.transaction.type': { + category: 'okta', + description: 'The type of transaction. Must be one of "WEB", "JOB". ', + name: 'okta.transaction.type', type: 'keyword', }, - 'crowdstrike.event.CommandLine': { - category: 'crowdstrike', - description: 'Executable path with command line arguments. ', - name: 'crowdstrike.event.CommandLine', + 'okta.debug_context.debug_data.device_fingerprint': { + category: 'okta', + description: 'The fingerprint of the device. ', + name: 'okta.debug_context.debug_data.device_fingerprint', type: 'keyword', }, - 'crowdstrike.event.SHA1String': { - category: 'crowdstrike', - description: 'SHA1 sum of the executable associated with the detection. ', - name: 'crowdstrike.event.SHA1String', + 'okta.debug_context.debug_data.request_id': { + category: 'okta', + description: 'The identifier of the request. ', + name: 'okta.debug_context.debug_data.request_id', type: 'keyword', }, - 'crowdstrike.event.SHA256String': { - category: 'crowdstrike', - description: 'SHA256 sum of the executable associated with the detection. ', - name: 'crowdstrike.event.SHA256String', + 'okta.debug_context.debug_data.request_uri': { + category: 'okta', + description: 'The request URI. ', + name: 'okta.debug_context.debug_data.request_uri', type: 'keyword', }, - 'crowdstrike.event.MD5String': { - category: 'crowdstrike', - description: 'MD5 sum of the executable associated with the detection. ', - name: 'crowdstrike.event.MD5String', + 'okta.debug_context.debug_data.threat_suspected': { + category: 'okta', + description: 'Threat suspected. ', + name: 'okta.debug_context.debug_data.threat_suspected', type: 'keyword', }, - 'crowdstrike.event.MachineDomain': { - category: 'crowdstrike', - description: 'Domain for the machine associated with the detection. ', - name: 'crowdstrike.event.MachineDomain', + 'okta.debug_context.debug_data.url': { + category: 'okta', + description: 'The URL. ', + name: 'okta.debug_context.debug_data.url', type: 'keyword', }, - 'crowdstrike.event.FalconHostLink': { - category: 'crowdstrike', - description: 'URL to view the detection in Falcon. ', - name: 'crowdstrike.event.FalconHostLink', + 'okta.debug_context.debug_data.suspicious_activity.browser': { + category: 'okta', + description: 'The browser used. ', + name: 'okta.debug_context.debug_data.suspicious_activity.browser', type: 'keyword', }, - 'crowdstrike.event.SensorId': { - category: 'crowdstrike', - description: 'Unique ID associated with the Falcon sensor. ', - name: 'crowdstrike.event.SensorId', + 'okta.debug_context.debug_data.suspicious_activity.event_city': { + category: 'okta', + description: 'The city where the suspicious activity took place. ', + name: 'okta.debug_context.debug_data.suspicious_activity.event_city', type: 'keyword', }, - 'crowdstrike.event.DetectId': { - category: 'crowdstrike', - description: 'Unique ID associated with the detection. ', - name: 'crowdstrike.event.DetectId', + 'okta.debug_context.debug_data.suspicious_activity.event_country': { + category: 'okta', + description: 'The country where the suspicious activity took place. ', + name: 'okta.debug_context.debug_data.suspicious_activity.event_country', type: 'keyword', }, - 'crowdstrike.event.LocalIP': { - category: 'crowdstrike', - description: 'IP address of the host associated with the detection. ', - name: 'crowdstrike.event.LocalIP', + 'okta.debug_context.debug_data.suspicious_activity.event_id': { + category: 'okta', + description: 'The event ID. ', + name: 'okta.debug_context.debug_data.suspicious_activity.event_id', type: 'keyword', }, - 'crowdstrike.event.MACAddress': { - category: 'crowdstrike', - description: 'MAC address of the host associated with the detection. ', - name: 'crowdstrike.event.MACAddress', + 'okta.debug_context.debug_data.suspicious_activity.event_ip': { + category: 'okta', + description: 'The IP of the suspicious event. ', + name: 'okta.debug_context.debug_data.suspicious_activity.event_ip', + type: 'ip', + }, + 'okta.debug_context.debug_data.suspicious_activity.event_latitude': { + category: 'okta', + description: 'The latitude where the suspicious activity took place. ', + name: 'okta.debug_context.debug_data.suspicious_activity.event_latitude', + type: 'float', + }, + 'okta.debug_context.debug_data.suspicious_activity.event_longitude': { + category: 'okta', + description: 'The longitude where the suspicious activity took place. ', + name: 'okta.debug_context.debug_data.suspicious_activity.event_longitude', + type: 'float', + }, + 'okta.debug_context.debug_data.suspicious_activity.event_state': { + category: 'okta', + description: 'The state where the suspicious activity took place. ', + name: 'okta.debug_context.debug_data.suspicious_activity.event_state', type: 'keyword', }, - 'crowdstrike.event.Tactic': { - category: 'crowdstrike', - description: 'MITRE tactic category of the detection. ', - name: 'crowdstrike.event.Tactic', + 'okta.debug_context.debug_data.suspicious_activity.event_transaction_id': { + category: 'okta', + description: 'The event transaction ID. ', + name: 'okta.debug_context.debug_data.suspicious_activity.event_transaction_id', type: 'keyword', }, - 'crowdstrike.event.Technique': { - category: 'crowdstrike', - description: 'MITRE technique category of the detection. ', - name: 'crowdstrike.event.Technique', + 'okta.debug_context.debug_data.suspicious_activity.event_type': { + category: 'okta', + description: 'The event type. ', + name: 'okta.debug_context.debug_data.suspicious_activity.event_type', type: 'keyword', }, - 'crowdstrike.event.Objective': { - category: 'crowdstrike', - description: 'Method of detection. ', - name: 'crowdstrike.event.Objective', + 'okta.debug_context.debug_data.suspicious_activity.os': { + category: 'okta', + description: 'The OS of the system from where the suspicious activity occured. ', + name: 'okta.debug_context.debug_data.suspicious_activity.os', type: 'keyword', }, - 'crowdstrike.event.PatternDispositionDescription': { - category: 'crowdstrike', - description: 'Action taken by Falcon. ', - name: 'crowdstrike.event.PatternDispositionDescription', + 'okta.debug_context.debug_data.suspicious_activity.timestamp': { + category: 'okta', + description: 'The timestamp of when the activity occurred. ', + name: 'okta.debug_context.debug_data.suspicious_activity.timestamp', + type: 'date', + }, + 'okta.authentication_context.authentication_provider': { + category: 'okta', + description: + 'The information about the authentication provider. Must be one of OKTA_AUTHENTICATION_PROVIDER, ACTIVE_DIRECTORY, LDAP, FEDERATION, SOCIAL, FACTOR_PROVIDER. ', + name: 'okta.authentication_context.authentication_provider', type: 'keyword', }, - 'crowdstrike.event.PatternDispositionValue': { - category: 'crowdstrike', - description: 'Unique ID associated with action taken. ', - name: 'crowdstrike.event.PatternDispositionValue', + 'okta.authentication_context.authentication_step': { + category: 'okta', + description: 'The authentication step. ', + name: 'okta.authentication_context.authentication_step', type: 'integer', }, - 'crowdstrike.event.PatternDispositionFlags': { - category: 'crowdstrike', - description: 'Flags indicating actions taken. ', - name: 'crowdstrike.event.PatternDispositionFlags', - type: 'object', + 'okta.authentication_context.credential_provider': { + category: 'okta', + description: + 'The information about credential provider. Must be one of OKTA_CREDENTIAL_PROVIDER, RSA, SYMANTEC, GOOGLE, DUO, YUBIKEY. ', + name: 'okta.authentication_context.credential_provider', + type: 'keyword', }, - 'crowdstrike.event.State': { - category: 'crowdstrike', - description: 'Whether the incident summary is open and ongoing or closed. ', - name: 'crowdstrike.event.State', + 'okta.authentication_context.credential_type': { + category: 'okta', + description: + 'The information about credential type. Must be one of OTP, SMS, PASSWORD, ASSERTION, IWA, EMAIL, OAUTH2, JWT, CERTIFICATE, PRE_SHARED_SYMMETRIC_KEY, OKTA_CLIENT_SESSION, DEVICE_UDID. ', + name: 'okta.authentication_context.credential_type', type: 'keyword', }, - 'crowdstrike.event.IncidentStartTime': { - category: 'crowdstrike', - description: 'Start time for the incident in UTC UNIX format. ', - name: 'crowdstrike.event.IncidentStartTime', - type: 'date', + 'okta.authentication_context.issuer.id': { + category: 'okta', + description: 'The identifier of the issuer. ', + name: 'okta.authentication_context.issuer.id', + type: 'keyword', }, - 'crowdstrike.event.IncidentEndTime': { - category: 'crowdstrike', - description: 'End time for the incident in UTC UNIX format. ', - name: 'crowdstrike.event.IncidentEndTime', - type: 'date', + 'okta.authentication_context.issuer.type': { + category: 'okta', + description: 'The type of the issuer. ', + name: 'okta.authentication_context.issuer.type', + type: 'keyword', }, - 'crowdstrike.event.FineScore': { - category: 'crowdstrike', - description: 'Score for incident. ', - name: 'crowdstrike.event.FineScore', - type: 'float', + 'okta.authentication_context.external_session_id': { + category: 'okta', + description: 'The session identifer of the external session if any. ', + name: 'okta.authentication_context.external_session_id', + type: 'keyword', }, - 'crowdstrike.event.UserId': { - category: 'crowdstrike', - description: 'Email address or user ID associated with the event. ', - name: 'crowdstrike.event.UserId', + 'okta.authentication_context.interface': { + category: 'okta', + description: 'The interface used. e.g., Outlook, Office365, wsTrust ', + name: 'okta.authentication_context.interface', type: 'keyword', }, - 'crowdstrike.event.UserIp': { - category: 'crowdstrike', - description: 'IP address associated with the user. ', - name: 'crowdstrike.event.UserIp', + 'okta.security_context.as.number': { + category: 'okta', + description: 'The AS number. ', + name: 'okta.security_context.as.number', + type: 'integer', + }, + 'okta.security_context.as.organization.name': { + category: 'okta', + description: 'The organization name. ', + name: 'okta.security_context.as.organization.name', type: 'keyword', }, - 'crowdstrike.event.OperationName': { - category: 'crowdstrike', - description: 'Event subtype. ', - name: 'crowdstrike.event.OperationName', + 'okta.security_context.isp': { + category: 'okta', + description: 'The Internet Service Provider. ', + name: 'okta.security_context.isp', type: 'keyword', }, - 'crowdstrike.event.ServiceName': { - category: 'crowdstrike', - description: 'Service associated with this event. ', - name: 'crowdstrike.event.ServiceName', + 'okta.security_context.domain': { + category: 'okta', + description: 'The domain name. ', + name: 'okta.security_context.domain', type: 'keyword', }, - 'crowdstrike.event.Success': { - category: 'crowdstrike', - description: 'Indicator of whether or not this event was successful. ', - name: 'crowdstrike.event.Success', + 'okta.security_context.is_proxy': { + category: 'okta', + description: 'Whether it is a proxy or not. ', + name: 'okta.security_context.is_proxy', type: 'boolean', }, - 'crowdstrike.event.UTCTimestamp': { - category: 'crowdstrike', - description: 'Timestamp associated with this event in UTC UNIX format. ', - name: 'crowdstrike.event.UTCTimestamp', - type: 'date', + 'okta.request.ip_chain.ip': { + category: 'okta', + description: 'IP address. ', + name: 'okta.request.ip_chain.ip', + type: 'ip', }, - 'crowdstrike.event.AuditKeyValues': { - category: 'crowdstrike', - description: 'Fields that were changed in this event. ', - name: 'crowdstrike.event.AuditKeyValues', - type: 'nested', + 'okta.request.ip_chain.version': { + category: 'okta', + description: 'IP version. Must be one of V4, V6. ', + name: 'okta.request.ip_chain.version', + type: 'keyword', }, - 'crowdstrike.event.ExecutablesWritten': { - category: 'crowdstrike', - description: 'Detected executables written to disk by a process. ', - name: 'crowdstrike.event.ExecutablesWritten', - type: 'nested', + 'okta.request.ip_chain.source': { + category: 'okta', + description: 'Source information. ', + name: 'okta.request.ip_chain.source', + type: 'keyword', }, - 'crowdstrike.event.SessionId': { - category: 'crowdstrike', - description: 'Session ID of the remote response session. ', - name: 'crowdstrike.event.SessionId', + 'okta.request.ip_chain.geographical_context.city': { + category: 'okta', + description: 'The city.', + name: 'okta.request.ip_chain.geographical_context.city', type: 'keyword', }, - 'crowdstrike.event.HostnameField': { - category: 'crowdstrike', - description: 'Host name of the machine for the remote session. ', - name: 'crowdstrike.event.HostnameField', + 'okta.request.ip_chain.geographical_context.state': { + category: 'okta', + description: 'The state.', + name: 'okta.request.ip_chain.geographical_context.state', type: 'keyword', }, - 'crowdstrike.event.StartTimestamp': { - category: 'crowdstrike', - description: 'Start time for the remote session in UTC UNIX format. ', - name: 'crowdstrike.event.StartTimestamp', - type: 'date', + 'okta.request.ip_chain.geographical_context.postal_code': { + category: 'okta', + description: 'The postal code.', + name: 'okta.request.ip_chain.geographical_context.postal_code', + type: 'keyword', }, - 'crowdstrike.event.EndTimestamp': { - category: 'crowdstrike', - description: 'End time for the remote session in UTC UNIX format. ', - name: 'crowdstrike.event.EndTimestamp', - type: 'date', + 'okta.request.ip_chain.geographical_context.country': { + category: 'okta', + description: 'The country.', + name: 'okta.request.ip_chain.geographical_context.country', + type: 'keyword', }, - 'crowdstrike.event.LateralMovement': { - category: 'crowdstrike', - description: 'Lateral movement field for incident. ', - name: 'crowdstrike.event.LateralMovement', - type: 'long', + 'okta.request.ip_chain.geographical_context.geolocation': { + category: 'okta', + description: 'Geolocation information. ', + name: 'okta.request.ip_chain.geographical_context.geolocation', + type: 'geo_point', }, - 'crowdstrike.event.ParentImageFileName': { - category: 'crowdstrike', - description: 'Path to the parent process. ', - name: 'crowdstrike.event.ParentImageFileName', + 'oracle.database_audit.status': { + category: 'oracle', + description: 'Database Audit Status. ', + name: 'oracle.database_audit.status', type: 'keyword', }, - 'crowdstrike.event.ParentCommandLine': { - category: 'crowdstrike', - description: 'Parent process command line arguments. ', - name: 'crowdstrike.event.ParentCommandLine', + 'oracle.database_audit.session_id': { + category: 'oracle', + description: 'Indicates the audit session ID number. ', + name: 'oracle.database_audit.session_id', type: 'keyword', }, - 'crowdstrike.event.GrandparentImageFileName': { - category: 'crowdstrike', - description: 'Path to the grandparent process. ', - name: 'crowdstrike.event.GrandparentImageFileName', + 'oracle.database_audit.client.terminal': { + category: 'oracle', + description: 'If available, the client terminal type, for example "pty". ', + name: 'oracle.database_audit.client.terminal', type: 'keyword', }, - 'crowdstrike.event.GrandparentCommandLine': { - category: 'crowdstrike', - description: 'Grandparent process command line arguments. ', - name: 'crowdstrike.event.GrandparentCommandLine', + 'oracle.database_audit.client.address': { + category: 'oracle', + description: 'The IP Address or Domain used by the client. ', + name: 'oracle.database_audit.client.address', type: 'keyword', }, - 'crowdstrike.event.IOCType': { - category: 'crowdstrike', - description: 'CrowdStrike type for indicator of compromise. ', - name: 'crowdstrike.event.IOCType', + 'oracle.database_audit.client.user': { + category: 'oracle', + description: 'The user running the client or connection to the database. ', + name: 'oracle.database_audit.client.user', type: 'keyword', }, - 'crowdstrike.event.IOCValue': { - category: 'crowdstrike', - description: 'CrowdStrike value for indicator of compromise. ', - name: 'crowdstrike.event.IOCValue', + 'oracle.database_audit.database.user': { + category: 'oracle', + description: 'The database user used to authenticate. ', + name: 'oracle.database_audit.database.user', type: 'keyword', }, - 'crowdstrike.event.CustomerId': { - category: 'crowdstrike', - description: 'Customer identifier. ', - name: 'crowdstrike.event.CustomerId', + 'oracle.database_audit.privilege': { + category: 'oracle', + description: 'The privilege group related to the database user. ', + name: 'oracle.database_audit.privilege', type: 'keyword', }, - 'crowdstrike.event.DeviceId': { - category: 'crowdstrike', - description: 'Device on which the event occurred. ', - name: 'crowdstrike.event.DeviceId', + 'oracle.database_audit.entry.id': { + category: 'oracle', + description: + 'Indicates the current audit entry number, assigned to each audit trail record. The audit entry.id sequence number is shared between fine-grained audit records and regular audit records. ', + name: 'oracle.database_audit.entry.id', type: 'keyword', }, - 'crowdstrike.event.Ipv': { - category: 'crowdstrike', - description: 'Protocol for network request. ', - name: 'crowdstrike.event.Ipv', + 'oracle.database_audit.database.host': { + category: 'oracle', + description: 'Client host machine name. ', + name: 'oracle.database_audit.database.host', type: 'keyword', }, - 'crowdstrike.event.ConnectionDirection': { - category: 'crowdstrike', - description: 'Direction for network connection. ', - name: 'crowdstrike.event.ConnectionDirection', + 'oracle.database_audit.action': { + category: 'oracle', + description: + 'The action performed during the audit event. This could for example be the raw query. ', + name: 'oracle.database_audit.action', type: 'keyword', }, - 'crowdstrike.event.EventType': { - category: 'crowdstrike', - description: 'CrowdStrike provided event type. ', - name: 'crowdstrike.event.EventType', + 'oracle.database_audit.action_number': { + category: 'oracle', + description: + 'Action is a numeric value representing the action the user performed. The corresponding name of the action type is in the AUDIT_ACTIONS table. For example, action 100 refers to LOGON. ', + name: 'oracle.database_audit.action_number', type: 'keyword', }, - 'crowdstrike.event.HostName': { - category: 'crowdstrike', - description: 'Host name of the local machine. ', - name: 'crowdstrike.event.HostName', + 'oracle.database_audit.database.id': { + category: 'oracle', + description: + 'Database identifier calculated when the database is created. It corresponds to the DBID column of the V$DATABASE data dictionary view. ', + name: 'oracle.database_audit.database.id', type: 'keyword', }, - 'crowdstrike.event.ICMPCode': { - category: 'crowdstrike', - description: 'RFC2780 ICMP Code field. ', - name: 'crowdstrike.event.ICMPCode', - type: 'keyword', + 'oracle.database_audit.length': { + category: 'oracle', + description: + 'Refers to the total number of bytes used in this audit record. This number includes the trailing newline bytes (\\n), if any, at the end of the audit record. ', + name: 'oracle.database_audit.length', + type: 'long', }, - 'crowdstrike.event.ICMPType': { - category: 'crowdstrike', - description: 'RFC2780 ICMP Type field. ', - name: 'crowdstrike.event.ICMPType', + 'panw.panos.ruleset': { + category: 'panw', + description: 'Name of the rule that matched this session. ', + name: 'panw.panos.ruleset', type: 'keyword', }, - 'crowdstrike.event.ImageFileName': { - category: 'crowdstrike', - description: 'File name of the associated process for the detection. ', - name: 'crowdstrike.event.ImageFileName', + 'panw.panos.source.zone': { + category: 'panw', + description: 'Source zone for this session. ', + name: 'panw.panos.source.zone', type: 'keyword', }, - 'crowdstrike.event.PID': { - category: 'crowdstrike', - description: 'Associated process id for the detection. ', - name: 'crowdstrike.event.PID', - type: 'long', + 'panw.panos.source.interface': { + category: 'panw', + description: 'Source interface for this session. ', + name: 'panw.panos.source.interface', + type: 'keyword', }, - 'crowdstrike.event.LocalAddress': { - category: 'crowdstrike', - description: 'IP address of local machine. ', - name: 'crowdstrike.event.LocalAddress', + 'panw.panos.source.nat.ip': { + category: 'panw', + description: 'Post-NAT source IP. ', + name: 'panw.panos.source.nat.ip', type: 'ip', }, - 'crowdstrike.event.LocalPort': { - category: 'crowdstrike', - description: 'Port of local machine. ', - name: 'crowdstrike.event.LocalPort', + 'panw.panos.source.nat.port': { + category: 'panw', + description: 'Post-NAT source port. ', + name: 'panw.panos.source.nat.port', type: 'long', }, - 'crowdstrike.event.RemoteAddress': { - category: 'crowdstrike', - description: 'IP address of remote machine. ', - name: 'crowdstrike.event.RemoteAddress', + 'panw.panos.destination.zone': { + category: 'panw', + description: 'Destination zone for this session. ', + name: 'panw.panos.destination.zone', + type: 'keyword', + }, + 'panw.panos.destination.interface': { + category: 'panw', + description: 'Destination interface for this session. ', + name: 'panw.panos.destination.interface', + type: 'keyword', + }, + 'panw.panos.destination.nat.ip': { + category: 'panw', + description: 'Post-NAT destination IP. ', + name: 'panw.panos.destination.nat.ip', type: 'ip', }, - 'crowdstrike.event.RemotePort': { - category: 'crowdstrike', - description: 'Port of remote machine. ', - name: 'crowdstrike.event.RemotePort', + 'panw.panos.destination.nat.port': { + category: 'panw', + description: 'Post-NAT destination port. ', + name: 'panw.panos.destination.nat.port', type: 'long', }, - 'crowdstrike.event.RuleAction': { - category: 'crowdstrike', - description: 'Firewall rule action. ', - name: 'crowdstrike.event.RuleAction', + 'panw.panos.endreason': { + category: 'panw', + description: 'The reason a session terminated. ', + name: 'panw.panos.endreason', type: 'keyword', }, - 'crowdstrike.event.RuleDescription': { - category: 'crowdstrike', - description: 'Firewall rule description. ', - name: 'crowdstrike.event.RuleDescription', + 'panw.panos.network.pcap_id': { + category: 'panw', + description: 'Packet capture ID for a threat. ', + name: 'panw.panos.network.pcap_id', type: 'keyword', }, - 'crowdstrike.event.RuleFamilyID': { - category: 'crowdstrike', - description: 'Firewall rule family id. ', - name: 'crowdstrike.event.RuleFamilyID', + 'panw.panos.network.nat.community_id': { + category: 'panw', + description: 'Community ID flow-hash for the NAT 5-tuple. ', + name: 'panw.panos.network.nat.community_id', type: 'keyword', }, - 'crowdstrike.event.RuleGroupName': { - category: 'crowdstrike', - description: 'Firewall rule group name. ', - name: 'crowdstrike.event.RuleGroupName', + 'panw.panos.file.hash': { + category: 'panw', + description: 'Binary hash for a threat file sent to be analyzed by the WildFire service. ', + name: 'panw.panos.file.hash', type: 'keyword', }, - 'crowdstrike.event.RuleName': { - category: 'crowdstrike', - description: 'Firewall rule name. ', - name: 'crowdstrike.event.RuleName', + 'panw.panos.url.category': { + category: 'panw', + description: + "For threat URLs, it's the URL category. For WildFire, the verdict on the file and is either 'malicious', 'grayware', or 'benign'. ", + name: 'panw.panos.url.category', type: 'keyword', }, - 'crowdstrike.event.RuleId': { - category: 'crowdstrike', - description: 'Firewall rule id. ', - name: 'crowdstrike.event.RuleId', + 'panw.panos.flow_id': { + category: 'panw', + description: 'Internal numeric identifier for each session. ', + name: 'panw.panos.flow_id', type: 'keyword', }, - 'crowdstrike.event.MatchCount': { - category: 'crowdstrike', - description: 'Number of firewall rule matches. ', - name: 'crowdstrike.event.MatchCount', + 'panw.panos.sequence_number': { + category: 'panw', + description: + 'Log entry identifier that is incremented sequentially. Unique for each log type. ', + name: 'panw.panos.sequence_number', type: 'long', }, - 'crowdstrike.event.MatchCountSinceLastReport': { - category: 'crowdstrike', - description: 'Number of firewall rule matches since the last report. ', - name: 'crowdstrike.event.MatchCountSinceLastReport', - type: 'long', + 'panw.panos.threat.resource': { + category: 'panw', + description: 'URL or file name for a threat. ', + name: 'panw.panos.threat.resource', + type: 'keyword', }, - 'crowdstrike.event.Timestamp': { - category: 'crowdstrike', - description: 'Firewall rule triggered timestamp. ', - name: 'crowdstrike.event.Timestamp', - type: 'date', + 'panw.panos.threat.id': { + category: 'panw', + description: 'Palo Alto Networks identifier for the threat. ', + name: 'panw.panos.threat.id', + type: 'keyword', }, - 'crowdstrike.event.Flags.Audit': { - category: 'crowdstrike', - description: 'CrowdStrike audit flag. ', - name: 'crowdstrike.event.Flags.Audit', - type: 'boolean', + 'panw.panos.threat.name': { + category: 'panw', + description: 'Palo Alto Networks name for the threat. ', + name: 'panw.panos.threat.name', + type: 'keyword', }, - 'crowdstrike.event.Flags.Log': { - category: 'crowdstrike', - description: 'CrowdStrike log flag. ', - name: 'crowdstrike.event.Flags.Log', - type: 'boolean', + 'panw.panos.action': { + category: 'panw', + description: 'Action taken for the session.', + name: 'panw.panos.action', + type: 'keyword', }, - 'crowdstrike.event.Flags.Monitor': { - category: 'crowdstrike', - description: 'CrowdStrike monitor flag. ', - name: 'crowdstrike.event.Flags.Monitor', - type: 'boolean', + 'panw.panos.type': { + category: 'panw', + description: 'Specifies the type of the log', + name: 'panw.panos.type', }, - 'crowdstrike.event.Protocol': { - category: 'crowdstrike', - description: 'CrowdStrike provided protocol. ', - name: 'crowdstrike.event.Protocol', - type: 'keyword', + 'panw.panos.sub_type': { + category: 'panw', + description: 'Specifies the sub type of the log', + name: 'panw.panos.sub_type', }, - 'crowdstrike.event.NetworkProfile': { - category: 'crowdstrike', - description: 'CrowdStrike network profile. ', - name: 'crowdstrike.event.NetworkProfile', + 'panw.panos.virtual_sys': { + category: 'panw', + description: 'Virtual system instance ', + name: 'panw.panos.virtual_sys', type: 'keyword', }, - 'crowdstrike.event.PolicyName': { - category: 'crowdstrike', - description: 'CrowdStrike policy name. ', - name: 'crowdstrike.event.PolicyName', + 'panw.panos.client_os_ver': { + category: 'panw', + description: 'The client device’s OS version. ', + name: 'panw.panos.client_os_ver', type: 'keyword', }, - 'crowdstrike.event.PolicyID': { - category: 'crowdstrike', - description: 'CrowdStrike policy id. ', - name: 'crowdstrike.event.PolicyID', + 'panw.panos.client_os': { + category: 'panw', + description: 'The client device’s OS version. ', + name: 'panw.panos.client_os', type: 'keyword', }, - 'crowdstrike.event.Status': { - category: 'crowdstrike', - description: 'CrowdStrike status. ', - name: 'crowdstrike.event.Status', + 'panw.panos.client_ver': { + category: 'panw', + description: 'The client’s GlobalProtect app version. ', + name: 'panw.panos.client_ver', type: 'keyword', }, - 'crowdstrike.event.TreeID': { - category: 'crowdstrike', - description: 'CrowdStrike tree id. ', - name: 'crowdstrike.event.TreeID', + 'panw.panos.stage': { + category: 'panw', + description: 'A string showing the stage of the connection ', + example: 'before-login', + name: 'panw.panos.stage', type: 'keyword', }, - 'crowdstrike.event.Commands': { - category: 'crowdstrike', - description: 'Commands run in a remote session. ', - name: 'crowdstrike.event.Commands', + 'panw.panos.actionflags': { + category: 'panw', + description: 'A bit field indicating if the log was forwarded to Panorama. ', + name: 'panw.panos.actionflags', type: 'keyword', }, - 'envoyproxy.log_type': { - category: 'envoyproxy', - description: 'Envoy log type, normally ACCESS ', - name: 'envoyproxy.log_type', + 'panw.panos.error': { + category: 'panw', + description: 'A string showing that error that has occurred in any event. ', + name: 'panw.panos.error', type: 'keyword', }, - 'envoyproxy.response_flags': { - category: 'envoyproxy', - description: 'Response flags ', - name: 'envoyproxy.response_flags', + 'panw.panos.error_code': { + category: 'panw', + description: 'An integer associated with any errors that occurred. ', + name: 'panw.panos.error_code', + type: 'integer', + }, + 'panw.panos.repeatcnt': { + category: 'panw', + description: + 'The number of sessions with the same source IP address, destination IP address, application, and subtype that GlobalProtect has detected within the last five seconds.An integer associated with any errors that occurred. ', + name: 'panw.panos.repeatcnt', + type: 'integer', + }, + 'panw.panos.serial_number': { + category: 'panw', + description: 'The serial number of the user’s machine or device. ', + name: 'panw.panos.serial_number', type: 'keyword', }, - 'envoyproxy.upstream_service_time': { - category: 'envoyproxy', - description: 'Upstream service time in nanoseconds ', - name: 'envoyproxy.upstream_service_time', - type: 'long', - format: 'duration', + 'panw.panos.auth_method': { + category: 'panw', + description: 'A string showing the authentication type ', + example: 'LDAP', + name: 'panw.panos.auth_method', + type: 'keyword', }, - 'envoyproxy.request_id': { - category: 'envoyproxy', - description: 'ID of the request ', - name: 'envoyproxy.request_id', + 'panw.panos.datasource': { + category: 'panw', + description: 'Source from which mapping information is collected. ', + name: 'panw.panos.datasource', type: 'keyword', }, - 'envoyproxy.authority': { - category: 'envoyproxy', - description: 'Envoy proxy authority field ', - name: 'envoyproxy.authority', + 'panw.panos.datasourcetype': { + category: 'panw', + description: 'Mechanism used to identify the IP/User mappings within a data source. ', + name: 'panw.panos.datasourcetype', type: 'keyword', }, - 'envoyproxy.proxy_type': { - category: 'envoyproxy', - description: 'Envoy proxy type, tcp or http ', - name: 'envoyproxy.proxy_type', + 'panw.panos.datasourcename': { + category: 'panw', + description: 'User-ID source that sends the IP (Port)-User Mapping. ', + name: 'panw.panos.datasourcename', type: 'keyword', }, - 'fortinet.file.hash.crc32': { - category: 'fortinet', - description: 'CRC32 Hash of file ', - name: 'fortinet.file.hash.crc32', + 'panw.panos.factorno': { + category: 'panw', + description: 'Indicates the use of primary authentication (1) or additional factors (2, 3). ', + name: 'panw.panos.factorno', + type: 'integer', + }, + 'panw.panos.factortype': { + category: 'panw', + description: 'Vendor used to authenticate a user when Multi Factor authentication is present. ', + name: 'panw.panos.factortype', type: 'keyword', }, - 'fortinet.firewall.acct_stat': { - category: 'fortinet', - description: 'Accounting state (RADIUS) ', - name: 'fortinet.firewall.acct_stat', + 'panw.panos.factorcompletiontime': { + category: 'panw', + description: 'Time the authentication was completed. ', + name: 'panw.panos.factorcompletiontime', + type: 'date', + }, + 'panw.panos.ugflags': { + category: 'panw', + description: + 'Displays whether the user group that was found during user group mapping. Supported values are: User Group Found—Indicates whether the user could be mapped to a group. Duplicate User—Indicates whether duplicate users were found in a user group. Displays N/A if no user group is found. ', + name: 'panw.panos.ugflags', type: 'keyword', }, - 'fortinet.firewall.acktime': { - category: 'fortinet', - description: 'Alarm Acknowledge Time ', - name: 'fortinet.firewall.acktime', + 'panw.panos.device_group_hierarchy.level_1': { + category: 'panw', + description: + 'A sequence of identification numbers that indicate the device group’s location within a device group hierarchy. The firewall (or virtual system) generating the log includes the identification number of each ancestor in its device group hierarchy. The shared device group (level 0) is not included in this structure. If the log values are 12, 34, 45, 0, it means that the log was generated by a firewall (or virtual system) that belongs to device group 45, and its ancestors are 34, and 12. ', + name: 'panw.panos.device_group_hierarchy.level_1', type: 'keyword', }, - 'fortinet.firewall.act': { - category: 'fortinet', - description: 'Action ', - name: 'fortinet.firewall.act', + 'panw.panos.device_group_hierarchy.level_2': { + category: 'panw', + description: + 'A sequence of identification numbers that indicate the device group’s location within a device group hierarchy. The firewall (or virtual system) generating the log includes the identification number of each ancestor in its device group hierarchy. The shared device group (level 0) is not included in this structure. If the log values are 12, 34, 45, 0, it means that the log was generated by a firewall (or virtual system) that belongs to device group 45, and its ancestors are 34, and 12. ', + name: 'panw.panos.device_group_hierarchy.level_2', type: 'keyword', }, - 'fortinet.firewall.action': { - category: 'fortinet', - description: 'Status of the session ', - name: 'fortinet.firewall.action', + 'panw.panos.device_group_hierarchy.level_3': { + category: 'panw', + description: + 'A sequence of identification numbers that indicate the device group’s location within a device group hierarchy. The firewall (or virtual system) generating the log includes the identification number of each ancestor in its device group hierarchy. The shared device group (level 0) is not included in this structure. If the log values are 12, 34, 45, 0, it means that the log was generated by a firewall (or virtual system) that belongs to device group 45, and its ancestors are 34, and 12. ', + name: 'panw.panos.device_group_hierarchy.level_3', type: 'keyword', }, - 'fortinet.firewall.activity': { - category: 'fortinet', - description: 'HA activity message ', - name: 'fortinet.firewall.activity', + 'panw.panos.device_group_hierarchy.level_4': { + category: 'panw', + description: + 'A sequence of identification numbers that indicate the device group’s location within a device group hierarchy. The firewall (or virtual system) generating the log includes the identification number of each ancestor in its device group hierarchy. The shared device group (level 0) is not included in this structure. If the log values are 12, 34, 45, 0, it means that the log was generated by a firewall (or virtual system) that belongs to device group 45, and its ancestors are 34, and 12. ', + name: 'panw.panos.device_group_hierarchy.level_4', type: 'keyword', }, - 'fortinet.firewall.addr': { - category: 'fortinet', - description: 'IP Address ', - name: 'fortinet.firewall.addr', - type: 'ip', + 'panw.panos.timeout': { + category: 'panw', + description: 'Timeout after which the IP/User Mappings are cleared. ', + name: 'panw.panos.timeout', + type: 'integer', }, - 'fortinet.firewall.addr_type': { - category: 'fortinet', - description: 'Address Type ', - name: 'fortinet.firewall.addr_type', + 'panw.panos.vsys_id': { + category: 'panw', + description: 'A unique identifier for a virtual system on a Palo Alto Networks firewall. ', + name: 'panw.panos.vsys_id', type: 'keyword', }, - 'fortinet.firewall.addrgrp': { - category: 'fortinet', - description: 'Address Group ', - name: 'fortinet.firewall.addrgrp', + 'panw.panos.vsys_name': { + category: 'panw', + description: + 'The name of the virtual system associated with the session; only valid on firewalls enabled for multiple virtual systems. ', + name: 'panw.panos.vsys_name', type: 'keyword', }, - 'fortinet.firewall.adgroup': { - category: 'fortinet', - description: 'AD Group Name ', - name: 'fortinet.firewall.adgroup', + 'panw.panos.description': { + category: 'panw', + description: 'Additional information for any event that has occurred. ', + name: 'panw.panos.description', type: 'keyword', }, - 'fortinet.firewall.admin': { - category: 'fortinet', - description: 'Admin User ', - name: 'fortinet.firewall.admin', + 'panw.panos.tunnel_type': { + category: 'panw', + description: 'The type of tunnel (either SSLVPN or IPSec). ', + name: 'panw.panos.tunnel_type', type: 'keyword', }, - 'fortinet.firewall.age': { - category: 'fortinet', - description: 'Time in seconds - time passed since last seen ', - name: 'fortinet.firewall.age', - type: 'integer', + 'panw.panos.connect_method': { + category: 'panw', + description: 'A string showing the how the GlobalProtect app connects to Gateway ', + name: 'panw.panos.connect_method', + type: 'keyword', }, - 'fortinet.firewall.agent': { - category: 'fortinet', - description: 'User agent - eg. agent="Mozilla/5.0" ', - name: 'fortinet.firewall.agent', + 'panw.panos.matchname': { + category: 'panw', + description: 'Name of the HIP object or profile. ', + name: 'panw.panos.matchname', type: 'keyword', }, - 'fortinet.firewall.alarmid': { - category: 'fortinet', - description: 'Alarm ID ', - name: 'fortinet.firewall.alarmid', - type: 'integer', + 'panw.panos.matchtype': { + category: 'panw', + description: 'Whether the hip field represents a HIP object or a HIP profile. ', + name: 'panw.panos.matchtype', + type: 'keyword', }, - 'fortinet.firewall.alert': { - category: 'fortinet', - description: 'Alert ', - name: 'fortinet.firewall.alert', + 'panw.panos.priority': { + category: 'panw', + description: + 'The priority order of the gateway that is based on highest (1), high (2), medium (3), low (4), or lowest (5) to which the GlobalProtect app can connect. ', + name: 'panw.panos.priority', type: 'keyword', }, - 'fortinet.firewall.analyticscksum': { - category: 'fortinet', - description: 'The checksum of the file submitted for analytics ', - name: 'fortinet.firewall.analyticscksum', + 'panw.panos.response_time': { + category: 'panw', + description: + 'The SSL response time of the selected gateway that is measured in milliseconds on the endpoint during tunnel setup. ', + name: 'panw.panos.response_time', type: 'keyword', }, - 'fortinet.firewall.analyticssubmit': { - category: 'fortinet', - description: 'The flag for analytics submission ', - name: 'fortinet.firewall.analyticssubmit', + 'panw.panos.attempted_gateways': { + category: 'panw', + description: + 'The fields that are collected for each gateway connection attempt with the gateway name, SSL response time, and priority ', + name: 'panw.panos.attempted_gateways', type: 'keyword', }, - 'fortinet.firewall.ap': { - category: 'fortinet', - description: 'Access Point ', - name: 'fortinet.firewall.ap', + 'panw.panos.gateway': { + category: 'panw', + description: 'The name of the gateway that is specified on the portal configuration. ', + name: 'panw.panos.gateway', type: 'keyword', }, - 'fortinet.firewall.app-type': { - category: 'fortinet', - description: 'Address Type ', - name: 'fortinet.firewall.app-type', + 'panw.panos.selection_type': { + category: 'panw', + description: 'The connection method that is selected to connect to the gateway. ', + name: 'panw.panos.selection_type', type: 'keyword', }, - 'fortinet.firewall.appact': { - category: 'fortinet', - description: 'The security action from app control ', - name: 'fortinet.firewall.appact', + 'rabbitmq.log.pid': { + category: 'rabbitmq', + description: 'The Erlang process id', + example: '<0.222.0>', + name: 'rabbitmq.log.pid', type: 'keyword', }, - 'fortinet.firewall.appid': { - category: 'fortinet', - description: 'Application ID ', - name: 'fortinet.firewall.appid', - type: 'integer', + 'snyk.projects': { + category: 'snyk', + description: 'Array with all related projects objects. ', + name: 'snyk.projects', + type: 'flattened', }, - 'fortinet.firewall.applist': { - category: 'fortinet', - description: 'Application Control profile ', - name: 'fortinet.firewall.applist', + 'snyk.related.projects': { + category: 'snyk', + description: "Array of all the related project ID's. ", + name: 'snyk.related.projects', type: 'keyword', }, - 'fortinet.firewall.apprisk': { - category: 'fortinet', - description: 'Application Risk Level ', - name: 'fortinet.firewall.apprisk', + 'snyk.audit.org_id': { + category: 'snyk', + description: 'ID of the related Organization related to the event. ', + name: 'snyk.audit.org_id', type: 'keyword', }, - 'fortinet.firewall.apscan': { - category: 'fortinet', - description: 'The name of the AP, which scanned and detected the rogue AP ', - name: 'fortinet.firewall.apscan', + 'snyk.audit.project_id': { + category: 'snyk', + description: 'ID of the project related to the event. ', + name: 'snyk.audit.project_id', type: 'keyword', }, - 'fortinet.firewall.apsn': { - category: 'fortinet', - description: 'Access Point ', - name: 'fortinet.firewall.apsn', + 'snyk.audit.content': { + category: 'snyk', + description: 'Overview of the content that was changed, both old and new values. ', + name: 'snyk.audit.content', + type: 'flattened', + }, + 'snyk.vulnerabilities.cvss3': { + category: 'snyk', + description: 'CSSv3 scores. ', + name: 'snyk.vulnerabilities.cvss3', type: 'keyword', }, - 'fortinet.firewall.apstatus': { - category: 'fortinet', - description: 'Access Point status ', - name: 'fortinet.firewall.apstatus', + 'snyk.vulnerabilities.disclosure_time': { + category: 'snyk', + description: + 'The time this vulnerability was originally disclosed to the package maintainers. ', + name: 'snyk.vulnerabilities.disclosure_time', + type: 'date', + }, + 'snyk.vulnerabilities.exploit_maturity': { + category: 'snyk', + description: 'The Snyk exploit maturity level. ', + name: 'snyk.vulnerabilities.exploit_maturity', type: 'keyword', }, - 'fortinet.firewall.aptype': { - category: 'fortinet', - description: 'Access Point type ', - name: 'fortinet.firewall.aptype', + 'snyk.vulnerabilities.id': { + category: 'snyk', + description: 'The vulnerability reference ID. ', + name: 'snyk.vulnerabilities.id', type: 'keyword', }, - 'fortinet.firewall.assigned': { - category: 'fortinet', - description: 'Assigned IP Address ', - name: 'fortinet.firewall.assigned', - type: 'ip', + 'snyk.vulnerabilities.is_ignored': { + category: 'snyk', + description: 'If the vulnerability report has been ignored. ', + name: 'snyk.vulnerabilities.is_ignored', + type: 'boolean', }, - 'fortinet.firewall.assignip': { - category: 'fortinet', - description: 'Assigned IP Address ', - name: 'fortinet.firewall.assignip', - type: 'ip', + 'snyk.vulnerabilities.is_patchable': { + category: 'snyk', + description: 'If vulnerability is fixable by using a Snyk supplied patch. ', + name: 'snyk.vulnerabilities.is_patchable', + type: 'boolean', }, - 'fortinet.firewall.attachment': { - category: 'fortinet', - description: 'The flag for email attachement ', - name: 'fortinet.firewall.attachment', - type: 'keyword', + 'snyk.vulnerabilities.is_patched': { + category: 'snyk', + description: 'If the vulnerability has been patched. ', + name: 'snyk.vulnerabilities.is_patched', + type: 'boolean', }, - 'fortinet.firewall.attack': { - category: 'fortinet', - description: 'Attack Name ', - name: 'fortinet.firewall.attack', + 'snyk.vulnerabilities.is_pinnable': { + category: 'snyk', + description: 'If the vulnerability is fixable by pinning a transitive dependency. ', + name: 'snyk.vulnerabilities.is_pinnable', + type: 'boolean', + }, + 'snyk.vulnerabilities.is_upgradable': { + category: 'snyk', + description: 'If the vulnerability fixable by upgrading a dependency. ', + name: 'snyk.vulnerabilities.is_upgradable', + type: 'boolean', + }, + 'snyk.vulnerabilities.language': { + category: 'snyk', + description: "The package's programming language. ", + name: 'snyk.vulnerabilities.language', type: 'keyword', }, - 'fortinet.firewall.attackcontext': { - category: 'fortinet', - description: 'The trigger patterns and the packetdata with base64 encoding ', - name: 'fortinet.firewall.attackcontext', + 'snyk.vulnerabilities.package': { + category: 'snyk', + description: 'The package identifier according to its package manager. ', + name: 'snyk.vulnerabilities.package', type: 'keyword', }, - 'fortinet.firewall.attackcontextid': { - category: 'fortinet', - description: 'Attack context id / total ', - name: 'fortinet.firewall.attackcontextid', + 'snyk.vulnerabilities.package_manager': { + category: 'snyk', + description: 'The package manager. ', + name: 'snyk.vulnerabilities.package_manager', type: 'keyword', }, - 'fortinet.firewall.attackid': { - category: 'fortinet', - description: 'Attack ID ', - name: 'fortinet.firewall.attackid', - type: 'integer', + 'snyk.vulnerabilities.patches': { + category: 'snyk', + description: 'Patches required to resolve the issue created by Snyk. ', + name: 'snyk.vulnerabilities.patches', + type: 'flattened', }, - 'fortinet.firewall.auditid': { - category: 'fortinet', - description: 'Audit ID ', - name: 'fortinet.firewall.auditid', + 'snyk.vulnerabilities.priority_score': { + category: 'snyk', + description: 'The CVS priority score. ', + name: 'snyk.vulnerabilities.priority_score', type: 'long', }, - 'fortinet.firewall.auditscore': { - category: 'fortinet', - description: 'The Audit Score ', - name: 'fortinet.firewall.auditscore', + 'snyk.vulnerabilities.publication_time': { + category: 'snyk', + description: 'The vulnerability publication time. ', + name: 'snyk.vulnerabilities.publication_time', + type: 'date', + }, + 'snyk.vulnerabilities.jira_issue_url': { + category: 'snyk', + description: 'Link to the related Jira issue. ', + name: 'snyk.vulnerabilities.jira_issue_url', type: 'keyword', }, - 'fortinet.firewall.audittime': { - category: 'fortinet', - description: 'The time of the audit ', - name: 'fortinet.firewall.audittime', + 'snyk.vulnerabilities.original_severity': { + category: 'snyk', + description: 'The original severity of the vulnerability. ', + name: 'snyk.vulnerabilities.original_severity', type: 'long', }, - 'fortinet.firewall.authgrp': { - category: 'fortinet', - description: 'Authorization Group ', - name: 'fortinet.firewall.authgrp', + 'snyk.vulnerabilities.reachability': { + category: 'snyk', + description: + 'If the vulnerable function from the library is used in the code scanned. Can either be No Info, Potentially reachable and Reachable. ', + name: 'snyk.vulnerabilities.reachability', type: 'keyword', }, - 'fortinet.firewall.authid': { - category: 'fortinet', - description: 'Authentication ID ', - name: 'fortinet.firewall.authid', + 'snyk.vulnerabilities.title': { + category: 'snyk', + description: 'The issue title. ', + name: 'snyk.vulnerabilities.title', type: 'keyword', }, - 'fortinet.firewall.authproto': { - category: 'fortinet', - description: 'The protocol that initiated the authentication ', - name: 'fortinet.firewall.authproto', + 'snyk.vulnerabilities.type': { + category: 'snyk', + description: 'The issue type. Can be either "license" or "vulnerability". ', + name: 'snyk.vulnerabilities.type', type: 'keyword', }, - 'fortinet.firewall.authserver': { - category: 'fortinet', - description: 'Authentication server ', - name: 'fortinet.firewall.authserver', + 'snyk.vulnerabilities.unique_severities_list': { + category: 'snyk', + description: 'A list of related unique severities. ', + name: 'snyk.vulnerabilities.unique_severities_list', type: 'keyword', }, - 'fortinet.firewall.bandwidth': { - category: 'fortinet', - description: 'Bandwidth ', - name: 'fortinet.firewall.bandwidth', + 'snyk.vulnerabilities.version': { + category: 'snyk', + description: 'The package version this issue is applicable to. ', + name: 'snyk.vulnerabilities.version', type: 'keyword', }, - 'fortinet.firewall.banned_rule': { - category: 'fortinet', - description: 'NAC quarantine Banned Rule Name ', - name: 'fortinet.firewall.banned_rule', + 'snyk.vulnerabilities.introduced_date': { + category: 'snyk', + description: 'The date the vulnerability was initially found. ', + name: 'snyk.vulnerabilities.introduced_date', + type: 'date', + }, + 'snyk.vulnerabilities.is_fixed': { + category: 'snyk', + description: 'If the related vulnerability has been resolved. ', + name: 'snyk.vulnerabilities.is_fixed', + type: 'boolean', + }, + 'snyk.vulnerabilities.credit': { + category: 'snyk', + description: 'Reference to the person that original found the vulnerability. ', + name: 'snyk.vulnerabilities.credit', type: 'keyword', }, - 'fortinet.firewall.banned_src': { - category: 'fortinet', - description: 'NAC quarantine Banned Source IP ', - name: 'fortinet.firewall.banned_src', + 'snyk.vulnerabilities.semver': { + category: 'snyk', + description: + 'One or more semver ranges this issue is applicable to. The format varies according to package manager. ', + name: 'snyk.vulnerabilities.semver', + type: 'flattened', + }, + 'snyk.vulnerabilities.identifiers.alternative': { + category: 'snyk', + description: 'Additional vulnerability identifiers. ', + name: 'snyk.vulnerabilities.identifiers.alternative', type: 'keyword', }, - 'fortinet.firewall.banword': { - category: 'fortinet', - description: 'Banned word ', - name: 'fortinet.firewall.banword', + 'snyk.vulnerabilities.identifiers.cwe': { + category: 'snyk', + description: 'CWE vulnerability identifiers. ', + name: 'snyk.vulnerabilities.identifiers.cwe', type: 'keyword', }, - 'fortinet.firewall.botnetdomain': { - category: 'fortinet', - description: 'Botnet Domain Name ', - name: 'fortinet.firewall.botnetdomain', + 'sophos.xg.device': { + category: 'sophos', + description: 'device ', + name: 'sophos.xg.device', type: 'keyword', }, - 'fortinet.firewall.botnetip': { - category: 'fortinet', - description: 'Botnet IP Address ', - name: 'fortinet.firewall.botnetip', - type: 'ip', + 'sophos.xg.date': { + category: 'sophos', + description: 'Date (yyyy-mm-dd) when the event occurred ', + name: 'sophos.xg.date', + type: 'date', }, - 'fortinet.firewall.bssid': { - category: 'fortinet', - description: 'Service Set ID ', - name: 'fortinet.firewall.bssid', + 'sophos.xg.timezone': { + category: 'sophos', + description: 'Time (hh:mm:ss) when the event occurred ', + name: 'sophos.xg.timezone', type: 'keyword', }, - 'fortinet.firewall.call_id': { - category: 'fortinet', - description: 'Caller ID ', - name: 'fortinet.firewall.call_id', + 'sophos.xg.device_name': { + category: 'sophos', + description: 'Model number of the device ', + name: 'sophos.xg.device_name', type: 'keyword', }, - 'fortinet.firewall.carrier_ep': { - category: 'fortinet', - description: 'The FortiOS Carrier end-point identification ', - name: 'fortinet.firewall.carrier_ep', + 'sophos.xg.device_id': { + category: 'sophos', + description: 'Serial number of the device ', + name: 'sophos.xg.device_id', type: 'keyword', }, - 'fortinet.firewall.cat': { - category: 'fortinet', - description: 'DNS category ID ', - name: 'fortinet.firewall.cat', - type: 'integer', - }, - 'fortinet.firewall.category': { - category: 'fortinet', - description: 'Authentication category ', - name: 'fortinet.firewall.category', + 'sophos.xg.log_id': { + category: 'sophos', + description: 'Unique 12 characters code (0101011) ', + name: 'sophos.xg.log_id', type: 'keyword', }, - 'fortinet.firewall.cc': { - category: 'fortinet', - description: 'CC Email Address ', - name: 'fortinet.firewall.cc', + 'sophos.xg.log_type': { + category: 'sophos', + description: 'Type of event e.g. firewall event ', + name: 'sophos.xg.log_type', type: 'keyword', }, - 'fortinet.firewall.cdrcontent': { - category: 'fortinet', - description: 'Cdrcontent ', - name: 'fortinet.firewall.cdrcontent', + 'sophos.xg.log_component': { + category: 'sophos', + description: 'Component responsible for logging e.g. Firewall rule ', + name: 'sophos.xg.log_component', type: 'keyword', }, - 'fortinet.firewall.centralnatid': { - category: 'fortinet', - description: 'Central NAT ID ', - name: 'fortinet.firewall.centralnatid', - type: 'integer', - }, - 'fortinet.firewall.cert': { - category: 'fortinet', - description: 'Certificate ', - name: 'fortinet.firewall.cert', + 'sophos.xg.log_subtype': { + category: 'sophos', + description: 'Sub type of event ', + name: 'sophos.xg.log_subtype', type: 'keyword', }, - 'fortinet.firewall.cert-type': { - category: 'fortinet', - description: 'Certificate type ', - name: 'fortinet.firewall.cert-type', + 'sophos.xg.hb_health': { + category: 'sophos', + description: 'Heartbeat status ', + name: 'sophos.xg.hb_health', type: 'keyword', }, - 'fortinet.firewall.certhash': { - category: 'fortinet', - description: 'Certificate hash ', - name: 'fortinet.firewall.certhash', + 'sophos.xg.priority': { + category: 'sophos', + description: 'Severity level of traffic ', + name: 'sophos.xg.priority', type: 'keyword', }, - 'fortinet.firewall.cfgattr': { - category: 'fortinet', - description: 'Configuration attribute ', - name: 'fortinet.firewall.cfgattr', + 'sophos.xg.status': { + category: 'sophos', + description: 'Ultimate status of traffic – Allowed or Denied ', + name: 'sophos.xg.status', type: 'keyword', }, - 'fortinet.firewall.cfgobj': { - category: 'fortinet', - description: 'Configuration object ', - name: 'fortinet.firewall.cfgobj', - type: 'keyword', + 'sophos.xg.duration': { + category: 'sophos', + description: 'Durability of traffic (seconds) ', + name: 'sophos.xg.duration', + type: 'long', }, - 'fortinet.firewall.cfgpath': { - category: 'fortinet', - description: 'Configuration path ', - name: 'fortinet.firewall.cfgpath', + 'sophos.xg.fw_rule_id': { + category: 'sophos', + description: 'Firewall Rule ID which is applied on the traffic ', + name: 'sophos.xg.fw_rule_id', + type: 'integer', + }, + 'sophos.xg.user_name': { + category: 'sophos', + description: 'user_name ', + name: 'sophos.xg.user_name', type: 'keyword', }, - 'fortinet.firewall.cfgtid': { - category: 'fortinet', - description: 'Configuration transaction ID ', - name: 'fortinet.firewall.cfgtid', + 'sophos.xg.user_group': { + category: 'sophos', + description: 'Group name to which the user belongs ', + name: 'sophos.xg.user_group', type: 'keyword', }, - 'fortinet.firewall.cfgtxpower': { - category: 'fortinet', - description: 'Configuration TX power ', - name: 'fortinet.firewall.cfgtxpower', - type: 'integer', + 'sophos.xg.iap': { + category: 'sophos', + description: 'Internet Access policy ID applied on the traffic ', + name: 'sophos.xg.iap', + type: 'keyword', }, - 'fortinet.firewall.channel': { - category: 'fortinet', - description: 'Wireless Channel ', - name: 'fortinet.firewall.channel', + 'sophos.xg.ips_policy_id': { + category: 'sophos', + description: 'IPS policy ID applied on the traffic ', + name: 'sophos.xg.ips_policy_id', type: 'integer', }, - 'fortinet.firewall.channeltype': { - category: 'fortinet', - description: 'SSH channel type ', - name: 'fortinet.firewall.channeltype', + 'sophos.xg.policy_type': { + category: 'sophos', + description: 'Policy type applied to the traffic ', + name: 'sophos.xg.policy_type', type: 'keyword', }, - 'fortinet.firewall.chassisid': { - category: 'fortinet', - description: 'Chassis ID ', - name: 'fortinet.firewall.chassisid', + 'sophos.xg.appfilter_policy_id': { + category: 'sophos', + description: 'Application Filter policy applied on the traffic ', + name: 'sophos.xg.appfilter_policy_id', type: 'integer', }, - 'fortinet.firewall.checksum': { - category: 'fortinet', - description: 'The checksum of the scanned file ', - name: 'fortinet.firewall.checksum', - type: 'keyword', + 'sophos.xg.application_filter_policy': { + category: 'sophos', + description: 'Application Filter policy applied on the traffic ', + name: 'sophos.xg.application_filter_policy', + type: 'integer', }, - 'fortinet.firewall.chgheaders': { - category: 'fortinet', - description: 'HTTP Headers ', - name: 'fortinet.firewall.chgheaders', + 'sophos.xg.application': { + category: 'sophos', + description: 'Application name ', + name: 'sophos.xg.application', type: 'keyword', }, - 'fortinet.firewall.cldobjid': { - category: 'fortinet', - description: 'Connector object ID ', - name: 'fortinet.firewall.cldobjid', + 'sophos.xg.application_name': { + category: 'sophos', + description: 'Application name ', + name: 'sophos.xg.application_name', type: 'keyword', }, - 'fortinet.firewall.client_addr': { - category: 'fortinet', - description: 'Wifi client address ', - name: 'fortinet.firewall.client_addr', + 'sophos.xg.application_risk': { + category: 'sophos', + description: 'Risk level assigned to the application ', + name: 'sophos.xg.application_risk', type: 'keyword', }, - 'fortinet.firewall.cloudaction': { - category: 'fortinet', - description: 'Cloud Action ', - name: 'fortinet.firewall.cloudaction', + 'sophos.xg.application_technology': { + category: 'sophos', + description: 'Technology of the application ', + name: 'sophos.xg.application_technology', type: 'keyword', }, - 'fortinet.firewall.clouduser': { - category: 'fortinet', - description: 'Cloud User ', - name: 'fortinet.firewall.clouduser', + 'sophos.xg.application_category': { + category: 'sophos', + description: 'Application is resolved by signature or synchronized application ', + name: 'sophos.xg.application_category', type: 'keyword', }, - 'fortinet.firewall.column': { - category: 'fortinet', - description: 'VOIP Column ', - name: 'fortinet.firewall.column', - type: 'integer', + 'sophos.xg.appresolvedby': { + category: 'sophos', + description: 'Technology of the application ', + name: 'sophos.xg.appresolvedby', + type: 'keyword', }, - 'fortinet.firewall.command': { - category: 'fortinet', - description: 'CLI Command ', - name: 'fortinet.firewall.command', + 'sophos.xg.app_is_cloud': { + category: 'sophos', + description: 'Application is Cloud ', + name: 'sophos.xg.app_is_cloud', type: 'keyword', }, - 'fortinet.firewall.community': { - category: 'fortinet', - description: 'SNMP Community ', - name: 'fortinet.firewall.community', + 'sophos.xg.in_interface': { + category: 'sophos', + description: 'Interface for incoming traffic, e.g., Port A ', + name: 'sophos.xg.in_interface', type: 'keyword', }, - 'fortinet.firewall.configcountry': { - category: 'fortinet', - description: 'Configuration country ', - name: 'fortinet.firewall.configcountry', + 'sophos.xg.out_interface': { + category: 'sophos', + description: 'Interface for outgoing traffic, e.g., Port B ', + name: 'sophos.xg.out_interface', type: 'keyword', }, - 'fortinet.firewall.connection_type': { - category: 'fortinet', - description: 'FortiClient Connection Type ', - name: 'fortinet.firewall.connection_type', + 'sophos.xg.src_ip': { + category: 'sophos', + description: 'Original source IP address of traffic ', + name: 'sophos.xg.src_ip', + type: 'ip', + }, + 'sophos.xg.src_mac': { + category: 'sophos', + description: 'Original source MAC address of traffic ', + name: 'sophos.xg.src_mac', type: 'keyword', }, - 'fortinet.firewall.conserve': { - category: 'fortinet', - description: 'Flag for conserve mode ', - name: 'fortinet.firewall.conserve', + 'sophos.xg.src_country_code': { + category: 'sophos', + description: 'Code of the country to which the source IP belongs ', + name: 'sophos.xg.src_country_code', type: 'keyword', }, - 'fortinet.firewall.constraint': { - category: 'fortinet', - description: 'WAF http protocol restrictions ', - name: 'fortinet.firewall.constraint', + 'sophos.xg.dst_ip': { + category: 'sophos', + description: 'Original destination IP address of traffic ', + name: 'sophos.xg.dst_ip', + type: 'ip', + }, + 'sophos.xg.dst_country_code': { + category: 'sophos', + description: 'Code of the country to which the destination IP belongs ', + name: 'sophos.xg.dst_country_code', type: 'keyword', }, - 'fortinet.firewall.contentdisarmed': { - category: 'fortinet', - description: 'Email scanned content ', - name: 'fortinet.firewall.contentdisarmed', + 'sophos.xg.protocol': { + category: 'sophos', + description: 'Protocol number of traffic ', + name: 'sophos.xg.protocol', type: 'keyword', }, - 'fortinet.firewall.contenttype': { - category: 'fortinet', - description: 'Content Type from HTTP header ', - name: 'fortinet.firewall.contenttype', + 'sophos.xg.src_port': { + category: 'sophos', + description: 'Original source port of TCP and UDP traffic ', + name: 'sophos.xg.src_port', + type: 'integer', + }, + 'sophos.xg.dst_port': { + category: 'sophos', + description: 'Original destination port of TCP and UDP traffic ', + name: 'sophos.xg.dst_port', + type: 'integer', + }, + 'sophos.xg.icmp_type': { + category: 'sophos', + description: 'ICMP type of ICMP traffic ', + name: 'sophos.xg.icmp_type', type: 'keyword', }, - 'fortinet.firewall.cookies': { - category: 'fortinet', - description: 'VPN Cookie ', - name: 'fortinet.firewall.cookies', + 'sophos.xg.icmp_code': { + category: 'sophos', + description: 'ICMP code of ICMP traffic ', + name: 'sophos.xg.icmp_code', type: 'keyword', }, - 'fortinet.firewall.count': { - category: 'fortinet', - description: 'Counts of action type ', - name: 'fortinet.firewall.count', + 'sophos.xg.sent_pkts': { + category: 'sophos', + description: 'Total number of packets sent ', + name: 'sophos.xg.sent_pkts', + type: 'long', + }, + 'sophos.xg.received_pkts': { + category: 'sophos', + description: 'Total number of packets received ', + name: 'sophos.xg.received_pkts', + type: 'long', + }, + 'sophos.xg.sent_bytes': { + category: 'sophos', + description: 'Total number of bytes sent ', + name: 'sophos.xg.sent_bytes', + type: 'long', + }, + 'sophos.xg.recv_bytes': { + category: 'sophos', + description: 'Total number of bytes received ', + name: 'sophos.xg.recv_bytes', + type: 'long', + }, + 'sophos.xg.trans_src_ip': { + category: 'sophos', + description: 'Translated source IP address for outgoing traffic ', + name: 'sophos.xg.trans_src_ip', + type: 'ip', + }, + 'sophos.xg.trans_src_port': { + category: 'sophos', + description: 'Translated source port for outgoing traffic ', + name: 'sophos.xg.trans_src_port', type: 'integer', }, - 'fortinet.firewall.countapp': { - category: 'fortinet', - description: 'Number of App Ctrl logs associated with the session ', - name: 'fortinet.firewall.countapp', - type: 'integer', + 'sophos.xg.trans_dst_ip': { + category: 'sophos', + description: 'Translated destination IP address for outgoing traffic ', + name: 'sophos.xg.trans_dst_ip', + type: 'ip', }, - 'fortinet.firewall.countav': { - category: 'fortinet', - description: 'Number of AV logs associated with the session ', - name: 'fortinet.firewall.countav', + 'sophos.xg.trans_dst_port': { + category: 'sophos', + description: 'Translated destination port for outgoing traffic ', + name: 'sophos.xg.trans_dst_port', type: 'integer', }, - 'fortinet.firewall.countcifs': { - category: 'fortinet', - description: 'Number of CIFS logs associated with the session ', - name: 'fortinet.firewall.countcifs', - type: 'integer', + 'sophos.xg.srczonetype': { + category: 'sophos', + description: 'Type of source zone, e.g., LAN ', + name: 'sophos.xg.srczonetype', + type: 'keyword', }, - 'fortinet.firewall.countdlp': { - category: 'fortinet', - description: 'Number of DLP logs associated with the session ', - name: 'fortinet.firewall.countdlp', - type: 'integer', + 'sophos.xg.srczone': { + category: 'sophos', + description: 'Name of source zone ', + name: 'sophos.xg.srczone', + type: 'keyword', }, - 'fortinet.firewall.countdns': { - category: 'fortinet', - description: 'Number of DNS logs associated with the session ', - name: 'fortinet.firewall.countdns', - type: 'integer', + 'sophos.xg.dstzonetype': { + category: 'sophos', + description: 'Type of destination zone, e.g., WAN ', + name: 'sophos.xg.dstzonetype', + type: 'keyword', }, - 'fortinet.firewall.countemail': { - category: 'fortinet', - description: 'Number of email logs associated with the session ', - name: 'fortinet.firewall.countemail', - type: 'integer', + 'sophos.xg.dstzone': { + category: 'sophos', + description: 'Name of destination zone ', + name: 'sophos.xg.dstzone', + type: 'keyword', }, - 'fortinet.firewall.countff': { - category: 'fortinet', - description: 'Number of ff logs associated with the session ', - name: 'fortinet.firewall.countff', - type: 'integer', + 'sophos.xg.dir_disp': { + category: 'sophos', + description: 'TPacket direction. Possible values:“org”, “reply”, “” ', + name: 'sophos.xg.dir_disp', + type: 'keyword', }, - 'fortinet.firewall.countips': { - category: 'fortinet', - description: 'Number of IPS logs associated with the session ', - name: 'fortinet.firewall.countips', - type: 'integer', + 'sophos.xg.connevent': { + category: 'sophos', + description: 'Event on which this log is generated ', + name: 'sophos.xg.connevent', + type: 'keyword', }, - 'fortinet.firewall.countssh': { - category: 'fortinet', - description: 'Number of SSH logs associated with the session ', - name: 'fortinet.firewall.countssh', + 'sophos.xg.conn_id': { + category: 'sophos', + description: 'Unique identifier of connection ', + name: 'sophos.xg.conn_id', type: 'integer', }, - 'fortinet.firewall.countssl': { - category: 'fortinet', - description: 'Number of SSL logs associated with the session ', - name: 'fortinet.firewall.countssl', + 'sophos.xg.vconn_id': { + category: 'sophos', + description: 'Connection ID of the master connection ', + name: 'sophos.xg.vconn_id', type: 'integer', }, - 'fortinet.firewall.countwaf': { - category: 'fortinet', - description: 'Number of WAF logs associated with the session ', - name: 'fortinet.firewall.countwaf', + 'sophos.xg.idp_policy_id': { + category: 'sophos', + description: 'IPS policy ID which is applied on the traffic ', + name: 'sophos.xg.idp_policy_id', type: 'integer', }, - 'fortinet.firewall.countweb': { - category: 'fortinet', - description: 'Number of Web filter logs associated with the session ', - name: 'fortinet.firewall.countweb', - type: 'integer', + 'sophos.xg.idp_policy_name': { + category: 'sophos', + description: 'IPS policy name i.e. IPS policy name which is applied on the traffic ', + name: 'sophos.xg.idp_policy_name', + type: 'keyword', }, - 'fortinet.firewall.cpu': { - category: 'fortinet', - description: 'CPU Usage ', - name: 'fortinet.firewall.cpu', - type: 'integer', + 'sophos.xg.signature_id': { + category: 'sophos', + description: 'Signature ID ', + name: 'sophos.xg.signature_id', + type: 'keyword', }, - 'fortinet.firewall.craction': { - category: 'fortinet', - description: 'Client Reputation Action ', - name: 'fortinet.firewall.craction', - type: 'integer', + 'sophos.xg.signature_msg': { + category: 'sophos', + description: 'Signature messsage ', + name: 'sophos.xg.signature_msg', + type: 'keyword', }, - 'fortinet.firewall.criticalcount': { - category: 'fortinet', - description: 'Number of critical ratings ', - name: 'fortinet.firewall.criticalcount', - type: 'integer', + 'sophos.xg.classification': { + category: 'sophos', + description: 'Signature classification ', + name: 'sophos.xg.classification', + type: 'keyword', }, - 'fortinet.firewall.crl': { - category: 'fortinet', - description: 'Client Reputation Level ', - name: 'fortinet.firewall.crl', + 'sophos.xg.rule_priority': { + category: 'sophos', + description: 'Priority of IPS policy ', + name: 'sophos.xg.rule_priority', type: 'keyword', }, - 'fortinet.firewall.crlevel': { - category: 'fortinet', - description: 'Client Reputation Level ', - name: 'fortinet.firewall.crlevel', + 'sophos.xg.platform': { + category: 'sophos', + description: 'Platform of the traffic. ', + name: 'sophos.xg.platform', type: 'keyword', }, - 'fortinet.firewall.crscore': { - category: 'fortinet', - description: 'Some description ', - name: 'fortinet.firewall.crscore', - type: 'integer', + 'sophos.xg.category': { + category: 'sophos', + description: 'IPS signature category. ', + name: 'sophos.xg.category', + type: 'keyword', }, - 'fortinet.firewall.cveid': { - category: 'fortinet', - description: 'CVE ID ', - name: 'fortinet.firewall.cveid', + 'sophos.xg.target': { + category: 'sophos', + description: 'Platform of the traffic. ', + name: 'sophos.xg.target', type: 'keyword', }, - 'fortinet.firewall.daemon': { - category: 'fortinet', - description: 'Daemon name ', - name: 'fortinet.firewall.daemon', + 'sophos.xg.eventid': { + category: 'sophos', + description: 'ATP Evenet ID ', + name: 'sophos.xg.eventid', type: 'keyword', }, - 'fortinet.firewall.datarange': { - category: 'fortinet', - description: 'Data range for reports ', - name: 'fortinet.firewall.datarange', + 'sophos.xg.ep_uuid': { + category: 'sophos', + description: 'Endpoint UUID ', + name: 'sophos.xg.ep_uuid', type: 'keyword', }, - 'fortinet.firewall.date': { - category: 'fortinet', - description: 'Date ', - name: 'fortinet.firewall.date', + 'sophos.xg.threatname': { + category: 'sophos', + description: 'ATP threatname ', + name: 'sophos.xg.threatname', type: 'keyword', }, - 'fortinet.firewall.ddnsserver': { - category: 'fortinet', - description: 'DDNS server ', - name: 'fortinet.firewall.ddnsserver', + 'sophos.xg.sourceip': { + category: 'sophos', + description: 'Original source IP address of traffic ', + name: 'sophos.xg.sourceip', type: 'ip', }, - 'fortinet.firewall.desc': { - category: 'fortinet', - description: 'Description ', - name: 'fortinet.firewall.desc', - type: 'keyword', + 'sophos.xg.destinationip': { + category: 'sophos', + description: 'Original destination IP address of traffic ', + name: 'sophos.xg.destinationip', + type: 'ip', }, - 'fortinet.firewall.detectionmethod': { - category: 'fortinet', - description: 'Detection method ', - name: 'fortinet.firewall.detectionmethod', + 'sophos.xg.login_user': { + category: 'sophos', + description: 'ATP login user ', + name: 'sophos.xg.login_user', type: 'keyword', }, - 'fortinet.firewall.devcategory': { - category: 'fortinet', - description: 'Device category ', - name: 'fortinet.firewall.devcategory', + 'sophos.xg.eventtype': { + category: 'sophos', + description: 'ATP event type ', + name: 'sophos.xg.eventtype', type: 'keyword', }, - 'fortinet.firewall.devintfname': { - category: 'fortinet', - description: 'HA device Interface Name ', - name: 'fortinet.firewall.devintfname', + 'sophos.xg.execution_path': { + category: 'sophos', + description: 'ATP execution path ', + name: 'sophos.xg.execution_path', type: 'keyword', }, - 'fortinet.firewall.devtype': { - category: 'fortinet', - description: 'Device type ', - name: 'fortinet.firewall.devtype', + 'sophos.xg.av_policy_name': { + category: 'sophos', + description: 'Malware scanning policy name which is applied on the traffic ', + name: 'sophos.xg.av_policy_name', type: 'keyword', }, - 'fortinet.firewall.dhcp_msg': { - category: 'fortinet', - description: 'DHCP Message ', - name: 'fortinet.firewall.dhcp_msg', + 'sophos.xg.from_email_address': { + category: 'sophos', + description: 'Sender email address ', + name: 'sophos.xg.from_email_address', type: 'keyword', }, - 'fortinet.firewall.dintf': { - category: 'fortinet', - description: 'Destination interface ', - name: 'fortinet.firewall.dintf', + 'sophos.xg.to_email_address': { + category: 'sophos', + description: 'Receipeint email address ', + name: 'sophos.xg.to_email_address', type: 'keyword', }, - 'fortinet.firewall.disk': { - category: 'fortinet', - description: 'Assosciated disk ', - name: 'fortinet.firewall.disk', + 'sophos.xg.subject': { + category: 'sophos', + description: 'Email subject ', + name: 'sophos.xg.subject', type: 'keyword', }, - 'fortinet.firewall.disklograte': { - category: 'fortinet', - description: 'Disk logging rate ', - name: 'fortinet.firewall.disklograte', - type: 'long', + 'sophos.xg.mailsize': { + category: 'sophos', + description: 'mailsize ', + name: 'sophos.xg.mailsize', + type: 'integer', }, - 'fortinet.firewall.dlpextra': { - category: 'fortinet', - description: 'DLP extra information ', - name: 'fortinet.firewall.dlpextra', + 'sophos.xg.virus': { + category: 'sophos', + description: 'virus name ', + name: 'sophos.xg.virus', type: 'keyword', }, - 'fortinet.firewall.docsource': { - category: 'fortinet', - description: 'DLP fingerprint document source ', - name: 'fortinet.firewall.docsource', + 'sophos.xg.ftp_url': { + category: 'sophos', + description: 'FTP URL from which virus was downloaded ', + name: 'sophos.xg.ftp_url', type: 'keyword', }, - 'fortinet.firewall.domainctrlauthstate': { - category: 'fortinet', - description: 'CIFS domain auth state ', - name: 'fortinet.firewall.domainctrlauthstate', - type: 'integer', + 'sophos.xg.ftp_direction': { + category: 'sophos', + description: 'Direction of FTP transfer: Upload or Download ', + name: 'sophos.xg.ftp_direction', + type: 'keyword', }, - 'fortinet.firewall.domainctrlauthtype': { - category: 'fortinet', - description: 'CIFS domain auth type ', - name: 'fortinet.firewall.domainctrlauthtype', + 'sophos.xg.filesize': { + category: 'sophos', + description: 'Size of the file that contained virus ', + name: 'sophos.xg.filesize', type: 'integer', }, - 'fortinet.firewall.domainctrldomain': { - category: 'fortinet', - description: 'CIFS domain auth domain ', - name: 'fortinet.firewall.domainctrldomain', + 'sophos.xg.filepath': { + category: 'sophos', + description: 'Path of the file containing virus ', + name: 'sophos.xg.filepath', type: 'keyword', }, - 'fortinet.firewall.domainctrlip': { - category: 'fortinet', - description: 'CIFS Domain IP ', - name: 'fortinet.firewall.domainctrlip', - type: 'ip', + 'sophos.xg.filename': { + category: 'sophos', + description: 'File name associated with the event ', + name: 'sophos.xg.filename', + type: 'keyword', }, - 'fortinet.firewall.domainctrlname': { - category: 'fortinet', - description: 'CIFS Domain name ', - name: 'fortinet.firewall.domainctrlname', + 'sophos.xg.ftpcommand': { + category: 'sophos', + description: 'FTP command used when virus was found ', + name: 'sophos.xg.ftpcommand', type: 'keyword', }, - 'fortinet.firewall.domainctrlprotocoltype': { - category: 'fortinet', - description: 'CIFS Domain connection protocol ', - name: 'fortinet.firewall.domainctrlprotocoltype', - type: 'integer', + 'sophos.xg.url': { + category: 'sophos', + description: 'URL from which virus was downloaded ', + name: 'sophos.xg.url', + type: 'keyword', }, - 'fortinet.firewall.domainctrlusername': { - category: 'fortinet', - description: 'CIFS Domain username ', - name: 'fortinet.firewall.domainctrlusername', + 'sophos.xg.domainname': { + category: 'sophos', + description: 'Domain from which virus was downloaded ', + name: 'sophos.xg.domainname', type: 'keyword', }, - 'fortinet.firewall.domainfilteridx': { - category: 'fortinet', - description: 'Domain filter ID ', - name: 'fortinet.firewall.domainfilteridx', - type: 'integer', + 'sophos.xg.quarantine': { + category: 'sophos', + description: 'Path and filename of the file quarantined ', + name: 'sophos.xg.quarantine', + type: 'keyword', }, - 'fortinet.firewall.domainfilterlist': { - category: 'fortinet', - description: 'Domain filter name ', - name: 'fortinet.firewall.domainfilterlist', + 'sophos.xg.src_domainname': { + category: 'sophos', + description: 'Sender domain name ', + name: 'sophos.xg.src_domainname', type: 'keyword', }, - 'fortinet.firewall.ds': { - category: 'fortinet', - description: 'Direction with distribution system ', - name: 'fortinet.firewall.ds', + 'sophos.xg.dst_domainname': { + category: 'sophos', + description: 'Receiver domain name ', + name: 'sophos.xg.dst_domainname', type: 'keyword', }, - 'fortinet.firewall.dst_int': { - category: 'fortinet', - description: 'Destination interface ', - name: 'fortinet.firewall.dst_int', + 'sophos.xg.reason': { + category: 'sophos', + description: 'Reason why the record was detected as spam/malicious ', + name: 'sophos.xg.reason', type: 'keyword', }, - 'fortinet.firewall.dstintfrole': { - category: 'fortinet', - description: 'Destination interface role ', - name: 'fortinet.firewall.dstintfrole', + 'sophos.xg.referer': { + category: 'sophos', + description: 'Referer ', + name: 'sophos.xg.referer', type: 'keyword', }, - 'fortinet.firewall.dstcountry': { - category: 'fortinet', - description: 'Destination country ', - name: 'fortinet.firewall.dstcountry', + 'sophos.xg.spamaction': { + category: 'sophos', + description: 'Spam Action ', + name: 'sophos.xg.spamaction', type: 'keyword', }, - 'fortinet.firewall.dstdevcategory': { - category: 'fortinet', - description: 'Destination device category ', - name: 'fortinet.firewall.dstdevcategory', + 'sophos.xg.mailid': { + category: 'sophos', + description: 'mailid ', + name: 'sophos.xg.mailid', type: 'keyword', }, - 'fortinet.firewall.dstdevtype': { - category: 'fortinet', - description: 'Destination device type ', - name: 'fortinet.firewall.dstdevtype', + 'sophos.xg.quarantine_reason': { + category: 'sophos', + description: 'Quarantine reason ', + name: 'sophos.xg.quarantine_reason', type: 'keyword', }, - 'fortinet.firewall.dstfamily': { - category: 'fortinet', - description: 'Destination OS family ', - name: 'fortinet.firewall.dstfamily', + 'sophos.xg.status_code': { + category: 'sophos', + description: 'Status code ', + name: 'sophos.xg.status_code', type: 'keyword', }, - 'fortinet.firewall.dsthwvendor': { - category: 'fortinet', - description: 'Destination HW vendor ', - name: 'fortinet.firewall.dsthwvendor', + 'sophos.xg.override_token': { + category: 'sophos', + description: 'Override token ', + name: 'sophos.xg.override_token', type: 'keyword', }, - 'fortinet.firewall.dsthwversion': { - category: 'fortinet', - description: 'Destination HW version ', - name: 'fortinet.firewall.dsthwversion', + 'sophos.xg.con_id': { + category: 'sophos', + description: 'Unique identifier of connection ', + name: 'sophos.xg.con_id', + type: 'integer', + }, + 'sophos.xg.override_authorizer': { + category: 'sophos', + description: 'Override authorizer ', + name: 'sophos.xg.override_authorizer', type: 'keyword', }, - 'fortinet.firewall.dstinetsvc': { - category: 'fortinet', - description: 'Destination interface service ', - name: 'fortinet.firewall.dstinetsvc', + 'sophos.xg.transactionid': { + category: 'sophos', + description: 'Transaction ID of the AV scan. ', + name: 'sophos.xg.transactionid', type: 'keyword', }, - 'fortinet.firewall.dstosname': { - category: 'fortinet', - description: 'Destination OS name ', - name: 'fortinet.firewall.dstosname', + 'sophos.xg.upload_file_type': { + category: 'sophos', + description: 'Upload file type ', + name: 'sophos.xg.upload_file_type', type: 'keyword', }, - 'fortinet.firewall.dstosversion': { - category: 'fortinet', - description: 'Destination OS version ', - name: 'fortinet.firewall.dstosversion', + 'sophos.xg.upload_file_name': { + category: 'sophos', + description: 'Upload file name ', + name: 'sophos.xg.upload_file_name', + type: 'keyword', + }, + 'sophos.xg.httpresponsecode': { + category: 'sophos', + description: 'code of HTTP response ', + name: 'sophos.xg.httpresponsecode', + type: 'long', + }, + 'sophos.xg.user_gp': { + category: 'sophos', + description: 'Group name to which the user belongs. ', + name: 'sophos.xg.user_gp', + type: 'keyword', + }, + 'sophos.xg.category_type': { + category: 'sophos', + description: 'Type of category under which website falls ', + name: 'sophos.xg.category_type', + type: 'keyword', + }, + 'sophos.xg.download_file_type': { + category: 'sophos', + description: 'Download file type ', + name: 'sophos.xg.download_file_type', + type: 'keyword', + }, + 'sophos.xg.exceptions': { + category: 'sophos', + description: 'List of the checks excluded by web exceptions. ', + name: 'sophos.xg.exceptions', + type: 'keyword', + }, + 'sophos.xg.contenttype': { + category: 'sophos', + description: 'Type of the content ', + name: 'sophos.xg.contenttype', type: 'keyword', }, - 'fortinet.firewall.dstserver': { - category: 'fortinet', - description: 'Destination server ', - name: 'fortinet.firewall.dstserver', - type: 'integer', + 'sophos.xg.override_name': { + category: 'sophos', + description: 'Override name ', + name: 'sophos.xg.override_name', + type: 'keyword', }, - 'fortinet.firewall.dstssid': { - category: 'fortinet', - description: 'Destination SSID ', - name: 'fortinet.firewall.dstssid', + 'sophos.xg.activityname': { + category: 'sophos', + description: 'Web policy activity that matched and caused the policy result. ', + name: 'sophos.xg.activityname', type: 'keyword', }, - 'fortinet.firewall.dstswversion': { - category: 'fortinet', - description: 'Destination software version ', - name: 'fortinet.firewall.dstswversion', + 'sophos.xg.download_file_name': { + category: 'sophos', + description: 'Download file name ', + name: 'sophos.xg.download_file_name', type: 'keyword', }, - 'fortinet.firewall.dstunauthusersource': { - category: 'fortinet', - description: 'Destination unauthenticated source ', - name: 'fortinet.firewall.dstunauthusersource', + 'sophos.xg.sha1sum': { + category: 'sophos', + description: 'SHA1 checksum of the item being analyzed ', + name: 'sophos.xg.sha1sum', type: 'keyword', }, - 'fortinet.firewall.dstuuid': { - category: 'fortinet', - description: 'UUID of the Destination IP address ', - name: 'fortinet.firewall.dstuuid', + 'sophos.xg.message_id': { + category: 'sophos', + description: 'Message ID ', + name: 'sophos.xg.message_id', type: 'keyword', }, - 'fortinet.firewall.duid': { - category: 'fortinet', - description: 'DHCP UID ', - name: 'fortinet.firewall.duid', + 'sophos.xg.connid': { + category: 'sophos', + description: 'Connection ID ', + name: 'sophos.xg.connid', type: 'keyword', }, - 'fortinet.firewall.eapolcnt': { - category: 'fortinet', - description: 'EAPOL packet count ', - name: 'fortinet.firewall.eapolcnt', - type: 'integer', + 'sophos.xg.message': { + category: 'sophos', + description: 'Message ', + name: 'sophos.xg.message', + type: 'keyword', }, - 'fortinet.firewall.eapoltype': { - category: 'fortinet', - description: 'EAPOL packet type ', - name: 'fortinet.firewall.eapoltype', + 'sophos.xg.email_subject': { + category: 'sophos', + description: 'Email Subject ', + name: 'sophos.xg.email_subject', type: 'keyword', }, - 'fortinet.firewall.encrypt': { - category: 'fortinet', - description: 'Whether the packet is encrypted or not ', - name: 'fortinet.firewall.encrypt', - type: 'integer', + 'sophos.xg.file_path': { + category: 'sophos', + description: 'File path ', + name: 'sophos.xg.file_path', + type: 'keyword', }, - 'fortinet.firewall.encryption': { - category: 'fortinet', - description: 'Encryption method ', - name: 'fortinet.firewall.encryption', + 'sophos.xg.dstdomain': { + category: 'sophos', + description: 'Destination Domain ', + name: 'sophos.xg.dstdomain', type: 'keyword', }, - 'fortinet.firewall.epoch': { - category: 'fortinet', - description: 'Epoch used for locating file ', - name: 'fortinet.firewall.epoch', + 'sophos.xg.file_size': { + category: 'sophos', + description: 'File Size ', + name: 'sophos.xg.file_size', type: 'integer', }, - 'fortinet.firewall.espauth': { - category: 'fortinet', - description: 'ESP Authentication ', - name: 'fortinet.firewall.espauth', + 'sophos.xg.transaction_id': { + category: 'sophos', + description: 'Transaction ID ', + name: 'sophos.xg.transaction_id', type: 'keyword', }, - 'fortinet.firewall.esptransform': { - category: 'fortinet', - description: 'ESP Transform ', - name: 'fortinet.firewall.esptransform', + 'sophos.xg.website': { + category: 'sophos', + description: 'Website ', + name: 'sophos.xg.website', type: 'keyword', }, - 'fortinet.firewall.exch': { - category: 'fortinet', - description: 'Mail Exchanges from DNS response answer section ', - name: 'fortinet.firewall.exch', + 'sophos.xg.file_name': { + category: 'sophos', + description: 'Filename ', + name: 'sophos.xg.file_name', type: 'keyword', }, - 'fortinet.firewall.exchange': { - category: 'fortinet', - description: 'Mail Exchanges from DNS response answer section ', - name: 'fortinet.firewall.exchange', + 'sophos.xg.context_prefix': { + category: 'sophos', + description: 'Content Prefix ', + name: 'sophos.xg.context_prefix', type: 'keyword', }, - 'fortinet.firewall.expectedsignature': { - category: 'fortinet', - description: 'Expected SSL signature ', - name: 'fortinet.firewall.expectedsignature', + 'sophos.xg.site_category': { + category: 'sophos', + description: 'Site Category ', + name: 'sophos.xg.site_category', type: 'keyword', }, - 'fortinet.firewall.expiry': { - category: 'fortinet', - description: 'FortiGuard override expiry timestamp ', - name: 'fortinet.firewall.expiry', + 'sophos.xg.context_suffix': { + category: 'sophos', + description: 'Context Suffix ', + name: 'sophos.xg.context_suffix', type: 'keyword', }, - 'fortinet.firewall.fams_pause': { - category: 'fortinet', - description: 'Fortinet Analysis and Management Service Pause ', - name: 'fortinet.firewall.fams_pause', - type: 'integer', - }, - 'fortinet.firewall.fazlograte': { - category: 'fortinet', - description: 'FortiAnalyzer Logging Rate ', - name: 'fortinet.firewall.fazlograte', - type: 'long', - }, - 'fortinet.firewall.fctemssn': { - category: 'fortinet', - description: 'FortiClient Endpoint SSN ', - name: 'fortinet.firewall.fctemssn', + 'sophos.xg.dictionary_name': { + category: 'sophos', + description: 'Dictionary Name ', + name: 'sophos.xg.dictionary_name', type: 'keyword', }, - 'fortinet.firewall.fctuid': { - category: 'fortinet', - description: 'FortiClient UID ', - name: 'fortinet.firewall.fctuid', + 'sophos.xg.action': { + category: 'sophos', + description: 'Event Action ', + name: 'sophos.xg.action', type: 'keyword', }, - 'fortinet.firewall.field': { - category: 'fortinet', - description: 'NTP status field ', - name: 'fortinet.firewall.field', + 'sophos.xg.user': { + category: 'sophos', + description: 'User ', + name: 'sophos.xg.user', type: 'keyword', }, - 'fortinet.firewall.filefilter': { - category: 'fortinet', - description: 'The filter used to identify the affected file ', - name: 'fortinet.firewall.filefilter', + 'sophos.xg.context_match': { + category: 'sophos', + description: 'Context Match ', + name: 'sophos.xg.context_match', type: 'keyword', }, - 'fortinet.firewall.filehashsrc': { - category: 'fortinet', - description: 'Filehash source ', - name: 'fortinet.firewall.filehashsrc', + 'sophos.xg.direction': { + category: 'sophos', + description: 'Direction ', + name: 'sophos.xg.direction', type: 'keyword', }, - 'fortinet.firewall.filtercat': { - category: 'fortinet', - description: 'DLP filter category ', - name: 'fortinet.firewall.filtercat', + 'sophos.xg.auth_client': { + category: 'sophos', + description: 'Auth Client ', + name: 'sophos.xg.auth_client', type: 'keyword', }, - 'fortinet.firewall.filteridx': { - category: 'fortinet', - description: 'DLP filter ID ', - name: 'fortinet.firewall.filteridx', - type: 'integer', + 'sophos.xg.auth_mechanism': { + category: 'sophos', + description: 'Auth mechanism ', + name: 'sophos.xg.auth_mechanism', + type: 'keyword', }, - 'fortinet.firewall.filtername': { - category: 'fortinet', - description: 'DLP rule name ', - name: 'fortinet.firewall.filtername', + 'sophos.xg.connectionname': { + category: 'sophos', + description: 'Connectionname ', + name: 'sophos.xg.connectionname', type: 'keyword', }, - 'fortinet.firewall.filtertype': { - category: 'fortinet', - description: 'DLP filter type ', - name: 'fortinet.firewall.filtertype', + 'sophos.xg.remotenetwork': { + category: 'sophos', + description: 'remotenetwork ', + name: 'sophos.xg.remotenetwork', type: 'keyword', }, - 'fortinet.firewall.fortiguardresp': { - category: 'fortinet', - description: 'Antispam ESP value ', - name: 'fortinet.firewall.fortiguardresp', + 'sophos.xg.localgateway': { + category: 'sophos', + description: 'Localgateway ', + name: 'sophos.xg.localgateway', type: 'keyword', }, - 'fortinet.firewall.forwardedfor': { - category: 'fortinet', - description: 'Email address forwarded ', - name: 'fortinet.firewall.forwardedfor', + 'sophos.xg.localnetwork': { + category: 'sophos', + description: 'Localnetwork ', + name: 'sophos.xg.localnetwork', type: 'keyword', }, - 'fortinet.firewall.fqdn': { - category: 'fortinet', - description: 'FQDN ', - name: 'fortinet.firewall.fqdn', + 'sophos.xg.connectiontype': { + category: 'sophos', + description: 'Connectiontype ', + name: 'sophos.xg.connectiontype', type: 'keyword', }, - 'fortinet.firewall.frametype': { - category: 'fortinet', - description: 'Wireless frametype ', - name: 'fortinet.firewall.frametype', + 'sophos.xg.oldversion': { + category: 'sophos', + description: 'Oldversion ', + name: 'sophos.xg.oldversion', type: 'keyword', }, - 'fortinet.firewall.freediskstorage': { - category: 'fortinet', - description: 'Free disk integer ', - name: 'fortinet.firewall.freediskstorage', - type: 'integer', + 'sophos.xg.newversion': { + category: 'sophos', + description: 'Newversion ', + name: 'sophos.xg.newversion', + type: 'keyword', }, - 'fortinet.firewall.from': { - category: 'fortinet', - description: 'From email address ', - name: 'fortinet.firewall.from', + 'sophos.xg.ipaddress': { + category: 'sophos', + description: 'Ipaddress ', + name: 'sophos.xg.ipaddress', type: 'keyword', }, - 'fortinet.firewall.from_vcluster': { - category: 'fortinet', - description: 'Source virtual cluster number ', - name: 'fortinet.firewall.from_vcluster', - type: 'integer', + 'sophos.xg.client_physical_address': { + category: 'sophos', + description: 'Client physical address ', + name: 'sophos.xg.client_physical_address', + type: 'keyword', }, - 'fortinet.firewall.fsaverdict': { - category: 'fortinet', - description: 'FSA verdict ', - name: 'fortinet.firewall.fsaverdict', + 'sophos.xg.client_host_name': { + category: 'sophos', + description: 'Client host name ', + name: 'sophos.xg.client_host_name', type: 'keyword', }, - 'fortinet.firewall.fwserver_name': { - category: 'fortinet', - description: 'Web proxy server name ', - name: 'fortinet.firewall.fwserver_name', + 'sophos.xg.raw_data': { + category: 'sophos', + description: 'Raw data ', + name: 'sophos.xg.raw_data', type: 'keyword', }, - 'fortinet.firewall.gateway': { - category: 'fortinet', - description: 'Gateway ip address for PPPoE status report ', - name: 'fortinet.firewall.gateway', - type: 'ip', + 'sophos.xg.Mode': { + category: 'sophos', + description: 'Mode ', + name: 'sophos.xg.Mode', + type: 'keyword', }, - 'fortinet.firewall.green': { - category: 'fortinet', - description: 'Memory status ', - name: 'fortinet.firewall.green', + 'sophos.xg.sessionid': { + category: 'sophos', + description: 'Sessionid ', + name: 'sophos.xg.sessionid', type: 'keyword', }, - 'fortinet.firewall.groupid': { - category: 'fortinet', - description: 'User Group ID ', - name: 'fortinet.firewall.groupid', - type: 'integer', + 'sophos.xg.starttime': { + category: 'sophos', + description: 'Starttime ', + name: 'sophos.xg.starttime', + type: 'date', }, - 'fortinet.firewall.ha-prio': { - category: 'fortinet', - description: 'HA Priority ', - name: 'fortinet.firewall.ha-prio', - type: 'integer', + 'sophos.xg.remote_ip': { + category: 'sophos', + description: 'Remote IP ', + name: 'sophos.xg.remote_ip', + type: 'ip', }, - 'fortinet.firewall.ha_group': { - category: 'fortinet', - description: 'HA Group ', - name: 'fortinet.firewall.ha_group', - type: 'keyword', + 'sophos.xg.timestamp': { + category: 'sophos', + description: 'timestamp ', + name: 'sophos.xg.timestamp', + type: 'date', }, - 'fortinet.firewall.ha_role': { - category: 'fortinet', - description: 'HA Role ', - name: 'fortinet.firewall.ha_role', + 'sophos.xg.SysLog_SERVER_NAME': { + category: 'sophos', + description: 'SysLog SERVER NAME ', + name: 'sophos.xg.SysLog_SERVER_NAME', type: 'keyword', }, - 'fortinet.firewall.handshake': { - category: 'fortinet', - description: 'SSL Handshake ', - name: 'fortinet.firewall.handshake', + 'sophos.xg.backup_mode': { + category: 'sophos', + description: 'Backup mode ', + name: 'sophos.xg.backup_mode', type: 'keyword', }, - 'fortinet.firewall.hash': { - category: 'fortinet', - description: 'Hash value of downloaded file ', - name: 'fortinet.firewall.hash', + 'sophos.xg.source': { + category: 'sophos', + description: 'Source ', + name: 'sophos.xg.source', type: 'keyword', }, - 'fortinet.firewall.hbdn_reason': { - category: 'fortinet', - description: 'Heartbeat down reason ', - name: 'fortinet.firewall.hbdn_reason', + 'sophos.xg.server': { + category: 'sophos', + description: 'Server ', + name: 'sophos.xg.server', type: 'keyword', }, - 'fortinet.firewall.highcount': { - category: 'fortinet', - description: 'Highcount fabric summary ', - name: 'fortinet.firewall.highcount', - type: 'integer', - }, - 'fortinet.firewall.host': { - category: 'fortinet', - description: 'Hostname ', - name: 'fortinet.firewall.host', + 'sophos.xg.host': { + category: 'sophos', + description: 'Host ', + name: 'sophos.xg.host', type: 'keyword', }, - 'fortinet.firewall.iaid': { - category: 'fortinet', - description: 'DHCPv6 id ', - name: 'fortinet.firewall.iaid', - type: 'keyword', + 'sophos.xg.responsetime': { + category: 'sophos', + description: 'Responsetime ', + name: 'sophos.xg.responsetime', + type: 'long', }, - 'fortinet.firewall.icmpcode': { - category: 'fortinet', - description: 'Destination Port of the ICMP message ', - name: 'fortinet.firewall.icmpcode', + 'sophos.xg.cookie': { + category: 'sophos', + description: 'cookie ', + name: 'sophos.xg.cookie', type: 'keyword', }, - 'fortinet.firewall.icmpid': { - category: 'fortinet', - description: 'Source port of the ICMP message ', - name: 'fortinet.firewall.icmpid', + 'sophos.xg.querystring': { + category: 'sophos', + description: 'querystring ', + name: 'sophos.xg.querystring', type: 'keyword', }, - 'fortinet.firewall.icmptype': { - category: 'fortinet', - description: 'The type of ICMP message ', - name: 'fortinet.firewall.icmptype', + 'sophos.xg.extra': { + category: 'sophos', + description: 'extra ', + name: 'sophos.xg.extra', type: 'keyword', }, - 'fortinet.firewall.identifier': { - category: 'fortinet', - description: 'Network traffic identifier ', - name: 'fortinet.firewall.identifier', - type: 'integer', - }, - 'fortinet.firewall.in_spi': { - category: 'fortinet', - description: 'IPSEC inbound SPI ', - name: 'fortinet.firewall.in_spi', + 'sophos.xg.PHPSESSID': { + category: 'sophos', + description: 'PHPSESSID ', + name: 'sophos.xg.PHPSESSID', type: 'keyword', }, - 'fortinet.firewall.incidentserialno': { - category: 'fortinet', - description: 'Incident serial number ', - name: 'fortinet.firewall.incidentserialno', - type: 'integer', - }, - 'fortinet.firewall.infected': { - category: 'fortinet', - description: 'Infected MMS ', - name: 'fortinet.firewall.infected', - type: 'integer', + 'sophos.xg.start_time': { + category: 'sophos', + description: 'Start time ', + name: 'sophos.xg.start_time', + type: 'date', }, - 'fortinet.firewall.infectedfilelevel': { - category: 'fortinet', - description: 'DLP infected file level ', - name: 'fortinet.firewall.infectedfilelevel', - type: 'integer', + 'sophos.xg.eventtime': { + category: 'sophos', + description: 'Event time ', + name: 'sophos.xg.eventtime', + type: 'date', }, - 'fortinet.firewall.informationsource': { - category: 'fortinet', - description: 'Information source ', - name: 'fortinet.firewall.informationsource', + 'sophos.xg.red_id': { + category: 'sophos', + description: 'RED ID ', + name: 'sophos.xg.red_id', type: 'keyword', }, - 'fortinet.firewall.init': { - category: 'fortinet', - description: 'IPSEC init stage ', - name: 'fortinet.firewall.init', + 'sophos.xg.branch_name': { + category: 'sophos', + description: 'Branch Name ', + name: 'sophos.xg.branch_name', type: 'keyword', }, - 'fortinet.firewall.initiator': { - category: 'fortinet', - description: 'Original login user name for Fortiguard override ', - name: 'fortinet.firewall.initiator', - type: 'keyword', + 'sophos.xg.updatedip': { + category: 'sophos', + description: 'updatedip ', + name: 'sophos.xg.updatedip', + type: 'ip', + }, + 'sophos.xg.idle_cpu': { + category: 'sophos', + description: 'idle ## ', + name: 'sophos.xg.idle_cpu', + type: 'float', + }, + 'sophos.xg.system_cpu': { + category: 'sophos', + description: 'system ', + name: 'sophos.xg.system_cpu', + type: 'float', }, - 'fortinet.firewall.interface': { - category: 'fortinet', - description: 'Related interface ', - name: 'fortinet.firewall.interface', - type: 'keyword', + 'sophos.xg.user_cpu': { + category: 'sophos', + description: 'system ', + name: 'sophos.xg.user_cpu', + type: 'float', }, - 'fortinet.firewall.intf': { - category: 'fortinet', - description: 'Related interface ', - name: 'fortinet.firewall.intf', - type: 'keyword', + 'sophos.xg.used': { + category: 'sophos', + description: 'used ', + name: 'sophos.xg.used', + type: 'integer', }, - 'fortinet.firewall.invalidmac': { - category: 'fortinet', - description: 'The MAC address with invalid OUI ', - name: 'fortinet.firewall.invalidmac', + 'sophos.xg.unit': { + category: 'sophos', + description: 'unit ', + name: 'sophos.xg.unit', type: 'keyword', }, - 'fortinet.firewall.ip': { - category: 'fortinet', - description: 'Related IP ', - name: 'fortinet.firewall.ip', - type: 'ip', + 'sophos.xg.total_memory': { + category: 'sophos', + description: 'Total Memory ', + name: 'sophos.xg.total_memory', + type: 'integer', }, - 'fortinet.firewall.iptype': { - category: 'fortinet', - description: 'Related IP type ', - name: 'fortinet.firewall.iptype', - type: 'keyword', + 'sophos.xg.free': { + category: 'sophos', + description: 'free ', + name: 'sophos.xg.free', + type: 'integer', }, - 'fortinet.firewall.keyword': { - category: 'fortinet', - description: 'Keyword used for search ', - name: 'fortinet.firewall.keyword', + 'sophos.xg.transmittederrors': { + category: 'sophos', + description: 'transmitted errors ', + name: 'sophos.xg.transmittederrors', type: 'keyword', }, - 'fortinet.firewall.kind': { - category: 'fortinet', - description: 'VOIP kind ', - name: 'fortinet.firewall.kind', + 'sophos.xg.receivederrors': { + category: 'sophos', + description: 'received errors ', + name: 'sophos.xg.receivederrors', type: 'keyword', }, - 'fortinet.firewall.lanin': { - category: 'fortinet', - description: 'LAN incoming traffic in bytes ', - name: 'fortinet.firewall.lanin', + 'sophos.xg.receivedkbits': { + category: 'sophos', + description: 'received kbits ', + name: 'sophos.xg.receivedkbits', type: 'long', }, - 'fortinet.firewall.lanout': { - category: 'fortinet', - description: 'LAN outbound traffic in bytes ', - name: 'fortinet.firewall.lanout', + 'sophos.xg.transmittedkbits': { + category: 'sophos', + description: 'transmitted kbits ', + name: 'sophos.xg.transmittedkbits', type: 'long', }, - 'fortinet.firewall.lease': { - category: 'fortinet', - description: 'DHCP lease ', - name: 'fortinet.firewall.lease', - type: 'integer', + 'sophos.xg.transmitteddrops': { + category: 'sophos', + description: 'transmitted drops ', + name: 'sophos.xg.transmitteddrops', + type: 'long', }, - 'fortinet.firewall.license_limit': { - category: 'fortinet', - description: 'Maximum Number of FortiClients for the License ', - name: 'fortinet.firewall.license_limit', - type: 'keyword', + 'sophos.xg.receiveddrops': { + category: 'sophos', + description: 'received drops ', + name: 'sophos.xg.receiveddrops', + type: 'long', }, - 'fortinet.firewall.limit': { - category: 'fortinet', - description: 'Virtual Domain Resource Limit ', - name: 'fortinet.firewall.limit', - type: 'integer', + 'sophos.xg.collisions': { + category: 'sophos', + description: 'collisions ', + name: 'sophos.xg.collisions', + type: 'long', }, - 'fortinet.firewall.line': { - category: 'fortinet', - description: 'VOIP line ', - name: 'fortinet.firewall.line', + 'sophos.xg.interface': { + category: 'sophos', + description: 'interface ', + name: 'sophos.xg.interface', type: 'keyword', }, - 'fortinet.firewall.live': { - category: 'fortinet', - description: 'Time in seconds ', - name: 'fortinet.firewall.live', - type: 'integer', - }, - 'fortinet.firewall.local': { - category: 'fortinet', - description: 'Local IP for a PPPD Connection ', - name: 'fortinet.firewall.local', - type: 'ip', + 'sophos.xg.Configuration': { + category: 'sophos', + description: 'Configuration ', + name: 'sophos.xg.Configuration', + type: 'float', }, - 'fortinet.firewall.log': { - category: 'fortinet', - description: 'Log message ', - name: 'fortinet.firewall.log', - type: 'keyword', + 'sophos.xg.Reports': { + category: 'sophos', + description: 'Reports ', + name: 'sophos.xg.Reports', + type: 'float', }, - 'fortinet.firewall.login': { - category: 'fortinet', - description: 'SSH login ', - name: 'fortinet.firewall.login', - type: 'keyword', + 'sophos.xg.Signature': { + category: 'sophos', + description: 'Signature ', + name: 'sophos.xg.Signature', + type: 'float', }, - 'fortinet.firewall.lowcount': { - category: 'fortinet', - description: 'Fabric lowcount ', - name: 'fortinet.firewall.lowcount', - type: 'integer', + 'sophos.xg.Temp': { + category: 'sophos', + description: 'Temp ', + name: 'sophos.xg.Temp', + type: 'float', }, - 'fortinet.firewall.mac': { - category: 'fortinet', - description: 'DHCP mac address ', - name: 'fortinet.firewall.mac', + 'sophos.xg.users': { + category: 'sophos', + description: 'users ', + name: 'sophos.xg.users', type: 'keyword', }, - 'fortinet.firewall.malform_data': { - category: 'fortinet', - description: 'VOIP malformed data ', - name: 'fortinet.firewall.malform_data', - type: 'integer', - }, - 'fortinet.firewall.malform_desc': { - category: 'fortinet', - description: 'VOIP malformed data description ', - name: 'fortinet.firewall.malform_desc', + 'sophos.xg.ssid': { + category: 'sophos', + description: 'ssid ', + name: 'sophos.xg.ssid', type: 'keyword', }, - 'fortinet.firewall.manuf': { - category: 'fortinet', - description: 'Manufacturer name ', - name: 'fortinet.firewall.manuf', + 'sophos.xg.ap': { + category: 'sophos', + description: 'ap ', + name: 'sophos.xg.ap', type: 'keyword', }, - 'fortinet.firewall.masterdstmac': { - category: 'fortinet', - description: 'Master mac address for a host with multiple network interfaces ', - name: 'fortinet.firewall.masterdstmac', + 'sophos.xg.clients_conn_ssid': { + category: 'sophos', + description: 'clients connection ssid ', + name: 'sophos.xg.clients_conn_ssid', type: 'keyword', }, - 'fortinet.firewall.mastersrcmac': { - category: 'fortinet', - description: 'The master MAC address for a host that has multiple network interfaces ', - name: 'fortinet.firewall.mastersrcmac', + 'sophos.xg.sqli': { + category: 'sophos', + description: 'The related SQLI caught by the WAF ', + name: 'sophos.xg.sqli', type: 'keyword', }, - 'fortinet.firewall.mediumcount': { - category: 'fortinet', - description: 'Fabric medium count ', - name: 'fortinet.firewall.mediumcount', - type: 'integer', + 'sophos.xg.xss': { + category: 'sophos', + description: 'The related XSS caught by the WAF ', + name: 'sophos.xg.xss', + type: 'keyword', }, - 'fortinet.firewall.mem': { - category: 'fortinet', - description: 'Memory usage system statistics ', - name: 'fortinet.firewall.mem', + 'sophos.xg.ether_type': { + category: 'sophos', + description: 'The ethernet frame type ', + name: 'sophos.xg.ether_type', type: 'keyword', }, - 'fortinet.firewall.meshmode': { - category: 'fortinet', - description: 'Wireless mesh mode ', - name: 'fortinet.firewall.meshmode', + 'suricata.eve.event_type': { + category: 'suricata', + name: 'suricata.eve.event_type', type: 'keyword', }, - 'fortinet.firewall.message_type': { - category: 'fortinet', - description: 'VOIP message type ', - name: 'fortinet.firewall.message_type', + 'suricata.eve.app_proto_orig': { + category: 'suricata', + name: 'suricata.eve.app_proto_orig', type: 'keyword', }, - 'fortinet.firewall.method': { - category: 'fortinet', - description: 'HTTP method ', - name: 'fortinet.firewall.method', + 'suricata.eve.tcp.tcp_flags': { + category: 'suricata', + name: 'suricata.eve.tcp.tcp_flags', type: 'keyword', }, - 'fortinet.firewall.mgmtcnt': { - category: 'fortinet', - description: 'The number of unauthorized client flooding managemet frames ', - name: 'fortinet.firewall.mgmtcnt', - type: 'integer', + 'suricata.eve.tcp.psh': { + category: 'suricata', + name: 'suricata.eve.tcp.psh', + type: 'boolean', }, - 'fortinet.firewall.mode': { - category: 'fortinet', - description: 'IPSEC mode ', - name: 'fortinet.firewall.mode', + 'suricata.eve.tcp.tcp_flags_tc': { + category: 'suricata', + name: 'suricata.eve.tcp.tcp_flags_tc', type: 'keyword', }, - 'fortinet.firewall.module': { - category: 'fortinet', - description: 'PCI-DSS module ', - name: 'fortinet.firewall.module', - type: 'keyword', + 'suricata.eve.tcp.ack': { + category: 'suricata', + name: 'suricata.eve.tcp.ack', + type: 'boolean', }, - 'fortinet.firewall.monitor-name': { - category: 'fortinet', - description: 'Health Monitor Name ', - name: 'fortinet.firewall.monitor-name', - type: 'keyword', + 'suricata.eve.tcp.syn': { + category: 'suricata', + name: 'suricata.eve.tcp.syn', + type: 'boolean', }, - 'fortinet.firewall.monitor-type': { - category: 'fortinet', - description: 'Health Monitor Type ', - name: 'fortinet.firewall.monitor-type', + 'suricata.eve.tcp.state': { + category: 'suricata', + name: 'suricata.eve.tcp.state', type: 'keyword', }, - 'fortinet.firewall.mpsk': { - category: 'fortinet', - description: 'Wireless MPSK ', - name: 'fortinet.firewall.mpsk', + 'suricata.eve.tcp.tcp_flags_ts': { + category: 'suricata', + name: 'suricata.eve.tcp.tcp_flags_ts', type: 'keyword', }, - 'fortinet.firewall.msgproto': { - category: 'fortinet', - description: 'Message Protocol Number ', - name: 'fortinet.firewall.msgproto', + 'suricata.eve.tcp.rst': { + category: 'suricata', + name: 'suricata.eve.tcp.rst', + type: 'boolean', + }, + 'suricata.eve.tcp.fin': { + category: 'suricata', + name: 'suricata.eve.tcp.fin', + type: 'boolean', + }, + 'suricata.eve.fileinfo.sha1': { + category: 'suricata', + name: 'suricata.eve.fileinfo.sha1', type: 'keyword', }, - 'fortinet.firewall.mtu': { - category: 'fortinet', - description: 'Max Transmission Unit Value ', - name: 'fortinet.firewall.mtu', - type: 'integer', + 'suricata.eve.fileinfo.tx_id': { + category: 'suricata', + name: 'suricata.eve.fileinfo.tx_id', + type: 'long', }, - 'fortinet.firewall.name': { - category: 'fortinet', - description: 'Name ', - name: 'fortinet.firewall.name', + 'suricata.eve.fileinfo.state': { + category: 'suricata', + name: 'suricata.eve.fileinfo.state', type: 'keyword', }, - 'fortinet.firewall.nat': { - category: 'fortinet', - description: 'NAT IP Address ', - name: 'fortinet.firewall.nat', + 'suricata.eve.fileinfo.stored': { + category: 'suricata', + name: 'suricata.eve.fileinfo.stored', + type: 'boolean', + }, + 'suricata.eve.fileinfo.gaps': { + category: 'suricata', + name: 'suricata.eve.fileinfo.gaps', + type: 'boolean', + }, + 'suricata.eve.fileinfo.sha256': { + category: 'suricata', + name: 'suricata.eve.fileinfo.sha256', type: 'keyword', }, - 'fortinet.firewall.netid': { - category: 'fortinet', - description: 'Connector NetID ', - name: 'fortinet.firewall.netid', + 'suricata.eve.fileinfo.md5': { + category: 'suricata', + name: 'suricata.eve.fileinfo.md5', type: 'keyword', }, - 'fortinet.firewall.new_status': { - category: 'fortinet', - description: 'New status on user change ', - name: 'fortinet.firewall.new_status', + 'suricata.eve.icmp_type': { + category: 'suricata', + name: 'suricata.eve.icmp_type', + type: 'long', + }, + 'suricata.eve.pcap_cnt': { + category: 'suricata', + name: 'suricata.eve.pcap_cnt', + type: 'long', + }, + 'suricata.eve.dns.type': { + category: 'suricata', + name: 'suricata.eve.dns.type', type: 'keyword', }, - 'fortinet.firewall.new_value': { - category: 'fortinet', - description: 'New Virtual Domain Name ', - name: 'fortinet.firewall.new_value', + 'suricata.eve.dns.rrtype': { + category: 'suricata', + name: 'suricata.eve.dns.rrtype', type: 'keyword', }, - 'fortinet.firewall.newchannel': { - category: 'fortinet', - description: 'New Channel Number ', - name: 'fortinet.firewall.newchannel', - type: 'integer', + 'suricata.eve.dns.rrname': { + category: 'suricata', + name: 'suricata.eve.dns.rrname', + type: 'keyword', }, - 'fortinet.firewall.newchassisid': { - category: 'fortinet', - description: 'New Chassis ID ', - name: 'fortinet.firewall.newchassisid', - type: 'integer', + 'suricata.eve.dns.rdata': { + category: 'suricata', + name: 'suricata.eve.dns.rdata', + type: 'keyword', }, - 'fortinet.firewall.newslot': { - category: 'fortinet', - description: 'New Slot Number ', - name: 'fortinet.firewall.newslot', - type: 'integer', + 'suricata.eve.dns.tx_id': { + category: 'suricata', + name: 'suricata.eve.dns.tx_id', + type: 'long', }, - 'fortinet.firewall.nextstat': { - category: 'fortinet', - description: 'Time interval in seconds for the next statistics. ', - name: 'fortinet.firewall.nextstat', - type: 'integer', + 'suricata.eve.dns.ttl': { + category: 'suricata', + name: 'suricata.eve.dns.ttl', + type: 'long', }, - 'fortinet.firewall.nf_type': { - category: 'fortinet', - description: 'Notification Type ', - name: 'fortinet.firewall.nf_type', + 'suricata.eve.dns.rcode': { + category: 'suricata', + name: 'suricata.eve.dns.rcode', type: 'keyword', }, - 'fortinet.firewall.noise': { - category: 'fortinet', - description: 'Wifi Noise ', - name: 'fortinet.firewall.noise', - type: 'integer', + 'suricata.eve.dns.id': { + category: 'suricata', + name: 'suricata.eve.dns.id', + type: 'long', }, - 'fortinet.firewall.old_status': { - category: 'fortinet', - description: 'Original Status ', - name: 'fortinet.firewall.old_status', + 'suricata.eve.flow_id': { + category: 'suricata', + name: 'suricata.eve.flow_id', type: 'keyword', }, - 'fortinet.firewall.old_value': { - category: 'fortinet', - description: 'Original Virtual Domain name ', - name: 'fortinet.firewall.old_value', + 'suricata.eve.email.status': { + category: 'suricata', + name: 'suricata.eve.email.status', type: 'keyword', }, - 'fortinet.firewall.oldchannel': { - category: 'fortinet', - description: 'Original channel ', - name: 'fortinet.firewall.oldchannel', - type: 'integer', + 'suricata.eve.icmp_code': { + category: 'suricata', + name: 'suricata.eve.icmp_code', + type: 'long', }, - 'fortinet.firewall.oldchassisid': { - category: 'fortinet', - description: 'Original Chassis Number ', - name: 'fortinet.firewall.oldchassisid', - type: 'integer', + 'suricata.eve.http.redirect': { + category: 'suricata', + name: 'suricata.eve.http.redirect', + type: 'keyword', }, - 'fortinet.firewall.oldslot': { - category: 'fortinet', - description: 'Original Slot Number ', - name: 'fortinet.firewall.oldslot', - type: 'integer', + 'suricata.eve.http.protocol': { + category: 'suricata', + name: 'suricata.eve.http.protocol', + type: 'keyword', }, - 'fortinet.firewall.oldsn': { - category: 'fortinet', - description: 'Old Serial number ', - name: 'fortinet.firewall.oldsn', + 'suricata.eve.http.http_content_type': { + category: 'suricata', + name: 'suricata.eve.http.http_content_type', type: 'keyword', }, - 'fortinet.firewall.oldwprof': { - category: 'fortinet', - description: 'Old Web Filter Profile ', - name: 'fortinet.firewall.oldwprof', + 'suricata.eve.in_iface': { + category: 'suricata', + name: 'suricata.eve.in_iface', type: 'keyword', }, - 'fortinet.firewall.onwire': { - category: 'fortinet', - description: 'A flag to indicate if the AP is onwire or not ', - name: 'fortinet.firewall.onwire', + 'suricata.eve.alert.metadata': { + category: 'suricata', + description: 'Metadata about the alert.', + name: 'suricata.eve.alert.metadata', + type: 'flattened', + }, + 'suricata.eve.alert.category': { + category: 'suricata', + name: 'suricata.eve.alert.category', type: 'keyword', }, - 'fortinet.firewall.opercountry': { - category: 'fortinet', - description: 'Operating Country ', - name: 'fortinet.firewall.opercountry', + 'suricata.eve.alert.rev': { + category: 'suricata', + name: 'suricata.eve.alert.rev', + type: 'long', + }, + 'suricata.eve.alert.gid': { + category: 'suricata', + name: 'suricata.eve.alert.gid', + type: 'long', + }, + 'suricata.eve.alert.signature': { + category: 'suricata', + name: 'suricata.eve.alert.signature', type: 'keyword', }, - 'fortinet.firewall.opertxpower': { - category: 'fortinet', - description: 'Operating TX power ', - name: 'fortinet.firewall.opertxpower', - type: 'integer', + 'suricata.eve.alert.signature_id': { + category: 'suricata', + name: 'suricata.eve.alert.signature_id', + type: 'long', }, - 'fortinet.firewall.osname': { - category: 'fortinet', - description: 'Operating System name ', - name: 'fortinet.firewall.osname', + 'suricata.eve.alert.protocols': { + category: 'suricata', + name: 'suricata.eve.alert.protocols', type: 'keyword', }, - 'fortinet.firewall.osversion': { - category: 'fortinet', - description: 'Operating System version ', - name: 'fortinet.firewall.osversion', + 'suricata.eve.alert.attack_target': { + category: 'suricata', + name: 'suricata.eve.alert.attack_target', type: 'keyword', }, - 'fortinet.firewall.out_spi': { - category: 'fortinet', - description: 'Out SPI ', - name: 'fortinet.firewall.out_spi', + 'suricata.eve.alert.capec_id': { + category: 'suricata', + name: 'suricata.eve.alert.capec_id', type: 'keyword', }, - 'fortinet.firewall.outintf': { - category: 'fortinet', - description: 'Out interface ', - name: 'fortinet.firewall.outintf', + 'suricata.eve.alert.cwe_id': { + category: 'suricata', + name: 'suricata.eve.alert.cwe_id', type: 'keyword', }, - 'fortinet.firewall.passedcount': { - category: 'fortinet', - description: 'Fabric passed count ', - name: 'fortinet.firewall.passedcount', - type: 'integer', + 'suricata.eve.alert.malware': { + category: 'suricata', + name: 'suricata.eve.alert.malware', + type: 'keyword', }, - 'fortinet.firewall.passwd': { - category: 'fortinet', - description: 'Changed user password information ', - name: 'fortinet.firewall.passwd', + 'suricata.eve.alert.cve': { + category: 'suricata', + name: 'suricata.eve.alert.cve', type: 'keyword', }, - 'fortinet.firewall.path': { - category: 'fortinet', - description: 'Path of looped configuration for security fabric ', - name: 'fortinet.firewall.path', + 'suricata.eve.alert.cvss_v2_base': { + category: 'suricata', + name: 'suricata.eve.alert.cvss_v2_base', type: 'keyword', }, - 'fortinet.firewall.peer': { - category: 'fortinet', - description: 'WAN optimization peer ', - name: 'fortinet.firewall.peer', + 'suricata.eve.alert.cvss_v2_temporal': { + category: 'suricata', + name: 'suricata.eve.alert.cvss_v2_temporal', type: 'keyword', }, - 'fortinet.firewall.peer_notif': { - category: 'fortinet', - description: 'VPN peer notification ', - name: 'fortinet.firewall.peer_notif', + 'suricata.eve.alert.cvss_v3_base': { + category: 'suricata', + name: 'suricata.eve.alert.cvss_v3_base', type: 'keyword', }, - 'fortinet.firewall.phase2_name': { - category: 'fortinet', - description: 'VPN phase2 name ', - name: 'fortinet.firewall.phase2_name', + 'suricata.eve.alert.cvss_v3_temporal': { + category: 'suricata', + name: 'suricata.eve.alert.cvss_v3_temporal', type: 'keyword', }, - 'fortinet.firewall.phone': { - category: 'fortinet', - description: 'VOIP Phone ', - name: 'fortinet.firewall.phone', + 'suricata.eve.alert.priority': { + category: 'suricata', + name: 'suricata.eve.alert.priority', type: 'keyword', }, - 'fortinet.firewall.pid': { - category: 'fortinet', - description: 'Process ID ', - name: 'fortinet.firewall.pid', - type: 'integer', + 'suricata.eve.alert.hostile': { + category: 'suricata', + name: 'suricata.eve.alert.hostile', + type: 'keyword', }, - 'fortinet.firewall.policytype': { - category: 'fortinet', - description: 'Policy Type ', - name: 'fortinet.firewall.policytype', + 'suricata.eve.alert.infected': { + category: 'suricata', + name: 'suricata.eve.alert.infected', type: 'keyword', }, - 'fortinet.firewall.poolname': { - category: 'fortinet', - description: 'IP Pool name ', - name: 'fortinet.firewall.poolname', + 'suricata.eve.alert.created_at': { + category: 'suricata', + name: 'suricata.eve.alert.created_at', + type: 'date', + }, + 'suricata.eve.alert.updated_at': { + category: 'suricata', + name: 'suricata.eve.alert.updated_at', + type: 'date', + }, + 'suricata.eve.alert.classtype': { + category: 'suricata', + name: 'suricata.eve.alert.classtype', type: 'keyword', }, - 'fortinet.firewall.port': { - category: 'fortinet', - description: 'Log upload error port ', - name: 'fortinet.firewall.port', - type: 'integer', + 'suricata.eve.alert.rule_source': { + category: 'suricata', + name: 'suricata.eve.alert.rule_source', + type: 'keyword', }, - 'fortinet.firewall.portbegin': { - category: 'fortinet', - description: 'IP Pool port number to begin ', - name: 'fortinet.firewall.portbegin', - type: 'integer', + 'suricata.eve.alert.sid': { + category: 'suricata', + name: 'suricata.eve.alert.sid', + type: 'keyword', }, - 'fortinet.firewall.portend': { - category: 'fortinet', - description: 'IP Pool port number to end ', - name: 'fortinet.firewall.portend', - type: 'integer', + 'suricata.eve.alert.affected_product': { + category: 'suricata', + name: 'suricata.eve.alert.affected_product', + type: 'keyword', }, - 'fortinet.firewall.probeproto': { - category: 'fortinet', - description: 'Link Monitor Probe Protocol ', - name: 'fortinet.firewall.probeproto', + 'suricata.eve.alert.deployment': { + category: 'suricata', + name: 'suricata.eve.alert.deployment', type: 'keyword', }, - 'fortinet.firewall.process': { - category: 'fortinet', - description: 'URL Filter process ', - name: 'fortinet.firewall.process', + 'suricata.eve.alert.former_category': { + category: 'suricata', + name: 'suricata.eve.alert.former_category', type: 'keyword', }, - 'fortinet.firewall.processtime': { - category: 'fortinet', - description: 'Process time for reports ', - name: 'fortinet.firewall.processtime', - type: 'integer', + 'suricata.eve.alert.mitre_tool_id': { + category: 'suricata', + name: 'suricata.eve.alert.mitre_tool_id', + type: 'keyword', }, - 'fortinet.firewall.profile': { - category: 'fortinet', - description: 'Profile Name ', - name: 'fortinet.firewall.profile', + 'suricata.eve.alert.performance_impact': { + category: 'suricata', + name: 'suricata.eve.alert.performance_impact', type: 'keyword', }, - 'fortinet.firewall.profile_vd': { - category: 'fortinet', - description: 'Virtual Domain Name ', - name: 'fortinet.firewall.profile_vd', + 'suricata.eve.alert.signature_severity': { + category: 'suricata', + name: 'suricata.eve.alert.signature_severity', type: 'keyword', }, - 'fortinet.firewall.profilegroup': { - category: 'fortinet', - description: 'Profile Group Name ', - name: 'fortinet.firewall.profilegroup', + 'suricata.eve.alert.tag': { + category: 'suricata', + name: 'suricata.eve.alert.tag', type: 'keyword', }, - 'fortinet.firewall.profiletype': { - category: 'fortinet', - description: 'Profile Type ', - name: 'fortinet.firewall.profiletype', + 'suricata.eve.ssh.client.proto_version': { + category: 'suricata', + name: 'suricata.eve.ssh.client.proto_version', type: 'keyword', }, - 'fortinet.firewall.qtypeval': { - category: 'fortinet', - description: 'DNS question type value ', - name: 'fortinet.firewall.qtypeval', - type: 'integer', + 'suricata.eve.ssh.client.software_version': { + category: 'suricata', + name: 'suricata.eve.ssh.client.software_version', + type: 'keyword', }, - 'fortinet.firewall.quarskip': { - category: 'fortinet', - description: 'Quarantine skip explanation ', - name: 'fortinet.firewall.quarskip', + 'suricata.eve.ssh.server.proto_version': { + category: 'suricata', + name: 'suricata.eve.ssh.server.proto_version', type: 'keyword', }, - 'fortinet.firewall.quotaexceeded': { - category: 'fortinet', - description: 'If quota has been exceeded ', - name: 'fortinet.firewall.quotaexceeded', + 'suricata.eve.ssh.server.software_version': { + category: 'suricata', + name: 'suricata.eve.ssh.server.software_version', type: 'keyword', }, - 'fortinet.firewall.quotamax': { - category: 'fortinet', - description: 'Maximum quota allowed - in seconds if time-based - in bytes if traffic-based ', - name: 'fortinet.firewall.quotamax', + 'suricata.eve.stats.capture.kernel_packets': { + category: 'suricata', + name: 'suricata.eve.stats.capture.kernel_packets', type: 'long', }, - 'fortinet.firewall.quotatype': { - category: 'fortinet', - description: 'Quota type ', - name: 'fortinet.firewall.quotatype', - type: 'keyword', + 'suricata.eve.stats.capture.kernel_drops': { + category: 'suricata', + name: 'suricata.eve.stats.capture.kernel_drops', + type: 'long', }, - 'fortinet.firewall.quotaused': { - category: 'fortinet', - description: 'Quota used - in seconds if time-based - in bytes if trafficbased) ', - name: 'fortinet.firewall.quotaused', + 'suricata.eve.stats.capture.kernel_ifdrops': { + category: 'suricata', + name: 'suricata.eve.stats.capture.kernel_ifdrops', type: 'long', }, - 'fortinet.firewall.radioband': { - category: 'fortinet', - description: 'Radio band ', - name: 'fortinet.firewall.radioband', - type: 'keyword', + 'suricata.eve.stats.uptime': { + category: 'suricata', + name: 'suricata.eve.stats.uptime', + type: 'long', }, - 'fortinet.firewall.radioid': { - category: 'fortinet', - description: 'Radio ID ', - name: 'fortinet.firewall.radioid', - type: 'integer', + 'suricata.eve.stats.detect.alert': { + category: 'suricata', + name: 'suricata.eve.stats.detect.alert', + type: 'long', }, - 'fortinet.firewall.radioidclosest': { - category: 'fortinet', - description: 'Radio ID on the AP closest the rogue AP ', - name: 'fortinet.firewall.radioidclosest', - type: 'integer', + 'suricata.eve.stats.http.memcap': { + category: 'suricata', + name: 'suricata.eve.stats.http.memcap', + type: 'long', }, - 'fortinet.firewall.radioiddetected': { - category: 'fortinet', - description: 'Radio ID on the AP which detected the rogue AP ', - name: 'fortinet.firewall.radioiddetected', - type: 'integer', + 'suricata.eve.stats.http.memuse': { + category: 'suricata', + name: 'suricata.eve.stats.http.memuse', + type: 'long', }, - 'fortinet.firewall.rate': { - category: 'fortinet', - description: 'Wireless rogue rate value ', - name: 'fortinet.firewall.rate', - type: 'keyword', + 'suricata.eve.stats.file_store.open_files': { + category: 'suricata', + name: 'suricata.eve.stats.file_store.open_files', + type: 'long', }, - 'fortinet.firewall.rawdata': { - category: 'fortinet', - description: 'Raw data value ', - name: 'fortinet.firewall.rawdata', - type: 'keyword', + 'suricata.eve.stats.defrag.max_frag_hits': { + category: 'suricata', + name: 'suricata.eve.stats.defrag.max_frag_hits', + type: 'long', }, - 'fortinet.firewall.rawdataid': { - category: 'fortinet', - description: 'Raw data ID ', - name: 'fortinet.firewall.rawdataid', - type: 'keyword', + 'suricata.eve.stats.defrag.ipv4.timeouts': { + category: 'suricata', + name: 'suricata.eve.stats.defrag.ipv4.timeouts', + type: 'long', }, - 'fortinet.firewall.rcvddelta': { - category: 'fortinet', - description: 'Received bytes delta ', - name: 'fortinet.firewall.rcvddelta', - type: 'keyword', + 'suricata.eve.stats.defrag.ipv4.fragments': { + category: 'suricata', + name: 'suricata.eve.stats.defrag.ipv4.fragments', + type: 'long', }, - 'fortinet.firewall.reason': { - category: 'fortinet', - description: 'Alert reason ', - name: 'fortinet.firewall.reason', - type: 'keyword', + 'suricata.eve.stats.defrag.ipv4.reassembled': { + category: 'suricata', + name: 'suricata.eve.stats.defrag.ipv4.reassembled', + type: 'long', + }, + 'suricata.eve.stats.defrag.ipv6.timeouts': { + category: 'suricata', + name: 'suricata.eve.stats.defrag.ipv6.timeouts', + type: 'long', + }, + 'suricata.eve.stats.defrag.ipv6.fragments': { + category: 'suricata', + name: 'suricata.eve.stats.defrag.ipv6.fragments', + type: 'long', + }, + 'suricata.eve.stats.defrag.ipv6.reassembled': { + category: 'suricata', + name: 'suricata.eve.stats.defrag.ipv6.reassembled', + type: 'long', + }, + 'suricata.eve.stats.flow.tcp_reuse': { + category: 'suricata', + name: 'suricata.eve.stats.flow.tcp_reuse', + type: 'long', + }, + 'suricata.eve.stats.flow.udp': { + category: 'suricata', + name: 'suricata.eve.stats.flow.udp', + type: 'long', + }, + 'suricata.eve.stats.flow.memcap': { + category: 'suricata', + name: 'suricata.eve.stats.flow.memcap', + type: 'long', + }, + 'suricata.eve.stats.flow.emerg_mode_entered': { + category: 'suricata', + name: 'suricata.eve.stats.flow.emerg_mode_entered', + type: 'long', + }, + 'suricata.eve.stats.flow.emerg_mode_over': { + category: 'suricata', + name: 'suricata.eve.stats.flow.emerg_mode_over', + type: 'long', + }, + 'suricata.eve.stats.flow.tcp': { + category: 'suricata', + name: 'suricata.eve.stats.flow.tcp', + type: 'long', + }, + 'suricata.eve.stats.flow.icmpv6': { + category: 'suricata', + name: 'suricata.eve.stats.flow.icmpv6', + type: 'long', + }, + 'suricata.eve.stats.flow.icmpv4': { + category: 'suricata', + name: 'suricata.eve.stats.flow.icmpv4', + type: 'long', + }, + 'suricata.eve.stats.flow.spare': { + category: 'suricata', + name: 'suricata.eve.stats.flow.spare', + type: 'long', + }, + 'suricata.eve.stats.flow.memuse': { + category: 'suricata', + name: 'suricata.eve.stats.flow.memuse', + type: 'long', + }, + 'suricata.eve.stats.tcp.pseudo_failed': { + category: 'suricata', + name: 'suricata.eve.stats.tcp.pseudo_failed', + type: 'long', + }, + 'suricata.eve.stats.tcp.ssn_memcap_drop': { + category: 'suricata', + name: 'suricata.eve.stats.tcp.ssn_memcap_drop', + type: 'long', + }, + 'suricata.eve.stats.tcp.insert_data_overlap_fail': { + category: 'suricata', + name: 'suricata.eve.stats.tcp.insert_data_overlap_fail', + type: 'long', + }, + 'suricata.eve.stats.tcp.sessions': { + category: 'suricata', + name: 'suricata.eve.stats.tcp.sessions', + type: 'long', + }, + 'suricata.eve.stats.tcp.pseudo': { + category: 'suricata', + name: 'suricata.eve.stats.tcp.pseudo', + type: 'long', + }, + 'suricata.eve.stats.tcp.synack': { + category: 'suricata', + name: 'suricata.eve.stats.tcp.synack', + type: 'long', + }, + 'suricata.eve.stats.tcp.insert_data_normal_fail': { + category: 'suricata', + name: 'suricata.eve.stats.tcp.insert_data_normal_fail', + type: 'long', + }, + 'suricata.eve.stats.tcp.syn': { + category: 'suricata', + name: 'suricata.eve.stats.tcp.syn', + type: 'long', + }, + 'suricata.eve.stats.tcp.memuse': { + category: 'suricata', + name: 'suricata.eve.stats.tcp.memuse', + type: 'long', + }, + 'suricata.eve.stats.tcp.invalid_checksum': { + category: 'suricata', + name: 'suricata.eve.stats.tcp.invalid_checksum', + type: 'long', + }, + 'suricata.eve.stats.tcp.segment_memcap_drop': { + category: 'suricata', + name: 'suricata.eve.stats.tcp.segment_memcap_drop', + type: 'long', + }, + 'suricata.eve.stats.tcp.overlap': { + category: 'suricata', + name: 'suricata.eve.stats.tcp.overlap', + type: 'long', + }, + 'suricata.eve.stats.tcp.insert_list_fail': { + category: 'suricata', + name: 'suricata.eve.stats.tcp.insert_list_fail', + type: 'long', + }, + 'suricata.eve.stats.tcp.rst': { + category: 'suricata', + name: 'suricata.eve.stats.tcp.rst', + type: 'long', + }, + 'suricata.eve.stats.tcp.stream_depth_reached': { + category: 'suricata', + name: 'suricata.eve.stats.tcp.stream_depth_reached', + type: 'long', + }, + 'suricata.eve.stats.tcp.reassembly_memuse': { + category: 'suricata', + name: 'suricata.eve.stats.tcp.reassembly_memuse', + type: 'long', + }, + 'suricata.eve.stats.tcp.reassembly_gap': { + category: 'suricata', + name: 'suricata.eve.stats.tcp.reassembly_gap', + type: 'long', + }, + 'suricata.eve.stats.tcp.overlap_diff_data': { + category: 'suricata', + name: 'suricata.eve.stats.tcp.overlap_diff_data', + type: 'long', + }, + 'suricata.eve.stats.tcp.no_flow': { + category: 'suricata', + name: 'suricata.eve.stats.tcp.no_flow', + type: 'long', + }, + 'suricata.eve.stats.decoder.avg_pkt_size': { + category: 'suricata', + name: 'suricata.eve.stats.decoder.avg_pkt_size', + type: 'long', + }, + 'suricata.eve.stats.decoder.bytes': { + category: 'suricata', + name: 'suricata.eve.stats.decoder.bytes', + type: 'long', + }, + 'suricata.eve.stats.decoder.tcp': { + category: 'suricata', + name: 'suricata.eve.stats.decoder.tcp', + type: 'long', + }, + 'suricata.eve.stats.decoder.raw': { + category: 'suricata', + name: 'suricata.eve.stats.decoder.raw', + type: 'long', + }, + 'suricata.eve.stats.decoder.ppp': { + category: 'suricata', + name: 'suricata.eve.stats.decoder.ppp', + type: 'long', + }, + 'suricata.eve.stats.decoder.vlan_qinq': { + category: 'suricata', + name: 'suricata.eve.stats.decoder.vlan_qinq', + type: 'long', + }, + 'suricata.eve.stats.decoder.null': { + category: 'suricata', + name: 'suricata.eve.stats.decoder.null', + type: 'long', + }, + 'suricata.eve.stats.decoder.ltnull.unsupported_type': { + category: 'suricata', + name: 'suricata.eve.stats.decoder.ltnull.unsupported_type', + type: 'long', + }, + 'suricata.eve.stats.decoder.ltnull.pkt_too_small': { + category: 'suricata', + name: 'suricata.eve.stats.decoder.ltnull.pkt_too_small', + type: 'long', + }, + 'suricata.eve.stats.decoder.invalid': { + category: 'suricata', + name: 'suricata.eve.stats.decoder.invalid', + type: 'long', + }, + 'suricata.eve.stats.decoder.gre': { + category: 'suricata', + name: 'suricata.eve.stats.decoder.gre', + type: 'long', + }, + 'suricata.eve.stats.decoder.ipv4': { + category: 'suricata', + name: 'suricata.eve.stats.decoder.ipv4', + type: 'long', + }, + 'suricata.eve.stats.decoder.ipv6': { + category: 'suricata', + name: 'suricata.eve.stats.decoder.ipv6', + type: 'long', + }, + 'suricata.eve.stats.decoder.pkts': { + category: 'suricata', + name: 'suricata.eve.stats.decoder.pkts', + type: 'long', + }, + 'suricata.eve.stats.decoder.ipv6_in_ipv6': { + category: 'suricata', + name: 'suricata.eve.stats.decoder.ipv6_in_ipv6', + type: 'long', + }, + 'suricata.eve.stats.decoder.ipraw.invalid_ip_version': { + category: 'suricata', + name: 'suricata.eve.stats.decoder.ipraw.invalid_ip_version', + type: 'long', + }, + 'suricata.eve.stats.decoder.pppoe': { + category: 'suricata', + name: 'suricata.eve.stats.decoder.pppoe', + type: 'long', }, - 'fortinet.firewall.received': { - category: 'fortinet', - description: 'Server key exchange received ', - name: 'fortinet.firewall.received', - type: 'integer', + 'suricata.eve.stats.decoder.udp': { + category: 'suricata', + name: 'suricata.eve.stats.decoder.udp', + type: 'long', }, - 'fortinet.firewall.receivedsignature': { - category: 'fortinet', - description: 'Server key exchange received signature ', - name: 'fortinet.firewall.receivedsignature', - type: 'keyword', + 'suricata.eve.stats.decoder.dce.pkt_too_small': { + category: 'suricata', + name: 'suricata.eve.stats.decoder.dce.pkt_too_small', + type: 'long', }, - 'fortinet.firewall.red': { - category: 'fortinet', - description: 'Memory information in red ', - name: 'fortinet.firewall.red', - type: 'keyword', + 'suricata.eve.stats.decoder.vlan': { + category: 'suricata', + name: 'suricata.eve.stats.decoder.vlan', + type: 'long', }, - 'fortinet.firewall.referralurl': { - category: 'fortinet', - description: 'Web filter referralurl ', - name: 'fortinet.firewall.referralurl', - type: 'keyword', + 'suricata.eve.stats.decoder.sctp': { + category: 'suricata', + name: 'suricata.eve.stats.decoder.sctp', + type: 'long', }, - 'fortinet.firewall.remote': { - category: 'fortinet', - description: 'Remote PPP IP address ', - name: 'fortinet.firewall.remote', - type: 'ip', + 'suricata.eve.stats.decoder.max_pkt_size': { + category: 'suricata', + name: 'suricata.eve.stats.decoder.max_pkt_size', + type: 'long', }, - 'fortinet.firewall.remotewtptime': { - category: 'fortinet', - description: 'Remote Wifi Radius authentication time ', - name: 'fortinet.firewall.remotewtptime', - type: 'keyword', + 'suricata.eve.stats.decoder.teredo': { + category: 'suricata', + name: 'suricata.eve.stats.decoder.teredo', + type: 'long', }, - 'fortinet.firewall.reporttype': { - category: 'fortinet', - description: 'Report type ', - name: 'fortinet.firewall.reporttype', - type: 'keyword', + 'suricata.eve.stats.decoder.mpls': { + category: 'suricata', + name: 'suricata.eve.stats.decoder.mpls', + type: 'long', }, - 'fortinet.firewall.reqtype': { - category: 'fortinet', - description: 'Request type ', - name: 'fortinet.firewall.reqtype', - type: 'keyword', + 'suricata.eve.stats.decoder.sll': { + category: 'suricata', + name: 'suricata.eve.stats.decoder.sll', + type: 'long', }, - 'fortinet.firewall.request_name': { - category: 'fortinet', - description: 'VOIP request name ', - name: 'fortinet.firewall.request_name', - type: 'keyword', + 'suricata.eve.stats.decoder.icmpv6': { + category: 'suricata', + name: 'suricata.eve.stats.decoder.icmpv6', + type: 'long', }, - 'fortinet.firewall.result': { - category: 'fortinet', - description: 'VPN phase result ', - name: 'fortinet.firewall.result', - type: 'keyword', + 'suricata.eve.stats.decoder.icmpv4': { + category: 'suricata', + name: 'suricata.eve.stats.decoder.icmpv4', + type: 'long', }, - 'fortinet.firewall.role': { - category: 'fortinet', - description: 'VPN Phase 2 role ', - name: 'fortinet.firewall.role', - type: 'keyword', + 'suricata.eve.stats.decoder.erspan': { + category: 'suricata', + name: 'suricata.eve.stats.decoder.erspan', + type: 'long', }, - 'fortinet.firewall.rssi': { - category: 'fortinet', - description: 'Received signal strength indicator ', - name: 'fortinet.firewall.rssi', - type: 'integer', + 'suricata.eve.stats.decoder.ethernet': { + category: 'suricata', + name: 'suricata.eve.stats.decoder.ethernet', + type: 'long', }, - 'fortinet.firewall.rsso_key': { - category: 'fortinet', - description: 'RADIUS SSO attribute value ', - name: 'fortinet.firewall.rsso_key', - type: 'keyword', + 'suricata.eve.stats.decoder.ipv4_in_ipv6': { + category: 'suricata', + name: 'suricata.eve.stats.decoder.ipv4_in_ipv6', + type: 'long', }, - 'fortinet.firewall.ruledata': { - category: 'fortinet', - description: 'Rule data ', - name: 'fortinet.firewall.ruledata', - type: 'keyword', + 'suricata.eve.stats.decoder.ieee8021ah': { + category: 'suricata', + name: 'suricata.eve.stats.decoder.ieee8021ah', + type: 'long', }, - 'fortinet.firewall.ruletype': { - category: 'fortinet', - description: 'Rule type ', - name: 'fortinet.firewall.ruletype', - type: 'keyword', + 'suricata.eve.stats.dns.memcap_global': { + category: 'suricata', + name: 'suricata.eve.stats.dns.memcap_global', + type: 'long', }, - 'fortinet.firewall.scanned': { - category: 'fortinet', - description: 'Number of Scanned MMSs ', - name: 'fortinet.firewall.scanned', - type: 'integer', + 'suricata.eve.stats.dns.memcap_state': { + category: 'suricata', + name: 'suricata.eve.stats.dns.memcap_state', + type: 'long', }, - 'fortinet.firewall.scantime': { - category: 'fortinet', - description: 'Scanned time ', - name: 'fortinet.firewall.scantime', + 'suricata.eve.stats.dns.memuse': { + category: 'suricata', + name: 'suricata.eve.stats.dns.memuse', type: 'long', }, - 'fortinet.firewall.scope': { - category: 'fortinet', - description: 'FortiGuard Override Scope ', - name: 'fortinet.firewall.scope', - type: 'keyword', + 'suricata.eve.stats.flow_mgr.rows_busy': { + category: 'suricata', + name: 'suricata.eve.stats.flow_mgr.rows_busy', + type: 'long', }, - 'fortinet.firewall.security': { - category: 'fortinet', - description: 'Wireless rogue security ', - name: 'fortinet.firewall.security', - type: 'keyword', + 'suricata.eve.stats.flow_mgr.flows_timeout': { + category: 'suricata', + name: 'suricata.eve.stats.flow_mgr.flows_timeout', + type: 'long', }, - 'fortinet.firewall.sensitivity': { - category: 'fortinet', - description: 'Sensitivity for document fingerprint ', - name: 'fortinet.firewall.sensitivity', - type: 'keyword', + 'suricata.eve.stats.flow_mgr.flows_notimeout': { + category: 'suricata', + name: 'suricata.eve.stats.flow_mgr.flows_notimeout', + type: 'long', }, - 'fortinet.firewall.sensor': { - category: 'fortinet', - description: 'NAC Sensor Name ', - name: 'fortinet.firewall.sensor', - type: 'keyword', + 'suricata.eve.stats.flow_mgr.rows_skipped': { + category: 'suricata', + name: 'suricata.eve.stats.flow_mgr.rows_skipped', + type: 'long', }, - 'fortinet.firewall.sentdelta': { - category: 'fortinet', - description: 'Sent bytes delta ', - name: 'fortinet.firewall.sentdelta', - type: 'keyword', + 'suricata.eve.stats.flow_mgr.closed_pruned': { + category: 'suricata', + name: 'suricata.eve.stats.flow_mgr.closed_pruned', + type: 'long', }, - 'fortinet.firewall.seq': { - category: 'fortinet', - description: 'Sequence number ', - name: 'fortinet.firewall.seq', - type: 'keyword', + 'suricata.eve.stats.flow_mgr.new_pruned': { + category: 'suricata', + name: 'suricata.eve.stats.flow_mgr.new_pruned', + type: 'long', }, - 'fortinet.firewall.serial': { - category: 'fortinet', - description: 'WAN optimisation serial ', - name: 'fortinet.firewall.serial', - type: 'keyword', + 'suricata.eve.stats.flow_mgr.flows_removed': { + category: 'suricata', + name: 'suricata.eve.stats.flow_mgr.flows_removed', + type: 'long', }, - 'fortinet.firewall.serialno': { - category: 'fortinet', - description: 'Serial number ', - name: 'fortinet.firewall.serialno', - type: 'keyword', + 'suricata.eve.stats.flow_mgr.bypassed_pruned': { + category: 'suricata', + name: 'suricata.eve.stats.flow_mgr.bypassed_pruned', + type: 'long', }, - 'fortinet.firewall.server': { - category: 'fortinet', - description: 'AD server FQDN or IP ', - name: 'fortinet.firewall.server', - type: 'keyword', + 'suricata.eve.stats.flow_mgr.est_pruned': { + category: 'suricata', + name: 'suricata.eve.stats.flow_mgr.est_pruned', + type: 'long', }, - 'fortinet.firewall.session_id': { - category: 'fortinet', - description: 'Session ID ', - name: 'fortinet.firewall.session_id', - type: 'keyword', + 'suricata.eve.stats.flow_mgr.flows_timeout_inuse': { + category: 'suricata', + name: 'suricata.eve.stats.flow_mgr.flows_timeout_inuse', + type: 'long', }, - 'fortinet.firewall.sessionid': { - category: 'fortinet', - description: 'WAD Session ID ', - name: 'fortinet.firewall.sessionid', - type: 'integer', + 'suricata.eve.stats.flow_mgr.flows_checked': { + category: 'suricata', + name: 'suricata.eve.stats.flow_mgr.flows_checked', + type: 'long', }, - 'fortinet.firewall.setuprate': { - category: 'fortinet', - description: 'Session Setup Rate ', - name: 'fortinet.firewall.setuprate', + 'suricata.eve.stats.flow_mgr.rows_maxlen': { + category: 'suricata', + name: 'suricata.eve.stats.flow_mgr.rows_maxlen', type: 'long', }, - 'fortinet.firewall.severity': { - category: 'fortinet', - description: 'Severity ', - name: 'fortinet.firewall.severity', - type: 'keyword', + 'suricata.eve.stats.flow_mgr.rows_checked': { + category: 'suricata', + name: 'suricata.eve.stats.flow_mgr.rows_checked', + type: 'long', }, - 'fortinet.firewall.shaperdroprcvdbyte': { - category: 'fortinet', - description: 'Received bytes dropped by shaper ', - name: 'fortinet.firewall.shaperdroprcvdbyte', - type: 'integer', + 'suricata.eve.stats.flow_mgr.rows_empty': { + category: 'suricata', + name: 'suricata.eve.stats.flow_mgr.rows_empty', + type: 'long', }, - 'fortinet.firewall.shaperdropsentbyte': { - category: 'fortinet', - description: 'Sent bytes dropped by shaper ', - name: 'fortinet.firewall.shaperdropsentbyte', - type: 'integer', + 'suricata.eve.stats.app_layer.flow.tls': { + category: 'suricata', + name: 'suricata.eve.stats.app_layer.flow.tls', + type: 'long', }, - 'fortinet.firewall.shaperperipdropbyte': { - category: 'fortinet', - description: 'Dropped bytes per IP by shaper ', - name: 'fortinet.firewall.shaperperipdropbyte', - type: 'integer', + 'suricata.eve.stats.app_layer.flow.ftp': { + category: 'suricata', + name: 'suricata.eve.stats.app_layer.flow.ftp', + type: 'long', }, - 'fortinet.firewall.shaperperipname': { - category: 'fortinet', - description: 'Traffic shaper name (per IP) ', - name: 'fortinet.firewall.shaperperipname', - type: 'keyword', + 'suricata.eve.stats.app_layer.flow.http': { + category: 'suricata', + name: 'suricata.eve.stats.app_layer.flow.http', + type: 'long', }, - 'fortinet.firewall.shaperrcvdname': { - category: 'fortinet', - description: 'Traffic shaper name for received traffic ', - name: 'fortinet.firewall.shaperrcvdname', - type: 'keyword', + 'suricata.eve.stats.app_layer.flow.failed_udp': { + category: 'suricata', + name: 'suricata.eve.stats.app_layer.flow.failed_udp', + type: 'long', }, - 'fortinet.firewall.shapersentname': { - category: 'fortinet', - description: 'Traffic shaper name for sent traffic ', - name: 'fortinet.firewall.shapersentname', - type: 'keyword', + 'suricata.eve.stats.app_layer.flow.dns_udp': { + category: 'suricata', + name: 'suricata.eve.stats.app_layer.flow.dns_udp', + type: 'long', }, - 'fortinet.firewall.shapingpolicyid': { - category: 'fortinet', - description: 'Traffic shaper policy ID ', - name: 'fortinet.firewall.shapingpolicyid', - type: 'integer', + 'suricata.eve.stats.app_layer.flow.dns_tcp': { + category: 'suricata', + name: 'suricata.eve.stats.app_layer.flow.dns_tcp', + type: 'long', }, - 'fortinet.firewall.signal': { - category: 'fortinet', - description: 'Wireless rogue API signal ', - name: 'fortinet.firewall.signal', - type: 'integer', + 'suricata.eve.stats.app_layer.flow.smtp': { + category: 'suricata', + name: 'suricata.eve.stats.app_layer.flow.smtp', + type: 'long', }, - 'fortinet.firewall.size': { - category: 'fortinet', - description: 'Email size in bytes ', - name: 'fortinet.firewall.size', + 'suricata.eve.stats.app_layer.flow.failed_tcp': { + category: 'suricata', + name: 'suricata.eve.stats.app_layer.flow.failed_tcp', type: 'long', }, - 'fortinet.firewall.slot': { - category: 'fortinet', - description: 'Slot number ', - name: 'fortinet.firewall.slot', - type: 'integer', + 'suricata.eve.stats.app_layer.flow.msn': { + category: 'suricata', + name: 'suricata.eve.stats.app_layer.flow.msn', + type: 'long', }, - 'fortinet.firewall.sn': { - category: 'fortinet', - description: 'Security fabric serial number ', - name: 'fortinet.firewall.sn', - type: 'keyword', + 'suricata.eve.stats.app_layer.flow.ssh': { + category: 'suricata', + name: 'suricata.eve.stats.app_layer.flow.ssh', + type: 'long', }, - 'fortinet.firewall.snclosest': { - category: 'fortinet', - description: 'SN of the AP closest to the rogue AP ', - name: 'fortinet.firewall.snclosest', - type: 'keyword', + 'suricata.eve.stats.app_layer.flow.imap': { + category: 'suricata', + name: 'suricata.eve.stats.app_layer.flow.imap', + type: 'long', }, - 'fortinet.firewall.sndetected': { - category: 'fortinet', - description: 'SN of the AP which detected the rogue AP ', - name: 'fortinet.firewall.sndetected', - type: 'keyword', + 'suricata.eve.stats.app_layer.flow.dcerpc_udp': { + category: 'suricata', + name: 'suricata.eve.stats.app_layer.flow.dcerpc_udp', + type: 'long', }, - 'fortinet.firewall.snmeshparent': { - category: 'fortinet', - description: 'SN of the mesh parent ', - name: 'fortinet.firewall.snmeshparent', - type: 'keyword', + 'suricata.eve.stats.app_layer.flow.dcerpc_tcp': { + category: 'suricata', + name: 'suricata.eve.stats.app_layer.flow.dcerpc_tcp', + type: 'long', }, - 'fortinet.firewall.spi': { - category: 'fortinet', - description: 'IPSEC SPI ', - name: 'fortinet.firewall.spi', - type: 'keyword', + 'suricata.eve.stats.app_layer.flow.smb': { + category: 'suricata', + name: 'suricata.eve.stats.app_layer.flow.smb', + type: 'long', }, - 'fortinet.firewall.src_int': { - category: 'fortinet', - description: 'Source interface ', - name: 'fortinet.firewall.src_int', - type: 'keyword', + 'suricata.eve.stats.app_layer.tx.tls': { + category: 'suricata', + name: 'suricata.eve.stats.app_layer.tx.tls', + type: 'long', }, - 'fortinet.firewall.srcintfrole': { - category: 'fortinet', - description: 'Source interface role ', - name: 'fortinet.firewall.srcintfrole', - type: 'keyword', + 'suricata.eve.stats.app_layer.tx.ftp': { + category: 'suricata', + name: 'suricata.eve.stats.app_layer.tx.ftp', + type: 'long', }, - 'fortinet.firewall.srccountry': { - category: 'fortinet', - description: 'Source country ', - name: 'fortinet.firewall.srccountry', - type: 'keyword', + 'suricata.eve.stats.app_layer.tx.http': { + category: 'suricata', + name: 'suricata.eve.stats.app_layer.tx.http', + type: 'long', }, - 'fortinet.firewall.srcfamily': { - category: 'fortinet', - description: 'Source family ', - name: 'fortinet.firewall.srcfamily', - type: 'keyword', + 'suricata.eve.stats.app_layer.tx.dns_udp': { + category: 'suricata', + name: 'suricata.eve.stats.app_layer.tx.dns_udp', + type: 'long', }, - 'fortinet.firewall.srchwvendor': { - category: 'fortinet', - description: 'Source hardware vendor ', - name: 'fortinet.firewall.srchwvendor', - type: 'keyword', + 'suricata.eve.stats.app_layer.tx.dns_tcp': { + category: 'suricata', + name: 'suricata.eve.stats.app_layer.tx.dns_tcp', + type: 'long', }, - 'fortinet.firewall.srchwversion': { - category: 'fortinet', - description: 'Source hardware version ', - name: 'fortinet.firewall.srchwversion', - type: 'keyword', + 'suricata.eve.stats.app_layer.tx.smtp': { + category: 'suricata', + name: 'suricata.eve.stats.app_layer.tx.smtp', + type: 'long', }, - 'fortinet.firewall.srcinetsvc': { - category: 'fortinet', - description: 'Source interface service ', - name: 'fortinet.firewall.srcinetsvc', - type: 'keyword', + 'suricata.eve.stats.app_layer.tx.ssh': { + category: 'suricata', + name: 'suricata.eve.stats.app_layer.tx.ssh', + type: 'long', }, - 'fortinet.firewall.srcname': { - category: 'fortinet', - description: 'Source name ', - name: 'fortinet.firewall.srcname', - type: 'keyword', + 'suricata.eve.stats.app_layer.tx.dcerpc_udp': { + category: 'suricata', + name: 'suricata.eve.stats.app_layer.tx.dcerpc_udp', + type: 'long', }, - 'fortinet.firewall.srcserver': { - category: 'fortinet', - description: 'Source server ', - name: 'fortinet.firewall.srcserver', - type: 'integer', + 'suricata.eve.stats.app_layer.tx.dcerpc_tcp': { + category: 'suricata', + name: 'suricata.eve.stats.app_layer.tx.dcerpc_tcp', + type: 'long', }, - 'fortinet.firewall.srcssid': { - category: 'fortinet', - description: 'Source SSID ', - name: 'fortinet.firewall.srcssid', - type: 'keyword', + 'suricata.eve.stats.app_layer.tx.smb': { + category: 'suricata', + name: 'suricata.eve.stats.app_layer.tx.smb', + type: 'long', }, - 'fortinet.firewall.srcswversion': { - category: 'fortinet', - description: 'Source software version ', - name: 'fortinet.firewall.srcswversion', - type: 'keyword', + 'suricata.eve.tls.notbefore': { + category: 'suricata', + name: 'suricata.eve.tls.notbefore', + type: 'date', }, - 'fortinet.firewall.srcuuid': { - category: 'fortinet', - description: 'Source UUID ', - name: 'fortinet.firewall.srcuuid', + 'suricata.eve.tls.issuerdn': { + category: 'suricata', + name: 'suricata.eve.tls.issuerdn', type: 'keyword', }, - 'fortinet.firewall.sscname': { - category: 'fortinet', - description: 'SSC name ', - name: 'fortinet.firewall.sscname', + 'suricata.eve.tls.sni': { + category: 'suricata', + name: 'suricata.eve.tls.sni', type: 'keyword', }, - 'fortinet.firewall.ssid': { - category: 'fortinet', - description: 'Base Service Set ID ', - name: 'fortinet.firewall.ssid', + 'suricata.eve.tls.version': { + category: 'suricata', + name: 'suricata.eve.tls.version', type: 'keyword', }, - 'fortinet.firewall.sslaction': { - category: 'fortinet', - description: 'SSL Action ', - name: 'fortinet.firewall.sslaction', - type: 'keyword', + 'suricata.eve.tls.session_resumed': { + category: 'suricata', + name: 'suricata.eve.tls.session_resumed', + type: 'boolean', }, - 'fortinet.firewall.ssllocal': { - category: 'fortinet', - description: 'WAD SSL local ', - name: 'fortinet.firewall.ssllocal', + 'suricata.eve.tls.fingerprint': { + category: 'suricata', + name: 'suricata.eve.tls.fingerprint', type: 'keyword', }, - 'fortinet.firewall.sslremote': { - category: 'fortinet', - description: 'WAD SSL remote ', - name: 'fortinet.firewall.sslremote', + 'suricata.eve.tls.serial': { + category: 'suricata', + name: 'suricata.eve.tls.serial', type: 'keyword', }, - 'fortinet.firewall.stacount': { - category: 'fortinet', - description: 'Number of stations/clients ', - name: 'fortinet.firewall.stacount', - type: 'integer', + 'suricata.eve.tls.notafter': { + category: 'suricata', + name: 'suricata.eve.tls.notafter', + type: 'date', }, - 'fortinet.firewall.stage': { - category: 'fortinet', - description: 'IPSEC stage ', - name: 'fortinet.firewall.stage', + 'suricata.eve.tls.subject': { + category: 'suricata', + name: 'suricata.eve.tls.subject', type: 'keyword', }, - 'fortinet.firewall.stamac': { - category: 'fortinet', - description: '802.1x station mac ', - name: 'fortinet.firewall.stamac', + 'suricata.eve.tls.ja3s.string': { + category: 'suricata', + name: 'suricata.eve.tls.ja3s.string', type: 'keyword', }, - 'fortinet.firewall.state': { - category: 'fortinet', - description: 'Admin login state ', - name: 'fortinet.firewall.state', + 'suricata.eve.tls.ja3s.hash': { + category: 'suricata', + name: 'suricata.eve.tls.ja3s.hash', type: 'keyword', }, - 'fortinet.firewall.status': { - category: 'fortinet', - description: 'Status ', - name: 'fortinet.firewall.status', + 'suricata.eve.tls.ja3.string': { + category: 'suricata', + name: 'suricata.eve.tls.ja3.string', type: 'keyword', }, - 'fortinet.firewall.stitch': { - category: 'fortinet', - description: 'Automation stitch triggered ', - name: 'fortinet.firewall.stitch', + 'suricata.eve.tls.ja3.hash': { + category: 'suricata', + name: 'suricata.eve.tls.ja3.hash', type: 'keyword', }, - 'fortinet.firewall.subject': { - category: 'fortinet', - description: 'Email subject ', - name: 'fortinet.firewall.subject', + 'suricata.eve.app_proto_ts': { + category: 'suricata', + name: 'suricata.eve.app_proto_ts', type: 'keyword', }, - 'fortinet.firewall.submodule': { - category: 'fortinet', - description: 'Configuration Sub-Module Name ', - name: 'fortinet.firewall.submodule', - type: 'keyword', + 'suricata.eve.flow.age': { + category: 'suricata', + name: 'suricata.eve.flow.age', + type: 'long', }, - 'fortinet.firewall.subservice': { - category: 'fortinet', - description: 'AV subservice ', - name: 'fortinet.firewall.subservice', + 'suricata.eve.flow.state': { + category: 'suricata', + name: 'suricata.eve.flow.state', type: 'keyword', }, - 'fortinet.firewall.subtype': { - category: 'fortinet', - description: 'Log subtype ', - name: 'fortinet.firewall.subtype', + 'suricata.eve.flow.reason': { + category: 'suricata', + name: 'suricata.eve.flow.reason', type: 'keyword', }, - 'fortinet.firewall.suspicious': { - category: 'fortinet', - description: 'Number of Suspicious MMSs ', - name: 'fortinet.firewall.suspicious', - type: 'integer', + 'suricata.eve.flow.alerted': { + category: 'suricata', + name: 'suricata.eve.flow.alerted', + type: 'boolean', }, - 'fortinet.firewall.switchproto': { - category: 'fortinet', - description: 'Protocol change information ', - name: 'fortinet.firewall.switchproto', - type: 'keyword', + 'suricata.eve.tx_id': { + category: 'suricata', + name: 'suricata.eve.tx_id', + type: 'long', }, - 'fortinet.firewall.sync_status': { - category: 'fortinet', - description: 'The sync status with the master ', - name: 'fortinet.firewall.sync_status', + 'suricata.eve.app_proto_tc': { + category: 'suricata', + name: 'suricata.eve.app_proto_tc', type: 'keyword', }, - 'fortinet.firewall.sync_type': { - category: 'fortinet', - description: 'The sync type with the master ', - name: 'fortinet.firewall.sync_type', + 'suricata.eve.smtp.rcpt_to': { + category: 'suricata', + name: 'suricata.eve.smtp.rcpt_to', type: 'keyword', }, - 'fortinet.firewall.sysuptime': { - category: 'fortinet', - description: 'System uptime ', - name: 'fortinet.firewall.sysuptime', + 'suricata.eve.smtp.mail_from': { + category: 'suricata', + name: 'suricata.eve.smtp.mail_from', type: 'keyword', }, - 'fortinet.firewall.tamac': { - category: 'fortinet', - description: 'the MAC address of Transmitter, if none, then Receiver ', - name: 'fortinet.firewall.tamac', + 'suricata.eve.smtp.helo': { + category: 'suricata', + name: 'suricata.eve.smtp.helo', type: 'keyword', }, - 'fortinet.firewall.threattype': { - category: 'fortinet', - description: 'WIDS threat type ', - name: 'fortinet.firewall.threattype', + 'suricata.eve.app_proto_expected': { + category: 'suricata', + name: 'suricata.eve.app_proto_expected', type: 'keyword', }, - 'fortinet.firewall.time': { - category: 'fortinet', - description: 'Time of the event ', - name: 'fortinet.firewall.time', - type: 'keyword', + 'suricata.eve.flags': { + category: 'suricata', + name: 'suricata.eve.flags', + type: 'group', }, - 'fortinet.firewall.to': { - category: 'fortinet', - description: 'Email to field ', - name: 'fortinet.firewall.to', + 'zeek.session_id': { + category: 'zeek', + description: 'A unique identifier of the session ', + name: 'zeek.session_id', type: 'keyword', }, - 'fortinet.firewall.to_vcluster': { - category: 'fortinet', - description: 'destination virtual cluster number ', - name: 'fortinet.firewall.to_vcluster', + 'zeek.capture_loss.ts_delta': { + category: 'zeek', + description: 'The time delay between this measurement and the last. ', + name: 'zeek.capture_loss.ts_delta', type: 'integer', }, - 'fortinet.firewall.total': { - category: 'fortinet', - description: 'Total memory ', - name: 'fortinet.firewall.total', + 'zeek.capture_loss.peer': { + category: 'zeek', + description: + 'In the event that there are multiple Bro instances logging to the same host, this distinguishes each peer with its individual name. ', + name: 'zeek.capture_loss.peer', + type: 'keyword', + }, + 'zeek.capture_loss.gaps': { + category: 'zeek', + description: 'Number of missed ACKs from the previous measurement interval. ', + name: 'zeek.capture_loss.gaps', type: 'integer', }, - 'fortinet.firewall.totalsession': { - category: 'fortinet', - description: 'Total Number of Sessions ', - name: 'fortinet.firewall.totalsession', + 'zeek.capture_loss.acks': { + category: 'zeek', + description: 'Total number of ACKs seen in the previous measurement interval. ', + name: 'zeek.capture_loss.acks', type: 'integer', }, - 'fortinet.firewall.trace_id': { - category: 'fortinet', - description: 'Session clash trace ID ', - name: 'fortinet.firewall.trace_id', - type: 'keyword', + 'zeek.capture_loss.percent_lost': { + category: 'zeek', + description: "Percentage of ACKs seen where the data being ACKed wasn't seen. ", + name: 'zeek.capture_loss.percent_lost', + type: 'double', }, - 'fortinet.firewall.trandisp': { - category: 'fortinet', - description: 'NAT translation type ', - name: 'fortinet.firewall.trandisp', - type: 'keyword', + 'zeek.connection.local_orig': { + category: 'zeek', + description: 'Indicates whether the session is originated locally. ', + name: 'zeek.connection.local_orig', + type: 'boolean', }, - 'fortinet.firewall.transid': { - category: 'fortinet', - description: 'HTTP transaction ID ', - name: 'fortinet.firewall.transid', - type: 'integer', + 'zeek.connection.local_resp': { + category: 'zeek', + description: 'Indicates whether the session is responded locally. ', + name: 'zeek.connection.local_resp', + type: 'boolean', }, - 'fortinet.firewall.translationid': { - category: 'fortinet', - description: 'DNS filter transaltion ID ', - name: 'fortinet.firewall.translationid', - type: 'keyword', + 'zeek.connection.missed_bytes': { + category: 'zeek', + description: 'Missed bytes for the session. ', + name: 'zeek.connection.missed_bytes', + type: 'long', }, - 'fortinet.firewall.trigger': { - category: 'fortinet', - description: 'Automation stitch trigger ', - name: 'fortinet.firewall.trigger', + 'zeek.connection.state': { + category: 'zeek', + description: 'Code indicating the state of the session. ', + name: 'zeek.connection.state', type: 'keyword', }, - 'fortinet.firewall.trueclntip': { - category: 'fortinet', - description: 'File filter true client IP ', - name: 'fortinet.firewall.trueclntip', - type: 'ip', + 'zeek.connection.state_message': { + category: 'zeek', + description: 'The state of the session. ', + name: 'zeek.connection.state_message', + type: 'keyword', }, - 'fortinet.firewall.tunnelid': { - category: 'fortinet', - description: 'IPSEC tunnel ID ', - name: 'fortinet.firewall.tunnelid', + 'zeek.connection.icmp.type': { + category: 'zeek', + description: 'ICMP message type. ', + name: 'zeek.connection.icmp.type', type: 'integer', }, - 'fortinet.firewall.tunnelip': { - category: 'fortinet', - description: 'IPSEC tunnel IP ', - name: 'fortinet.firewall.tunnelip', - type: 'ip', - }, - 'fortinet.firewall.tunneltype': { - category: 'fortinet', - description: 'IPSEC tunnel type ', - name: 'fortinet.firewall.tunneltype', - type: 'keyword', - }, - 'fortinet.firewall.type': { - category: 'fortinet', - description: 'Module type ', - name: 'fortinet.firewall.type', - type: 'keyword', + 'zeek.connection.icmp.code': { + category: 'zeek', + description: 'ICMP message code. ', + name: 'zeek.connection.icmp.code', + type: 'integer', }, - 'fortinet.firewall.ui': { - category: 'fortinet', - description: 'Admin authentication UI type ', - name: 'fortinet.firewall.ui', + 'zeek.connection.history': { + category: 'zeek', + description: 'Flags indicating the history of the session. ', + name: 'zeek.connection.history', type: 'keyword', }, - 'fortinet.firewall.unauthusersource': { - category: 'fortinet', - description: 'Unauthenticated user source ', - name: 'fortinet.firewall.unauthusersource', - type: 'keyword', + 'zeek.connection.vlan': { + category: 'zeek', + description: 'VLAN identifier. ', + name: 'zeek.connection.vlan', + type: 'integer', }, - 'fortinet.firewall.unit': { - category: 'fortinet', - description: 'Power supply unit ', - name: 'fortinet.firewall.unit', + 'zeek.connection.inner_vlan': { + category: 'zeek', + description: 'VLAN identifier. ', + name: 'zeek.connection.inner_vlan', type: 'integer', }, - 'fortinet.firewall.urlfilteridx': { - category: 'fortinet', - description: 'URL filter ID ', - name: 'fortinet.firewall.urlfilteridx', + 'zeek.dce_rpc.rtt': { + category: 'zeek', + description: + "Round trip time from the request to the response. If either the request or response wasn't seen, this will be null. ", + name: 'zeek.dce_rpc.rtt', type: 'integer', }, - 'fortinet.firewall.urlfilterlist': { - category: 'fortinet', - description: 'URL filter list ', - name: 'fortinet.firewall.urlfilterlist', + 'zeek.dce_rpc.named_pipe': { + category: 'zeek', + description: 'Remote pipe name. ', + name: 'zeek.dce_rpc.named_pipe', type: 'keyword', }, - 'fortinet.firewall.urlsource': { - category: 'fortinet', - description: 'URL filter source ', - name: 'fortinet.firewall.urlsource', + 'zeek.dce_rpc.endpoint': { + category: 'zeek', + description: 'Endpoint name looked up from the uuid. ', + name: 'zeek.dce_rpc.endpoint', type: 'keyword', }, - 'fortinet.firewall.urltype': { - category: 'fortinet', - description: 'URL filter type ', - name: 'fortinet.firewall.urltype', + 'zeek.dce_rpc.operation': { + category: 'zeek', + description: 'Operation seen in the call. ', + name: 'zeek.dce_rpc.operation', type: 'keyword', }, - 'fortinet.firewall.used': { - category: 'fortinet', - description: 'Number of Used IPs ', - name: 'fortinet.firewall.used', - type: 'integer', - }, - 'fortinet.firewall.used_for_type': { - category: 'fortinet', - description: 'Connection for the type ', - name: 'fortinet.firewall.used_for_type', - type: 'integer', - }, - 'fortinet.firewall.utmaction': { - category: 'fortinet', - description: 'Security action performed by UTM ', - name: 'fortinet.firewall.utmaction', + 'zeek.dhcp.domain': { + category: 'zeek', + description: 'Domain given by the server in option 15. ', + name: 'zeek.dhcp.domain', type: 'keyword', }, - 'fortinet.firewall.vap': { - category: 'fortinet', - description: 'Virtual AP ', - name: 'fortinet.firewall.vap', + 'zeek.dhcp.duration': { + category: 'zeek', + description: + 'Duration of the DHCP session representing the time from the first message to the last, in seconds. ', + name: 'zeek.dhcp.duration', + type: 'double', + }, + 'zeek.dhcp.hostname': { + category: 'zeek', + description: 'Name given by client in Hostname option 12. ', + name: 'zeek.dhcp.hostname', type: 'keyword', }, - 'fortinet.firewall.vapmode': { - category: 'fortinet', - description: 'Virtual AP mode ', - name: 'fortinet.firewall.vapmode', + 'zeek.dhcp.client_fqdn': { + category: 'zeek', + description: 'FQDN given by client in Client FQDN option 81. ', + name: 'zeek.dhcp.client_fqdn', type: 'keyword', }, - 'fortinet.firewall.vcluster': { - category: 'fortinet', - description: 'virtual cluster id ', - name: 'fortinet.firewall.vcluster', + 'zeek.dhcp.lease_time': { + category: 'zeek', + description: 'IP address lease interval in seconds. ', + name: 'zeek.dhcp.lease_time', type: 'integer', }, - 'fortinet.firewall.vcluster_member': { - category: 'fortinet', - description: 'Virtual cluster member ', - name: 'fortinet.firewall.vcluster_member', - type: 'integer', + 'zeek.dhcp.address.assigned': { + category: 'zeek', + description: 'IP address assigned by the server. ', + name: 'zeek.dhcp.address.assigned', + type: 'ip', }, - 'fortinet.firewall.vcluster_state': { - category: 'fortinet', - description: 'Virtual cluster state ', - name: 'fortinet.firewall.vcluster_state', - type: 'keyword', + 'zeek.dhcp.address.client': { + category: 'zeek', + description: + 'IP address of the client. If a transaction is only a client sending INFORM messages then there is no lease information exchanged so this is helpful to know who sent the messages. Getting an address in this field does require that the client sources at least one DHCP message using a non-broadcast address. ', + name: 'zeek.dhcp.address.client', + type: 'ip', }, - 'fortinet.firewall.vd': { - category: 'fortinet', - description: 'Virtual Domain Name ', - name: 'fortinet.firewall.vd', + 'zeek.dhcp.address.mac': { + category: 'zeek', + description: "Client's hardware address. ", + name: 'zeek.dhcp.address.mac', type: 'keyword', }, - 'fortinet.firewall.vdname': { - category: 'fortinet', - description: 'Virtual Domain Name ', - name: 'fortinet.firewall.vdname', - type: 'keyword', + 'zeek.dhcp.address.requested': { + category: 'zeek', + description: 'IP address requested by the client. ', + name: 'zeek.dhcp.address.requested', + type: 'ip', }, - 'fortinet.firewall.vendorurl': { - category: 'fortinet', - description: 'Vulnerability scan vendor name ', - name: 'fortinet.firewall.vendorurl', - type: 'keyword', + 'zeek.dhcp.address.server': { + category: 'zeek', + description: 'IP address of the DHCP server. ', + name: 'zeek.dhcp.address.server', + type: 'ip', }, - 'fortinet.firewall.version': { - category: 'fortinet', - description: 'Version ', - name: 'fortinet.firewall.version', + 'zeek.dhcp.msg.types': { + category: 'zeek', + description: 'List of DHCP message types seen in this exchange. ', + name: 'zeek.dhcp.msg.types', type: 'keyword', }, - 'fortinet.firewall.vip': { - category: 'fortinet', - description: 'Virtual IP ', - name: 'fortinet.firewall.vip', + 'zeek.dhcp.msg.origin': { + category: 'zeek', + description: + '(present if policy/protocols/dhcp/msg-orig.bro is loaded) The address that originated each message from the msg.types field. ', + name: 'zeek.dhcp.msg.origin', + type: 'ip', + }, + 'zeek.dhcp.msg.client': { + category: 'zeek', + description: + 'Message typically accompanied with a DHCP_DECLINE so the client can tell the server why it rejected an address. ', + name: 'zeek.dhcp.msg.client', type: 'keyword', }, - 'fortinet.firewall.virus': { - category: 'fortinet', - description: 'Virus name ', - name: 'fortinet.firewall.virus', + 'zeek.dhcp.msg.server': { + category: 'zeek', + description: + 'Message typically accompanied with a DHCP_NAK to let the client know why it rejected the request. ', + name: 'zeek.dhcp.msg.server', type: 'keyword', }, - 'fortinet.firewall.virusid': { - category: 'fortinet', - description: 'Virus ID (unique virus identifier) ', - name: 'fortinet.firewall.virusid', - type: 'integer', + 'zeek.dhcp.software.client': { + category: 'zeek', + description: + '(present if policy/protocols/dhcp/software.bro is loaded) Software reported by the client in the vendor_class option. ', + name: 'zeek.dhcp.software.client', + type: 'keyword', }, - 'fortinet.firewall.voip_proto': { - category: 'fortinet', - description: 'VOIP protocol ', - name: 'fortinet.firewall.voip_proto', + 'zeek.dhcp.software.server': { + category: 'zeek', + description: + '(present if policy/protocols/dhcp/software.bro is loaded) Software reported by the client in the vendor_class option. ', + name: 'zeek.dhcp.software.server', type: 'keyword', }, - 'fortinet.firewall.vpn': { - category: 'fortinet', - description: 'VPN description ', - name: 'fortinet.firewall.vpn', + 'zeek.dhcp.id.circuit': { + category: 'zeek', + description: + '(present if policy/protocols/dhcp/sub-opts.bro is loaded) Added by DHCP relay agents which terminate switched or permanent circuits. It encodes an agent-local identifier of the circuit from which a DHCP client-to-server packet was received. Typically it should represent a router or switch interface number. ', + name: 'zeek.dhcp.id.circuit', type: 'keyword', }, - 'fortinet.firewall.vpntunnel': { - category: 'fortinet', - description: 'IPsec Vpn Tunnel Name ', - name: 'fortinet.firewall.vpntunnel', + 'zeek.dhcp.id.remote_agent': { + category: 'zeek', + description: + '(present if policy/protocols/dhcp/sub-opts.bro is loaded) A globally unique identifier added by relay agents to identify the remote host end of the circuit. ', + name: 'zeek.dhcp.id.remote_agent', type: 'keyword', }, - 'fortinet.firewall.vpntype': { - category: 'fortinet', - description: 'The type of the VPN tunnel ', - name: 'fortinet.firewall.vpntype', + 'zeek.dhcp.id.subscriber': { + category: 'zeek', + description: + "(present if policy/protocols/dhcp/sub-opts.bro is loaded) The subscriber ID is a value independent of the physical network configuration so that a customer's DHCP configuration can be given to them correctly no matter where they are physically connected. ", + name: 'zeek.dhcp.id.subscriber', type: 'keyword', }, - 'fortinet.firewall.vrf': { - category: 'fortinet', - description: 'VRF number ', - name: 'fortinet.firewall.vrf', - type: 'integer', + 'zeek.dnp3.function.request': { + category: 'zeek', + description: 'The name of the function message in the request. ', + name: 'zeek.dnp3.function.request', + type: 'keyword', }, - 'fortinet.firewall.vulncat': { - category: 'fortinet', - description: 'Vulnerability Category ', - name: 'fortinet.firewall.vulncat', + 'zeek.dnp3.function.reply': { + category: 'zeek', + description: 'The name of the function message in the reply. ', + name: 'zeek.dnp3.function.reply', type: 'keyword', }, - 'fortinet.firewall.vulnid': { - category: 'fortinet', - description: 'Vulnerability ID ', - name: 'fortinet.firewall.vulnid', + 'zeek.dnp3.id': { + category: 'zeek', + description: "The response's internal indication number. ", + name: 'zeek.dnp3.id', type: 'integer', }, - 'fortinet.firewall.vulnname': { - category: 'fortinet', - description: 'Vulnerability name ', - name: 'fortinet.firewall.vulnname', + 'zeek.dns.trans_id': { + category: 'zeek', + description: 'DNS transaction identifier. ', + name: 'zeek.dns.trans_id', type: 'keyword', }, - 'fortinet.firewall.vwlid': { - category: 'fortinet', - description: 'VWL ID ', - name: 'fortinet.firewall.vwlid', - type: 'integer', + 'zeek.dns.rtt': { + category: 'zeek', + description: 'Round trip time for the query and response. ', + name: 'zeek.dns.rtt', + type: 'double', }, - 'fortinet.firewall.vwlquality': { - category: 'fortinet', - description: 'VWL quality ', - name: 'fortinet.firewall.vwlquality', + 'zeek.dns.query': { + category: 'zeek', + description: 'The domain name that is the subject of the DNS query. ', + name: 'zeek.dns.query', type: 'keyword', }, - 'fortinet.firewall.vwlservice': { - category: 'fortinet', - description: 'VWL service ', - name: 'fortinet.firewall.vwlservice', - type: 'keyword', + 'zeek.dns.qclass': { + category: 'zeek', + description: 'The QCLASS value specifying the class of the query. ', + name: 'zeek.dns.qclass', + type: 'long', }, - 'fortinet.firewall.vwpvlanid': { - category: 'fortinet', - description: 'VWP VLAN ID ', - name: 'fortinet.firewall.vwpvlanid', - type: 'integer', + 'zeek.dns.qclass_name': { + category: 'zeek', + description: 'A descriptive name for the class of the query. ', + name: 'zeek.dns.qclass_name', + type: 'keyword', }, - 'fortinet.firewall.wanin': { - category: 'fortinet', - description: 'WAN incoming traffic in bytes ', - name: 'fortinet.firewall.wanin', + 'zeek.dns.qtype': { + category: 'zeek', + description: 'A QTYPE value specifying the type of the query. ', + name: 'zeek.dns.qtype', type: 'long', }, - 'fortinet.firewall.wanoptapptype': { - category: 'fortinet', - description: 'WAN Optimization Application type ', - name: 'fortinet.firewall.wanoptapptype', + 'zeek.dns.qtype_name': { + category: 'zeek', + description: 'A descriptive name for the type of the query. ', + name: 'zeek.dns.qtype_name', type: 'keyword', }, - 'fortinet.firewall.wanout': { - category: 'fortinet', - description: 'WAN outgoing traffic in bytes ', - name: 'fortinet.firewall.wanout', + 'zeek.dns.rcode': { + category: 'zeek', + description: 'The response code value in DNS response messages. ', + name: 'zeek.dns.rcode', type: 'long', }, - 'fortinet.firewall.weakwepiv': { - category: 'fortinet', - description: 'Weak Wep Initiation Vector ', - name: 'fortinet.firewall.weakwepiv', + 'zeek.dns.rcode_name': { + category: 'zeek', + description: 'A descriptive name for the response code value. ', + name: 'zeek.dns.rcode_name', type: 'keyword', }, - 'fortinet.firewall.xauthgroup': { - category: 'fortinet', - description: 'XAuth Group Name ', - name: 'fortinet.firewall.xauthgroup', - type: 'keyword', + 'zeek.dns.AA': { + category: 'zeek', + description: + 'The Authoritative Answer bit for response messages specifies that the responding name server is an authority for the domain name in the question section. ', + name: 'zeek.dns.AA', + type: 'boolean', }, - 'fortinet.firewall.xauthuser': { - category: 'fortinet', - description: 'XAuth User Name ', - name: 'fortinet.firewall.xauthuser', - type: 'keyword', + 'zeek.dns.TC': { + category: 'zeek', + description: 'The Truncation bit specifies that the message was truncated. ', + name: 'zeek.dns.TC', + type: 'boolean', }, - 'fortinet.firewall.xid': { - category: 'fortinet', - description: 'Wireless X ID ', - name: 'fortinet.firewall.xid', - type: 'integer', + 'zeek.dns.RD': { + category: 'zeek', + description: + 'The Recursion Desired bit in a request message indicates that the client wants recursive service for this query. ', + name: 'zeek.dns.RD', + type: 'boolean', }, - 'googlecloud.destination.instance.project_id': { - category: 'googlecloud', - description: 'ID of the project containing the VM. ', - name: 'googlecloud.destination.instance.project_id', - type: 'keyword', + 'zeek.dns.RA': { + category: 'zeek', + description: + 'The Recursion Available bit in a response message indicates that the name server supports recursive queries. ', + name: 'zeek.dns.RA', + type: 'boolean', }, - 'googlecloud.destination.instance.region': { - category: 'googlecloud', - description: 'Region of the VM. ', - name: 'googlecloud.destination.instance.region', + 'zeek.dns.answers': { + category: 'zeek', + description: 'The set of resource descriptions in the query answer. ', + name: 'zeek.dns.answers', type: 'keyword', }, - 'googlecloud.destination.instance.zone': { - category: 'googlecloud', - description: 'Zone of the VM. ', - name: 'googlecloud.destination.instance.zone', - type: 'keyword', + 'zeek.dns.TTLs': { + category: 'zeek', + description: 'The caching intervals of the associated RRs described by the answers field. ', + name: 'zeek.dns.TTLs', + type: 'double', }, - 'googlecloud.destination.vpc.project_id': { - category: 'googlecloud', - description: 'ID of the project containing the VM. ', - name: 'googlecloud.destination.vpc.project_id', - type: 'keyword', + 'zeek.dns.rejected': { + category: 'zeek', + description: 'Indicates whether the DNS query was rejected by the server. ', + name: 'zeek.dns.rejected', + type: 'boolean', }, - 'googlecloud.destination.vpc.vpc_name': { - category: 'googlecloud', - description: 'VPC on which the VM is operating. ', - name: 'googlecloud.destination.vpc.vpc_name', - type: 'keyword', + 'zeek.dns.total_answers': { + category: 'zeek', + description: 'The total number of resource records in the reply. ', + name: 'zeek.dns.total_answers', + type: 'integer', }, - 'googlecloud.destination.vpc.subnetwork_name': { - category: 'googlecloud', - description: 'Subnetwork on which the VM is operating. ', - name: 'googlecloud.destination.vpc.subnetwork_name', - type: 'keyword', + 'zeek.dns.total_replies': { + category: 'zeek', + description: 'The total number of resource records in the reply message. ', + name: 'zeek.dns.total_replies', + type: 'integer', }, - 'googlecloud.source.instance.project_id': { - category: 'googlecloud', - description: 'ID of the project containing the VM. ', - name: 'googlecloud.source.instance.project_id', - type: 'keyword', + 'zeek.dns.saw_query': { + category: 'zeek', + description: 'Whether the full DNS query has been seen. ', + name: 'zeek.dns.saw_query', + type: 'boolean', }, - 'googlecloud.source.instance.region': { - category: 'googlecloud', - description: 'Region of the VM. ', - name: 'googlecloud.source.instance.region', - type: 'keyword', + 'zeek.dns.saw_reply': { + category: 'zeek', + description: 'Whether the full DNS reply has been seen. ', + name: 'zeek.dns.saw_reply', + type: 'boolean', }, - 'googlecloud.source.instance.zone': { - category: 'googlecloud', - description: 'Zone of the VM. ', - name: 'googlecloud.source.instance.zone', + 'zeek.dpd.analyzer': { + category: 'zeek', + description: 'The analyzer that generated the violation. ', + name: 'zeek.dpd.analyzer', type: 'keyword', }, - 'googlecloud.source.vpc.project_id': { - category: 'googlecloud', - description: 'ID of the project containing the VM. ', - name: 'googlecloud.source.vpc.project_id', + 'zeek.dpd.failure_reason': { + category: 'zeek', + description: 'The textual reason for the analysis failure. ', + name: 'zeek.dpd.failure_reason', type: 'keyword', }, - 'googlecloud.source.vpc.vpc_name': { - category: 'googlecloud', - description: 'VPC on which the VM is operating. ', - name: 'googlecloud.source.vpc.vpc_name', + 'zeek.dpd.packet_segment': { + category: 'zeek', + description: + '(present if policy/frameworks/dpd/packet-segment-logging.bro is loaded) A chunk of the payload that most likely resulted in the protocol violation. ', + name: 'zeek.dpd.packet_segment', type: 'keyword', }, - 'googlecloud.source.vpc.subnetwork_name': { - category: 'googlecloud', - description: 'Subnetwork on which the VM is operating. ', - name: 'googlecloud.source.vpc.subnetwork_name', + 'zeek.files.fuid': { + category: 'zeek', + description: 'A file unique identifier. ', + name: 'zeek.files.fuid', type: 'keyword', }, - 'googlecloud.audit.type': { - category: 'googlecloud', - description: 'Type property. ', - name: 'googlecloud.audit.type', - type: 'keyword', + 'zeek.files.tx_host': { + category: 'zeek', + description: 'The host that transferred the file. ', + name: 'zeek.files.tx_host', + type: 'ip', }, - 'googlecloud.audit.authentication_info.principal_email': { - category: 'googlecloud', - description: 'The email address of the authenticated user making the request. ', - name: 'googlecloud.audit.authentication_info.principal_email', - type: 'keyword', + 'zeek.files.rx_host': { + category: 'zeek', + description: 'The host that received the file. ', + name: 'zeek.files.rx_host', + type: 'ip', }, - 'googlecloud.audit.authentication_info.authority_selector': { - category: 'googlecloud', - description: - 'The authority selector specified by the requestor, if any. It is not guaranteed that the principal was allowed to use this authority. ', - name: 'googlecloud.audit.authentication_info.authority_selector', + 'zeek.files.session_ids': { + category: 'zeek', + description: 'The sessions that have this file. ', + name: 'zeek.files.session_ids', type: 'keyword', }, - 'googlecloud.audit.authorization_info.permission': { - category: 'googlecloud', - description: 'The required IAM permission. ', - name: 'googlecloud.audit.authorization_info.permission', + 'zeek.files.source': { + category: 'zeek', + description: + 'An identification of the source of the file data. E.g. it may be a network protocol over which it was transferred, or a local file path which was read, or some other input source. ', + name: 'zeek.files.source', type: 'keyword', }, - 'googlecloud.audit.authorization_info.granted': { - category: 'googlecloud', - description: 'Whether or not authorization for resource and permission was granted. ', - name: 'googlecloud.audit.authorization_info.granted', - type: 'boolean', + 'zeek.files.depth': { + category: 'zeek', + description: + 'A value to represent the depth of this file in relation to its source. In SMTP, it is the depth of the MIME attachment on the message. In HTTP, it is the depth of the request within the TCP connection. ', + name: 'zeek.files.depth', + type: 'long', }, - 'googlecloud.audit.authorization_info.resource_attributes.service': { - category: 'googlecloud', - description: 'The name of the service. ', - name: 'googlecloud.audit.authorization_info.resource_attributes.service', + 'zeek.files.analyzers': { + category: 'zeek', + description: 'A set of analysis types done during the file analysis. ', + name: 'zeek.files.analyzers', type: 'keyword', }, - 'googlecloud.audit.authorization_info.resource_attributes.name': { - category: 'googlecloud', - description: 'The name of the resource. ', - name: 'googlecloud.audit.authorization_info.resource_attributes.name', + 'zeek.files.mime_type': { + category: 'zeek', + description: 'Mime type of the file. ', + name: 'zeek.files.mime_type', type: 'keyword', }, - 'googlecloud.audit.authorization_info.resource_attributes.type': { - category: 'googlecloud', - description: 'The type of the resource. ', - name: 'googlecloud.audit.authorization_info.resource_attributes.type', + 'zeek.files.filename': { + category: 'zeek', + description: 'Name of the file if available. ', + name: 'zeek.files.filename', type: 'keyword', }, - 'googlecloud.audit.method_name': { - category: 'googlecloud', + 'zeek.files.local_orig': { + category: 'zeek', description: - "The name of the service method or operation. For API calls, this should be the name of the API method. For example, 'google.datastore.v1.Datastore.RunQuery'. ", - name: 'googlecloud.audit.method_name', - type: 'keyword', - }, - 'googlecloud.audit.num_response_items': { - category: 'googlecloud', - description: 'The number of items returned from a List or Query API method, if applicable. ', - name: 'googlecloud.audit.num_response_items', - type: 'long', + 'If the source of this file is a network connection, this field indicates if the data originated from the local network or not. ', + name: 'zeek.files.local_orig', + type: 'boolean', }, - 'googlecloud.audit.request.proto_name': { - category: 'googlecloud', - description: 'Type property of the request. ', - name: 'googlecloud.audit.request.proto_name', - type: 'keyword', + 'zeek.files.is_orig': { + category: 'zeek', + description: + 'If the source of this file is a network connection, this field indicates if the file is being sent by the originator of the connection or the responder. ', + name: 'zeek.files.is_orig', + type: 'boolean', }, - 'googlecloud.audit.request.filter': { - category: 'googlecloud', - description: 'Filter of the request. ', - name: 'googlecloud.audit.request.filter', - type: 'keyword', + 'zeek.files.duration': { + category: 'zeek', + description: 'The duration the file was analyzed for. Not the duration of the session. ', + name: 'zeek.files.duration', + type: 'double', }, - 'googlecloud.audit.request.name': { - category: 'googlecloud', - description: 'Name of the request. ', - name: 'googlecloud.audit.request.name', - type: 'keyword', + 'zeek.files.seen_bytes': { + category: 'zeek', + description: 'Number of bytes provided to the file analysis engine for the file. ', + name: 'zeek.files.seen_bytes', + type: 'long', }, - 'googlecloud.audit.request.resource_name': { - category: 'googlecloud', - description: 'Name of the request resource. ', - name: 'googlecloud.audit.request.resource_name', - type: 'keyword', + 'zeek.files.total_bytes': { + category: 'zeek', + description: 'Total number of bytes that are supposed to comprise the full file. ', + name: 'zeek.files.total_bytes', + type: 'long', }, - 'googlecloud.audit.request_metadata.caller_ip': { - category: 'googlecloud', - description: 'The IP address of the caller. ', - name: 'googlecloud.audit.request_metadata.caller_ip', - type: 'ip', + 'zeek.files.missing_bytes': { + category: 'zeek', + description: + 'The number of bytes in the file stream that were completely missed during the process of analysis. ', + name: 'zeek.files.missing_bytes', + type: 'long', }, - 'googlecloud.audit.request_metadata.caller_supplied_user_agent': { - category: 'googlecloud', + 'zeek.files.overflow_bytes': { + category: 'zeek', description: - 'The user agent of the caller. This information is not authenticated and should be treated accordingly. ', - name: 'googlecloud.audit.request_metadata.caller_supplied_user_agent', - type: 'keyword', + "The number of bytes in the file stream that were not delivered to stream file analyzers. This could be overlapping bytes or bytes that couldn't be reassembled. ", + name: 'zeek.files.overflow_bytes', + type: 'long', }, - 'googlecloud.audit.response.proto_name': { - category: 'googlecloud', - description: 'Type property of the response. ', - name: 'googlecloud.audit.response.proto_name', - type: 'keyword', + 'zeek.files.timedout': { + category: 'zeek', + description: 'Whether the file analysis timed out at least once for the file. ', + name: 'zeek.files.timedout', + type: 'boolean', }, - 'googlecloud.audit.response.details.group': { - category: 'googlecloud', - description: 'The name of the group. ', - name: 'googlecloud.audit.response.details.group', + 'zeek.files.parent_fuid': { + category: 'zeek', + description: + 'Identifier associated with a container file from which this one was extracted as part of the file analysis. ', + name: 'zeek.files.parent_fuid', type: 'keyword', }, - 'googlecloud.audit.response.details.kind': { - category: 'googlecloud', - description: 'The kind of the response details. ', - name: 'googlecloud.audit.response.details.kind', + 'zeek.files.md5': { + category: 'zeek', + description: 'An MD5 digest of the file contents. ', + name: 'zeek.files.md5', type: 'keyword', }, - 'googlecloud.audit.response.details.name': { - category: 'googlecloud', - description: 'The name of the response details. ', - name: 'googlecloud.audit.response.details.name', + 'zeek.files.sha1': { + category: 'zeek', + description: 'A SHA1 digest of the file contents. ', + name: 'zeek.files.sha1', type: 'keyword', }, - 'googlecloud.audit.response.details.uid': { - category: 'googlecloud', - description: 'The uid of the response details. ', - name: 'googlecloud.audit.response.details.uid', + 'zeek.files.sha256': { + category: 'zeek', + description: 'A SHA256 digest of the file contents. ', + name: 'zeek.files.sha256', type: 'keyword', }, - 'googlecloud.audit.response.status': { - category: 'googlecloud', - description: 'Status of the response. ', - name: 'googlecloud.audit.response.status', + 'zeek.files.extracted': { + category: 'zeek', + description: 'Local filename of extracted file. ', + name: 'zeek.files.extracted', type: 'keyword', }, - 'googlecloud.audit.resource_name': { - category: 'googlecloud', + 'zeek.files.extracted_cutoff': { + category: 'zeek', description: - "The resource or collection that is the target of the operation. The name is a scheme-less URI, not including the API service name. For example, 'shelves/SHELF_ID/books'. ", - name: 'googlecloud.audit.resource_name', - type: 'keyword', + 'Indicate whether the file being extracted was cut off hence not extracted completely. ', + name: 'zeek.files.extracted_cutoff', + type: 'boolean', }, - 'googlecloud.audit.resource_location.current_locations': { - category: 'googlecloud', - description: 'Current locations of the resource. ', - name: 'googlecloud.audit.resource_location.current_locations', + 'zeek.files.extracted_size': { + category: 'zeek', + description: 'The number of bytes extracted to disk. ', + name: 'zeek.files.extracted_size', + type: 'long', + }, + 'zeek.files.entropy': { + category: 'zeek', + description: 'The information density of the contents of the file. ', + name: 'zeek.files.entropy', + type: 'double', + }, + 'zeek.ftp.user': { + category: 'zeek', + description: 'User name for the current FTP session. ', + name: 'zeek.ftp.user', type: 'keyword', }, - 'googlecloud.audit.service_name': { - category: 'googlecloud', - description: - 'The name of the API service performing the operation. For example, datastore.googleapis.com. ', - name: 'googlecloud.audit.service_name', + 'zeek.ftp.password': { + category: 'zeek', + description: 'Password for the current FTP session if captured. ', + name: 'zeek.ftp.password', type: 'keyword', }, - 'googlecloud.audit.status.code': { - category: 'googlecloud', - description: 'The status code, which should be an enum value of google.rpc.Code. ', - name: 'googlecloud.audit.status.code', - type: 'integer', + 'zeek.ftp.command': { + category: 'zeek', + description: 'Command given by the client. ', + name: 'zeek.ftp.command', + type: 'keyword', }, - 'googlecloud.audit.status.message': { - category: 'googlecloud', - description: - 'A developer-facing error message, which should be in English. Any user-facing error message should be localized and sent in the google.rpc.Status.details field, or localized by the client. ', - name: 'googlecloud.audit.status.message', + 'zeek.ftp.arg': { + category: 'zeek', + description: 'Argument for the command if one is given. ', + name: 'zeek.ftp.arg', type: 'keyword', }, - 'googlecloud.firewall.rule_details.priority': { - category: 'googlecloud', - description: 'The priority for the firewall rule.', - name: 'googlecloud.firewall.rule_details.priority', + 'zeek.ftp.file.size': { + category: 'zeek', + description: 'Size of the file if the command indicates a file transfer. ', + name: 'zeek.ftp.file.size', type: 'long', }, - 'googlecloud.firewall.rule_details.action': { - category: 'googlecloud', - description: 'Action that the rule performs on match.', - name: 'googlecloud.firewall.rule_details.action', + 'zeek.ftp.file.mime_type': { + category: 'zeek', + description: 'Sniffed mime type of file. ', + name: 'zeek.ftp.file.mime_type', type: 'keyword', }, - 'googlecloud.firewall.rule_details.direction': { - category: 'googlecloud', - description: 'Direction of traffic that matches this rule.', - name: 'googlecloud.firewall.rule_details.direction', + 'zeek.ftp.file.fuid': { + category: 'zeek', + description: '(present if base/protocols/ftp/files.bro is loaded) File unique ID. ', + name: 'zeek.ftp.file.fuid', type: 'keyword', }, - 'googlecloud.firewall.rule_details.reference': { - category: 'googlecloud', - description: 'Reference to the firewall rule.', - name: 'googlecloud.firewall.rule_details.reference', - type: 'keyword', + 'zeek.ftp.reply.code': { + category: 'zeek', + description: 'Reply code from the server in response to the command. ', + name: 'zeek.ftp.reply.code', + type: 'integer', }, - 'googlecloud.firewall.rule_details.source_range': { - category: 'googlecloud', - description: 'List of source ranges that the firewall rule applies to.', - name: 'googlecloud.firewall.rule_details.source_range', + 'zeek.ftp.reply.msg': { + category: 'zeek', + description: 'Reply message from the server in response to the command. ', + name: 'zeek.ftp.reply.msg', type: 'keyword', }, - 'googlecloud.firewall.rule_details.destination_range': { - category: 'googlecloud', - description: 'List of destination ranges that the firewall applies to.', - name: 'googlecloud.firewall.rule_details.destination_range', - type: 'keyword', + 'zeek.ftp.data_channel.passive': { + category: 'zeek', + description: 'Whether PASV mode is toggled for control channel. ', + name: 'zeek.ftp.data_channel.passive', + type: 'boolean', }, - 'googlecloud.firewall.rule_details.source_tag': { - category: 'googlecloud', - description: 'List of all the source tags that the firewall rule applies to. ', - name: 'googlecloud.firewall.rule_details.source_tag', - type: 'keyword', + 'zeek.ftp.data_channel.originating_host': { + category: 'zeek', + description: 'The host that will be initiating the data connection. ', + name: 'zeek.ftp.data_channel.originating_host', + type: 'ip', }, - 'googlecloud.firewall.rule_details.target_tag': { - category: 'googlecloud', - description: 'List of all the target tags that the firewall rule applies to. ', - name: 'googlecloud.firewall.rule_details.target_tag', - type: 'keyword', + 'zeek.ftp.data_channel.response_host': { + category: 'zeek', + description: 'The host that will be accepting the data connection. ', + name: 'zeek.ftp.data_channel.response_host', + type: 'ip', }, - 'googlecloud.firewall.rule_details.ip_port_info': { - category: 'googlecloud', - description: 'List of ip protocols and applicable port ranges for rules. ', - name: 'googlecloud.firewall.rule_details.ip_port_info', - type: 'array', + 'zeek.ftp.data_channel.response_port': { + category: 'zeek', + description: 'The port at which the acceptor is listening for the data connection. ', + name: 'zeek.ftp.data_channel.response_port', + type: 'integer', }, - 'googlecloud.firewall.rule_details.source_service_account': { - category: 'googlecloud', - description: 'List of all the source service accounts that the firewall rule applies to. ', - name: 'googlecloud.firewall.rule_details.source_service_account', + 'zeek.ftp.cwd': { + category: 'zeek', + description: + "Current working directory that this session is in. By making the default value '.', we can indicate that unless something more concrete is discovered that the existing but unknown directory is ok to use. ", + name: 'zeek.ftp.cwd', type: 'keyword', }, - 'googlecloud.firewall.rule_details.target_service_account': { - category: 'googlecloud', - description: 'List of all the target service accounts that the firewall rule applies to. ', - name: 'googlecloud.firewall.rule_details.target_service_account', + 'zeek.ftp.cmdarg.cmd': { + category: 'zeek', + description: 'Command. ', + name: 'zeek.ftp.cmdarg.cmd', type: 'keyword', }, - 'googlecloud.vpcflow.reporter': { - category: 'googlecloud', - description: "The side which reported the flow. Can be either 'SRC' or 'DEST'. ", - name: 'googlecloud.vpcflow.reporter', + 'zeek.ftp.cmdarg.arg': { + category: 'zeek', + description: 'Argument for the command if one was given. ', + name: 'zeek.ftp.cmdarg.arg', type: 'keyword', }, - 'googlecloud.vpcflow.rtt.ms': { - category: 'googlecloud', + 'zeek.ftp.cmdarg.seq': { + category: 'zeek', + description: 'Counter to track how many commands have been executed. ', + name: 'zeek.ftp.cmdarg.seq', + type: 'integer', + }, + 'zeek.ftp.pending_commands': { + category: 'zeek', description: - 'Latency as measured (for TCP flows only) during the time interval. This is the time elapsed between sending a SEQ and receiving a corresponding ACK and it contains the network RTT as well as the application related delay. ', - name: 'googlecloud.vpcflow.rtt.ms', - type: 'long', + 'Queue for commands that have been sent but not yet responded to are tracked here. ', + name: 'zeek.ftp.pending_commands', + type: 'integer', + }, + 'zeek.ftp.passive': { + category: 'zeek', + description: 'Indicates if the session is in active or passive mode. ', + name: 'zeek.ftp.passive', + type: 'boolean', + }, + 'zeek.ftp.capture_password': { + category: 'zeek', + description: 'Determines if the password will be captured for this request. ', + name: 'zeek.ftp.capture_password', + type: 'boolean', }, - 'gsuite.actor.type': { - category: 'gsuite', + 'zeek.ftp.last_auth_requested': { + category: 'zeek', description: - 'The type of actor. Values can be: *USER*: Another user in the same domain. *EXTERNAL_USER*: A user outside the domain. *KEY*: A non-human actor. ', - name: 'gsuite.actor.type', + 'present if base/protocols/ftp/gridftp.bro is loaded. Last authentication/security mechanism that was used. ', + name: 'zeek.ftp.last_auth_requested', type: 'keyword', }, - 'gsuite.actor.key': { - category: 'gsuite', + 'zeek.http.trans_depth': { + category: 'zeek', description: - 'Only present when `actor.type` is `KEY`. Can be the `consumer_key` of the requestor for OAuth 2LO API requests or an identifier for robot accounts. ', - name: 'gsuite.actor.key', - type: 'keyword', + 'Represents the pipelined depth into the connection of this request/response transaction. ', + name: 'zeek.http.trans_depth', + type: 'integer', }, - 'gsuite.event.type': { - category: 'gsuite', - description: - 'The type of GSuite event, mapped from `items[].events[].type` in the original payload. Each fileset can have a different set of values for it, more details can be found at https://developers.google.com/admin-sdk/reports/v1/reference/activities/list ', - example: 'audit#activity', - name: 'gsuite.event.type', + 'zeek.http.status_msg': { + category: 'zeek', + description: 'Status message returned by the server. ', + name: 'zeek.http.status_msg', type: 'keyword', }, - 'gsuite.kind': { - category: 'gsuite', - description: - 'The type of API resource, mapped from `kind` in the original payload. More details can be found at https://developers.google.com/admin-sdk/reports/v1/reference/activities/list ', - example: 'audit#activity', - name: 'gsuite.kind', - type: 'keyword', + 'zeek.http.info_code': { + category: 'zeek', + description: 'Last seen 1xx informational reply code returned by the server. ', + name: 'zeek.http.info_code', + type: 'integer', }, - 'gsuite.organization.domain': { - category: 'gsuite', - description: "The domain that is affected by the report's event. ", - name: 'gsuite.organization.domain', + 'zeek.http.info_msg': { + category: 'zeek', + description: 'Last seen 1xx informational reply message returned by the server. ', + name: 'zeek.http.info_msg', type: 'keyword', }, - 'gsuite.admin.application.edition': { - category: 'gsuite', - description: 'The GSuite edition.', - name: 'gsuite.admin.application.edition', + 'zeek.http.tags': { + category: 'zeek', + description: + 'A set of indicators of various attributes discovered and related to a particular request/response pair. ', + name: 'zeek.http.tags', type: 'keyword', }, - 'gsuite.admin.application.name': { - category: 'gsuite', - description: "The application's name.", - name: 'gsuite.admin.application.name', + 'zeek.http.password': { + category: 'zeek', + description: 'Password if basic-auth is performed for the request. ', + name: 'zeek.http.password', type: 'keyword', }, - 'gsuite.admin.application.enabled': { - category: 'gsuite', - description: 'The enabled application.', - name: 'gsuite.admin.application.enabled', - type: 'keyword', + 'zeek.http.captured_password': { + category: 'zeek', + description: 'Determines if the password will be captured for this request. ', + name: 'zeek.http.captured_password', + type: 'boolean', }, - 'gsuite.admin.application.licences_order_number': { - category: 'gsuite', - description: 'Order number used to redeem licenses.', - name: 'gsuite.admin.application.licences_order_number', + 'zeek.http.proxied': { + category: 'zeek', + description: 'All of the headers that may indicate if the HTTP request was proxied. ', + name: 'zeek.http.proxied', type: 'keyword', }, - 'gsuite.admin.application.licences_purchased': { - category: 'gsuite', - description: 'Number of licences purchased.', - name: 'gsuite.admin.application.licences_purchased', - type: 'keyword', + 'zeek.http.range_request': { + category: 'zeek', + description: 'Indicates if this request can assume 206 partial content in response. ', + name: 'zeek.http.range_request', + type: 'boolean', }, - 'gsuite.admin.application.id': { - category: 'gsuite', - description: 'The application ID.', - name: 'gsuite.admin.application.id', + 'zeek.http.client_header_names': { + category: 'zeek', + description: + 'The vector of HTTP header names sent by the client. No header values are included here, just the header names. ', + name: 'zeek.http.client_header_names', type: 'keyword', }, - 'gsuite.admin.application.asp_id': { - category: 'gsuite', - description: 'The application specific password ID.', - name: 'gsuite.admin.application.asp_id', + 'zeek.http.server_header_names': { + category: 'zeek', + description: + 'The vector of HTTP header names sent by the server. No header values are included here, just the header names. ', + name: 'zeek.http.server_header_names', type: 'keyword', }, - 'gsuite.admin.application.package_id': { - category: 'gsuite', - description: 'The mobile application package ID.', - name: 'gsuite.admin.application.package_id', + 'zeek.http.orig_fuids': { + category: 'zeek', + description: 'An ordered vector of file unique IDs from the originator. ', + name: 'zeek.http.orig_fuids', type: 'keyword', }, - 'gsuite.admin.group.email': { - category: 'gsuite', - description: "The group's primary email address.", - name: 'gsuite.admin.group.email', + 'zeek.http.orig_mime_types': { + category: 'zeek', + description: 'An ordered vector of mime types from the originator. ', + name: 'zeek.http.orig_mime_types', type: 'keyword', }, - 'gsuite.admin.new_value': { - category: 'gsuite', - description: 'The new value for the setting.', - name: 'gsuite.admin.new_value', + 'zeek.http.orig_filenames': { + category: 'zeek', + description: 'An ordered vector of filenames from the originator. ', + name: 'zeek.http.orig_filenames', type: 'keyword', }, - 'gsuite.admin.old_value': { - category: 'gsuite', - description: 'The old value for the setting.', - name: 'gsuite.admin.old_value', + 'zeek.http.resp_fuids': { + category: 'zeek', + description: 'An ordered vector of file unique IDs from the responder. ', + name: 'zeek.http.resp_fuids', type: 'keyword', }, - 'gsuite.admin.org_unit.name': { - category: 'gsuite', - description: 'The organizational unit name.', - name: 'gsuite.admin.org_unit.name', + 'zeek.http.resp_mime_types': { + category: 'zeek', + description: 'An ordered vector of mime types from the responder. ', + name: 'zeek.http.resp_mime_types', type: 'keyword', }, - 'gsuite.admin.org_unit.full': { - category: 'gsuite', - description: 'The org unit full path including the root org unit name.', - name: 'gsuite.admin.org_unit.full', + 'zeek.http.resp_filenames': { + category: 'zeek', + description: 'An ordered vector of filenames from the responder. ', + name: 'zeek.http.resp_filenames', type: 'keyword', }, - 'gsuite.admin.setting.name': { - category: 'gsuite', - description: 'The setting name.', - name: 'gsuite.admin.setting.name', - type: 'keyword', + 'zeek.http.orig_mime_depth': { + category: 'zeek', + description: 'Current number of MIME entities in the HTTP request message body. ', + name: 'zeek.http.orig_mime_depth', + type: 'integer', }, - 'gsuite.admin.user_defined_setting.name': { - category: 'gsuite', - description: 'The name of the user-defined setting.', - name: 'gsuite.admin.user_defined_setting.name', - type: 'keyword', + 'zeek.http.resp_mime_depth': { + category: 'zeek', + description: 'Current number of MIME entities in the HTTP response message body. ', + name: 'zeek.http.resp_mime_depth', + type: 'integer', }, - 'gsuite.admin.setting.description': { - category: 'gsuite', - description: 'The setting name.', - name: 'gsuite.admin.setting.description', + 'zeek.intel.seen.indicator': { + category: 'zeek', + description: 'The intelligence indicator. ', + name: 'zeek.intel.seen.indicator', type: 'keyword', }, - 'gsuite.admin.group.priorities': { - category: 'gsuite', - description: 'Group priorities.', - name: 'gsuite.admin.group.priorities', + 'zeek.intel.seen.indicator_type': { + category: 'zeek', + description: 'The type of data the indicator represents. ', + name: 'zeek.intel.seen.indicator_type', type: 'keyword', }, - 'gsuite.admin.domain.alias': { - category: 'gsuite', - description: 'The domain alias.', - name: 'gsuite.admin.domain.alias', + 'zeek.intel.seen.host': { + category: 'zeek', + description: 'If the indicator type was Intel::ADDR, then this field will be present. ', + name: 'zeek.intel.seen.host', type: 'keyword', }, - 'gsuite.admin.domain.name': { - category: 'gsuite', - description: 'The primary domain name.', - name: 'gsuite.admin.domain.name', + 'zeek.intel.seen.conn': { + category: 'zeek', + description: + 'If the data was discovered within a connection, the connection record should go here to give context to the data. ', + name: 'zeek.intel.seen.conn', type: 'keyword', }, - 'gsuite.admin.domain.secondary_name': { - category: 'gsuite', - description: 'The secondary domain name.', - name: 'gsuite.admin.domain.secondary_name', + 'zeek.intel.seen.where': { + category: 'zeek', + description: 'Where the data was discovered. ', + name: 'zeek.intel.seen.where', type: 'keyword', }, - 'gsuite.admin.managed_configuration': { - category: 'gsuite', - description: 'The name of the managed configuration.', - name: 'gsuite.admin.managed_configuration', + 'zeek.intel.seen.node': { + category: 'zeek', + description: 'The name of the node where the match was discovered. ', + name: 'zeek.intel.seen.node', type: 'keyword', }, - 'gsuite.admin.non_featured_services_selection': { - category: 'gsuite', + 'zeek.intel.seen.uid': { + category: 'zeek', description: - 'Non-featured services selection. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/admin-application-settings#FLASHLIGHT_EDU_NON_FEATURED_SERVICES_SELECTED ', - name: 'gsuite.admin.non_featured_services_selection', + 'If the data was discovered within a connection, the connection uid should go here to give context to the data. If the conn field is provided, this will be automatically filled out. ', + name: 'zeek.intel.seen.uid', type: 'keyword', }, - 'gsuite.admin.field': { - category: 'gsuite', - description: 'The name of the field.', - name: 'gsuite.admin.field', - type: 'keyword', + 'zeek.intel.seen.f': { + category: 'zeek', + description: + 'If the data was discovered within a file, the file record should go here to provide context to the data. ', + name: 'zeek.intel.seen.f', + type: 'object', }, - 'gsuite.admin.resource.id': { - category: 'gsuite', - description: 'The name of the resource identifier.', - name: 'gsuite.admin.resource.id', + 'zeek.intel.seen.fuid': { + category: 'zeek', + description: + 'If the data was discovered within a file, the file uid should go here to provide context to the data. If the file record f is provided, this will be automatically filled out. ', + name: 'zeek.intel.seen.fuid', type: 'keyword', }, - 'gsuite.admin.user.email': { - category: 'gsuite', - description: "The user's primary email address.", - name: 'gsuite.admin.user.email', + 'zeek.intel.matched': { + category: 'zeek', + description: 'Event to represent a match in the intelligence data from data that was seen. ', + name: 'zeek.intel.matched', type: 'keyword', }, - 'gsuite.admin.user.nickname': { - category: 'gsuite', - description: "The user's nickname.", - name: 'gsuite.admin.user.nickname', + 'zeek.intel.sources': { + category: 'zeek', + description: 'Sources which supplied data for this match. ', + name: 'zeek.intel.sources', type: 'keyword', }, - 'gsuite.admin.user.birthdate': { - category: 'gsuite', - description: "The user's birth date.", - name: 'gsuite.admin.user.birthdate', - type: 'date', - }, - 'gsuite.admin.gateway.name': { - category: 'gsuite', - description: 'Gateway name. Present on some chat settings.', - name: 'gsuite.admin.gateway.name', + 'zeek.intel.fuid': { + category: 'zeek', + description: + 'If a file was associated with this intelligence hit, this is the uid for the file. ', + name: 'zeek.intel.fuid', type: 'keyword', }, - 'gsuite.admin.chrome_os.session_type': { - category: 'gsuite', - description: 'Chrome OS session type.', - name: 'gsuite.admin.chrome_os.session_type', + 'zeek.intel.file_mime_type': { + category: 'zeek', + description: + 'A mime type if the intelligence hit is related to a file. If the $f field is provided this will be automatically filled out. ', + name: 'zeek.intel.file_mime_type', type: 'keyword', }, - 'gsuite.admin.device.serial_number': { - category: 'gsuite', - description: 'Device serial number.', - name: 'gsuite.admin.device.serial_number', + 'zeek.intel.file_desc': { + category: 'zeek', + description: + 'Frequently files can be described to give a bit more context. If the $f field is provided this field will be automatically filled out. ', + name: 'zeek.intel.file_desc', type: 'keyword', }, - 'gsuite.admin.device.id': { - category: 'gsuite', - name: 'gsuite.admin.device.id', + 'zeek.irc.nick': { + category: 'zeek', + description: 'Nickname given for the connection. ', + name: 'zeek.irc.nick', type: 'keyword', }, - 'gsuite.admin.device.type': { - category: 'gsuite', - description: 'Device type.', - name: 'gsuite.admin.device.type', + 'zeek.irc.user': { + category: 'zeek', + description: 'Username given for the connection. ', + name: 'zeek.irc.user', type: 'keyword', }, - 'gsuite.admin.print_server.name': { - category: 'gsuite', - description: 'The name of the print server.', - name: 'gsuite.admin.print_server.name', + 'zeek.irc.command': { + category: 'zeek', + description: 'Command given by the client. ', + name: 'zeek.irc.command', type: 'keyword', }, - 'gsuite.admin.printer.name': { - category: 'gsuite', - description: 'The name of the printer.', - name: 'gsuite.admin.printer.name', + 'zeek.irc.value': { + category: 'zeek', + description: 'Value for the command given by the client. ', + name: 'zeek.irc.value', type: 'keyword', }, - 'gsuite.admin.device.command_details': { - category: 'gsuite', - description: 'Command details.', - name: 'gsuite.admin.device.command_details', + 'zeek.irc.addl': { + category: 'zeek', + description: 'Any additional data for the command. ', + name: 'zeek.irc.addl', type: 'keyword', }, - 'gsuite.admin.role.id': { - category: 'gsuite', - description: 'Unique identifier for this role privilege.', - name: 'gsuite.admin.role.id', + 'zeek.irc.dcc.file.name': { + category: 'zeek', + description: 'Present if base/protocols/irc/dcc-send.bro is loaded. DCC filename requested. ', + name: 'zeek.irc.dcc.file.name', type: 'keyword', }, - 'gsuite.admin.role.name': { - category: 'gsuite', + 'zeek.irc.dcc.file.size': { + category: 'zeek', description: - 'The role name. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/admin-delegated-admin-settings ', - name: 'gsuite.admin.role.name', - type: 'keyword', + 'Present if base/protocols/irc/dcc-send.bro is loaded. Size of the DCC transfer as indicated by the sender. ', + name: 'zeek.irc.dcc.file.size', + type: 'long', }, - 'gsuite.admin.privilege.name': { - category: 'gsuite', - description: 'Privilege name.', - name: 'gsuite.admin.privilege.name', + 'zeek.irc.dcc.mime_type': { + category: 'zeek', + description: + 'present if base/protocols/irc/dcc-send.bro is loaded. Sniffed mime type of the file. ', + name: 'zeek.irc.dcc.mime_type', type: 'keyword', }, - 'gsuite.admin.service.name': { - category: 'gsuite', - description: 'The service name.', - name: 'gsuite.admin.service.name', + 'zeek.irc.fuid': { + category: 'zeek', + description: 'present if base/protocols/irc/files.bro is loaded. File unique ID. ', + name: 'zeek.irc.fuid', type: 'keyword', }, - 'gsuite.admin.url.name': { - category: 'gsuite', - description: 'The website name.', - name: 'gsuite.admin.url.name', + 'zeek.kerberos.request_type': { + category: 'zeek', + description: 'Request type - Authentication Service (AS) or Ticket Granting Service (TGS). ', + name: 'zeek.kerberos.request_type', type: 'keyword', }, - 'gsuite.admin.product.name': { - category: 'gsuite', - description: 'The product name.', - name: 'gsuite.admin.product.name', + 'zeek.kerberos.client': { + category: 'zeek', + description: 'Client name. ', + name: 'zeek.kerberos.client', type: 'keyword', }, - 'gsuite.admin.product.sku': { - category: 'gsuite', - description: 'The product SKU.', - name: 'gsuite.admin.product.sku', + 'zeek.kerberos.service': { + category: 'zeek', + description: 'Service name. ', + name: 'zeek.kerberos.service', type: 'keyword', }, - 'gsuite.admin.bulk_upload.failed': { - category: 'gsuite', - description: 'Number of failed records in bulk upload operation.', - name: 'gsuite.admin.bulk_upload.failed', - type: 'long', - }, - 'gsuite.admin.bulk_upload.total': { - category: 'gsuite', - description: 'Number of total records in bulk upload operation.', - name: 'gsuite.admin.bulk_upload.total', - type: 'long', - }, - 'gsuite.admin.group.allowed_list': { - category: 'gsuite', - description: 'Names of allow-listed groups.', - name: 'gsuite.admin.group.allowed_list', - type: 'keyword', + 'zeek.kerberos.success': { + category: 'zeek', + description: 'Request result. ', + name: 'zeek.kerberos.success', + type: 'boolean', }, - 'gsuite.admin.email.quarantine_name': { - category: 'gsuite', - description: 'The name of the quarantine.', - name: 'gsuite.admin.email.quarantine_name', - type: 'keyword', + 'zeek.kerberos.error.code': { + category: 'zeek', + description: 'Error code. ', + name: 'zeek.kerberos.error.code', + type: 'integer', }, - 'gsuite.admin.email.log_search_filter.message_id': { - category: 'gsuite', - description: "The log search filter's email message ID.", - name: 'gsuite.admin.email.log_search_filter.message_id', + 'zeek.kerberos.error.msg': { + category: 'zeek', + description: 'Error message. ', + name: 'zeek.kerberos.error.msg', type: 'keyword', }, - 'gsuite.admin.email.log_search_filter.start_date': { - category: 'gsuite', - description: "The log search filter's start date.", - name: 'gsuite.admin.email.log_search_filter.start_date', + 'zeek.kerberos.valid.from': { + category: 'zeek', + description: 'Ticket valid from. ', + name: 'zeek.kerberos.valid.from', type: 'date', }, - 'gsuite.admin.email.log_search_filter.end_date': { - category: 'gsuite', - description: "The log search filter's ending date.", - name: 'gsuite.admin.email.log_search_filter.end_date', + 'zeek.kerberos.valid.until': { + category: 'zeek', + description: 'Ticket valid until. ', + name: 'zeek.kerberos.valid.until', type: 'date', }, - 'gsuite.admin.email.log_search_filter.recipient.value': { - category: 'gsuite', - description: "The log search filter's email recipient.", - name: 'gsuite.admin.email.log_search_filter.recipient.value', - type: 'keyword', + 'zeek.kerberos.valid.days': { + category: 'zeek', + description: 'Number of days the ticket is valid for. ', + name: 'zeek.kerberos.valid.days', + type: 'integer', }, - 'gsuite.admin.email.log_search_filter.sender.value': { - category: 'gsuite', - description: "The log search filter's email sender.", - name: 'gsuite.admin.email.log_search_filter.sender.value', + 'zeek.kerberos.cipher': { + category: 'zeek', + description: 'Ticket encryption type. ', + name: 'zeek.kerberos.cipher', type: 'keyword', }, - 'gsuite.admin.email.log_search_filter.recipient.ip': { - category: 'gsuite', - description: "The log search filter's email recipient's IP address.", - name: 'gsuite.admin.email.log_search_filter.recipient.ip', - type: 'ip', - }, - 'gsuite.admin.email.log_search_filter.sender.ip': { - category: 'gsuite', - description: "The log search filter's email sender's IP address.", - name: 'gsuite.admin.email.log_search_filter.sender.ip', - type: 'ip', + 'zeek.kerberos.forwardable': { + category: 'zeek', + description: 'Forwardable ticket requested. ', + name: 'zeek.kerberos.forwardable', + type: 'boolean', }, - 'gsuite.admin.chrome_licenses.enabled': { - category: 'gsuite', - description: - 'Licences enabled. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/admin-org-settings ', - name: 'gsuite.admin.chrome_licenses.enabled', - type: 'keyword', + 'zeek.kerberos.renewable': { + category: 'zeek', + description: 'Renewable ticket requested. ', + name: 'zeek.kerberos.renewable', + type: 'boolean', }, - 'gsuite.admin.chrome_licenses.allowed': { - category: 'gsuite', - description: - 'Licences enabled. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/admin-org-settings ', - name: 'gsuite.admin.chrome_licenses.allowed', + 'zeek.kerberos.ticket.auth': { + category: 'zeek', + description: 'Hash of ticket used to authorize request/transaction. ', + name: 'zeek.kerberos.ticket.auth', type: 'keyword', }, - 'gsuite.admin.oauth2.service.name': { - category: 'gsuite', - description: - 'OAuth2 service name. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/admin-security-settings ', - name: 'gsuite.admin.oauth2.service.name', + 'zeek.kerberos.ticket.new': { + category: 'zeek', + description: 'Hash of ticket returned by the KDC. ', + name: 'zeek.kerberos.ticket.new', type: 'keyword', }, - 'gsuite.admin.oauth2.application.id': { - category: 'gsuite', - description: 'OAuth2 application ID.', - name: 'gsuite.admin.oauth2.application.id', + 'zeek.kerberos.cert.client.value': { + category: 'zeek', + description: 'Client certificate. ', + name: 'zeek.kerberos.cert.client.value', type: 'keyword', }, - 'gsuite.admin.oauth2.application.name': { - category: 'gsuite', - description: 'OAuth2 application name.', - name: 'gsuite.admin.oauth2.application.name', + 'zeek.kerberos.cert.client.fuid': { + category: 'zeek', + description: 'File unique ID of client cert. ', + name: 'zeek.kerberos.cert.client.fuid', type: 'keyword', }, - 'gsuite.admin.oauth2.application.type': { - category: 'gsuite', - description: - 'OAuth2 application type. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/admin-security-settings ', - name: 'gsuite.admin.oauth2.application.type', + 'zeek.kerberos.cert.client.subject': { + category: 'zeek', + description: 'Subject of client certificate. ', + name: 'zeek.kerberos.cert.client.subject', type: 'keyword', }, - 'gsuite.admin.verification_method': { - category: 'gsuite', - description: - 'Related verification method. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/admin-security-settings and https://developers.google.com/admin-sdk/reports/v1/appendix/activity/admin-domain-settings ', - name: 'gsuite.admin.verification_method', + 'zeek.kerberos.cert.server.value': { + category: 'zeek', + description: 'Server certificate. ', + name: 'zeek.kerberos.cert.server.value', type: 'keyword', }, - 'gsuite.admin.alert.name': { - category: 'gsuite', - description: 'The alert name.', - name: 'gsuite.admin.alert.name', + 'zeek.kerberos.cert.server.fuid': { + category: 'zeek', + description: 'File unique ID of server certificate. ', + name: 'zeek.kerberos.cert.server.fuid', type: 'keyword', }, - 'gsuite.admin.rule.name': { - category: 'gsuite', - description: 'The rule name.', - name: 'gsuite.admin.rule.name', + 'zeek.kerberos.cert.server.subject': { + category: 'zeek', + description: 'Subject of server certificate. ', + name: 'zeek.kerberos.cert.server.subject', type: 'keyword', }, - 'gsuite.admin.api.client.name': { - category: 'gsuite', - description: 'The API client name.', - name: 'gsuite.admin.api.client.name', + 'zeek.modbus.function': { + category: 'zeek', + description: 'The name of the function message that was sent. ', + name: 'zeek.modbus.function', type: 'keyword', }, - 'gsuite.admin.api.scopes': { - category: 'gsuite', - description: 'The API scopes.', - name: 'gsuite.admin.api.scopes', + 'zeek.modbus.exception': { + category: 'zeek', + description: 'The exception if the response was a failure. ', + name: 'zeek.modbus.exception', type: 'keyword', }, - 'gsuite.admin.mdm.token': { - category: 'gsuite', - description: 'The MDM vendor enrollment token.', - name: 'gsuite.admin.mdm.token', - type: 'keyword', + 'zeek.modbus.track_address': { + category: 'zeek', + description: + 'Present if policy/protocols/modbus/track-memmap.bro is loaded. Modbus track address. ', + name: 'zeek.modbus.track_address', + type: 'integer', }, - 'gsuite.admin.mdm.vendor': { - category: 'gsuite', - description: "The MDM vendor's name.", - name: 'gsuite.admin.mdm.vendor', + 'zeek.mysql.cmd': { + category: 'zeek', + description: 'The command that was issued. ', + name: 'zeek.mysql.cmd', type: 'keyword', }, - 'gsuite.admin.info_type': { - category: 'gsuite', - description: - 'This will be used to state what kind of information was changed. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/admin-domain-settings ', - name: 'gsuite.admin.info_type', + 'zeek.mysql.arg': { + category: 'zeek', + description: 'The argument issued to the command. ', + name: 'zeek.mysql.arg', type: 'keyword', }, - 'gsuite.admin.email_monitor.dest_email': { - category: 'gsuite', - description: 'The destination address of the email monitor.', - name: 'gsuite.admin.email_monitor.dest_email', - type: 'keyword', + 'zeek.mysql.success': { + category: 'zeek', + description: 'Whether the command succeeded. ', + name: 'zeek.mysql.success', + type: 'boolean', }, - 'gsuite.admin.email_monitor.level.chat': { - category: 'gsuite', - description: 'The chat email monitor level.', - name: 'gsuite.admin.email_monitor.level.chat', - type: 'keyword', + 'zeek.mysql.rows': { + category: 'zeek', + description: 'The number of affected rows, if any. ', + name: 'zeek.mysql.rows', + type: 'integer', }, - 'gsuite.admin.email_monitor.level.draft': { - category: 'gsuite', - description: 'The draft email monitor level.', - name: 'gsuite.admin.email_monitor.level.draft', + 'zeek.mysql.response': { + category: 'zeek', + description: 'Server message, if any. ', + name: 'zeek.mysql.response', type: 'keyword', }, - 'gsuite.admin.email_monitor.level.incoming': { - category: 'gsuite', - description: 'The incoming email monitor level.', - name: 'gsuite.admin.email_monitor.level.incoming', + 'zeek.notice.connection_id': { + category: 'zeek', + description: 'Identifier of the related connection session. ', + name: 'zeek.notice.connection_id', type: 'keyword', }, - 'gsuite.admin.email_monitor.level.outgoing': { - category: 'gsuite', - description: 'The outgoing email monitor level.', - name: 'gsuite.admin.email_monitor.level.outgoing', + 'zeek.notice.icmp_id': { + category: 'zeek', + description: 'Identifier of the related ICMP session. ', + name: 'zeek.notice.icmp_id', type: 'keyword', }, - 'gsuite.admin.email_dump.include_deleted': { - category: 'gsuite', - description: 'Indicates if deleted emails are included in the export.', - name: 'gsuite.admin.email_dump.include_deleted', - type: 'boolean', - }, - 'gsuite.admin.email_dump.package_content': { - category: 'gsuite', - description: 'The contents of the mailbox package.', - name: 'gsuite.admin.email_dump.package_content', + 'zeek.notice.file.id': { + category: 'zeek', + description: 'An identifier associated with a single file that is related to this notice. ', + name: 'zeek.notice.file.id', type: 'keyword', }, - 'gsuite.admin.email_dump.query': { - category: 'gsuite', - description: 'The search query used for the dump.', - name: 'gsuite.admin.email_dump.query', + 'zeek.notice.file.parent_id': { + category: 'zeek', + description: 'Identifier associated with a container file from which this one was extracted. ', + name: 'zeek.notice.file.parent_id', type: 'keyword', }, - 'gsuite.admin.request.id': { - category: 'gsuite', - description: 'The request ID.', - name: 'gsuite.admin.request.id', + 'zeek.notice.file.source': { + category: 'zeek', + description: + 'An identification of the source of the file data. E.g. it may be a network protocol over which it was transferred, or a local file path which was read, or some other input source. ', + name: 'zeek.notice.file.source', type: 'keyword', }, - 'gsuite.admin.mobile.action.id': { - category: 'gsuite', - description: "The mobile device action's ID.", - name: 'gsuite.admin.mobile.action.id', + 'zeek.notice.file.mime_type': { + category: 'zeek', + description: 'A mime type if the notice is related to a file. ', + name: 'zeek.notice.file.mime_type', type: 'keyword', }, - 'gsuite.admin.mobile.action.type': { - category: 'gsuite', + 'zeek.notice.file.is_orig': { + category: 'zeek', description: - "The mobile device action's type. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/admin-mobile-settings ", - name: 'gsuite.admin.mobile.action.type', - type: 'keyword', + 'If the source of this file is a network connection, this field indicates if the file is being sent by the originator of the connection or the responder. ', + name: 'zeek.notice.file.is_orig', + type: 'boolean', }, - 'gsuite.admin.mobile.certificate.name': { - category: 'gsuite', - description: 'The mobile certificate common name.', - name: 'gsuite.admin.mobile.certificate.name', - type: 'keyword', + 'zeek.notice.file.seen_bytes': { + category: 'zeek', + description: 'Number of bytes provided to the file analysis engine for the file. ', + name: 'zeek.notice.file.seen_bytes', + type: 'long', }, - 'gsuite.admin.mobile.company_owned_devices': { - category: 'gsuite', - description: 'The number of devices a company owns.', - name: 'gsuite.admin.mobile.company_owned_devices', + 'zeek.notice.ffile.total_bytes': { + category: 'zeek', + description: 'Total number of bytes that are supposed to comprise the full file. ', + name: 'zeek.notice.ffile.total_bytes', type: 'long', }, - 'gsuite.admin.distribution.entity.name': { - category: 'gsuite', + 'zeek.notice.file.missing_bytes': { + category: 'zeek', description: - 'The distribution entity value, which can be a group name or an org-unit name. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/admin-mobile-settings ', - name: 'gsuite.admin.distribution.entity.name', - type: 'keyword', + 'The number of bytes in the file stream that were completely missed during the process of analysis. ', + name: 'zeek.notice.file.missing_bytes', + type: 'long', }, - 'gsuite.admin.distribution.entity.type': { - category: 'gsuite', + 'zeek.notice.file.overflow_bytes': { + category: 'zeek', description: - 'The distribution entity type, which can be a group or an org-unit. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/admin-mobile-settings ', - name: 'gsuite.admin.distribution.entity.type', - type: 'keyword', - }, - 'gsuite.drive.billable': { - category: 'gsuite', - description: 'Whether this activity is billable.', - name: 'gsuite.drive.billable', - type: 'boolean', + "The number of bytes in the file stream that were not delivered to stream file analyzers. This could be overlapping bytes or bytes that couldn't be reassembled. ", + name: 'zeek.notice.file.overflow_bytes', + type: 'long', }, - 'gsuite.drive.source_folder_id': { - category: 'gsuite', - name: 'gsuite.drive.source_folder_id', + 'zeek.notice.fuid': { + category: 'zeek', + description: 'A file unique ID if this notice is related to a file. ', + name: 'zeek.notice.fuid', type: 'keyword', }, - 'gsuite.drive.source_folder_title': { - category: 'gsuite', - name: 'gsuite.drive.source_folder_title', + 'zeek.notice.note': { + category: 'zeek', + description: 'The type of the notice. ', + name: 'zeek.notice.note', type: 'keyword', }, - 'gsuite.drive.destination_folder_id': { - category: 'gsuite', - name: 'gsuite.drive.destination_folder_id', + 'zeek.notice.msg': { + category: 'zeek', + description: 'The human readable message for the notice. ', + name: 'zeek.notice.msg', type: 'keyword', }, - 'gsuite.drive.destination_folder_title': { - category: 'gsuite', - name: 'gsuite.drive.destination_folder_title', + 'zeek.notice.sub': { + category: 'zeek', + description: 'The human readable sub-message. ', + name: 'zeek.notice.sub', type: 'keyword', }, - 'gsuite.drive.file.id': { - category: 'gsuite', - name: 'gsuite.drive.file.id', - type: 'keyword', + 'zeek.notice.n': { + category: 'zeek', + description: 'Associated count, or a status code. ', + name: 'zeek.notice.n', + type: 'long', }, - 'gsuite.drive.file.type': { - category: 'gsuite', - description: - 'Document Drive type. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/drive ', - name: 'gsuite.drive.file.type', + 'zeek.notice.peer_name': { + category: 'zeek', + description: 'Name of remote peer that raised this notice. ', + name: 'zeek.notice.peer_name', type: 'keyword', }, - 'gsuite.drive.originating_app_id': { - category: 'gsuite', - description: 'The Google Cloud Project ID of the application that performed the action. ', - name: 'gsuite.drive.originating_app_id', - type: 'keyword', + 'zeek.notice.peer_descr': { + category: 'zeek', + description: 'Textual description for the peer that raised this notice. ', + name: 'zeek.notice.peer_descr', + type: 'text', }, - 'gsuite.drive.file.owner.email': { - category: 'gsuite', - name: 'gsuite.drive.file.owner.email', + 'zeek.notice.actions': { + category: 'zeek', + description: 'The actions which have been applied to this notice. ', + name: 'zeek.notice.actions', type: 'keyword', }, - 'gsuite.drive.file.owner.is_shared_drive': { - category: 'gsuite', - description: 'Boolean flag denoting whether owner is a shared drive. ', - name: 'gsuite.drive.file.owner.is_shared_drive', - type: 'boolean', - }, - 'gsuite.drive.primary_event': { - category: 'gsuite', + 'zeek.notice.email_body_sections': { + category: 'zeek', description: - 'Whether this is a primary event. A single user action in Drive may generate several events. ', - name: 'gsuite.drive.primary_event', - type: 'boolean', + 'By adding chunks of text into this element, other scripts can expand on notices that are being emailed. ', + name: 'zeek.notice.email_body_sections', + type: 'text', }, - 'gsuite.drive.shared_drive_id': { - category: 'gsuite', + 'zeek.notice.email_delay_tokens': { + category: 'zeek', description: - 'The unique identifier of the Team Drive. Only populated for for events relating to a Team Drive or item contained inside a Team Drive. ', - name: 'gsuite.drive.shared_drive_id', + 'Adding a string token to this set will cause the built-in emailing functionality to delay sending the email either the token has been removed or the email has been delayed for the specified time duration. ', + name: 'zeek.notice.email_delay_tokens', type: 'keyword', }, - 'gsuite.drive.visibility': { - category: 'gsuite', + 'zeek.notice.identifier': { + category: 'zeek', description: - 'Visibility of target file. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/drive ', - name: 'gsuite.drive.visibility', + 'This field is provided when a notice is generated for the purpose of deduplicating notices. ', + name: 'zeek.notice.identifier', type: 'keyword', }, - 'gsuite.drive.new_value': { - category: 'gsuite', + 'zeek.notice.suppress_for': { + category: 'zeek', description: - 'When a setting or property of the file changes, the new value for it will appear here. ', - name: 'gsuite.drive.new_value', - type: 'keyword', + 'This field indicates the length of time that this unique notice should be suppressed. ', + name: 'zeek.notice.suppress_for', + type: 'double', }, - 'gsuite.drive.old_value': { - category: 'gsuite', - description: - 'When a setting or property of the file changes, the old value for it will appear here. ', - name: 'gsuite.drive.old_value', - type: 'keyword', + 'zeek.notice.dropped': { + category: 'zeek', + description: 'Indicate if the source IP address was dropped and denied network access. ', + name: 'zeek.notice.dropped', + type: 'boolean', }, - 'gsuite.drive.sheets_import_range_recipient_doc': { - category: 'gsuite', - description: 'Doc ID of the recipient of a sheets import range.', - name: 'gsuite.drive.sheets_import_range_recipient_doc', + 'zeek.ntlm.domain': { + category: 'zeek', + description: 'Domain name given by the client. ', + name: 'zeek.ntlm.domain', type: 'keyword', }, - 'gsuite.drive.old_visibility': { - category: 'gsuite', - description: 'When visibility changes, this holds the old value. ', - name: 'gsuite.drive.old_visibility', + 'zeek.ntlm.hostname': { + category: 'zeek', + description: 'Hostname given by the client. ', + name: 'zeek.ntlm.hostname', type: 'keyword', }, - 'gsuite.drive.visibility_change': { - category: 'gsuite', - description: 'When visibility changes, this holds the new overall visibility of the file. ', - name: 'gsuite.drive.visibility_change', - type: 'keyword', + 'zeek.ntlm.success': { + category: 'zeek', + description: 'Indicate whether or not the authentication was successful. ', + name: 'zeek.ntlm.success', + type: 'boolean', }, - 'gsuite.drive.target_domain': { - category: 'gsuite', - description: - 'The domain for which the acccess scope was changed. This can also be the alias all to indicate the access scope was changed for all domains that have visibility for this document. ', - name: 'gsuite.drive.target_domain', + 'zeek.ntlm.username': { + category: 'zeek', + description: 'Username given by the client. ', + name: 'zeek.ntlm.username', type: 'keyword', }, - 'gsuite.drive.added_role': { - category: 'gsuite', - description: - 'Added membership role of a user/group in a Team Drive. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/drive ', - name: 'gsuite.drive.added_role', + 'zeek.ntlm.server.name.dns': { + category: 'zeek', + description: 'DNS name given by the server in a CHALLENGE. ', + name: 'zeek.ntlm.server.name.dns', type: 'keyword', }, - 'gsuite.drive.membership_change_type': { - category: 'gsuite', - description: - 'Type of change in Team Drive membership of a user/group. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/drive ', - name: 'gsuite.drive.membership_change_type', + 'zeek.ntlm.server.name.netbios': { + category: 'zeek', + description: 'NetBIOS name given by the server in a CHALLENGE. ', + name: 'zeek.ntlm.server.name.netbios', type: 'keyword', }, - 'gsuite.drive.shared_drive_settings_change_type': { - category: 'gsuite', - description: - 'Type of change in Team Drive settings. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/drive ', - name: 'gsuite.drive.shared_drive_settings_change_type', + 'zeek.ntlm.server.name.tree': { + category: 'zeek', + description: 'Tree name given by the server in a CHALLENGE. ', + name: 'zeek.ntlm.server.name.tree', type: 'keyword', }, - 'gsuite.drive.removed_role': { - category: 'gsuite', - description: - 'Removed membership role of a user/group in a Team Drive. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/drive ', - name: 'gsuite.drive.removed_role', - type: 'keyword', + 'zeek.ntp.version': { + category: 'zeek', + description: 'The NTP version number (1, 2, 3, 4). ', + name: 'zeek.ntp.version', + type: 'integer', }, - 'gsuite.drive.target': { - category: 'gsuite', - description: 'Target user or group.', - name: 'gsuite.drive.target', - type: 'keyword', + 'zeek.ntp.mode': { + category: 'zeek', + description: 'The NTP mode being used. ', + name: 'zeek.ntp.mode', + type: 'integer', }, - 'gsuite.groups.acl_permission': { - category: 'gsuite', - description: - 'Group permission setting updated. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/groups ', - name: 'gsuite.groups.acl_permission', - type: 'keyword', + 'zeek.ntp.stratum': { + category: 'zeek', + description: 'The stratum (primary server, secondary server, etc.). ', + name: 'zeek.ntp.stratum', + type: 'integer', }, - 'gsuite.groups.email': { - category: 'gsuite', - description: 'Group email. ', - name: 'gsuite.groups.email', - type: 'keyword', + 'zeek.ntp.poll': { + category: 'zeek', + description: 'The maximum interval between successive messages in seconds. ', + name: 'zeek.ntp.poll', + type: 'double', }, - 'gsuite.groups.member.email': { - category: 'gsuite', - description: 'Member email. ', - name: 'gsuite.groups.member.email', - type: 'keyword', + 'zeek.ntp.precision': { + category: 'zeek', + description: 'The precision of the system clock in seconds. ', + name: 'zeek.ntp.precision', + type: 'double', }, - 'gsuite.groups.member.role': { - category: 'gsuite', - description: - 'Member role. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/groups ', - name: 'gsuite.groups.member.role', - type: 'keyword', + 'zeek.ntp.root_delay': { + category: 'zeek', + description: 'Total round-trip delay to the reference clock in seconds. ', + name: 'zeek.ntp.root_delay', + type: 'double', }, - 'gsuite.groups.setting': { - category: 'gsuite', - description: - 'Group setting updated. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/groups ', - name: 'gsuite.groups.setting', - type: 'keyword', + 'zeek.ntp.root_disp': { + category: 'zeek', + description: 'Total dispersion to the reference clock in seconds. ', + name: 'zeek.ntp.root_disp', + type: 'double', }, - 'gsuite.groups.new_value': { - category: 'gsuite', + 'zeek.ntp.ref_id': { + category: 'zeek', description: - 'New value(s) of the group setting. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/groups ', - name: 'gsuite.groups.new_value', + 'For stratum 0, 4 character string used for debugging. For stratum 1, ID assigned to the reference clock by IANA. Above stratum 1, when using IPv4, the IP address of the reference clock. Note that the NTP protocol did not originally specify a large enough field to represent IPv6 addresses, so they use the first four bytes of the MD5 hash of the reference clock’s IPv6 address (i.e. an IPv4 address here is not necessarily IPv4). ', + name: 'zeek.ntp.ref_id', type: 'keyword', }, - 'gsuite.groups.old_value': { - category: 'gsuite', - description: - 'Old value(s) of the group setting. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/groups', - name: 'gsuite.groups.old_value', - type: 'keyword', + 'zeek.ntp.ref_time': { + category: 'zeek', + description: 'Time when the system clock was last set or correct. ', + name: 'zeek.ntp.ref_time', + type: 'date', }, - 'gsuite.groups.value': { - category: 'gsuite', - description: - 'Value of the group setting. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/groups ', - name: 'gsuite.groups.value', - type: 'keyword', + 'zeek.ntp.org_time': { + category: 'zeek', + description: 'Time at the client when the request departed for the NTP server. ', + name: 'zeek.ntp.org_time', + type: 'date', }, - 'gsuite.groups.message.id': { - category: 'gsuite', - description: 'SMTP message Id of an email message. Present for moderation events. ', - name: 'gsuite.groups.message.id', - type: 'keyword', + 'zeek.ntp.rec_time': { + category: 'zeek', + description: 'Time at the server when the request arrived from the NTP client. ', + name: 'zeek.ntp.rec_time', + type: 'date', }, - 'gsuite.groups.message.moderation_action': { - category: 'gsuite', - description: 'Message moderation action. Possible values are `approved` and `rejected`. ', - name: 'gsuite.groups.message.moderation_action', - type: 'keyword', + 'zeek.ntp.xmt_time': { + category: 'zeek', + description: 'Time at the server when the response departed for the NTP client. ', + name: 'zeek.ntp.xmt_time', + type: 'date', }, - 'gsuite.groups.status': { - category: 'gsuite', - description: - 'A status describing the output of an operation. Possible values are `failed` and `succeeded`. ', - name: 'gsuite.groups.status', - type: 'keyword', + 'zeek.ntp.num_exts': { + category: 'zeek', + description: 'Number of extension fields (which are not currently parsed). ', + name: 'zeek.ntp.num_exts', + type: 'integer', }, - 'gsuite.login.affected_email_address': { - category: 'gsuite', - name: 'gsuite.login.affected_email_address', + 'zeek.ocsp.file_id': { + category: 'zeek', + description: 'File id of the OCSP reply. ', + name: 'zeek.ocsp.file_id', type: 'keyword', }, - 'gsuite.login.challenge_method': { - category: 'gsuite', - description: - 'Login challenge method. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/login. ', - name: 'gsuite.login.challenge_method', + 'zeek.ocsp.hash.algorithm': { + category: 'zeek', + description: 'Hash algorithm used to generate issuerNameHash and issuerKeyHash. ', + name: 'zeek.ocsp.hash.algorithm', type: 'keyword', }, - 'gsuite.login.failure_type': { - category: 'gsuite', - description: - 'Login failure type. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/login. ', - name: 'gsuite.login.failure_type', + 'zeek.ocsp.hash.issuer.name': { + category: 'zeek', + description: "Hash of the issuer's distingueshed name. ", + name: 'zeek.ocsp.hash.issuer.name', type: 'keyword', }, - 'gsuite.login.type': { - category: 'gsuite', - description: - 'Login credentials type. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/login. ', - name: 'gsuite.login.type', + 'zeek.ocsp.hash.issuer.key': { + category: 'zeek', + description: "Hash of the issuer's public key. ", + name: 'zeek.ocsp.hash.issuer.key', type: 'keyword', }, - 'gsuite.login.is_second_factor': { - category: 'gsuite', - name: 'gsuite.login.is_second_factor', - type: 'boolean', - }, - 'gsuite.login.is_suspicious': { - category: 'gsuite', - name: 'gsuite.login.is_suspicious', - type: 'boolean', - }, - 'gsuite.saml.application_name': { - category: 'gsuite', - description: 'Saml SP application name. ', - name: 'gsuite.saml.application_name', + 'zeek.ocsp.serial_number': { + category: 'zeek', + description: 'Serial number of the affected certificate. ', + name: 'zeek.ocsp.serial_number', type: 'keyword', }, - 'gsuite.saml.failure_type': { - category: 'gsuite', - description: - 'Login failure type. For a list of possible values refer to https://developers.google.com/admin-sdk/reports/v1/appendix/activity/saml. ', - name: 'gsuite.saml.failure_type', + 'zeek.ocsp.status': { + category: 'zeek', + description: 'Status of the affected certificate. ', + name: 'zeek.ocsp.status', type: 'keyword', }, - 'gsuite.saml.initiated_by': { - category: 'gsuite', - description: 'Requester of SAML authentication. ', - name: 'gsuite.saml.initiated_by', - type: 'keyword', + 'zeek.ocsp.revoke.time': { + category: 'zeek', + description: 'Time at which the certificate was revoked. ', + name: 'zeek.ocsp.revoke.time', + type: 'date', }, - 'gsuite.saml.orgunit_path': { - category: 'gsuite', - description: 'User orgunit. ', - name: 'gsuite.saml.orgunit_path', + 'zeek.ocsp.revoke.reason': { + category: 'zeek', + description: 'Reason for which the certificate was revoked. ', + name: 'zeek.ocsp.revoke.reason', type: 'keyword', }, - 'gsuite.saml.status_code': { - category: 'gsuite', - description: 'SAML status code. ', - name: 'gsuite.saml.status_code', - type: 'long', - }, - 'gsuite.saml.second_level_status_code': { - category: 'gsuite', - description: 'SAML second level status code. ', - name: 'gsuite.saml.second_level_status_code', - type: 'long', + 'zeek.ocsp.update.this': { + category: 'zeek', + description: 'The time at which the status being shows is known to have been correct. ', + name: 'zeek.ocsp.update.this', + type: 'date', }, - 'ibmmq.errorlog.installation': { - category: 'ibmmq', + 'zeek.ocsp.update.next': { + category: 'zeek', description: - 'This is the installation name which can be given at installation time. Each installation of IBM MQ on UNIX, Linux, and Windows, has a unique identifier known as an installation name. The installation name is used to associate things such as queue managers and configuration files with an installation. ', - name: 'ibmmq.errorlog.installation', - type: 'keyword', + 'The latest time at which new information about the status of the certificate will be available. ', + name: 'zeek.ocsp.update.next', + type: 'date', }, - 'ibmmq.errorlog.qmgr': { - category: 'ibmmq', - description: - 'Name of the queue manager. Queue managers provide queuing services to applications, and manages the queues that belong to them. ', - name: 'ibmmq.errorlog.qmgr', + 'zeek.pe.client': { + category: 'zeek', + description: "The client's version string. ", + name: 'zeek.pe.client', type: 'keyword', }, - 'ibmmq.errorlog.arithinsert': { - category: 'ibmmq', - description: 'Changing content based on error.id', - name: 'ibmmq.errorlog.arithinsert', + 'zeek.pe.id': { + category: 'zeek', + description: 'File id of this portable executable file. ', + name: 'zeek.pe.id', type: 'keyword', }, - 'ibmmq.errorlog.commentinsert': { - category: 'ibmmq', - description: 'Changing content based on error.id', - name: 'ibmmq.errorlog.commentinsert', + 'zeek.pe.machine': { + category: 'zeek', + description: 'The target machine that the file was compiled for. ', + name: 'zeek.pe.machine', type: 'keyword', }, - 'ibmmq.errorlog.errordescription': { - category: 'ibmmq', - description: 'Please add description', - example: 'Please add example', - name: 'ibmmq.errorlog.errordescription', - type: 'text', - }, - 'ibmmq.errorlog.explanation': { - category: 'ibmmq', - description: 'Explaines the error in more detail', - name: 'ibmmq.errorlog.explanation', - type: 'keyword', + 'zeek.pe.compile_time': { + category: 'zeek', + description: 'The time that the file was created at. ', + name: 'zeek.pe.compile_time', + type: 'date', }, - 'ibmmq.errorlog.action': { - category: 'ibmmq', - description: 'Defines what to do when the error occurs', - name: 'ibmmq.errorlog.action', + 'zeek.pe.os': { + category: 'zeek', + description: 'The required operating system. ', + name: 'zeek.pe.os', type: 'keyword', }, - 'ibmmq.errorlog.code': { - category: 'ibmmq', - description: 'Error code.', - name: 'ibmmq.errorlog.code', + 'zeek.pe.subsystem': { + category: 'zeek', + description: 'The subsystem that is required to run this file. ', + name: 'zeek.pe.subsystem', type: 'keyword', }, - 'iptables.ether_type': { - category: 'iptables', - description: 'Value of the ethernet type field identifying the network layer protocol. ', - name: 'iptables.ether_type', - type: 'long', - }, - 'iptables.flow_label': { - category: 'iptables', - description: 'IPv6 flow label. ', - name: 'iptables.flow_label', - type: 'integer', + 'zeek.pe.is_exe': { + category: 'zeek', + description: 'Is the file an executable, or just an object file? ', + name: 'zeek.pe.is_exe', + type: 'boolean', }, - 'iptables.fragment_flags': { - category: 'iptables', - description: 'IP fragment flags. A combination of CE, DF and MF. ', - name: 'iptables.fragment_flags', - type: 'keyword', + 'zeek.pe.is_64bit': { + category: 'zeek', + description: 'Is the file a 64-bit executable? ', + name: 'zeek.pe.is_64bit', + type: 'boolean', }, - 'iptables.fragment_offset': { - category: 'iptables', - description: 'Offset of the current IP fragment. ', - name: 'iptables.fragment_offset', - type: 'long', + 'zeek.pe.uses_aslr': { + category: 'zeek', + description: 'Does the file support Address Space Layout Randomization? ', + name: 'zeek.pe.uses_aslr', + type: 'boolean', }, - 'iptables.icmp.code': { - category: 'iptables', - description: 'ICMP code. ', - name: 'iptables.icmp.code', - type: 'long', + 'zeek.pe.uses_dep': { + category: 'zeek', + description: 'Does the file support Data Execution Prevention? ', + name: 'zeek.pe.uses_dep', + type: 'boolean', }, - 'iptables.icmp.id': { - category: 'iptables', - description: 'ICMP ID. ', - name: 'iptables.icmp.id', - type: 'long', + 'zeek.pe.uses_code_integrity': { + category: 'zeek', + description: 'Does the file enforce code integrity checks? ', + name: 'zeek.pe.uses_code_integrity', + type: 'boolean', }, - 'iptables.icmp.parameter': { - category: 'iptables', - description: 'ICMP parameter. ', - name: 'iptables.icmp.parameter', - type: 'long', + 'zeek.pe.uses_seh': { + category: 'zeek', + description: 'Does the file use structured exception handing? ', + name: 'zeek.pe.uses_seh', + type: 'boolean', }, - 'iptables.icmp.redirect': { - category: 'iptables', - description: 'ICMP redirect address. ', - name: 'iptables.icmp.redirect', - type: 'ip', + 'zeek.pe.has_import_table': { + category: 'zeek', + description: 'Does the file have an import table? ', + name: 'zeek.pe.has_import_table', + type: 'boolean', }, - 'iptables.icmp.seq': { - category: 'iptables', - description: 'ICMP sequence number. ', - name: 'iptables.icmp.seq', - type: 'long', + 'zeek.pe.has_export_table': { + category: 'zeek', + description: 'Does the file have an export table? ', + name: 'zeek.pe.has_export_table', + type: 'boolean', }, - 'iptables.icmp.type': { - category: 'iptables', - description: 'ICMP type. ', - name: 'iptables.icmp.type', - type: 'long', + 'zeek.pe.has_cert_table': { + category: 'zeek', + description: 'Does the file have an attribute certificate table? ', + name: 'zeek.pe.has_cert_table', + type: 'boolean', }, - 'iptables.id': { - category: 'iptables', - description: 'Packet identifier. ', - name: 'iptables.id', - type: 'long', + 'zeek.pe.has_debug_data': { + category: 'zeek', + description: 'Does the file have a debug table? ', + name: 'zeek.pe.has_debug_data', + type: 'boolean', }, - 'iptables.incomplete_bytes': { - category: 'iptables', - description: 'Number of incomplete bytes. ', - name: 'iptables.incomplete_bytes', - type: 'long', + 'zeek.pe.section_names': { + category: 'zeek', + description: 'The names of the sections, in order. ', + name: 'zeek.pe.section_names', + type: 'keyword', }, - 'iptables.input_device': { - category: 'iptables', - description: 'Device that received the packet. ', - name: 'iptables.input_device', + 'zeek.radius.username': { + category: 'zeek', + description: 'The username, if present. ', + name: 'zeek.radius.username', type: 'keyword', }, - 'iptables.precedence_bits': { - category: 'iptables', - description: 'IP precedence bits. ', - name: 'iptables.precedence_bits', - type: 'short', + 'zeek.radius.mac': { + category: 'zeek', + description: 'MAC address, if present. ', + name: 'zeek.radius.mac', + type: 'keyword', }, - 'iptables.tos': { - category: 'iptables', - description: 'IP Type of Service field. ', - name: 'iptables.tos', - type: 'long', + 'zeek.radius.framed_addr': { + category: 'zeek', + description: + 'The address given to the network access server, if present. This is only a hint from the RADIUS server and the network access server is not required to honor the address. ', + name: 'zeek.radius.framed_addr', + type: 'ip', }, - 'iptables.length': { - category: 'iptables', - description: 'Packet length. ', - name: 'iptables.length', - type: 'long', + 'zeek.radius.remote_ip': { + category: 'zeek', + description: + 'Remote IP address, if present. This is collected from the Tunnel-Client-Endpoint attribute. ', + name: 'zeek.radius.remote_ip', + type: 'ip', }, - 'iptables.output_device': { - category: 'iptables', - description: 'Device that output the packet. ', - name: 'iptables.output_device', + 'zeek.radius.connect_info': { + category: 'zeek', + description: 'Connect info, if present. ', + name: 'zeek.radius.connect_info', type: 'keyword', }, - 'iptables.tcp.flags': { - category: 'iptables', - description: 'TCP flags. ', - name: 'iptables.tcp.flags', + 'zeek.radius.reply_msg': { + category: 'zeek', + description: + 'Reply message from the server challenge. This is frequently shown to the user authenticating. ', + name: 'zeek.radius.reply_msg', type: 'keyword', }, - 'iptables.tcp.reserved_bits': { - category: 'iptables', - description: 'TCP reserved bits. ', - name: 'iptables.tcp.reserved_bits', - type: 'short', - }, - 'iptables.tcp.seq': { - category: 'iptables', - description: 'TCP sequence number. ', - name: 'iptables.tcp.seq', - type: 'long', - }, - 'iptables.tcp.ack': { - category: 'iptables', - description: 'TCP Acknowledgment number. ', - name: 'iptables.tcp.ack', - type: 'long', - }, - 'iptables.tcp.window': { - category: 'iptables', - description: 'Advertised TCP window size. ', - name: 'iptables.tcp.window', - type: 'long', + 'zeek.radius.result': { + category: 'zeek', + description: 'Successful or failed authentication. ', + name: 'zeek.radius.result', + type: 'keyword', }, - 'iptables.ttl': { - category: 'iptables', - description: 'Time To Live field. ', - name: 'iptables.ttl', + 'zeek.radius.ttl': { + category: 'zeek', + description: + 'The duration between the first request and either the "Access-Accept" message or an error. If the field is empty, it means that either the request or response was not seen. ', + name: 'zeek.radius.ttl', type: 'integer', }, - 'iptables.udp.length': { - category: 'iptables', - description: 'Length of the UDP header and payload. ', - name: 'iptables.udp.length', - type: 'long', - }, - 'iptables.ubiquiti.input_zone': { - category: 'iptables', - description: 'Input zone. ', - name: 'iptables.ubiquiti.input_zone', - type: 'keyword', + 'zeek.radius.logged': { + category: 'zeek', + description: 'Whether this has already been logged and can be ignored. ', + name: 'zeek.radius.logged', + type: 'boolean', }, - 'iptables.ubiquiti.output_zone': { - category: 'iptables', - description: 'Output zone. ', - name: 'iptables.ubiquiti.output_zone', + 'zeek.rdp.cookie': { + category: 'zeek', + description: 'Cookie value used by the client machine. This is typically a username. ', + name: 'zeek.rdp.cookie', type: 'keyword', }, - 'iptables.ubiquiti.rule_number': { - category: 'iptables', - description: 'The rule number within the rule set.', - name: 'iptables.ubiquiti.rule_number', + 'zeek.rdp.result': { + category: 'zeek', + description: + "Status result for the connection. It's a mix between RDP negotation failure messages and GCC server create response messages. ", + name: 'zeek.rdp.result', type: 'keyword', }, - 'iptables.ubiquiti.rule_set': { - category: 'iptables', - description: 'The rule set name.', - name: 'iptables.ubiquiti.rule_set', + 'zeek.rdp.security_protocol': { + category: 'zeek', + description: 'Security protocol chosen by the server. ', + name: 'zeek.rdp.security_protocol', type: 'keyword', }, - 'microsoft.defender_atp.lastUpdateTime': { - category: 'microsoft', - description: 'The date and time (in UTC) the alert was last updated. ', - name: 'microsoft.defender_atp.lastUpdateTime', - type: 'date', - }, - 'microsoft.defender_atp.resolvedTime': { - category: 'microsoft', - description: "The date and time in which the status of the alert was changed to 'Resolved'. ", - name: 'microsoft.defender_atp.resolvedTime', - type: 'date', - }, - 'microsoft.defender_atp.incidentId': { - category: 'microsoft', - description: 'The Incident ID of the Alert. ', - name: 'microsoft.defender_atp.incidentId', + 'zeek.rdp.keyboard_layout': { + category: 'zeek', + description: 'Keyboard layout (language) of the client machine. ', + name: 'zeek.rdp.keyboard_layout', type: 'keyword', }, - 'microsoft.defender_atp.investigationId': { - category: 'microsoft', - description: 'The Investigation ID related to the Alert. ', - name: 'microsoft.defender_atp.investigationId', + 'zeek.rdp.client.build': { + category: 'zeek', + description: 'RDP client version used by the client machine. ', + name: 'zeek.rdp.client.build', type: 'keyword', }, - 'microsoft.defender_atp.investigationState': { - category: 'microsoft', - description: 'The current state of the Investigation. ', - name: 'microsoft.defender_atp.investigationState', + 'zeek.rdp.client.client_name': { + category: 'zeek', + description: 'Name of the client machine. ', + name: 'zeek.rdp.client.client_name', type: 'keyword', }, - 'microsoft.defender_atp.assignedTo': { - category: 'microsoft', - description: 'Owner of the alert. ', - name: 'microsoft.defender_atp.assignedTo', + 'zeek.rdp.client.product_id': { + category: 'zeek', + description: 'Product ID of the client machine. ', + name: 'zeek.rdp.client.product_id', type: 'keyword', }, - 'microsoft.defender_atp.status': { - category: 'microsoft', - description: - "Specifies the current status of the alert. Possible values are: 'Unknown', 'New', 'InProgress' and 'Resolved'. ", - name: 'microsoft.defender_atp.status', + 'zeek.rdp.desktop.width': { + category: 'zeek', + description: 'Desktop width of the client machine. ', + name: 'zeek.rdp.desktop.width', + type: 'integer', + }, + 'zeek.rdp.desktop.height': { + category: 'zeek', + description: 'Desktop height of the client machine. ', + name: 'zeek.rdp.desktop.height', + type: 'integer', + }, + 'zeek.rdp.desktop.color_depth': { + category: 'zeek', + description: 'The color depth requested by the client in the high_color_depth field. ', + name: 'zeek.rdp.desktop.color_depth', type: 'keyword', }, - 'microsoft.defender_atp.classification': { - category: 'microsoft', + 'zeek.rdp.cert.type': { + category: 'zeek', description: - "Specification of the alert. Possible values are: 'Unknown', 'FalsePositive', 'TruePositive'. ", - name: 'microsoft.defender_atp.classification', + 'If the connection is being encrypted with native RDP encryption, this is the type of cert being used. ', + name: 'zeek.rdp.cert.type', type: 'keyword', }, - 'microsoft.defender_atp.determination': { - category: 'microsoft', + 'zeek.rdp.cert.count': { + category: 'zeek', + description: 'The number of certs seen. X.509 can transfer an entire certificate chain. ', + name: 'zeek.rdp.cert.count', + type: 'integer', + }, + 'zeek.rdp.cert.permanent': { + category: 'zeek', description: - "Specifies the determination of the alert. Possible values are: 'NotAvailable', 'Apt', 'Malware', 'SecurityPersonnel', 'SecurityTesting', 'UnwantedSoftware', 'Other'. ", - name: 'microsoft.defender_atp.determination', - type: 'keyword', + 'Indicates if the provided certificate or certificate chain is permanent or temporary. ', + name: 'zeek.rdp.cert.permanent', + type: 'boolean', }, - 'microsoft.defender_atp.threatFamilyName': { - category: 'microsoft', - description: 'Threat family. ', - name: 'microsoft.defender_atp.threatFamilyName', + 'zeek.rdp.encryption.level': { + category: 'zeek', + description: 'Encryption level of the connection. ', + name: 'zeek.rdp.encryption.level', type: 'keyword', }, - 'microsoft.defender_atp.rbacGroupName': { - category: 'microsoft', - description: 'User group related to the alert ', - name: 'microsoft.defender_atp.rbacGroupName', + 'zeek.rdp.encryption.method': { + category: 'zeek', + description: 'Encryption method of the connection. ', + name: 'zeek.rdp.encryption.method', type: 'keyword', }, - 'microsoft.defender_atp.evidence.domainName': { - category: 'microsoft', - description: 'Domain name related to the alert ', - name: 'microsoft.defender_atp.evidence.domainName', - type: 'keyword', + 'zeek.rdp.done': { + category: 'zeek', + description: 'Track status of logging RDP connections. ', + name: 'zeek.rdp.done', + type: 'boolean', }, - 'microsoft.defender_atp.evidence.ipAddress': { - category: 'microsoft', - description: 'IP address involved in the alert ', - name: 'microsoft.defender_atp.evidence.ipAddress', - type: 'ip', + 'zeek.rdp.ssl': { + category: 'zeek', + description: + '(present if policy/protocols/rdp/indicate_ssl.bro is loaded) Flag the connection if it was seen over SSL. ', + name: 'zeek.rdp.ssl', + type: 'boolean', }, - 'microsoft.defender_atp.evidence.aadUserId': { - category: 'microsoft', - description: 'ID of the user involved in the alert ', - name: 'microsoft.defender_atp.evidence.aadUserId', + 'zeek.rfb.version.client.major': { + category: 'zeek', + description: 'Major version of the client. ', + name: 'zeek.rfb.version.client.major', type: 'keyword', }, - 'microsoft.defender_atp.evidence.accountName': { - category: 'microsoft', - description: 'Username of the user involved in the alert ', - name: 'microsoft.defender_atp.evidence.accountName', + 'zeek.rfb.version.client.minor': { + category: 'zeek', + description: 'Minor version of the client. ', + name: 'zeek.rfb.version.client.minor', type: 'keyword', }, - 'microsoft.defender_atp.evidence.entityType': { - category: 'microsoft', - description: 'The type of evidence ', - name: 'microsoft.defender_atp.evidence.entityType', + 'zeek.rfb.version.server.major': { + category: 'zeek', + description: 'Major version of the server. ', + name: 'zeek.rfb.version.server.major', type: 'keyword', }, - 'microsoft.defender_atp.evidence.userPrincipalName': { - category: 'microsoft', - description: 'Principal name of the user involved in the alert ', - name: 'microsoft.defender_atp.evidence.userPrincipalName', + 'zeek.rfb.version.server.minor': { + category: 'zeek', + description: 'Minor version of the server. ', + name: 'zeek.rfb.version.server.minor', type: 'keyword', }, - 'misp.attack_pattern.id': { - category: 'misp', - description: 'Identifier of the threat indicator. ', - name: 'misp.attack_pattern.id', - type: 'keyword', + 'zeek.rfb.auth.success': { + category: 'zeek', + description: 'Whether or not authentication was successful. ', + name: 'zeek.rfb.auth.success', + type: 'boolean', }, - 'misp.attack_pattern.name': { - category: 'misp', - description: 'Name of the attack pattern. ', - name: 'misp.attack_pattern.name', + 'zeek.rfb.auth.method': { + category: 'zeek', + description: 'Identifier of authentication method used. ', + name: 'zeek.rfb.auth.method', type: 'keyword', }, - 'misp.attack_pattern.description': { - category: 'misp', - description: 'Description of the attack pattern. ', - name: 'misp.attack_pattern.description', - type: 'text', + 'zeek.rfb.share_flag': { + category: 'zeek', + description: 'Whether the client has an exclusive or a shared session. ', + name: 'zeek.rfb.share_flag', + type: 'boolean', }, - 'misp.attack_pattern.kill_chain_phases': { - category: 'misp', - description: 'The kill chain phase(s) to which this attack pattern corresponds. ', - name: 'misp.attack_pattern.kill_chain_phases', + 'zeek.rfb.desktop_name': { + category: 'zeek', + description: 'Name of the screen that is being shared. ', + name: 'zeek.rfb.desktop_name', type: 'keyword', }, - 'misp.campaign.id': { - category: 'misp', - description: 'Identifier of the campaign. ', - name: 'misp.campaign.id', + 'zeek.rfb.width': { + category: 'zeek', + description: 'Width of the screen that is being shared. ', + name: 'zeek.rfb.width', + type: 'integer', + }, + 'zeek.rfb.height': { + category: 'zeek', + description: 'Height of the screen that is being shared. ', + name: 'zeek.rfb.height', + type: 'integer', + }, + 'zeek.signature.note': { + category: 'zeek', + description: 'Notice associated with signature event. ', + name: 'zeek.signature.note', type: 'keyword', }, - 'misp.campaign.name': { - category: 'misp', - description: 'Name of the campaign. ', - name: 'misp.campaign.name', + 'zeek.signature.sig_id': { + category: 'zeek', + description: 'The name of the signature that matched. ', + name: 'zeek.signature.sig_id', type: 'keyword', }, - 'misp.campaign.description': { - category: 'misp', - description: 'Description of the campaign. ', - name: 'misp.campaign.description', - type: 'text', + 'zeek.signature.event_msg': { + category: 'zeek', + description: 'A more descriptive message of the signature-matching event. ', + name: 'zeek.signature.event_msg', + type: 'keyword', }, - 'misp.campaign.aliases': { - category: 'misp', - description: 'Alternative names used to identify this campaign. ', - name: 'misp.campaign.aliases', - type: 'text', + 'zeek.signature.sub_msg': { + category: 'zeek', + description: 'Extracted payload data or extra message. ', + name: 'zeek.signature.sub_msg', + type: 'keyword', }, - 'misp.campaign.first_seen': { - category: 'misp', - description: 'The time that this Campaign was first seen, in RFC3339 format. ', - name: 'misp.campaign.first_seen', - type: 'date', + 'zeek.signature.sig_count': { + category: 'zeek', + description: 'Number of sigs, usually from summary count. ', + name: 'zeek.signature.sig_count', + type: 'integer', }, - 'misp.campaign.last_seen': { - category: 'misp', - description: 'The time that this Campaign was last seen, in RFC3339 format. ', - name: 'misp.campaign.last_seen', - type: 'date', + 'zeek.signature.host_count': { + category: 'zeek', + description: 'Number of hosts, from a summary count. ', + name: 'zeek.signature.host_count', + type: 'integer', }, - 'misp.campaign.objective': { - category: 'misp', + 'zeek.sip.transaction_depth': { + category: 'zeek', description: - "This field defines the Campaign's primary goal, objective, desired outcome, or intended effect. ", - name: 'misp.campaign.objective', - type: 'keyword', + 'Represents the pipelined depth into the connection of this request/response transaction. ', + name: 'zeek.sip.transaction_depth', + type: 'integer', }, - 'misp.course_of_action.id': { - category: 'misp', - description: 'Identifier of the Course of Action. ', - name: 'misp.course_of_action.id', + 'zeek.sip.sequence.method': { + category: 'zeek', + description: 'Verb used in the SIP request (INVITE, REGISTER etc.). ', + name: 'zeek.sip.sequence.method', type: 'keyword', }, - 'misp.course_of_action.name': { - category: 'misp', - description: 'The name used to identify the Course of Action. ', - name: 'misp.course_of_action.name', + 'zeek.sip.sequence.number': { + category: 'zeek', + description: 'Contents of the CSeq: header from the client. ', + name: 'zeek.sip.sequence.number', type: 'keyword', }, - 'misp.course_of_action.description': { - category: 'misp', - description: 'Description of the Course of Action. ', - name: 'misp.course_of_action.description', - type: 'text', - }, - 'misp.identity.id': { - category: 'misp', - description: 'Identifier of the Identity. ', - name: 'misp.identity.id', + 'zeek.sip.uri': { + category: 'zeek', + description: 'URI used in the request. ', + name: 'zeek.sip.uri', type: 'keyword', }, - 'misp.identity.name': { - category: 'misp', - description: 'The name used to identify the Identity. ', - name: 'misp.identity.name', + 'zeek.sip.date': { + category: 'zeek', + description: 'Contents of the Date: header from the client. ', + name: 'zeek.sip.date', type: 'keyword', }, - 'misp.identity.description': { - category: 'misp', - description: 'Description of the Identity. ', - name: 'misp.identity.description', - type: 'text', - }, - 'misp.identity.identity_class': { - category: 'misp', + 'zeek.sip.request.from': { + category: 'zeek', description: - 'The type of entity that this Identity describes, e.g., an individual or organization. Open Vocab - identity-class-ov ', - name: 'misp.identity.identity_class', + "Contents of the request From: header Note: The tag= value that's usually appended to the sender is stripped off and not logged. ", + name: 'zeek.sip.request.from', type: 'keyword', }, - 'misp.identity.labels': { - category: 'misp', - description: 'The list of roles that this Identity performs. ', - example: 'CEO\n', - name: 'misp.identity.labels', + 'zeek.sip.request.to': { + category: 'zeek', + description: 'Contents of the To: header. ', + name: 'zeek.sip.request.to', type: 'keyword', }, - 'misp.identity.sectors': { - category: 'misp', - description: - 'The list of sectors that this Identity belongs to. Open Vocab - industry-sector-ov ', - name: 'misp.identity.sectors', + 'zeek.sip.request.path': { + category: 'zeek', + description: 'The client message transmission path, as extracted from the headers. ', + name: 'zeek.sip.request.path', type: 'keyword', }, - 'misp.identity.contact_information': { - category: 'misp', - description: 'The contact information (e-mail, phone number, etc.) for this Identity. ', - name: 'misp.identity.contact_information', - type: 'text', + 'zeek.sip.request.body_length': { + category: 'zeek', + description: 'Contents of the Content-Length: header from the client. ', + name: 'zeek.sip.request.body_length', + type: 'long', }, - 'misp.intrusion_set.id': { - category: 'misp', - description: 'Identifier of the Intrusion Set. ', - name: 'misp.intrusion_set.id', + 'zeek.sip.response.from': { + category: 'zeek', + description: + "Contents of the response From: header Note: The tag= value that's usually appended to the sender is stripped off and not logged. ", + name: 'zeek.sip.response.from', type: 'keyword', }, - 'misp.intrusion_set.name': { - category: 'misp', - description: 'The name used to identify the Intrusion Set. ', - name: 'misp.intrusion_set.name', + 'zeek.sip.response.to': { + category: 'zeek', + description: 'Contents of the response To: header. ', + name: 'zeek.sip.response.to', type: 'keyword', }, - 'misp.intrusion_set.description': { - category: 'misp', - description: 'Description of the Intrusion Set. ', - name: 'misp.intrusion_set.description', - type: 'text', - }, - 'misp.intrusion_set.aliases': { - category: 'misp', - description: 'Alternative names used to identify the Intrusion Set. ', - name: 'misp.intrusion_set.aliases', - type: 'text', - }, - 'misp.intrusion_set.first_seen': { - category: 'misp', - description: 'The time that this Intrusion Set was first seen, in RFC3339 format. ', - name: 'misp.intrusion_set.first_seen', - type: 'date', - }, - 'misp.intrusion_set.last_seen': { - category: 'misp', - description: 'The time that this Intrusion Set was last seen, in RFC3339 format. ', - name: 'misp.intrusion_set.last_seen', - type: 'date', - }, - 'misp.intrusion_set.goals': { - category: 'misp', - description: 'The high level goals of this Intrusion Set, namely, what are they trying to do. ', - name: 'misp.intrusion_set.goals', - type: 'text', - }, - 'misp.intrusion_set.resource_level': { - category: 'misp', - description: - 'This defines the organizational level at which this Intrusion Set typically works. Open Vocab - attack-resource-level-ov ', - name: 'misp.intrusion_set.resource_level', - type: 'text', - }, - 'misp.intrusion_set.primary_motivation': { - category: 'misp', - description: - 'The primary reason, motivation, or purpose behind this Intrusion Set. Open Vocab - attack-motivation-ov ', - name: 'misp.intrusion_set.primary_motivation', - type: 'text', + 'zeek.sip.response.path': { + category: 'zeek', + description: 'The server message transmission path, as extracted from the headers. ', + name: 'zeek.sip.response.path', + type: 'keyword', }, - 'misp.intrusion_set.secondary_motivations': { - category: 'misp', - description: - 'The secondary reasons, motivations, or purposes behind this Intrusion Set. Open Vocab - attack-motivation-ov ', - name: 'misp.intrusion_set.secondary_motivations', - type: 'text', + 'zeek.sip.response.body_length': { + category: 'zeek', + description: 'Contents of the Content-Length: header from the server. ', + name: 'zeek.sip.response.body_length', + type: 'long', }, - 'misp.malware.id': { - category: 'misp', - description: 'Identifier of the Malware. ', - name: 'misp.malware.id', + 'zeek.sip.reply_to': { + category: 'zeek', + description: 'Contents of the Reply-To: header. ', + name: 'zeek.sip.reply_to', type: 'keyword', }, - 'misp.malware.name': { - category: 'misp', - description: 'The name used to identify the Malware. ', - name: 'misp.malware.name', + 'zeek.sip.call_id': { + category: 'zeek', + description: 'Contents of the Call-ID: header from the client. ', + name: 'zeek.sip.call_id', type: 'keyword', }, - 'misp.malware.description': { - category: 'misp', - description: 'Description of the Malware. ', - name: 'misp.malware.description', - type: 'text', - }, - 'misp.malware.labels': { - category: 'misp', - description: - 'The type of malware being described. Open Vocab - malware-label-ov. adware,backdoor,bot,ddos,dropper,exploit-kit,keylogger,ransomware, remote-access-trojan,resource-exploitation,rogue-security-software,rootkit, screen-capture,spyware,trojan,virus,worm ', - name: 'misp.malware.labels', + 'zeek.sip.subject': { + category: 'zeek', + description: 'Contents of the Subject: header from the client. ', + name: 'zeek.sip.subject', type: 'keyword', }, - 'misp.malware.kill_chain_phases': { - category: 'misp', - description: 'The list of kill chain phases for which this Malware instance can be used. ', - name: 'misp.malware.kill_chain_phases', + 'zeek.sip.user_agent': { + category: 'zeek', + description: 'Contents of the User-Agent: header from the client. ', + name: 'zeek.sip.user_agent', type: 'keyword', - format: 'string', }, - 'misp.note.id': { - category: 'misp', - description: 'Identifier of the Note. ', - name: 'misp.note.id', - type: 'keyword', + 'zeek.sip.status.code': { + category: 'zeek', + description: 'Status code returned by the server. ', + name: 'zeek.sip.status.code', + type: 'integer', }, - 'misp.note.summary': { - category: 'misp', - description: 'A brief description used as a summary of the Note. ', - name: 'misp.note.summary', + 'zeek.sip.status.msg': { + category: 'zeek', + description: 'Status message returned by the server. ', + name: 'zeek.sip.status.msg', type: 'keyword', }, - 'misp.note.description': { - category: 'misp', - description: 'The content of the Note. ', - name: 'misp.note.description', - type: 'text', - }, - 'misp.note.authors': { - category: 'misp', - description: 'The name of the author(s) of this Note. ', - name: 'misp.note.authors', + 'zeek.sip.warning': { + category: 'zeek', + description: 'Contents of the Warning: header. ', + name: 'zeek.sip.warning', type: 'keyword', }, - 'misp.note.object_refs': { - category: 'misp', - description: 'The STIX Objects (SDOs and SROs) that the note is being applied to. ', - name: 'misp.note.object_refs', + 'zeek.sip.content_type': { + category: 'zeek', + description: 'Contents of the Content-Type: header from the server. ', + name: 'zeek.sip.content_type', type: 'keyword', }, - 'misp.threat_indicator.labels': { - category: 'misp', - description: 'list of type open-vocab that specifies the type of indicator. ', - example: 'Domain Watchlist\n', - name: 'misp.threat_indicator.labels', + 'zeek.smb_cmd.command': { + category: 'zeek', + description: 'The command sent by the client. ', + name: 'zeek.smb_cmd.command', type: 'keyword', }, - 'misp.threat_indicator.id': { - category: 'misp', - description: 'Identifier of the threat indicator. ', - name: 'misp.threat_indicator.id', + 'zeek.smb_cmd.sub_command': { + category: 'zeek', + description: 'The subcommand sent by the client, if present. ', + name: 'zeek.smb_cmd.sub_command', type: 'keyword', }, - 'misp.threat_indicator.version': { - category: 'misp', - description: 'Version of the threat indicator. ', - name: 'misp.threat_indicator.version', + 'zeek.smb_cmd.argument': { + category: 'zeek', + description: 'Command argument sent by the client, if any. ', + name: 'zeek.smb_cmd.argument', type: 'keyword', }, - 'misp.threat_indicator.type': { - category: 'misp', - description: 'Type of the threat indicator. ', - name: 'misp.threat_indicator.type', + 'zeek.smb_cmd.status': { + category: 'zeek', + description: "Server reply to the client's command. ", + name: 'zeek.smb_cmd.status', type: 'keyword', }, - 'misp.threat_indicator.description': { - category: 'misp', - description: 'Description of the threat indicator. ', - name: 'misp.threat_indicator.description', - type: 'text', + 'zeek.smb_cmd.rtt': { + category: 'zeek', + description: 'Round trip time from the request to the response. ', + name: 'zeek.smb_cmd.rtt', + type: 'double', }, - 'misp.threat_indicator.feed': { - category: 'misp', - description: 'Name of the threat feed. ', - name: 'misp.threat_indicator.feed', - type: 'text', + 'zeek.smb_cmd.version': { + category: 'zeek', + description: 'Version of SMB for the command. ', + name: 'zeek.smb_cmd.version', + type: 'keyword', }, - 'misp.threat_indicator.valid_from': { - category: 'misp', - description: - 'The time from which this Indicator should be considered valuable intelligence, in RFC3339 format. ', - name: 'misp.threat_indicator.valid_from', - type: 'date', + 'zeek.smb_cmd.username': { + category: 'zeek', + description: 'Authenticated username, if available. ', + name: 'zeek.smb_cmd.username', + type: 'keyword', }, - 'misp.threat_indicator.valid_until': { - category: 'misp', + 'zeek.smb_cmd.tree': { + category: 'zeek', description: - 'The time at which this Indicator should no longer be considered valuable intelligence. If the valid_until property is omitted, then there is no constraint on the latest time for which the indicator should be used, in RFC3339 format. ', - name: 'misp.threat_indicator.valid_until', - type: 'date', - }, - 'misp.threat_indicator.severity': { - category: 'misp', - description: 'Threat severity to which this indicator corresponds. ', - example: 'high', - name: 'misp.threat_indicator.severity', + 'If this is related to a tree, this is the tree that was used for the current command. ', + name: 'zeek.smb_cmd.tree', type: 'keyword', - format: 'string', }, - 'misp.threat_indicator.confidence': { - category: 'misp', - description: 'Confidence level to which this indicator corresponds. ', - example: 'high', - name: 'misp.threat_indicator.confidence', + 'zeek.smb_cmd.tree_service': { + category: 'zeek', + description: 'The type of tree (disk share, printer share, named pipe, etc.). ', + name: 'zeek.smb_cmd.tree_service', type: 'keyword', }, - 'misp.threat_indicator.kill_chain_phases': { - category: 'misp', - description: 'The kill chain phase(s) to which this indicator corresponds. ', - name: 'misp.threat_indicator.kill_chain_phases', + 'zeek.smb_cmd.file.name': { + category: 'zeek', + description: 'Filename if one was seen. ', + name: 'zeek.smb_cmd.file.name', type: 'keyword', - format: 'string', }, - 'misp.threat_indicator.mitre_tactic': { - category: 'misp', - description: 'MITRE tactics to which this indicator corresponds. ', - example: 'Initial Access', - name: 'misp.threat_indicator.mitre_tactic', + 'zeek.smb_cmd.file.action': { + category: 'zeek', + description: 'Action this log record represents. ', + name: 'zeek.smb_cmd.file.action', type: 'keyword', - format: 'string', }, - 'misp.threat_indicator.mitre_technique': { - category: 'misp', - description: 'MITRE techniques to which this indicator corresponds. ', - example: 'Drive-by Compromise', - name: 'misp.threat_indicator.mitre_technique', + 'zeek.smb_cmd.file.uid': { + category: 'zeek', + description: 'UID of the referenced file. ', + name: 'zeek.smb_cmd.file.uid', type: 'keyword', - format: 'string', }, - 'misp.threat_indicator.attack_pattern': { - category: 'misp', + 'zeek.smb_cmd.file.host.tx': { + category: 'zeek', + description: 'Address of the transmitting host. ', + name: 'zeek.smb_cmd.file.host.tx', + type: 'ip', + }, + 'zeek.smb_cmd.file.host.rx': { + category: 'zeek', + description: 'Address of the receiving host. ', + name: 'zeek.smb_cmd.file.host.rx', + type: 'ip', + }, + 'zeek.smb_cmd.smb1_offered_dialects': { + category: 'zeek', description: - 'The attack_pattern for this indicator is a STIX Pattern as specified in STIX Version 2.0 Part 5 - STIX Patterning. ', - example: "[destination:ip = '91.219.29.188/32']\n", - name: 'misp.threat_indicator.attack_pattern', + 'Present if base/protocols/smb/smb1-main.bro is loaded. Dialects offered by the client. ', + name: 'zeek.smb_cmd.smb1_offered_dialects', type: 'keyword', }, - 'misp.threat_indicator.attack_pattern_kql': { - category: 'misp', + 'zeek.smb_cmd.smb2_offered_dialects': { + category: 'zeek', description: - 'The attack_pattern for this indicator is KQL query that matches the attack_pattern specified in the STIX Pattern format. ', - example: 'destination.ip: "91.219.29.188/32"\n', - name: 'misp.threat_indicator.attack_pattern_kql', + 'Present if base/protocols/smb/smb2-main.bro is loaded. Dialects offered by the client. ', + name: 'zeek.smb_cmd.smb2_offered_dialects', + type: 'integer', + }, + 'zeek.smb_files.action': { + category: 'zeek', + description: 'Action this log record represents. ', + name: 'zeek.smb_files.action', type: 'keyword', }, - 'misp.threat_indicator.negate': { - category: 'misp', - description: 'When set to true, it specifies the absence of the attack_pattern. ', - name: 'misp.threat_indicator.negate', - type: 'boolean', + 'zeek.smb_files.fid': { + category: 'zeek', + description: 'ID referencing this file. ', + name: 'zeek.smb_files.fid', + type: 'integer', }, - 'misp.threat_indicator.intrusion_set': { - category: 'misp', - description: 'Name of the intrusion set if known. ', - name: 'misp.threat_indicator.intrusion_set', + 'zeek.smb_files.name': { + category: 'zeek', + description: 'Filename if one was seen. ', + name: 'zeek.smb_files.name', type: 'keyword', }, - 'misp.threat_indicator.campaign': { - category: 'misp', - description: 'Name of the attack campaign if known. ', - name: 'misp.threat_indicator.campaign', + 'zeek.smb_files.path': { + category: 'zeek', + description: 'Path pulled from the tree this file was transferred to or from. ', + name: 'zeek.smb_files.path', type: 'keyword', }, - 'misp.threat_indicator.threat_actor': { - category: 'misp', - description: 'Name of the threat actor if known. ', - name: 'misp.threat_indicator.threat_actor', + 'zeek.smb_files.previous_name': { + category: 'zeek', + description: "If the rename action was seen, this will be the file's previous name. ", + name: 'zeek.smb_files.previous_name', type: 'keyword', }, - 'misp.observed_data.id': { - category: 'misp', - description: 'Identifier of the Observed Data. ', - name: 'misp.observed_data.id', - type: 'keyword', + 'zeek.smb_files.size': { + category: 'zeek', + description: 'Byte size of the file. ', + name: 'zeek.smb_files.size', + type: 'long', }, - 'misp.observed_data.first_observed': { - category: 'misp', - description: 'The beginning of the time window that the data was observed, in RFC3339 format. ', - name: 'misp.observed_data.first_observed', + 'zeek.smb_files.times.accessed': { + category: 'zeek', + description: "The file's access time. ", + name: 'zeek.smb_files.times.accessed', type: 'date', }, - 'misp.observed_data.last_observed': { - category: 'misp', - description: 'The end of the time window that the data was observed, in RFC3339 format. ', - name: 'misp.observed_data.last_observed', + 'zeek.smb_files.times.changed': { + category: 'zeek', + description: "The file's change time. ", + name: 'zeek.smb_files.times.changed', type: 'date', }, - 'misp.observed_data.number_observed': { - category: 'misp', - description: - 'The number of times the data represented in the objects property was observed. This MUST be an integer between 1 and 999,999,999 inclusive. ', - name: 'misp.observed_data.number_observed', - type: 'integer', + 'zeek.smb_files.times.created': { + category: 'zeek', + description: "The file's create time. ", + name: 'zeek.smb_files.times.created', + type: 'date', }, - 'misp.observed_data.objects': { - category: 'misp', - description: - 'A dictionary of Cyber Observable Objects that describes the single fact that was observed. ', - name: 'misp.observed_data.objects', - type: 'keyword', + 'zeek.smb_files.times.modified': { + category: 'zeek', + description: "The file's modify time. ", + name: 'zeek.smb_files.times.modified', + type: 'date', }, - 'misp.report.id': { - category: 'misp', - description: 'Identifier of the Report. ', - name: 'misp.report.id', + 'zeek.smb_files.uuid': { + category: 'zeek', + description: 'UUID referencing this file if DCE/RPC. ', + name: 'zeek.smb_files.uuid', type: 'keyword', }, - 'misp.report.labels': { - category: 'misp', - description: - 'This field is an Open Vocabulary that specifies the primary subject of this report. Open Vocab - report-label-ov. threat-report,attack-pattern,campaign,identity,indicator,malware,observed-data,threat-actor,tool,vulnerability ', - name: 'misp.report.labels', + 'zeek.smb_mapping.path': { + category: 'zeek', + description: 'Name of the tree path. ', + name: 'zeek.smb_mapping.path', type: 'keyword', }, - 'misp.report.name': { - category: 'misp', - description: 'The name used to identify the Report. ', - name: 'misp.report.name', + 'zeek.smb_mapping.service': { + category: 'zeek', + description: 'The type of resource of the tree (disk share, printer share, named pipe, etc.). ', + name: 'zeek.smb_mapping.service', type: 'keyword', }, - 'misp.report.description': { - category: 'misp', - description: 'A description that provides more details and context about Report. ', - name: 'misp.report.description', - type: 'text', + 'zeek.smb_mapping.native_file_system': { + category: 'zeek', + description: 'File system of the tree. ', + name: 'zeek.smb_mapping.native_file_system', + type: 'keyword', }, - 'misp.report.published': { - category: 'misp', + 'zeek.smb_mapping.share_type': { + category: 'zeek', description: - 'The date that this report object was officially published by the creator of this report, in RFC3339 format. ', - name: 'misp.report.published', - type: 'date', + 'If this is SMB2, a share type will be included. For SMB1, the type of share will be deduced and included as well. ', + name: 'zeek.smb_mapping.share_type', + type: 'keyword', }, - 'misp.report.object_refs': { - category: 'misp', - description: 'Specifies the STIX Objects that are referred to by this Report. ', - name: 'misp.report.object_refs', - type: 'text', + 'zeek.smtp.transaction_depth': { + category: 'zeek', + description: + 'A count to represent the depth of this message transaction in a single connection where multiple messages were transferred. ', + name: 'zeek.smtp.transaction_depth', + type: 'integer', }, - 'misp.threat_actor.id': { - category: 'misp', - description: 'Identifier of the Threat Actor. ', - name: 'misp.threat_actor.id', + 'zeek.smtp.helo': { + category: 'zeek', + description: 'Contents of the Helo header. ', + name: 'zeek.smtp.helo', type: 'keyword', }, - 'misp.threat_actor.labels': { - category: 'misp', - description: - 'This field specifies the type of threat actor. Open Vocab - threat-actor-label-ov. activist,competitor,crime-syndicate,criminal,hacker,insider-accidental,insider-disgruntled,nation-state,sensationalist,spy,terrorist ', - name: 'misp.threat_actor.labels', + 'zeek.smtp.mail_from': { + category: 'zeek', + description: 'Email addresses found in the MAIL FROM header. ', + name: 'zeek.smtp.mail_from', type: 'keyword', }, - 'misp.threat_actor.name': { - category: 'misp', - description: 'The name used to identify this Threat Actor or Threat Actor group. ', - name: 'misp.threat_actor.name', + 'zeek.smtp.rcpt_to': { + category: 'zeek', + description: 'Email addresses found in the RCPT TO header. ', + name: 'zeek.smtp.rcpt_to', type: 'keyword', }, - 'misp.threat_actor.description': { - category: 'misp', - description: 'A description that provides more details and context about the Threat Actor. ', - name: 'misp.threat_actor.description', - type: 'text', + 'zeek.smtp.date': { + category: 'zeek', + description: 'Contents of the Date header. ', + name: 'zeek.smtp.date', + type: 'date', }, - 'misp.threat_actor.aliases': { - category: 'misp', - description: 'A list of other names that this Threat Actor is believed to use. ', - name: 'misp.threat_actor.aliases', - type: 'text', + 'zeek.smtp.from': { + category: 'zeek', + description: 'Contents of the From header. ', + name: 'zeek.smtp.from', + type: 'keyword', }, - 'misp.threat_actor.roles': { - category: 'misp', - description: - 'This is a list of roles the Threat Actor plays. Open Vocab - threat-actor-role-ov. agent,director,independent,sponsor,infrastructure-operator,infrastructure-architect,malware-author ', - name: 'misp.threat_actor.roles', - type: 'text', + 'zeek.smtp.to': { + category: 'zeek', + description: 'Contents of the To header. ', + name: 'zeek.smtp.to', + type: 'keyword', }, - 'misp.threat_actor.goals': { - category: 'misp', - description: 'The high level goals of this Threat Actor, namely, what are they trying to do. ', - name: 'misp.threat_actor.goals', - type: 'text', + 'zeek.smtp.cc': { + category: 'zeek', + description: 'Contents of the CC header. ', + name: 'zeek.smtp.cc', + type: 'keyword', }, - 'misp.threat_actor.sophistication': { - category: 'misp', - description: - 'The skill, specific knowledge, special training, or expertise a Threat Actor must have to perform the attack. Open Vocab - threat-actor-sophistication-ov. none,minimal,intermediate,advanced,strategic,expert,innovator ', - name: 'misp.threat_actor.sophistication', - type: 'text', + 'zeek.smtp.reply_to': { + category: 'zeek', + description: 'Contents of the ReplyTo header. ', + name: 'zeek.smtp.reply_to', + type: 'keyword', }, - 'misp.threat_actor.resource_level': { - category: 'misp', - description: - 'This defines the organizational level at which this Threat Actor typically works. Open Vocab - attack-resource-level-ov. individual,club,contest,team,organization,government ', - name: 'misp.threat_actor.resource_level', - type: 'text', + 'zeek.smtp.msg_id': { + category: 'zeek', + description: 'Contents of the MsgID header. ', + name: 'zeek.smtp.msg_id', + type: 'keyword', }, - 'misp.threat_actor.primary_motivation': { - category: 'misp', - description: - 'The primary reason, motivation, or purpose behind this Threat Actor. Open Vocab - attack-motivation-ov. accidental,coercion,dominance,ideology,notoriety,organizational-gain,personal-gain,personal-satisfaction,revenge,unpredictable ', - name: 'misp.threat_actor.primary_motivation', - type: 'text', + 'zeek.smtp.in_reply_to': { + category: 'zeek', + description: 'Contents of the In-Reply-To header. ', + name: 'zeek.smtp.in_reply_to', + type: 'keyword', }, - 'misp.threat_actor.secondary_motivations': { - category: 'misp', - description: - 'The secondary reasons, motivations, or purposes behind this Threat Actor. Open Vocab - attack-motivation-ov. accidental,coercion,dominance,ideology,notoriety,organizational-gain,personal-gain,personal-satisfaction,revenge,unpredictable ', - name: 'misp.threat_actor.secondary_motivations', - type: 'text', + 'zeek.smtp.subject': { + category: 'zeek', + description: 'Contents of the Subject header. ', + name: 'zeek.smtp.subject', + type: 'keyword', }, - 'misp.threat_actor.personal_motivations': { - category: 'misp', - description: - 'The personal reasons, motivations, or purposes of the Threat Actor regardless of organizational goals. Open Vocab - attack-motivation-ov. accidental,coercion,dominance,ideology,notoriety,organizational-gain,personal-gain,personal-satisfaction,revenge,unpredictable ', - name: 'misp.threat_actor.personal_motivations', - type: 'text', + 'zeek.smtp.x_originating_ip': { + category: 'zeek', + description: 'Contents of the X-Originating-IP header. ', + name: 'zeek.smtp.x_originating_ip', + type: 'keyword', }, - 'misp.tool.id': { - category: 'misp', - description: 'Identifier of the Tool. ', - name: 'misp.tool.id', + 'zeek.smtp.first_received': { + category: 'zeek', + description: 'Contents of the first Received header. ', + name: 'zeek.smtp.first_received', type: 'keyword', }, - 'misp.tool.labels': { - category: 'misp', - description: - 'The kind(s) of tool(s) being described. Open Vocab - tool-label-ov. denial-of-service,exploitation,information-gathering,network-capture,credential-exploitation,remote-access,vulnerability-scanning ', - name: 'misp.tool.labels', + 'zeek.smtp.second_received': { + category: 'zeek', + description: 'Contents of the second Received header. ', + name: 'zeek.smtp.second_received', type: 'keyword', }, - 'misp.tool.name': { - category: 'misp', - description: 'The name used to identify the Tool. ', - name: 'misp.tool.name', + 'zeek.smtp.last_reply': { + category: 'zeek', + description: 'The last message that the server sent to the client. ', + name: 'zeek.smtp.last_reply', type: 'keyword', }, - 'misp.tool.description': { - category: 'misp', - description: 'A description that provides more details and context about the Tool. ', - name: 'misp.tool.description', - type: 'text', + 'zeek.smtp.path': { + category: 'zeek', + description: 'The message transmission path, as extracted from the headers. ', + name: 'zeek.smtp.path', + type: 'ip', }, - 'misp.tool.tool_version': { - category: 'misp', - description: 'The version identifier associated with the Tool. ', - name: 'misp.tool.tool_version', + 'zeek.smtp.user_agent': { + category: 'zeek', + description: 'Value of the User-Agent header from the client. ', + name: 'zeek.smtp.user_agent', type: 'keyword', }, - 'misp.tool.kill_chain_phases': { - category: 'misp', - description: 'The list of kill chain phases for which this Tool instance can be used. ', - name: 'misp.tool.kill_chain_phases', - type: 'text', + 'zeek.smtp.tls': { + category: 'zeek', + description: 'Indicates that the connection has switched to using TLS. ', + name: 'zeek.smtp.tls', + type: 'boolean', }, - 'misp.vulnerability.id': { - category: 'misp', - description: 'Identifier of the Vulnerability. ', - name: 'misp.vulnerability.id', - type: 'keyword', + 'zeek.smtp.process_received_from': { + category: 'zeek', + description: 'Indicates if the "Received: from" headers should still be processed. ', + name: 'zeek.smtp.process_received_from', + type: 'boolean', }, - 'misp.vulnerability.name': { - category: 'misp', - description: 'The name used to identify the Vulnerability. ', - name: 'misp.vulnerability.name', + 'zeek.smtp.has_client_activity': { + category: 'zeek', + description: 'Indicates if client activity has been seen, but not yet logged. ', + name: 'zeek.smtp.has_client_activity', + type: 'boolean', + }, + 'zeek.smtp.fuids': { + category: 'zeek', + description: + '(present if base/protocols/smtp/files.bro is loaded) An ordered vector of file unique IDs seen attached to the message. ', + name: 'zeek.smtp.fuids', type: 'keyword', }, - 'misp.vulnerability.description': { - category: 'misp', - description: 'A description that provides more details and context about the Vulnerability. ', - name: 'misp.vulnerability.description', - type: 'text', + 'zeek.smtp.is_webmail': { + category: 'zeek', + description: 'Indicates if the message was sent through a webmail interface. ', + name: 'zeek.smtp.is_webmail', + type: 'boolean', }, - 'mssql.log.origin': { - category: 'mssql', - description: 'Origin of the message, usually the server but it can also be a recovery process', - name: 'mssql.log.origin', - type: 'keyword', + 'zeek.snmp.duration': { + category: 'zeek', + description: + 'The amount of time between the first packet beloning to the SNMP session and the latest one seen. ', + name: 'zeek.snmp.duration', + type: 'double', }, - 'o365.audit.Actor.ID': { - category: 'o365', - name: 'o365.audit.Actor.ID', + 'zeek.snmp.version': { + category: 'zeek', + description: 'The version of SNMP being used. ', + name: 'zeek.snmp.version', type: 'keyword', }, - 'o365.audit.Actor.Type': { - category: 'o365', - name: 'o365.audit.Actor.Type', + 'zeek.snmp.community': { + category: 'zeek', + description: + "The community string of the first SNMP packet associated with the session. This is used as part of SNMP's (v1 and v2c) administrative/security framework. See RFC 1157 or RFC 1901. ", + name: 'zeek.snmp.community', type: 'keyword', }, - 'o365.audit.ActorContextId': { - category: 'o365', - name: 'o365.audit.ActorContextId', - type: 'keyword', + 'zeek.snmp.get.requests': { + category: 'zeek', + description: + 'The number of variable bindings in GetRequest/GetNextRequest PDUs seen for the session. ', + name: 'zeek.snmp.get.requests', + type: 'integer', }, - 'o365.audit.ActorIpAddress': { - category: 'o365', - name: 'o365.audit.ActorIpAddress', - type: 'keyword', + 'zeek.snmp.get.bulk_requests': { + category: 'zeek', + description: 'The number of variable bindings in GetBulkRequest PDUs seen for the session. ', + name: 'zeek.snmp.get.bulk_requests', + type: 'integer', }, - 'o365.audit.ActorUserId': { - category: 'o365', - name: 'o365.audit.ActorUserId', - type: 'keyword', + 'zeek.snmp.get.responses': { + category: 'zeek', + description: + 'The number of variable bindings in GetResponse/Response PDUs seen for the session. ', + name: 'zeek.snmp.get.responses', + type: 'integer', }, - 'o365.audit.ActorYammerUserId': { - category: 'o365', - name: 'o365.audit.ActorYammerUserId', - type: 'keyword', + 'zeek.snmp.set.requests': { + category: 'zeek', + description: 'The number of variable bindings in SetRequest PDUs seen for the session. ', + name: 'zeek.snmp.set.requests', + type: 'integer', }, - 'o365.audit.AlertEntityId': { - category: 'o365', - name: 'o365.audit.AlertEntityId', + 'zeek.snmp.display_string': { + category: 'zeek', + description: 'A system description of the SNMP responder endpoint. ', + name: 'zeek.snmp.display_string', type: 'keyword', }, - 'o365.audit.AlertId': { - category: 'o365', - name: 'o365.audit.AlertId', - type: 'keyword', + 'zeek.snmp.up_since': { + category: 'zeek', + description: "The time at which the SNMP responder endpoint claims it's been up since. ", + name: 'zeek.snmp.up_since', + type: 'date', }, - 'o365.audit.AlertLinks': { - category: 'o365', - name: 'o365.audit.AlertLinks', - type: 'array', + 'zeek.socks.version': { + category: 'zeek', + description: 'Protocol version of SOCKS. ', + name: 'zeek.socks.version', + type: 'integer', }, - 'o365.audit.AlertType': { - category: 'o365', - name: 'o365.audit.AlertType', + 'zeek.socks.user': { + category: 'zeek', + description: 'Username used to request a login to the proxy. ', + name: 'zeek.socks.user', type: 'keyword', }, - 'o365.audit.AppId': { - category: 'o365', - name: 'o365.audit.AppId', + 'zeek.socks.password': { + category: 'zeek', + description: 'Password used to request a login to the proxy. ', + name: 'zeek.socks.password', type: 'keyword', }, - 'o365.audit.ApplicationDisplayName': { - category: 'o365', - name: 'o365.audit.ApplicationDisplayName', + 'zeek.socks.status': { + category: 'zeek', + description: 'Server status for the attempt at using the proxy. ', + name: 'zeek.socks.status', type: 'keyword', }, - 'o365.audit.ApplicationId': { - category: 'o365', - name: 'o365.audit.ApplicationId', + 'zeek.socks.request.host': { + category: 'zeek', + description: 'Client requested SOCKS address. Could be an address, a name or both. ', + name: 'zeek.socks.request.host', type: 'keyword', }, - 'o365.audit.AzureActiveDirectoryEventType': { - category: 'o365', - name: 'o365.audit.AzureActiveDirectoryEventType', + 'zeek.socks.request.port': { + category: 'zeek', + description: 'Client requested port. ', + name: 'zeek.socks.request.port', + type: 'integer', + }, + 'zeek.socks.bound.host': { + category: 'zeek', + description: 'Server bound address. Could be an address, a name or both. ', + name: 'zeek.socks.bound.host', type: 'keyword', }, - 'o365.audit.ExchangeMetaData.*': { - category: 'o365', - name: 'o365.audit.ExchangeMetaData.*', - type: 'object', + 'zeek.socks.bound.port': { + category: 'zeek', + description: 'Server bound port. ', + name: 'zeek.socks.bound.port', + type: 'integer', }, - 'o365.audit.Category': { - category: 'o365', - name: 'o365.audit.Category', - type: 'keyword', + 'zeek.socks.capture_password': { + category: 'zeek', + description: 'Determines if the password will be captured for this request. ', + name: 'zeek.socks.capture_password', + type: 'boolean', }, - 'o365.audit.ClientAppId': { - category: 'o365', - name: 'o365.audit.ClientAppId', + 'zeek.ssh.client': { + category: 'zeek', + description: "The client's version string. ", + name: 'zeek.ssh.client', type: 'keyword', }, - 'o365.audit.ClientInfoString': { - category: 'o365', - name: 'o365.audit.ClientInfoString', + 'zeek.ssh.direction': { + category: 'zeek', + description: + 'Direction of the connection. If the client was a local host logging into an external host, this would be OUTBOUND. INBOUND would be set for the opposite situation. ', + name: 'zeek.ssh.direction', type: 'keyword', }, - 'o365.audit.ClientIP': { - category: 'o365', - name: 'o365.audit.ClientIP', + 'zeek.ssh.host_key': { + category: 'zeek', + description: "The server's key thumbprint. ", + name: 'zeek.ssh.host_key', type: 'keyword', }, - 'o365.audit.ClientIPAddress': { - category: 'o365', - name: 'o365.audit.ClientIPAddress', + 'zeek.ssh.server': { + category: 'zeek', + description: "The server's version string. ", + name: 'zeek.ssh.server', type: 'keyword', }, - 'o365.audit.Comments': { - category: 'o365', - name: 'o365.audit.Comments', - type: 'text', + 'zeek.ssh.version': { + category: 'zeek', + description: 'SSH major version (1 or 2). ', + name: 'zeek.ssh.version', + type: 'integer', }, - 'o365.audit.CorrelationId': { - category: 'o365', - name: 'o365.audit.CorrelationId', + 'zeek.ssh.algorithm.cipher': { + category: 'zeek', + description: 'The encryption algorithm in use. ', + name: 'zeek.ssh.algorithm.cipher', type: 'keyword', }, - 'o365.audit.CreationTime': { - category: 'o365', - name: 'o365.audit.CreationTime', + 'zeek.ssh.algorithm.compression': { + category: 'zeek', + description: 'The compression algorithm in use. ', + name: 'zeek.ssh.algorithm.compression', type: 'keyword', }, - 'o365.audit.CustomUniqueId': { - category: 'o365', - name: 'o365.audit.CustomUniqueId', + 'zeek.ssh.algorithm.host_key': { + category: 'zeek', + description: "The server host key's algorithm. ", + name: 'zeek.ssh.algorithm.host_key', type: 'keyword', }, - 'o365.audit.Data': { - category: 'o365', - name: 'o365.audit.Data', + 'zeek.ssh.algorithm.key_exchange': { + category: 'zeek', + description: 'The key exchange algorithm in use. ', + name: 'zeek.ssh.algorithm.key_exchange', type: 'keyword', }, - 'o365.audit.DataType': { - category: 'o365', - name: 'o365.audit.DataType', + 'zeek.ssh.algorithm.mac': { + category: 'zeek', + description: 'The signing (MAC) algorithm in use. ', + name: 'zeek.ssh.algorithm.mac', type: 'keyword', }, - 'o365.audit.EntityType': { - category: 'o365', - name: 'o365.audit.EntityType', - type: 'keyword', + 'zeek.ssh.auth.attempts': { + category: 'zeek', + description: + "The number of authentication attemps we observed. There's always at least one, since some servers might support no authentication at all. It's important to note that not all of these are failures, since some servers require two-factor auth (e.g. password AND pubkey). ", + name: 'zeek.ssh.auth.attempts', + type: 'integer', }, - 'o365.audit.EventData': { - category: 'o365', - name: 'o365.audit.EventData', + 'zeek.ssh.auth.success': { + category: 'zeek', + description: 'Authentication result. ', + name: 'zeek.ssh.auth.success', + type: 'boolean', + }, + 'zeek.ssl.version': { + category: 'zeek', + description: 'SSL/TLS version that was logged. ', + name: 'zeek.ssl.version', type: 'keyword', }, - 'o365.audit.EventSource': { - category: 'o365', - name: 'o365.audit.EventSource', + 'zeek.ssl.cipher': { + category: 'zeek', + description: 'SSL/TLS cipher suite that was logged. ', + name: 'zeek.ssl.cipher', type: 'keyword', }, - 'o365.audit.ExceptionInfo.*': { - category: 'o365', - name: 'o365.audit.ExceptionInfo.*', - type: 'object', + 'zeek.ssl.curve': { + category: 'zeek', + description: 'Elliptic curve that was logged when using ECDH/ECDHE. ', + name: 'zeek.ssl.curve', + type: 'keyword', }, - 'o365.audit.ExtendedProperties.*': { - category: 'o365', - name: 'o365.audit.ExtendedProperties.*', - type: 'object', + 'zeek.ssl.resumed': { + category: 'zeek', + description: + 'Flag to indicate if the session was resumed reusing the key material exchanged in an earlier connection. ', + name: 'zeek.ssl.resumed', + type: 'boolean', }, - 'o365.audit.ExternalAccess': { - category: 'o365', - name: 'o365.audit.ExternalAccess', + 'zeek.ssl.next_protocol': { + category: 'zeek', + description: + 'Next protocol the server chose using the application layer next protocol extension. ', + name: 'zeek.ssl.next_protocol', type: 'keyword', }, - 'o365.audit.GroupName': { - category: 'o365', - name: 'o365.audit.GroupName', - type: 'keyword', + 'zeek.ssl.established': { + category: 'zeek', + description: 'Flag to indicate if this ssl session has been established successfully. ', + name: 'zeek.ssl.established', + type: 'boolean', }, - 'o365.audit.Id': { - category: 'o365', - name: 'o365.audit.Id', + 'zeek.ssl.validation.status': { + category: 'zeek', + description: 'Result of certificate validation for this connection. ', + name: 'zeek.ssl.validation.status', type: 'keyword', }, - 'o365.audit.ImplicitShare': { - category: 'o365', - name: 'o365.audit.ImplicitShare', + 'zeek.ssl.validation.code': { + category: 'zeek', + description: + 'Result of certificate validation for this connection, given as OpenSSL validation code. ', + name: 'zeek.ssl.validation.code', type: 'keyword', }, - 'o365.audit.IncidentId': { - category: 'o365', - name: 'o365.audit.IncidentId', + 'zeek.ssl.last_alert': { + category: 'zeek', + description: 'Last alert that was seen during the connection. ', + name: 'zeek.ssl.last_alert', type: 'keyword', }, - 'o365.audit.InternalLogonType': { - category: 'o365', - name: 'o365.audit.InternalLogonType', + 'zeek.ssl.server.name': { + category: 'zeek', + description: + 'Value of the Server Name Indicator SSL/TLS extension. It indicates the server name that the client was requesting. ', + name: 'zeek.ssl.server.name', type: 'keyword', }, - 'o365.audit.InterSystemsId': { - category: 'o365', - name: 'o365.audit.InterSystemsId', + 'zeek.ssl.server.cert_chain': { + category: 'zeek', + description: + 'Chain of certificates offered by the server to validate its complete signing chain. ', + name: 'zeek.ssl.server.cert_chain', type: 'keyword', }, - 'o365.audit.IntraSystemId': { - category: 'o365', - name: 'o365.audit.IntraSystemId', + 'zeek.ssl.server.cert_chain_fuids': { + category: 'zeek', + description: + 'An ordered vector of certificate file identifiers for the certificates offered by the server. ', + name: 'zeek.ssl.server.cert_chain_fuids', type: 'keyword', }, - 'o365.audit.Item.*': { - category: 'o365', - name: 'o365.audit.Item.*', - type: 'object', - }, - 'o365.audit.Item.*.*': { - category: 'o365', - name: 'o365.audit.Item.*.*', - type: 'object', - }, - 'o365.audit.ItemName': { - category: 'o365', - name: 'o365.audit.ItemName', + 'zeek.ssl.server.issuer.common_name': { + category: 'zeek', + description: 'Common name of the signer of the X.509 certificate offered by the server. ', + name: 'zeek.ssl.server.issuer.common_name', type: 'keyword', }, - 'o365.audit.ItemType': { - category: 'o365', - name: 'o365.audit.ItemType', + 'zeek.ssl.server.issuer.country': { + category: 'zeek', + description: 'Country code of the signer of the X.509 certificate offered by the server. ', + name: 'zeek.ssl.server.issuer.country', type: 'keyword', }, - 'o365.audit.ListId': { - category: 'o365', - name: 'o365.audit.ListId', + 'zeek.ssl.server.issuer.locality': { + category: 'zeek', + description: 'Locality of the signer of the X.509 certificate offered by the server. ', + name: 'zeek.ssl.server.issuer.locality', type: 'keyword', }, - 'o365.audit.ListItemUniqueId': { - category: 'o365', - name: 'o365.audit.ListItemUniqueId', + 'zeek.ssl.server.issuer.organization': { + category: 'zeek', + description: 'Organization of the signer of the X.509 certificate offered by the server. ', + name: 'zeek.ssl.server.issuer.organization', type: 'keyword', }, - 'o365.audit.LogonError': { - category: 'o365', - name: 'o365.audit.LogonError', + 'zeek.ssl.server.issuer.organizational_unit': { + category: 'zeek', + description: + 'Organizational unit of the signer of the X.509 certificate offered by the server. ', + name: 'zeek.ssl.server.issuer.organizational_unit', type: 'keyword', }, - 'o365.audit.LogonType': { - category: 'o365', - name: 'o365.audit.LogonType', + 'zeek.ssl.server.issuer.state': { + category: 'zeek', + description: + 'State or province name of the signer of the X.509 certificate offered by the server. ', + name: 'zeek.ssl.server.issuer.state', type: 'keyword', }, - 'o365.audit.LogonUserSid': { - category: 'o365', - name: 'o365.audit.LogonUserSid', + 'zeek.ssl.server.subject.common_name': { + category: 'zeek', + description: 'Common name of the X.509 certificate offered by the server. ', + name: 'zeek.ssl.server.subject.common_name', type: 'keyword', }, - 'o365.audit.MailboxGuid': { - category: 'o365', - name: 'o365.audit.MailboxGuid', + 'zeek.ssl.server.subject.country': { + category: 'zeek', + description: 'Country code of the X.509 certificate offered by the server. ', + name: 'zeek.ssl.server.subject.country', type: 'keyword', }, - 'o365.audit.MailboxOwnerMasterAccountSid': { - category: 'o365', - name: 'o365.audit.MailboxOwnerMasterAccountSid', + 'zeek.ssl.server.subject.locality': { + category: 'zeek', + description: 'Locality of the X.509 certificate offered by the server. ', + name: 'zeek.ssl.server.subject.locality', type: 'keyword', }, - 'o365.audit.MailboxOwnerSid': { - category: 'o365', - name: 'o365.audit.MailboxOwnerSid', + 'zeek.ssl.server.subject.organization': { + category: 'zeek', + description: 'Organization of the X.509 certificate offered by the server. ', + name: 'zeek.ssl.server.subject.organization', type: 'keyword', }, - 'o365.audit.MailboxOwnerUPN': { - category: 'o365', - name: 'o365.audit.MailboxOwnerUPN', + 'zeek.ssl.server.subject.organizational_unit': { + category: 'zeek', + description: 'Organizational unit of the X.509 certificate offered by the server. ', + name: 'zeek.ssl.server.subject.organizational_unit', type: 'keyword', }, - 'o365.audit.Members': { - category: 'o365', - name: 'o365.audit.Members', - type: 'array', - }, - 'o365.audit.Members.*': { - category: 'o365', - name: 'o365.audit.Members.*', - type: 'object', - }, - 'o365.audit.ModifiedProperties.*.*': { - category: 'o365', - name: 'o365.audit.ModifiedProperties.*.*', - type: 'object', - }, - 'o365.audit.Name': { - category: 'o365', - name: 'o365.audit.Name', + 'zeek.ssl.server.subject.state': { + category: 'zeek', + description: 'State or province name of the X.509 certificate offered by the server. ', + name: 'zeek.ssl.server.subject.state', type: 'keyword', }, - 'o365.audit.ObjectId': { - category: 'o365', - name: 'o365.audit.ObjectId', + 'zeek.ssl.client.cert_chain': { + category: 'zeek', + description: + 'Chain of certificates offered by the client to validate its complete signing chain. ', + name: 'zeek.ssl.client.cert_chain', type: 'keyword', }, - 'o365.audit.Operation': { - category: 'o365', - name: 'o365.audit.Operation', + 'zeek.ssl.client.cert_chain_fuids': { + category: 'zeek', + description: + 'An ordered vector of certificate file identifiers for the certificates offered by the client. ', + name: 'zeek.ssl.client.cert_chain_fuids', type: 'keyword', }, - 'o365.audit.OrganizationId': { - category: 'o365', - name: 'o365.audit.OrganizationId', + 'zeek.ssl.client.issuer.common_name': { + category: 'zeek', + description: 'Common name of the signer of the X.509 certificate offered by the client. ', + name: 'zeek.ssl.client.issuer.common_name', type: 'keyword', }, - 'o365.audit.OrganizationName': { - category: 'o365', - name: 'o365.audit.OrganizationName', + 'zeek.ssl.client.issuer.country': { + category: 'zeek', + description: 'Country code of the signer of the X.509 certificate offered by the client. ', + name: 'zeek.ssl.client.issuer.country', type: 'keyword', }, - 'o365.audit.OriginatingServer': { - category: 'o365', - name: 'o365.audit.OriginatingServer', + 'zeek.ssl.client.issuer.locality': { + category: 'zeek', + description: 'Locality of the signer of the X.509 certificate offered by the client. ', + name: 'zeek.ssl.client.issuer.locality', type: 'keyword', }, - 'o365.audit.Parameters.*': { - category: 'o365', - name: 'o365.audit.Parameters.*', - type: 'object', - }, - 'o365.audit.PolicyDetails': { - category: 'o365', - name: 'o365.audit.PolicyDetails', - type: 'array', - }, - 'o365.audit.PolicyId': { - category: 'o365', - name: 'o365.audit.PolicyId', + 'zeek.ssl.client.issuer.organization': { + category: 'zeek', + description: 'Organization of the signer of the X.509 certificate offered by the client. ', + name: 'zeek.ssl.client.issuer.organization', type: 'keyword', }, - 'o365.audit.RecordType': { - category: 'o365', - name: 'o365.audit.RecordType', + 'zeek.ssl.client.issuer.organizational_unit': { + category: 'zeek', + description: + 'Organizational unit of the signer of the X.509 certificate offered by the client. ', + name: 'zeek.ssl.client.issuer.organizational_unit', type: 'keyword', }, - 'o365.audit.ResultStatus': { - category: 'o365', - name: 'o365.audit.ResultStatus', + 'zeek.ssl.client.issuer.state': { + category: 'zeek', + description: + 'State or province name of the signer of the X.509 certificate offered by the client. ', + name: 'zeek.ssl.client.issuer.state', type: 'keyword', }, - 'o365.audit.SensitiveInfoDetectionIsIncluded': { - category: 'o365', - name: 'o365.audit.SensitiveInfoDetectionIsIncluded', + 'zeek.ssl.client.subject.common_name': { + category: 'zeek', + description: 'Common name of the X.509 certificate offered by the client. ', + name: 'zeek.ssl.client.subject.common_name', type: 'keyword', }, - 'o365.audit.SharePointMetaData.*': { - category: 'o365', - name: 'o365.audit.SharePointMetaData.*', - type: 'object', + 'zeek.ssl.client.subject.country': { + category: 'zeek', + description: 'Country code of the X.509 certificate offered by the client. ', + name: 'zeek.ssl.client.subject.country', + type: 'keyword', }, - 'o365.audit.SessionId': { - category: 'o365', - name: 'o365.audit.SessionId', + 'zeek.ssl.client.subject.locality': { + category: 'zeek', + description: 'Locality of the X.509 certificate offered by the client. ', + name: 'zeek.ssl.client.subject.locality', type: 'keyword', }, - 'o365.audit.Severity': { - category: 'o365', - name: 'o365.audit.Severity', + 'zeek.ssl.client.subject.organization': { + category: 'zeek', + description: 'Organization of the X.509 certificate offered by the client. ', + name: 'zeek.ssl.client.subject.organization', type: 'keyword', }, - 'o365.audit.Site': { - category: 'o365', - name: 'o365.audit.Site', + 'zeek.ssl.client.subject.organizational_unit': { + category: 'zeek', + description: 'Organizational unit of the X.509 certificate offered by the client. ', + name: 'zeek.ssl.client.subject.organizational_unit', type: 'keyword', }, - 'o365.audit.SiteUrl': { - category: 'o365', - name: 'o365.audit.SiteUrl', + 'zeek.ssl.client.subject.state': { + category: 'zeek', + description: 'State or province name of the X.509 certificate offered by the client. ', + name: 'zeek.ssl.client.subject.state', type: 'keyword', }, - 'o365.audit.Source': { - category: 'o365', - name: 'o365.audit.Source', + 'zeek.stats.peer': { + category: 'zeek', + description: 'Peer that generated this log. Mostly for clusters. ', + name: 'zeek.stats.peer', type: 'keyword', }, - 'o365.audit.SourceFileExtension': { - category: 'o365', - name: 'o365.audit.SourceFileExtension', - type: 'keyword', + 'zeek.stats.memory': { + category: 'zeek', + description: 'Amount of memory currently in use in MB. ', + name: 'zeek.stats.memory', + type: 'integer', }, - 'o365.audit.SourceFileName': { - category: 'o365', - name: 'o365.audit.SourceFileName', - type: 'keyword', + 'zeek.stats.packets.processed': { + category: 'zeek', + description: 'Number of packets processed since the last stats interval. ', + name: 'zeek.stats.packets.processed', + type: 'long', }, - 'o365.audit.SourceRelativeUrl': { - category: 'o365', - name: 'o365.audit.SourceRelativeUrl', - type: 'keyword', + 'zeek.stats.packets.dropped': { + category: 'zeek', + description: + 'Number of packets dropped since the last stats interval if reading live traffic. ', + name: 'zeek.stats.packets.dropped', + type: 'long', }, - 'o365.audit.Status': { - category: 'o365', - name: 'o365.audit.Status', - type: 'keyword', + 'zeek.stats.packets.received': { + category: 'zeek', + description: + 'Number of packets seen on the link since the last stats interval if reading live traffic. ', + name: 'zeek.stats.packets.received', + type: 'long', }, - 'o365.audit.SupportTicketId': { - category: 'o365', - name: 'o365.audit.SupportTicketId', - type: 'keyword', + 'zeek.stats.bytes.received': { + category: 'zeek', + description: 'Number of bytes received since the last stats interval if reading live traffic. ', + name: 'zeek.stats.bytes.received', + type: 'long', }, - 'o365.audit.Target.ID': { - category: 'o365', - name: 'o365.audit.Target.ID', - type: 'keyword', + 'zeek.stats.connections.tcp.active': { + category: 'zeek', + description: 'TCP connections currently in memory. ', + name: 'zeek.stats.connections.tcp.active', + type: 'integer', }, - 'o365.audit.Target.Type': { - category: 'o365', - name: 'o365.audit.Target.Type', - type: 'keyword', + 'zeek.stats.connections.tcp.count': { + category: 'zeek', + description: 'TCP connections seen since last stats interval. ', + name: 'zeek.stats.connections.tcp.count', + type: 'integer', }, - 'o365.audit.TargetContextId': { - category: 'o365', - name: 'o365.audit.TargetContextId', - type: 'keyword', + 'zeek.stats.connections.udp.active': { + category: 'zeek', + description: 'UDP connections currently in memory. ', + name: 'zeek.stats.connections.udp.active', + type: 'integer', }, - 'o365.audit.TargetUserOrGroupName': { - category: 'o365', - name: 'o365.audit.TargetUserOrGroupName', - type: 'keyword', + 'zeek.stats.connections.udp.count': { + category: 'zeek', + description: 'UDP connections seen since last stats interval. ', + name: 'zeek.stats.connections.udp.count', + type: 'integer', }, - 'o365.audit.TargetUserOrGroupType': { - category: 'o365', - name: 'o365.audit.TargetUserOrGroupType', - type: 'keyword', + 'zeek.stats.connections.icmp.active': { + category: 'zeek', + description: 'ICMP connections currently in memory. ', + name: 'zeek.stats.connections.icmp.active', + type: 'integer', }, - 'o365.audit.TeamName': { - category: 'o365', - name: 'o365.audit.TeamName', - type: 'keyword', + 'zeek.stats.connections.icmp.count': { + category: 'zeek', + description: 'ICMP connections seen since last stats interval. ', + name: 'zeek.stats.connections.icmp.count', + type: 'integer', }, - 'o365.audit.TeamGuid': { - category: 'o365', - name: 'o365.audit.TeamGuid', - type: 'keyword', + 'zeek.stats.events.processed': { + category: 'zeek', + description: 'Number of events processed since the last stats interval. ', + name: 'zeek.stats.events.processed', + type: 'integer', }, - 'o365.audit.UniqueSharingId': { - category: 'o365', - name: 'o365.audit.UniqueSharingId', - type: 'keyword', + 'zeek.stats.events.queued': { + category: 'zeek', + description: 'Number of events that have been queued since the last stats interval. ', + name: 'zeek.stats.events.queued', + type: 'integer', }, - 'o365.audit.UserAgent': { - category: 'o365', - name: 'o365.audit.UserAgent', - type: 'keyword', + 'zeek.stats.timers.count': { + category: 'zeek', + description: 'Number of timers scheduled since last stats interval. ', + name: 'zeek.stats.timers.count', + type: 'integer', }, - 'o365.audit.UserId': { - category: 'o365', - name: 'o365.audit.UserId', - type: 'keyword', + 'zeek.stats.timers.active': { + category: 'zeek', + description: 'Current number of scheduled timers. ', + name: 'zeek.stats.timers.active', + type: 'integer', }, - 'o365.audit.UserKey': { - category: 'o365', - name: 'o365.audit.UserKey', - type: 'keyword', + 'zeek.stats.files.count': { + category: 'zeek', + description: 'Number of files seen since last stats interval. ', + name: 'zeek.stats.files.count', + type: 'integer', }, - 'o365.audit.UserType': { - category: 'o365', - name: 'o365.audit.UserType', - type: 'keyword', + 'zeek.stats.files.active': { + category: 'zeek', + description: 'Current number of files actively being seen. ', + name: 'zeek.stats.files.active', + type: 'integer', }, - 'o365.audit.Version': { - category: 'o365', - name: 'o365.audit.Version', - type: 'keyword', + 'zeek.stats.dns_requests.count': { + category: 'zeek', + description: 'Number of DNS requests seen since last stats interval. ', + name: 'zeek.stats.dns_requests.count', + type: 'integer', }, - 'o365.audit.WebId': { - category: 'o365', - name: 'o365.audit.WebId', - type: 'keyword', + 'zeek.stats.dns_requests.active': { + category: 'zeek', + description: 'Current number of DNS requests awaiting a reply. ', + name: 'zeek.stats.dns_requests.active', + type: 'integer', }, - 'o365.audit.Workload': { - category: 'o365', - name: 'o365.audit.Workload', - type: 'keyword', + 'zeek.stats.reassembly_size.tcp': { + category: 'zeek', + description: 'Current size of TCP data in reassembly. ', + name: 'zeek.stats.reassembly_size.tcp', + type: 'integer', }, - 'o365.audit.YammerNetworkId': { - category: 'o365', - name: 'o365.audit.YammerNetworkId', - type: 'keyword', + 'zeek.stats.reassembly_size.file': { + category: 'zeek', + description: 'Current size of File data in reassembly. ', + name: 'zeek.stats.reassembly_size.file', + type: 'integer', }, - 'okta.uuid': { - category: 'okta', - description: 'The unique identifier of the Okta LogEvent. ', - name: 'okta.uuid', - type: 'keyword', + 'zeek.stats.reassembly_size.frag': { + category: 'zeek', + description: 'Current size of packet fragment data in reassembly. ', + name: 'zeek.stats.reassembly_size.frag', + type: 'integer', }, - 'okta.event_type': { - category: 'okta', - description: 'The type of the LogEvent. ', - name: 'okta.event_type', - type: 'keyword', + 'zeek.stats.reassembly_size.unknown': { + category: 'zeek', + description: 'Current size of unknown data in reassembly (this is only PIA buffer right now). ', + name: 'zeek.stats.reassembly_size.unknown', + type: 'integer', }, - 'okta.version': { - category: 'okta', - description: 'The version of the LogEvent. ', - name: 'okta.version', + 'zeek.stats.timestamp_lag': { + category: 'zeek', + description: 'Lag between the wall clock and packet timestamps if reading live traffic. ', + name: 'zeek.stats.timestamp_lag', + type: 'integer', + }, + 'zeek.syslog.facility': { + category: 'zeek', + description: 'Syslog facility for the message. ', + name: 'zeek.syslog.facility', type: 'keyword', }, - 'okta.severity': { - category: 'okta', - description: 'The severity of the LogEvent. Must be one of DEBUG, INFO, WARN, or ERROR. ', - name: 'okta.severity', + 'zeek.syslog.severity': { + category: 'zeek', + description: 'Syslog severity for the message. ', + name: 'zeek.syslog.severity', type: 'keyword', }, - 'okta.display_message': { - category: 'okta', - description: 'The display message of the LogEvent. ', - name: 'okta.display_message', + 'zeek.syslog.message': { + category: 'zeek', + description: 'The plain text message. ', + name: 'zeek.syslog.message', type: 'keyword', }, - 'okta.actor.id': { - category: 'okta', - description: 'Identifier of the actor. ', - name: 'okta.actor.id', + 'zeek.tunnel.type': { + category: 'zeek', + description: 'The type of tunnel. ', + name: 'zeek.tunnel.type', type: 'keyword', }, - 'okta.actor.type': { - category: 'okta', - description: 'Type of the actor. ', - name: 'okta.actor.type', + 'zeek.tunnel.action': { + category: 'zeek', + description: 'The type of activity that occurred. ', + name: 'zeek.tunnel.action', type: 'keyword', }, - 'okta.actor.alternate_id': { - category: 'okta', - description: 'Alternate identifier of the actor. ', - name: 'okta.actor.alternate_id', + 'zeek.weird.name': { + category: 'zeek', + description: 'The name of the weird that occurred. ', + name: 'zeek.weird.name', type: 'keyword', }, - 'okta.actor.display_name': { - category: 'okta', - description: 'Display name of the actor. ', - name: 'okta.actor.display_name', + 'zeek.weird.additional_info': { + category: 'zeek', + description: 'Additional information accompanying the weird if any. ', + name: 'zeek.weird.additional_info', type: 'keyword', }, - 'okta.client.ip': { - category: 'okta', - description: 'The IP address of the client. ', - name: 'okta.client.ip', - type: 'ip', + 'zeek.weird.notice': { + category: 'zeek', + description: 'Indicate if this weird was also turned into a notice. ', + name: 'zeek.weird.notice', + type: 'boolean', }, - 'okta.client.user_agent.raw_user_agent': { - category: 'okta', - description: 'The raw informaton of the user agent. ', - name: 'okta.client.user_agent.raw_user_agent', + 'zeek.weird.peer': { + category: 'zeek', + description: + 'The peer that originated this weird. This is helpful in cluster deployments if a particular cluster node is having trouble to help identify which node is having trouble. ', + name: 'zeek.weird.peer', type: 'keyword', }, - 'okta.client.user_agent.os': { - category: 'okta', - description: 'The OS informaton. ', - name: 'okta.client.user_agent.os', + 'zeek.weird.identifier': { + category: 'zeek', + description: + 'This field is to be provided when a weird is generated for the purpose of deduplicating weirds. The identifier string should be unique for a single instance of the weird. This field is used to define when a weird is conceptually a duplicate of a previous weird. ', + name: 'zeek.weird.identifier', type: 'keyword', }, - 'okta.client.user_agent.browser': { - category: 'okta', - description: 'The browser informaton of the client. ', - name: 'okta.client.user_agent.browser', + 'zeek.x509.id': { + category: 'zeek', + description: 'File id of this certificate. ', + name: 'zeek.x509.id', type: 'keyword', }, - 'okta.client.zone': { - category: 'okta', - description: 'The zone information of the client. ', - name: 'okta.client.zone', - type: 'keyword', + 'zeek.x509.certificate.version': { + category: 'zeek', + description: 'Version number. ', + name: 'zeek.x509.certificate.version', + type: 'integer', }, - 'okta.client.device': { - category: 'okta', - description: 'The information of the client device. ', - name: 'okta.client.device', + 'zeek.x509.certificate.serial': { + category: 'zeek', + description: 'Serial number. ', + name: 'zeek.x509.certificate.serial', type: 'keyword', }, - 'okta.client.id': { - category: 'okta', - description: 'The identifier of the client. ', - name: 'okta.client.id', + 'zeek.x509.certificate.subject.country': { + category: 'zeek', + description: 'Country provided in the certificate subject. ', + name: 'zeek.x509.certificate.subject.country', type: 'keyword', }, - 'okta.outcome.reason': { - category: 'okta', - description: 'The reason of the outcome. ', - name: 'okta.outcome.reason', + 'zeek.x509.certificate.subject.common_name': { + category: 'zeek', + description: 'Common name provided in the certificate subject. ', + name: 'zeek.x509.certificate.subject.common_name', type: 'keyword', }, - 'okta.outcome.result': { - category: 'okta', - description: - 'The result of the outcome. Must be one of: SUCCESS, FAILURE, SKIPPED, ALLOW, DENY, CHALLENGE, UNKNOWN. ', - name: 'okta.outcome.result', + 'zeek.x509.certificate.subject.locality': { + category: 'zeek', + description: 'Locality provided in the certificate subject. ', + name: 'zeek.x509.certificate.subject.locality', type: 'keyword', }, - 'okta.target.id': { - category: 'okta', - description: 'Identifier of the actor. ', - name: 'okta.target.id', + 'zeek.x509.certificate.subject.organization': { + category: 'zeek', + description: 'Organization provided in the certificate subject. ', + name: 'zeek.x509.certificate.subject.organization', type: 'keyword', }, - 'okta.target.type': { - category: 'okta', - description: 'Type of the actor. ', - name: 'okta.target.type', + 'zeek.x509.certificate.subject.organizational_unit': { + category: 'zeek', + description: 'Organizational unit provided in the certificate subject. ', + name: 'zeek.x509.certificate.subject.organizational_unit', type: 'keyword', }, - 'okta.target.alternate_id': { - category: 'okta', - description: 'Alternate identifier of the actor. ', - name: 'okta.target.alternate_id', + 'zeek.x509.certificate.subject.state': { + category: 'zeek', + description: 'State or province provided in the certificate subject. ', + name: 'zeek.x509.certificate.subject.state', type: 'keyword', }, - 'okta.target.display_name': { - category: 'okta', - description: 'Display name of the actor. ', - name: 'okta.target.display_name', + 'zeek.x509.certificate.issuer.country': { + category: 'zeek', + description: 'Country provided in the certificate issuer field. ', + name: 'zeek.x509.certificate.issuer.country', type: 'keyword', }, - 'okta.transaction.id': { - category: 'okta', - description: 'Identifier of the transaction. ', - name: 'okta.transaction.id', + 'zeek.x509.certificate.issuer.common_name': { + category: 'zeek', + description: 'Common name provided in the certificate issuer field. ', + name: 'zeek.x509.certificate.issuer.common_name', type: 'keyword', }, - 'okta.transaction.type': { - category: 'okta', - description: 'The type of transaction. Must be one of "WEB", "JOB". ', - name: 'okta.transaction.type', + 'zeek.x509.certificate.issuer.locality': { + category: 'zeek', + description: 'Locality provided in the certificate issuer field. ', + name: 'zeek.x509.certificate.issuer.locality', type: 'keyword', }, - 'okta.debug_context.debug_data.device_fingerprint': { - category: 'okta', - description: 'The fingerprint of the device. ', - name: 'okta.debug_context.debug_data.device_fingerprint', + 'zeek.x509.certificate.issuer.organization': { + category: 'zeek', + description: 'Organization provided in the certificate issuer field. ', + name: 'zeek.x509.certificate.issuer.organization', type: 'keyword', }, - 'okta.debug_context.debug_data.request_id': { - category: 'okta', - description: 'The identifier of the request. ', - name: 'okta.debug_context.debug_data.request_id', + 'zeek.x509.certificate.issuer.organizational_unit': { + category: 'zeek', + description: 'Organizational unit provided in the certificate issuer field. ', + name: 'zeek.x509.certificate.issuer.organizational_unit', type: 'keyword', }, - 'okta.debug_context.debug_data.request_uri': { - category: 'okta', - description: 'The request URI. ', - name: 'okta.debug_context.debug_data.request_uri', + 'zeek.x509.certificate.issuer.state': { + category: 'zeek', + description: 'State or province provided in the certificate issuer field. ', + name: 'zeek.x509.certificate.issuer.state', type: 'keyword', }, - 'okta.debug_context.debug_data.threat_suspected': { - category: 'okta', - description: 'Threat suspected. ', - name: 'okta.debug_context.debug_data.threat_suspected', + 'zeek.x509.certificate.common_name': { + category: 'zeek', + description: 'Last (most specific) common name. ', + name: 'zeek.x509.certificate.common_name', type: 'keyword', }, - 'okta.debug_context.debug_data.url': { - category: 'okta', - description: 'The URL. ', - name: 'okta.debug_context.debug_data.url', + 'zeek.x509.certificate.valid.from': { + category: 'zeek', + description: 'Timestamp before when certificate is not valid. ', + name: 'zeek.x509.certificate.valid.from', + type: 'date', + }, + 'zeek.x509.certificate.valid.until': { + category: 'zeek', + description: 'Timestamp after when certificate is not valid. ', + name: 'zeek.x509.certificate.valid.until', + type: 'date', + }, + 'zeek.x509.certificate.key.algorithm': { + category: 'zeek', + description: 'Name of the key algorithm. ', + name: 'zeek.x509.certificate.key.algorithm', type: 'keyword', }, - 'okta.authentication_context.authentication_provider': { - category: 'okta', - description: - 'The information about the authentication provider. Must be one of OKTA_AUTHENTICATION_PROVIDER, ACTIVE_DIRECTORY, LDAP, FEDERATION, SOCIAL, FACTOR_PROVIDER. ', - name: 'okta.authentication_context.authentication_provider', + 'zeek.x509.certificate.key.type': { + category: 'zeek', + description: 'Key type, if key parseable by openssl (either rsa, dsa or ec). ', + name: 'zeek.x509.certificate.key.type', type: 'keyword', }, - 'okta.authentication_context.authentication_step': { - category: 'okta', - description: 'The authentication step. ', - name: 'okta.authentication_context.authentication_step', + 'zeek.x509.certificate.key.length': { + category: 'zeek', + description: 'Key length in bits. ', + name: 'zeek.x509.certificate.key.length', type: 'integer', }, - 'okta.authentication_context.credential_provider': { - category: 'okta', - description: - 'The information about credential provider. Must be one of OKTA_CREDENTIAL_PROVIDER, RSA, SYMANTEC, GOOGLE, DUO, YUBIKEY. ', - name: 'okta.authentication_context.credential_provider', + 'zeek.x509.certificate.signature_algorithm': { + category: 'zeek', + description: 'Name of the signature algorithm. ', + name: 'zeek.x509.certificate.signature_algorithm', type: 'keyword', - }, - 'okta.authentication_context.credential_type': { - category: 'okta', - description: - 'The information about credential type. Must be one of OTP, SMS, PASSWORD, ASSERTION, IWA, EMAIL, OAUTH2, JWT, CERTIFICATE, PRE_SHARED_SYMMETRIC_KEY, OKTA_CLIENT_SESSION, DEVICE_UDID. ', - name: 'okta.authentication_context.credential_type', + }, + 'zeek.x509.certificate.exponent': { + category: 'zeek', + description: 'Exponent, if RSA-certificate. ', + name: 'zeek.x509.certificate.exponent', type: 'keyword', }, - 'okta.authentication_context.issuer.id': { - category: 'okta', - description: 'The identifier of the issuer. ', - name: 'okta.authentication_context.issuer.id', + 'zeek.x509.certificate.curve': { + category: 'zeek', + description: 'Curve, if EC-certificate. ', + name: 'zeek.x509.certificate.curve', type: 'keyword', }, - 'okta.authentication_context.issuer.type': { - category: 'okta', - description: 'The type of the issuer. ', - name: 'okta.authentication_context.issuer.type', + 'zeek.x509.san.dns': { + category: 'zeek', + description: 'List of DNS entries in SAN. ', + name: 'zeek.x509.san.dns', type: 'keyword', }, - 'okta.authentication_context.external_session_id': { - category: 'okta', - description: 'The session identifer of the external session if any. ', - name: 'okta.authentication_context.external_session_id', + 'zeek.x509.san.uri': { + category: 'zeek', + description: 'List of URI entries in SAN. ', + name: 'zeek.x509.san.uri', type: 'keyword', }, - 'okta.authentication_context.interface': { - category: 'okta', - description: 'The interface used. e.g., Outlook, Office365, wsTrust ', - name: 'okta.authentication_context.interface', + 'zeek.x509.san.email': { + category: 'zeek', + description: 'List of email entries in SAN. ', + name: 'zeek.x509.san.email', type: 'keyword', }, - 'okta.security_context.as.number': { - category: 'okta', - description: 'The AS number. ', - name: 'okta.security_context.as.number', - type: 'integer', + 'zeek.x509.san.ip': { + category: 'zeek', + description: 'List of IP entries in SAN. ', + name: 'zeek.x509.san.ip', + type: 'ip', }, - 'okta.security_context.as.organization.name': { - category: 'okta', - description: 'The organization name. ', - name: 'okta.security_context.as.organization.name', - type: 'keyword', + 'zeek.x509.san.other_fields': { + category: 'zeek', + description: 'True if the certificate contained other, not recognized or parsed name fields. ', + name: 'zeek.x509.san.other_fields', + type: 'boolean', }, - 'okta.security_context.isp': { - category: 'okta', - description: 'The Internet Service Provider. ', - name: 'okta.security_context.isp', - type: 'keyword', + 'zeek.x509.basic_constraints.certificate_authority': { + category: 'zeek', + description: 'CA flag set or not. ', + name: 'zeek.x509.basic_constraints.certificate_authority', + type: 'boolean', }, - 'okta.security_context.domain': { - category: 'okta', - description: 'The domain name. ', - name: 'okta.security_context.domain', - type: 'keyword', + 'zeek.x509.basic_constraints.path_length': { + category: 'zeek', + description: 'Maximum path length. ', + name: 'zeek.x509.basic_constraints.path_length', + type: 'integer', }, - 'okta.security_context.is_proxy': { - category: 'okta', - description: 'Whether it is a proxy or not. ', - name: 'okta.security_context.is_proxy', + 'zeek.x509.log_cert': { + category: 'zeek', + description: + 'Present if policy/protocols/ssl/log-hostcerts-only.bro is loaded Logging of certificate is suppressed if set to F. ', + name: 'zeek.x509.log_cert', type: 'boolean', }, - 'okta.request.ip_chain.ip': { - category: 'okta', - description: 'IP address. ', - name: 'okta.request.ip_chain.ip', - type: 'ip', + 'zookeeper.audit.session': { + category: 'zookeeper', + description: 'Client session id ', + name: 'zookeeper.audit.session', + type: 'keyword', }, - 'okta.request.ip_chain.version': { - category: 'okta', - description: 'IP version. Must be one of V4, V6. ', - name: 'okta.request.ip_chain.version', + 'zookeeper.audit.znode': { + category: 'zookeeper', + description: 'Path of the znode ', + name: 'zookeeper.audit.znode', type: 'keyword', }, - 'okta.request.ip_chain.source': { - category: 'okta', - description: 'Source information. ', - name: 'okta.request.ip_chain.source', + 'zookeeper.audit.znode_type': { + category: 'zookeeper', + description: 'Type of znode in case of creation operation ', + name: 'zookeeper.audit.znode_type', type: 'keyword', }, - 'okta.request.ip_chain.geographical_context.city': { - category: 'okta', - description: 'The city.', - name: 'okta.request.ip_chain.geographical_context.city', + 'zookeeper.audit.acl': { + category: 'zookeeper', + description: + 'String representation of znode ACL like cdrwa(create, delete,read, write, admin). This is logged only for setAcl operation ', + name: 'zookeeper.audit.acl', type: 'keyword', }, - 'okta.request.ip_chain.geographical_context.state': { - category: 'okta', - description: 'The state.', - name: 'okta.request.ip_chain.geographical_context.state', + 'zookeeper.audit.result': { + category: 'zookeeper', + description: + 'Result of the operation. Possible values are (success/failure/invoked). Result "invoked" is used for serverStop operation because stop is logged before ensuring that server actually stopped. ', + name: 'zookeeper.audit.result', type: 'keyword', }, - 'okta.request.ip_chain.geographical_context.postal_code': { - category: 'okta', - description: 'The postal code.', - name: 'okta.request.ip_chain.geographical_context.postal_code', + 'zookeeper.audit.user': { + category: 'zookeeper', + description: 'Comma separated list of users who are associate with a client session ', + name: 'zookeeper.audit.user', type: 'keyword', }, - 'okta.request.ip_chain.geographical_context.country': { - category: 'okta', - description: 'The country.', - name: 'okta.request.ip_chain.geographical_context.country', + 'zookeeper.log': { + category: 'zookeeper', + description: 'ZooKeeper logs. ', + name: 'zookeeper.log', + type: 'group', + }, + 'zoom.master_account_id': { + category: 'zoom', + description: 'Master Account related to a specific Sub Account ', + name: 'zoom.master_account_id', type: 'keyword', }, - 'okta.request.ip_chain.geographical_context.geolocation': { - category: 'okta', - description: 'Geolocation information. ', - name: 'okta.request.ip_chain.geographical_context.geolocation', - type: 'geo_point', + 'zoom.sub_account_id': { + category: 'zoom', + description: 'Related Sub Account ', + name: 'zoom.sub_account_id', + type: 'keyword', }, - 'panw.panos.ruleset': { - category: 'panw', - description: 'Name of the rule that matched this session. ', - name: 'panw.panos.ruleset', + 'zoom.operator_id': { + category: 'zoom', + description: 'UserID that triggered the event ', + name: 'zoom.operator_id', type: 'keyword', }, - 'panw.panos.source.zone': { - category: 'panw', - description: 'Source zone for this session. ', - name: 'panw.panos.source.zone', + 'zoom.operator': { + category: 'zoom', + description: 'Username/Email related to the user that triggered the event ', + name: 'zoom.operator', type: 'keyword', }, - 'panw.panos.source.interface': { - category: 'panw', - description: 'Source interface for this session. ', - name: 'panw.panos.source.interface', + 'zoom.account_id': { + category: 'zoom', + description: 'Related accountID to the event ', + name: 'zoom.account_id', type: 'keyword', }, - 'panw.panos.source.nat.ip': { - category: 'panw', - description: 'Post-NAT source IP. ', - name: 'panw.panos.source.nat.ip', - type: 'ip', + 'zoom.timestamp': { + category: 'zoom', + description: 'Timestamp related to the event ', + name: 'zoom.timestamp', + type: 'date', }, - 'panw.panos.source.nat.port': { - category: 'panw', - description: 'Post-NAT source port. ', - name: 'panw.panos.source.nat.port', - type: 'long', + 'zoom.creation_type': { + category: 'zoom', + description: 'Creation type ', + name: 'zoom.creation_type', + type: 'keyword', }, - 'panw.panos.destination.zone': { - category: 'panw', - description: 'Destination zone for this session. ', - name: 'panw.panos.destination.zone', + 'zoom.account.owner_id': { + category: 'zoom', + description: 'UserID of the user whose sub account was created/disassociated ', + name: 'zoom.account.owner_id', type: 'keyword', }, - 'panw.panos.destination.interface': { - category: 'panw', - description: 'Destination interface for this session. ', - name: 'panw.panos.destination.interface', + 'zoom.account.email': { + category: 'zoom', + description: 'Email related to the user the action was performed on ', + name: 'zoom.account.email', type: 'keyword', }, - 'panw.panos.destination.nat.ip': { - category: 'panw', - description: 'Post-NAT destination IP. ', - name: 'panw.panos.destination.nat.ip', - type: 'ip', + 'zoom.account.owner_email': { + category: 'zoom', + description: 'Email of the user whose sub account was created/disassociated ', + name: 'zoom.account.owner_email', + type: 'keyword', }, - 'panw.panos.destination.nat.port': { - category: 'panw', - description: 'Post-NAT destination port. ', - name: 'panw.panos.destination.nat.port', - type: 'long', + 'zoom.account.account_name': { + category: 'zoom', + description: 'When an account name is updated, this is the new value set ', + name: 'zoom.account.account_name', + type: 'keyword', }, - 'panw.panos.network.pcap_id': { - category: 'panw', - description: 'Packet capture ID for a threat. ', - name: 'panw.panos.network.pcap_id', + 'zoom.account.account_alias': { + category: 'zoom', + description: 'When an account alias is updated, this is the new value set ', + name: 'zoom.account.account_alias', type: 'keyword', }, - 'panw.panos.network.nat.community_id': { - category: 'panw', - description: 'Community ID flow-hash for the NAT 5-tuple. ', - name: 'panw.panos.network.nat.community_id', + 'zoom.account.account_support_name': { + category: 'zoom', + description: 'When an account support_name is updated, this is the new value set ', + name: 'zoom.account.account_support_name', type: 'keyword', }, - 'panw.panos.file.hash': { - category: 'panw', - description: 'Binary hash for a threat file sent to be analyzed by the WildFire service. ', - name: 'panw.panos.file.hash', + 'zoom.account.account_support_email': { + category: 'zoom', + description: 'When an account support_email is updated, this is the new value set ', + name: 'zoom.account.account_support_email', type: 'keyword', }, - 'panw.panos.url.category': { - category: 'panw', - description: - "For threat URLs, it's the URL category. For WildFire, the verdict on the file and is either 'malicious', 'grayware', or 'benign'. ", - name: 'panw.panos.url.category', + 'zoom.chat_channel.name': { + category: 'zoom', + description: 'The name of the channel that has been added/modified/deleted ', + name: 'zoom.chat_channel.name', type: 'keyword', }, - 'panw.panos.flow_id': { - category: 'panw', - description: 'Internal numeric identifier for each session. ', - name: 'panw.panos.flow_id', + 'zoom.chat_channel.id': { + category: 'zoom', + description: 'The ID of the channel that has been added/modified/deleted ', + name: 'zoom.chat_channel.id', type: 'keyword', }, - 'panw.panos.sequence_number': { - category: 'panw', + 'zoom.chat_channel.type': { + category: 'zoom', description: - 'Log entry identifier that is incremented sequentially. Unique for each log type. ', - name: 'panw.panos.sequence_number', - type: 'long', - }, - 'panw.panos.threat.resource': { - category: 'panw', - description: 'URL or file name for a threat. ', - name: 'panw.panos.threat.resource', + 'Type of channel related to the event. Can be 1(Invite-Only), 2(Private) or 3(Public) ', + name: 'zoom.chat_channel.type', type: 'keyword', }, - 'panw.panos.threat.id': { - category: 'panw', - description: 'Palo Alto Networks identifier for the threat. ', - name: 'panw.panos.threat.id', + 'zoom.chat_message.id': { + category: 'zoom', + description: 'Unique ID of the related chat message ', + name: 'zoom.chat_message.id', type: 'keyword', }, - 'panw.panos.threat.name': { - category: 'panw', - description: 'Palo Alto Networks name for the threat. ', - name: 'panw.panos.threat.name', + 'zoom.chat_message.type': { + category: 'zoom', + description: 'Type of message, can be either "to_contact" or "to_channel" ', + name: 'zoom.chat_message.type', type: 'keyword', }, - 'panw.panos.action': { - category: 'panw', - description: 'Action taken for the session.', - name: 'panw.panos.action', + 'zoom.chat_message.session_id': { + category: 'zoom', + description: 'SessionID for the channel related to the message ', + name: 'zoom.chat_message.session_id', type: 'keyword', }, - 'rabbitmq.log.pid': { - category: 'rabbitmq', - description: 'The Erlang process id', - example: '<0.222.0>', - name: 'rabbitmq.log.pid', + 'zoom.chat_message.contact_email': { + category: 'zoom', + description: 'Email address related to the user sending the message ', + name: 'zoom.chat_message.contact_email', type: 'keyword', }, - 'sophos.xg.device': { - category: 'sophos', - description: 'device ', - name: 'sophos.xg.device', + 'zoom.chat_message.contact_id': { + category: 'zoom', + description: 'UserID belonging to the user receiving a message ', + name: 'zoom.chat_message.contact_id', type: 'keyword', }, - 'sophos.xg.date': { - category: 'sophos', - description: 'Date (yyyy-mm-dd) when the event occurred ', - name: 'sophos.xg.date', - type: 'date', - }, - 'sophos.xg.timezone': { - category: 'sophos', - description: 'Time (hh:mm:ss) when the event occurred ', - name: 'sophos.xg.timezone', + 'zoom.chat_message.channel_id': { + category: 'zoom', + description: 'ChannelID related to the message ', + name: 'zoom.chat_message.channel_id', type: 'keyword', }, - 'sophos.xg.device_name': { - category: 'sophos', - description: 'Model number of the device ', - name: 'sophos.xg.device_name', + 'zoom.chat_message.channel_name': { + category: 'zoom', + description: 'Channel name related to the message ', + name: 'zoom.chat_message.channel_name', type: 'keyword', }, - 'sophos.xg.device_id': { - category: 'sophos', - description: 'Serial number of the device ', - name: 'sophos.xg.device_id', + 'zoom.chat_message.message': { + category: 'zoom', + description: 'A string containing the full message that was sent ', + name: 'zoom.chat_message.message', type: 'keyword', }, - 'sophos.xg.log_id': { - category: 'sophos', - description: 'Unique 12 characters code (0101011) ', - name: 'sophos.xg.log_id', + 'zoom.meeting.id': { + category: 'zoom', + description: 'Unique ID of the related meeting ', + name: 'zoom.meeting.id', type: 'keyword', }, - 'sophos.xg.log_type': { - category: 'sophos', - description: 'Type of event e.g. firewall event ', - name: 'sophos.xg.log_type', + 'zoom.meeting.uuid': { + category: 'zoom', + description: 'The UUID of the related meeting ', + name: 'zoom.meeting.uuid', type: 'keyword', }, - 'sophos.xg.log_component': { - category: 'sophos', - description: 'Component responsible for logging e.g. Firewall rule ', - name: 'sophos.xg.log_component', + 'zoom.meeting.host_id': { + category: 'zoom', + description: 'The UserID of the configured meeting host ', + name: 'zoom.meeting.host_id', type: 'keyword', }, - 'sophos.xg.log_subtype': { - category: 'sophos', - description: 'Sub type of event ', - name: 'sophos.xg.log_subtype', + 'zoom.meeting.topic': { + category: 'zoom', + description: 'Topic of the related meeting ', + name: 'zoom.meeting.topic', type: 'keyword', }, - 'sophos.xg.hb_health': { - category: 'sophos', - description: 'Heartbeat status ', - name: 'sophos.xg.hb_health', + 'zoom.meeting.type': { + category: 'zoom', + description: 'Type of meeting created ', + name: 'zoom.meeting.type', type: 'keyword', }, - 'sophos.xg.priority': { - category: 'sophos', - description: 'Severity level of traffic ', - name: 'sophos.xg.priority', - type: 'keyword', + 'zoom.meeting.start_time': { + category: 'zoom', + description: 'Date and time the meeting started ', + name: 'zoom.meeting.start_time', + type: 'date', }, - 'sophos.xg.status': { - category: 'sophos', - description: 'Ultimate status of traffic – Allowed or Denied ', - name: 'sophos.xg.status', + 'zoom.meeting.timezone': { + category: 'zoom', + description: 'Which timezone is used for the meeting timestamps ', + name: 'zoom.meeting.timezone', type: 'keyword', }, - 'sophos.xg.duration': { - category: 'sophos', - description: 'Durability of traffic (seconds) ', - name: 'sophos.xg.duration', + 'zoom.meeting.duration': { + category: 'zoom', + description: 'The duration of a meeting in minutes ', + name: 'zoom.meeting.duration', type: 'long', }, - 'sophos.xg.fw_rule_id': { - category: 'sophos', - description: 'Firewall Rule ID which is applied on the traffic ', - name: 'sophos.xg.fw_rule_id', - type: 'integer', - }, - 'sophos.xg.user_name': { - category: 'sophos', - description: 'user_name ', - name: 'sophos.xg.user_name', + 'zoom.meeting.issues': { + category: 'zoom', + description: + 'When a user reports an issue with the meeting, for example: "Unstable audio quality" ', + name: 'zoom.meeting.issues', type: 'keyword', }, - 'sophos.xg.user_group': { - category: 'sophos', - description: 'Group name to which the user belongs ', - name: 'sophos.xg.user_group', + 'zoom.meeting.password': { + category: 'zoom', + description: 'Password related to the meeting ', + name: 'zoom.meeting.password', type: 'keyword', }, - 'sophos.xg.iap': { - category: 'sophos', - description: 'Internet Access policy ID applied on the traffic ', - name: 'sophos.xg.iap', + 'zoom.phone.id': { + category: 'zoom', + description: 'Unique ID for the phone or conversation ', + name: 'zoom.phone.id', type: 'keyword', }, - 'sophos.xg.ips_policy_id': { - category: 'sophos', - description: 'IPS policy ID applied on the traffic ', - name: 'sophos.xg.ips_policy_id', - type: 'integer', + 'zoom.phone.user_id': { + category: 'zoom', + description: 'UserID for the phone owner related to a Call Log being completed ', + name: 'zoom.phone.user_id', + type: 'keyword', }, - 'sophos.xg.policy_type': { - category: 'sophos', - description: 'Policy type applied to the traffic ', - name: 'sophos.xg.policy_type', + 'zoom.phone.download_url': { + category: 'zoom', + description: 'Download URL for the voicemail ', + name: 'zoom.phone.download_url', type: 'keyword', }, - 'sophos.xg.appfilter_policy_id': { - category: 'sophos', - description: 'Application Filter policy applied on the traffic ', - name: 'sophos.xg.appfilter_policy_id', - type: 'integer', + 'zoom.phone.ringing_start_time': { + category: 'zoom', + description: 'The timestamp when a ringtone was established to the callee ', + name: 'zoom.phone.ringing_start_time', + type: 'date', }, - 'sophos.xg.application_filter_policy': { - category: 'sophos', - description: 'Application Filter policy applied on the traffic ', - name: 'sophos.xg.application_filter_policy', - type: 'integer', + 'zoom.phone.connected_start_time': { + category: 'zoom', + description: 'The date and time when a ringtone was established to the callee ', + name: 'zoom.phone.connected_start_time', + type: 'date', }, - 'sophos.xg.application': { - category: 'sophos', - description: 'Application name ', - name: 'sophos.xg.application', - type: 'keyword', + 'zoom.phone.answer_start_time': { + category: 'zoom', + description: 'The date and time when the call was answered ', + name: 'zoom.phone.answer_start_time', + type: 'date', }, - 'sophos.xg.application_name': { - category: 'sophos', - description: 'Application name ', - name: 'sophos.xg.application_name', - type: 'keyword', + 'zoom.phone.call_end_time': { + category: 'zoom', + description: 'The date and time when the call ended ', + name: 'zoom.phone.call_end_time', + type: 'date', }, - 'sophos.xg.application_risk': { - category: 'sophos', - description: 'Risk level assigned to the application ', - name: 'sophos.xg.application_risk', + 'zoom.phone.call_id': { + category: 'zoom', + description: 'Unique ID of the related call ', + name: 'zoom.phone.call_id', type: 'keyword', }, - 'sophos.xg.application_technology': { - category: 'sophos', - description: 'Technology of the application ', - name: 'sophos.xg.application_technology', - type: 'keyword', + 'zoom.phone.duration': { + category: 'zoom', + description: 'Duration of a voicemail in minutes ', + name: 'zoom.phone.duration', + type: 'long', }, - 'sophos.xg.application_category': { - category: 'sophos', - description: 'Application is resolved by signature or synchronized application ', - name: 'sophos.xg.application_category', + 'zoom.phone.caller.id': { + category: 'zoom', + description: 'UserID of the caller related to the voicemail/call ', + name: 'zoom.phone.caller.id', type: 'keyword', }, - 'sophos.xg.appresolvedby': { - category: 'sophos', - description: 'Technology of the application ', - name: 'sophos.xg.appresolvedby', + 'zoom.phone.caller.user_id': { + category: 'zoom', + description: 'UserID of the person which initiated the call ', + name: 'zoom.phone.caller.user_id', type: 'keyword', }, - 'sophos.xg.app_is_cloud': { - category: 'sophos', - description: 'Application is Cloud ', - name: 'sophos.xg.app_is_cloud', + 'zoom.phone.caller.number_type': { + category: 'zoom', + description: 'The type of number, can be 1(Internal) or 2(External) ', + name: 'zoom.phone.caller.number_type', type: 'keyword', }, - 'sophos.xg.in_interface': { - category: 'sophos', - description: 'Interface for incoming traffic, e.g., Port A ', - name: 'sophos.xg.in_interface', + 'zoom.phone.caller.name': { + category: 'zoom', + description: 'The name of the related callee ', + name: 'zoom.phone.caller.name', type: 'keyword', }, - 'sophos.xg.out_interface': { - category: 'sophos', - description: 'Interface for outgoing traffic, e.g., Port B ', - name: 'sophos.xg.out_interface', + 'zoom.phone.caller.phone_number': { + category: 'zoom', + description: 'Phone Number of the caller related to the call ', + name: 'zoom.phone.caller.phone_number', type: 'keyword', }, - 'sophos.xg.src_ip': { - category: 'sophos', - description: 'Original source IP address of traffic ', - name: 'sophos.xg.src_ip', - type: 'ip', - }, - 'sophos.xg.src_mac': { - category: 'sophos', - description: 'Original source MAC address of traffic ', - name: 'sophos.xg.src_mac', + 'zoom.phone.caller.extension_type': { + category: 'zoom', + description: + 'Extension type of the caller number, can be user, callQueue, autoReceptionist or shareLineGroup ', + name: 'zoom.phone.caller.extension_type', type: 'keyword', }, - 'sophos.xg.src_country_code': { - category: 'sophos', - description: 'Code of the country to which the source IP belongs ', - name: 'sophos.xg.src_country_code', + 'zoom.phone.caller.extension_number': { + category: 'zoom', + description: 'Extension number of the caller ', + name: 'zoom.phone.caller.extension_number', type: 'keyword', }, - 'sophos.xg.dst_ip': { - category: 'sophos', - description: 'Original destination IP address of traffic ', - name: 'sophos.xg.dst_ip', - type: 'ip', - }, - 'sophos.xg.dst_country_code': { - category: 'sophos', - description: 'Code of the country to which the destination IP belongs ', - name: 'sophos.xg.dst_country_code', + 'zoom.phone.caller.timezone': { + category: 'zoom', + description: 'Timezone of the caller ', + name: 'zoom.phone.caller.timezone', type: 'keyword', }, - 'sophos.xg.protocol': { - category: 'sophos', - description: 'Protocol number of traffic ', - name: 'sophos.xg.protocol', + 'zoom.phone.caller.device_type': { + category: 'zoom', + description: 'Device type used by the caller ', + name: 'zoom.phone.caller.device_type', type: 'keyword', }, - 'sophos.xg.src_port': { - category: 'sophos', - description: 'Original source port of TCP and UDP traffic ', - name: 'sophos.xg.src_port', - type: 'integer', - }, - 'sophos.xg.dst_port': { - category: 'sophos', - description: 'Original destination port of TCP and UDP traffic ', - name: 'sophos.xg.dst_port', - type: 'integer', - }, - 'sophos.xg.icmp_type': { - category: 'sophos', - description: 'ICMP type of ICMP traffic ', - name: 'sophos.xg.icmp_type', + 'zoom.phone.callee.id': { + category: 'zoom', + description: 'UserID of the callee related to the voicemail/call ', + name: 'zoom.phone.callee.id', type: 'keyword', }, - 'sophos.xg.icmp_code': { - category: 'sophos', - description: 'ICMP code of ICMP traffic ', - name: 'sophos.xg.icmp_code', + 'zoom.phone.callee.user_id': { + category: 'zoom', + description: 'UserID of the related callee of a voicemail/call ', + name: 'zoom.phone.callee.user_id', type: 'keyword', }, - 'sophos.xg.sent_pkts': { - category: 'sophos', - description: 'Total number of packets sent ', - name: 'sophos.xg.sent_pkts', - type: 'long', + 'zoom.phone.callee.name': { + category: 'zoom', + description: 'The name of the related callee ', + name: 'zoom.phone.callee.name', + type: 'keyword', }, - 'sophos.xg.received_pkts': { - category: 'sophos', - description: 'Total number of packets received ', - name: 'sophos.xg.received_pkts', - type: 'long', + 'zoom.phone.callee.number_type': { + category: 'zoom', + description: 'The type of number, can be 1(Internal) or 2(External) ', + name: 'zoom.phone.callee.number_type', + type: 'keyword', }, - 'sophos.xg.sent_bytes': { - category: 'sophos', - description: 'Total number of bytes sent ', - name: 'sophos.xg.sent_bytes', - type: 'long', + 'zoom.phone.callee.phone_number': { + category: 'zoom', + description: 'Phone Number of the callee related to the call ', + name: 'zoom.phone.callee.phone_number', + type: 'keyword', }, - 'sophos.xg.recv_bytes': { - category: 'sophos', - description: 'Total number of bytes received ', - name: 'sophos.xg.recv_bytes', - type: 'long', + 'zoom.phone.callee.extension_type': { + category: 'zoom', + description: + 'Extension type of the callee number, can be user, callQueue, autoReceptionist or shareLineGroup ', + name: 'zoom.phone.callee.extension_type', + type: 'keyword', }, - 'sophos.xg.trans_src_ ip': { - category: 'sophos', - description: 'Translated source IP address for outgoing traffic ', - name: 'sophos.xg.trans_src_ ip', - type: 'ip', + 'zoom.phone.callee.extension_number': { + category: 'zoom', + description: 'Extension number of the callee related to the call ', + name: 'zoom.phone.callee.extension_number', + type: 'keyword', }, - 'sophos.xg.trans_src_port': { - category: 'sophos', - description: 'Translated source port for outgoing traffic ', - name: 'sophos.xg.trans_src_port', - type: 'integer', + 'zoom.phone.callee.timezone': { + category: 'zoom', + description: 'Timezone of the callee related to the call ', + name: 'zoom.phone.callee.timezone', + type: 'keyword', }, - 'sophos.xg.trans_dst_ip': { - category: 'sophos', - description: 'Translated destination IP address for outgoing traffic ', - name: 'sophos.xg.trans_dst_ip', - type: 'ip', + 'zoom.phone.callee.device_type': { + category: 'zoom', + description: 'Device type used by the callee related to the call ', + name: 'zoom.phone.callee.device_type', + type: 'keyword', }, - 'sophos.xg.trans_dst_port': { - category: 'sophos', - description: 'Translated destination port for outgoing traffic ', - name: 'sophos.xg.trans_dst_port', - type: 'integer', + 'zoom.phone.date_time': { + category: 'zoom', + description: 'Date and time of the related phone event ', + name: 'zoom.phone.date_time', + type: 'date', }, - 'sophos.xg.srczonetype': { - category: 'sophos', - description: 'Type of source zone, e.g., LAN ', - name: 'sophos.xg.srczonetype', + 'zoom.recording.id': { + category: 'zoom', + description: 'Unique ID of the related recording ', + name: 'zoom.recording.id', type: 'keyword', }, - 'sophos.xg.srczone': { - category: 'sophos', - description: 'Name of source zone ', - name: 'sophos.xg.srczone', + 'zoom.recording.uuid': { + category: 'zoom', + description: 'UUID of the related recording ', + name: 'zoom.recording.uuid', type: 'keyword', }, - 'sophos.xg.dstzonetype': { - category: 'sophos', - description: 'Type of destination zone, e.g., WAN ', - name: 'sophos.xg.dstzonetype', + 'zoom.recording.host_id': { + category: 'zoom', + description: 'UserID of the host of the meeting that was recorded ', + name: 'zoom.recording.host_id', type: 'keyword', }, - 'sophos.xg.dstzone': { - category: 'sophos', - description: 'Name of destination zone ', - name: 'sophos.xg.dstzone', + 'zoom.recording.topic': { + category: 'zoom', + description: 'Topic of the meeting related to the recording ', + name: 'zoom.recording.topic', type: 'keyword', }, - 'sophos.xg.dir_disp': { - category: 'sophos', - description: 'TPacket direction. Possible values:“org”, “reply”, “” ', - name: 'sophos.xg.dir_disp', + 'zoom.recording.type': { + category: 'zoom', + description: + 'Type of recording, can be multiple type of values, please check Zoom documentation ', + name: 'zoom.recording.type', type: 'keyword', }, - 'sophos.xg.connevent': { - category: 'sophos', - description: 'Event on which this log is generated ', - name: 'sophos.xg.connevent', + 'zoom.recording.start_time': { + category: 'zoom', + description: 'The date and time when the recording started ', + name: 'zoom.recording.start_time', + type: 'date', + }, + 'zoom.recording.timezone': { + category: 'zoom', + description: 'The timezone used for the recording date ', + name: 'zoom.recording.timezone', type: 'keyword', }, - 'sophos.xg.conn_id': { - category: 'sophos', - description: 'Unique identifier of connection ', - name: 'sophos.xg.conn_id', - type: 'integer', + 'zoom.recording.duration': { + category: 'zoom', + description: 'Duration of the recording in minutes ', + name: 'zoom.recording.duration', + type: 'long', }, - 'sophos.xg.vconn_id': { - category: 'sophos', - description: 'Connection ID of the master connection ', - name: 'sophos.xg.vconn_id', - type: 'integer', + 'zoom.recording.share_url': { + category: 'zoom', + description: 'The URL to access the recording ', + name: 'zoom.recording.share_url', + type: 'keyword', }, - 'sophos.xg.idp_policy_id': { - category: 'sophos', - description: 'IPS policy ID which is applied on the traffic ', - name: 'sophos.xg.idp_policy_id', - type: 'integer', + 'zoom.recording.total_size': { + category: 'zoom', + description: 'Total size of the recording in bytes ', + name: 'zoom.recording.total_size', + type: 'long', }, - 'sophos.xg.idp_policy_name': { - category: 'sophos', - description: 'IPS policy name i.e. IPS policy name which is applied on the traffic ', - name: 'sophos.xg.idp_policy_name', - type: 'keyword', + 'zoom.recording.recording_count': { + category: 'zoom', + description: 'Number of recording files related to the recording ', + name: 'zoom.recording.recording_count', + type: 'long', }, - 'sophos.xg.signature_id': { - category: 'sophos', - description: 'Signature ID ', - name: 'sophos.xg.signature_id', - type: 'keyword', + 'zoom.recording.recording_file.recording_start': { + category: 'zoom', + description: 'The date and time the recording started ', + name: 'zoom.recording.recording_file.recording_start', + type: 'date', + }, + 'zoom.recording.recording_file.recording_end': { + category: 'zoom', + description: 'The date and time the recording finished ', + name: 'zoom.recording.recording_file.recording_end', + type: 'date', }, - 'sophos.xg.signature_msg': { - category: 'sophos', - description: 'Signature messsage ', - name: 'sophos.xg.signature_msg', + 'zoom.recording.host_email': { + category: 'zoom', + description: 'Email address of the host related to the meeting that was recorded ', + name: 'zoom.recording.host_email', type: 'keyword', }, - 'sophos.xg.classification': { - category: 'sophos', - description: 'Signature classification ', - name: 'sophos.xg.classification', + 'zoom.user.id': { + category: 'zoom', + description: 'UserID related to the user event ', + name: 'zoom.user.id', type: 'keyword', }, - 'sophos.xg.rule_priority': { - category: 'sophos', - description: 'Priority of IPS policy ', - name: 'sophos.xg.rule_priority', + 'zoom.user.first_name': { + category: 'zoom', + description: 'User first name related to the user event ', + name: 'zoom.user.first_name', type: 'keyword', }, - 'sophos.xg.platform': { - category: 'sophos', - description: 'Platform of the traffic. ', - name: 'sophos.xg.platform', + 'zoom.user.last_name': { + category: 'zoom', + description: 'User last name related to the user event ', + name: 'zoom.user.last_name', type: 'keyword', }, - 'sophos.xg.category': { - category: 'sophos', - description: 'IPS signature category. ', - name: 'sophos.xg.category', + 'zoom.user.email': { + category: 'zoom', + description: 'User email related to the user event ', + name: 'zoom.user.email', type: 'keyword', }, - 'sophos.xg.target': { - category: 'sophos', - description: 'Platform of the traffic. ', - name: 'sophos.xg.target', + 'zoom.user.type': { + category: 'zoom', + description: 'User type related to the user event ', + name: 'zoom.user.type', type: 'keyword', }, - 'sophos.xg.eventid': { - category: 'sophos', - description: 'ATP Evenet ID ', - name: 'sophos.xg.eventid', + 'zoom.user.phone_number': { + category: 'zoom', + description: 'User phone number related to the user event ', + name: 'zoom.user.phone_number', type: 'keyword', }, - 'sophos.xg.ep_uuid': { - category: 'sophos', - description: 'Endpoint UUID ', - name: 'sophos.xg.ep_uuid', + 'zoom.user.phone_country': { + category: 'zoom', + description: 'User country code related to the user event ', + name: 'zoom.user.phone_country', type: 'keyword', }, - 'sophos.xg.threatname': { - category: 'sophos', - description: 'ATP threatname ', - name: 'sophos.xg.threatname', + 'zoom.user.company': { + category: 'zoom', + description: 'User company related to the user event ', + name: 'zoom.user.company', type: 'keyword', }, - 'sophos.xg.sourceip': { - category: 'sophos', - description: 'Original source IP address of traffic ', - name: 'sophos.xg.sourceip', - type: 'ip', + 'zoom.user.pmi': { + category: 'zoom', + description: 'User personal meeting ID related to the user event ', + name: 'zoom.user.pmi', + type: 'keyword', }, - 'sophos.xg.destinationip': { - category: 'sophos', - description: 'Original destination IP address of traffic ', - name: 'sophos.xg.destinationip', - type: 'ip', + 'zoom.user.use_pmi': { + category: 'zoom', + description: 'If a user has PMI enabled ', + name: 'zoom.user.use_pmi', + type: 'boolean', }, - 'sophos.xg.login_user': { - category: 'sophos', - description: 'ATP login user ', - name: 'sophos.xg.login_user', + 'zoom.user.pic_url': { + category: 'zoom', + description: 'Full URL to the profile picture used by the user ', + name: 'zoom.user.pic_url', type: 'keyword', }, - 'sophos.xg.eventtype': { - category: 'sophos', - description: 'ATP event type ', - name: 'sophos.xg.eventtype', + 'zoom.user.vanity_name': { + category: 'zoom', + description: 'Name of the personal meeting room related to the user event ', + name: 'zoom.user.vanity_name', type: 'keyword', }, - 'sophos.xg.execution_path': { - category: 'sophos', - description: 'ATP execution path ', - name: 'sophos.xg.execution_path', + 'zoom.user.timezone': { + category: 'zoom', + description: 'Timezone configured for the user ', + name: 'zoom.user.timezone', type: 'keyword', }, - 'sophos.xg.av_policy_name': { - category: 'sophos', - description: 'Malware scanning policy name which is applied on the traffic ', - name: 'sophos.xg.av_policy_name', + 'zoom.user.language': { + category: 'zoom', + description: 'Language configured for the user ', + name: 'zoom.user.language', type: 'keyword', }, - 'sophos.xg.from_email_address': { - category: 'sophos', - description: 'Sender email address ', - name: 'sophos.xg.from_email_address', + 'zoom.user.host_key': { + category: 'zoom', + description: 'Host key set for the user ', + name: 'zoom.user.host_key', type: 'keyword', }, - 'sophos.xg.to_email_address': { - category: 'sophos', - description: 'Receipeint email address ', - name: 'sophos.xg.to_email_address', + 'zoom.user.role': { + category: 'zoom', + description: 'The configured role for the user ', + name: 'zoom.user.role', type: 'keyword', }, - 'sophos.xg.subject': { - category: 'sophos', - description: 'Email subject ', - name: 'sophos.xg.subject', + 'zoom.user.dept': { + category: 'zoom', + description: 'The configured departement for the user ', + name: 'zoom.user.dept', type: 'keyword', }, - 'sophos.xg.mailsize': { - category: 'sophos', - description: 'mailsize ', - name: 'sophos.xg.mailsize', - type: 'integer', - }, - 'sophos.xg.virus': { - category: 'sophos', - description: 'virus name ', - name: 'sophos.xg.virus', + 'zoom.user.presence_status': { + category: 'zoom', + description: 'Current presence status of user ', + name: 'zoom.user.presence_status', type: 'keyword', }, - 'sophos.xg.FTP_url': { - category: 'sophos', - description: 'FTP URL from which virus was downloaded ', - name: 'sophos.xg.FTP_url', + 'zoom.user.personal_notes': { + category: 'zoom', + description: 'Personal notes for the User ', + name: 'zoom.user.personal_notes', type: 'keyword', }, - 'sophos.xg.FTP_direction': { - category: 'sophos', - description: 'Direction of FTP transfer: Upload or Download ', - name: 'sophos.xg.FTP_direction', + 'zoom.user.client_type': { + category: 'zoom', + description: 'Type of client used by the user. Can be browser, mac, win, iphone or android ', + name: 'zoom.user.client_type', type: 'keyword', }, - 'sophos.xg.filesize': { - category: 'sophos', - description: 'Size of the file that contained virus ', - name: 'sophos.xg.filesize', - type: 'integer', + 'zoom.user.version': { + category: 'zoom', + description: 'Version of the client used by the user ', + name: 'zoom.user.version', + type: 'keyword', }, - 'sophos.xg.filepath': { - category: 'sophos', - description: 'Path of the file containing virus ', - name: 'sophos.xg.filepath', + 'zoom.webinar.id': { + category: 'zoom', + description: 'Unique ID for the related webinar ', + name: 'zoom.webinar.id', type: 'keyword', }, - 'sophos.xg.filename': { - category: 'sophos', - description: 'File name associated with the event ', - name: 'sophos.xg.filename', + 'zoom.webinar.join_url': { + category: 'zoom', + description: 'The URL configured to join the webinar ', + name: 'zoom.webinar.join_url', type: 'keyword', }, - 'sophos.xg.ftpcommand': { - category: 'sophos', - description: 'FTP command used when virus was found ', - name: 'sophos.xg.ftpcommand', + 'zoom.webinar.uuid': { + category: 'zoom', + description: 'UUID for the related webinar ', + name: 'zoom.webinar.uuid', type: 'keyword', }, - 'sophos.xg.url': { - category: 'sophos', - description: 'URL from which virus was downloaded ', - name: 'sophos.xg.url', + 'zoom.webinar.host_id': { + category: 'zoom', + description: 'UserID for the configured host of the webinar ', + name: 'zoom.webinar.host_id', type: 'keyword', }, - 'sophos.xg.domainname': { - category: 'sophos', - description: 'Domain from which virus was downloaded ', - name: 'sophos.xg.domainname', + 'zoom.webinar.topic': { + category: 'zoom', + description: 'Meeting topic of the related webinar ', + name: 'zoom.webinar.topic', type: 'keyword', }, - 'sophos.xg.quarantine': { - category: 'sophos', - description: 'Path and filename of the file quarantined ', - name: 'sophos.xg.quarantine', + 'zoom.webinar.type': { + category: 'zoom', + description: + 'Type of webinar created. Can be either 5(Webinar), 6(Recurring webinar without fixed time) or 9(Recurring webinar with fixed time) ', + name: 'zoom.webinar.type', type: 'keyword', }, - 'sophos.xg.src_domainname': { - category: 'sophos', - description: 'Sender domain name ', - name: 'sophos.xg.src_domainname', + 'zoom.webinar.start_time': { + category: 'zoom', + description: 'The date and time when the webinar started ', + name: 'zoom.webinar.start_time', + type: 'date', + }, + 'zoom.webinar.timezone': { + category: 'zoom', + description: 'Timezone used for the dates related to the webinar ', + name: 'zoom.webinar.timezone', type: 'keyword', }, - 'sophos.xg.dst_domainname': { - category: 'sophos', - description: 'Receiver domain name ', - name: 'sophos.xg.dst_domainname', + 'zoom.webinar.duration': { + category: 'zoom', + description: 'Duration of the webinar in minutes ', + name: 'zoom.webinar.duration', + type: 'long', + }, + 'zoom.webinar.agenda': { + category: 'zoom', + description: 'The configured agenda of the webinar ', + name: 'zoom.webinar.agenda', type: 'keyword', }, - 'sophos.xg.reason': { - category: 'sophos', - description: 'Reason why the record was detected as spam/malicious ', - name: 'sophos.xg.reason', + 'zoom.webinar.password': { + category: 'zoom', + description: 'Password configured to access the webinar ', + name: 'zoom.webinar.password', type: 'keyword', }, - 'sophos.xg.referer': { - category: 'sophos', - description: 'Referer ', - name: 'sophos.xg.referer', + 'zoom.webinar.issues': { + category: 'zoom', + description: 'Any reported issues about a webinar is reported in this field ', + name: 'zoom.webinar.issues', type: 'keyword', }, - 'sophos.xg.spamaction': { - category: 'sophos', - description: 'Spam Action ', - name: 'sophos.xg.spamaction', + 'zoom.zoomroom.id': { + category: 'zoom', + description: 'Unique ID of the Zoom room ', + name: 'zoom.zoomroom.id', type: 'keyword', }, - 'sophos.xg.mailid': { - category: 'sophos', - description: 'mailid ', - name: 'sophos.xg.mailid', + 'zoom.zoomroom.room_name': { + category: 'zoom', + description: 'The configured name of the Zoom room ', + name: 'zoom.zoomroom.room_name', type: 'keyword', }, - 'sophos.xg.quarantine_reason': { - category: 'sophos', - description: 'Quarantine reason ', - name: 'sophos.xg.quarantine_reason', + 'zoom.zoomroom.calendar_name': { + category: 'zoom', + description: 'Calendar name of the Zoom room ', + name: 'zoom.zoomroom.calendar_name', type: 'keyword', }, - 'sophos.xg.status_code': { - category: 'sophos', - description: 'Status code ', - name: 'sophos.xg.status_code', + 'zoom.zoomroom.calendar_id': { + category: 'zoom', + description: 'Unique ID of the calendar used by the Zoom room ', + name: 'zoom.zoomroom.calendar_id', type: 'keyword', }, - 'sophos.xg.override_token': { - category: 'sophos', - description: 'Override token ', - name: 'sophos.xg.override_token', + 'zoom.zoomroom.event_id': { + category: 'zoom', + description: 'Unique ID of the calendar event associated with the Zoom Room ', + name: 'zoom.zoomroom.event_id', type: 'keyword', }, - 'sophos.xg.con_id': { - category: 'sophos', - description: 'Unique identifier of connection ', - name: 'sophos.xg.con_id', - type: 'integer', + 'zoom.zoomroom.change_key': { + category: 'zoom', + description: + 'Key used by Microsoft products integration that represents a specific version of a calendar ', + name: 'zoom.zoomroom.change_key', + type: 'keyword', }, - 'sophos.xg.override_authorizer': { - category: 'sophos', - description: 'Override authorizer ', - name: 'sophos.xg.override_authorizer', + 'zoom.zoomroom.resource_email': { + category: 'zoom', + description: 'Email address associated with the calendar in use by the Zoom room ', + name: 'zoom.zoomroom.resource_email', type: 'keyword', }, - 'sophos.xg.transactionid': { - category: 'sophos', - description: 'Transaction ID of the AV scan. ', - name: 'sophos.xg.transactionid', + 'zoom.zoomroom.email': { + category: 'zoom', + description: 'Email address associated with the Zoom room itself ', + name: 'zoom.zoomroom.email', type: 'keyword', }, - 'sophos.xg.upload_file_type': { - category: 'sophos', - description: 'Upload file type ', - name: 'sophos.xg.upload_file_type', + 'zoom.zoomroom.issue': { + category: 'zoom', + description: 'Any reported alerts or issues related to the Zoom room or its equipment ', + name: 'zoom.zoomroom.issue', type: 'keyword', }, - 'sophos.xg.upload_file_name': { - category: 'sophos', - description: 'Upload file name ', - name: 'sophos.xg.upload_file_name', + 'zoom.zoomroom.alert_type': { + category: 'zoom', + description: + 'An integer value representing the type of alert. The list of alert types can be found in the Zoom documentation ', + name: 'zoom.zoomroom.alert_type', type: 'keyword', }, - 'sophos.xg.httpresponsecode': { - category: 'sophos', - description: 'code of HTTP response ', - name: 'sophos.xg.httpresponsecode', - type: 'long', + 'zoom.zoomroom.component': { + category: 'zoom', + description: + 'An integer value representing the type of equipment or component, The list of component types can be found in the Zoom documentation ', + name: 'zoom.zoomroom.component', + type: 'keyword', }, - 'sophos.xg.user_gp': { - category: 'sophos', - description: 'Group name to which the user belongs. ', - name: 'sophos.xg.user_gp', + 'zoom.zoomroom.alert_kind': { + category: 'zoom', + description: + 'An integer value showing if the Zoom room alert has been either 1(Triggered) or 2(Cleared) ', + name: 'zoom.zoomroom.alert_kind', type: 'keyword', }, - 'sophos.xg.category_type': { - category: 'sophos', - description: 'Type of category under which website falls ', - name: 'sophos.xg.category_type', + 'zoom.registrant.id': { + category: 'zoom', + description: 'Unique ID of the user registering to a meeting or webinar ', + name: 'zoom.registrant.id', type: 'keyword', }, - 'sophos.xg.download_file_type': { - category: 'sophos', - description: 'Download file type ', - name: 'sophos.xg.download_file_type', + 'zoom.registrant.status': { + category: 'zoom', + description: 'Status of the specific user registration ', + name: 'zoom.registrant.status', type: 'keyword', }, - 'sophos.xg.exceptions': { - category: 'sophos', - description: 'List of the checks excluded by web exceptions. ', - name: 'sophos.xg.exceptions', + 'zoom.registrant.email': { + category: 'zoom', + description: 'Email of the user registering to a meeting or webinar ', + name: 'zoom.registrant.email', type: 'keyword', }, - 'sophos.xg.contenttype': { - category: 'sophos', - description: 'Type of the content ', - name: 'sophos.xg.contenttype', + 'zoom.registrant.first_name': { + category: 'zoom', + description: 'First name of the user registering to a meeting or webinar ', + name: 'zoom.registrant.first_name', type: 'keyword', }, - 'sophos.xg.override_name': { - category: 'sophos', - description: 'Override name ', - name: 'sophos.xg.override_name', + 'zoom.registrant.last_name': { + category: 'zoom', + description: 'Last name of the user registering to a meeting or webinar ', + name: 'zoom.registrant.last_name', type: 'keyword', }, - 'sophos.xg.activityname': { - category: 'sophos', - description: 'Web policy activity that matched and caused the policy result. ', - name: 'sophos.xg.activityname', + 'zoom.registrant.address': { + category: 'zoom', + description: 'Address of the user registering to a meeting or webinar ', + name: 'zoom.registrant.address', type: 'keyword', }, - 'sophos.xg.download_file_name': { - category: 'sophos', - description: 'Download file name ', - name: 'sophos.xg.download_file_name', + 'zoom.registrant.city': { + category: 'zoom', + description: 'City of the user registering to a meeting or webinar ', + name: 'zoom.registrant.city', type: 'keyword', }, - 'sophos.xg.sha1sum': { - category: 'sophos', - description: 'SHA1 checksum of the item being analyzed ', - name: 'sophos.xg.sha1sum', + 'zoom.registrant.country': { + category: 'zoom', + description: 'Country of the user registering to a meeting or webinar ', + name: 'zoom.registrant.country', type: 'keyword', }, - 'sophos.xg.message_id': { - category: 'sophos', - description: 'Message ID ', - name: 'sophos.xg.message_id', + 'zoom.registrant.zip': { + category: 'zoom', + description: 'Zip code of the user registering to a meeting or webinar ', + name: 'zoom.registrant.zip', type: 'keyword', }, - 'sophos.xg.connid': { - category: 'sophos', - description: 'Connection ID ', - name: 'sophos.xg.connid', + 'zoom.registrant.state': { + category: 'zoom', + description: 'State of the user registering to a meeting or webinar ', + name: 'zoom.registrant.state', type: 'keyword', }, - 'sophos.xg.message': { - category: 'sophos', - description: 'Message ', - name: 'sophos.xg.message', + 'zoom.registrant.phone': { + category: 'zoom', + description: 'Phone number of the user registering to a meeting or webinar ', + name: 'zoom.registrant.phone', type: 'keyword', }, - 'sophos.xg.email_subject': { - category: 'sophos', - description: 'Email Subject ', - name: 'sophos.xg.email_subject', + 'zoom.registrant.industry': { + category: 'zoom', + description: 'Related industry of the user registering to a meeting or webinar ', + name: 'zoom.registrant.industry', type: 'keyword', }, - 'sophos.xg.file_path': { - category: 'sophos', - description: 'File path ', - name: 'sophos.xg.file_path', + 'zoom.registrant.org': { + category: 'zoom', + description: 'Organization related to the user registering to a meeting or webinar ', + name: 'zoom.registrant.org', type: 'keyword', }, - 'sophos.xg.dstdomain': { - category: 'sophos', - description: 'Destination Domain ', - name: 'sophos.xg.dstdomain', + 'zoom.registrant.job_title': { + category: 'zoom', + description: 'Job title of the user registering to a meeting or webinar ', + name: 'zoom.registrant.job_title', type: 'keyword', }, - 'sophos.xg.file_size': { - category: 'sophos', - description: 'File Size ', - name: 'sophos.xg.file_size', - type: 'integer', + 'zoom.registrant.purchasing_time_frame': { + category: 'zoom', + description: 'Choosen purchase timeframe of the user registering to a meeting or webinar ', + name: 'zoom.registrant.purchasing_time_frame', + type: 'keyword', }, - 'sophos.xg.transaction_id': { - category: 'sophos', - description: 'Transaction ID ', - name: 'sophos.xg.transaction_id', + 'zoom.registrant.role_in_purchase_process': { + category: 'zoom', + description: + 'Choosen role in a purchase process related to the user registering to a meeting or webinar ', + name: 'zoom.registrant.role_in_purchase_process', type: 'keyword', }, - 'sophos.xg.website': { - category: 'sophos', - description: 'Website ', - name: 'sophos.xg.website', + 'zoom.registrant.no_of_employees': { + category: 'zoom', + description: 'Number of employees choosen by the user registering to a meeting or webinar ', + name: 'zoom.registrant.no_of_employees', type: 'keyword', }, - 'sophos.xg.file_name': { - category: 'sophos', - description: 'Filename ', - name: 'sophos.xg.file_name', + 'zoom.registrant.comments': { + category: 'zoom', + description: 'Comments left by the user registering to a meeting or webinar ', + name: 'zoom.registrant.comments', type: 'keyword', }, - 'sophos.xg.context_prefix': { - category: 'sophos', - description: 'Content Prefix ', - name: 'sophos.xg.context_prefix', + 'zoom.registrant.join_url': { + category: 'zoom', + description: 'The URL that the registrant can use to join the webinar ', + name: 'zoom.registrant.join_url', type: 'keyword', }, - 'sophos.xg.site_category': { - category: 'sophos', - description: 'Site Category ', - name: 'sophos.xg.site_category', + 'zoom.participant.id': { + category: 'zoom', + description: 'Unique ID of the participant related to a meeting ', + name: 'zoom.participant.id', type: 'keyword', }, - 'sophos.xg.context_suffix': { - category: 'sophos', - description: 'Context Suffix ', - name: 'sophos.xg.context_suffix', + 'zoom.participant.user_id': { + category: 'zoom', + description: 'UserID of the participant related to a meeting ', + name: 'zoom.participant.user_id', type: 'keyword', }, - 'sophos.xg.dictionary_name': { - category: 'sophos', - description: 'Dictionary Name ', - name: 'sophos.xg.dictionary_name', + 'zoom.participant.user_name': { + category: 'zoom', + description: 'Username of the participant related to a meeting ', + name: 'zoom.participant.user_name', type: 'keyword', }, - 'sophos.xg.action': { - category: 'sophos', - description: 'Event Action ', - name: 'sophos.xg.action', + 'zoom.participant.join_time': { + category: 'zoom', + description: 'The date and time a participant joined a meeting ', + name: 'zoom.participant.join_time', + type: 'date', + }, + 'zoom.participant.leave_time': { + category: 'zoom', + description: 'The date and time a participant left a meeting ', + name: 'zoom.participant.leave_time', + type: 'date', + }, + 'zoom.participant.sharing_details.link_source': { + category: 'zoom', + description: 'Method of sharing with dropbox integration ', + name: 'zoom.participant.sharing_details.link_source', type: 'keyword', }, - 'sophos.xg.user': { - category: 'sophos', - description: 'User ', - name: 'sophos.xg.user', + 'zoom.participant.sharing_details.content': { + category: 'zoom', + description: 'Type of content that was shared ', + name: 'zoom.participant.sharing_details.content', type: 'keyword', }, - 'sophos.xg.context_match': { - category: 'sophos', - description: 'Context Match ', - name: 'sophos.xg.context_match', + 'zoom.participant.sharing_details.file_link': { + category: 'zoom', + description: 'The file link that was shared ', + name: 'zoom.participant.sharing_details.file_link', type: 'keyword', }, - 'sophos.xg.direction': { - category: 'sophos', - description: 'Direction ', - name: 'sophos.xg.direction', + 'zoom.participant.sharing_details.date_time': { + category: 'zoom', + description: 'Timestamp the sharing started ', + name: 'zoom.participant.sharing_details.date_time', type: 'keyword', }, - 'sophos.xg.auth_client': { - category: 'sophos', - description: 'Auth Client ', - name: 'sophos.xg.auth_client', + 'zoom.participant.sharing_details.source': { + category: 'zoom', + description: 'The file source that was share ', + name: 'zoom.participant.sharing_details.source', type: 'keyword', }, - 'sophos.xg.auth_mechanism': { - category: 'sophos', - description: 'Auth mechanism ', - name: 'sophos.xg.auth_mechanism', + 'zoom.old_values': { + category: 'zoom', + description: + 'Includes the old values when updating a object like user, meeting, account or webinar ', + name: 'zoom.old_values', + type: 'flattened', + }, + 'zoom.settings': { + category: 'zoom', + description: + 'The current active settings related to a object like user, meeting, account or webinar ', + name: 'zoom.settings', + type: 'flattened', + }, + 'aws-cloudwatch.log_group': { + category: 'aws-cloudwatch', + description: 'The name of the log group to which this event belongs.', + name: 'aws-cloudwatch.log_group', type: 'keyword', }, - 'sophos.xg.connectionname': { - category: 'sophos', - description: 'Connectionname ', - name: 'sophos.xg.connectionname', + 'aws-cloudwatch.log_stream': { + category: 'aws-cloudwatch', + description: 'The name of the log stream to which this event belongs.', + name: 'aws-cloudwatch.log_stream', type: 'keyword', }, - 'sophos.xg.remotenetwork': { - category: 'sophos', - description: 'remotenetwork ', - name: 'sophos.xg.remotenetwork', + 'aws-cloudwatch.ingestion_time': { + category: 'aws-cloudwatch', + description: 'The time the event was ingested in AWS CloudWatch.', + name: 'aws-cloudwatch.ingestion_time', type: 'keyword', }, - 'sophos.xg.localgateway': { - category: 'sophos', - description: 'Localgateway ', - name: 'sophos.xg.localgateway', + 'bucket.name': { + category: 'bucket', + description: 'Name of the S3 bucket that this log retrieved from. ', + name: 'bucket.name', type: 'keyword', }, - 'sophos.xg.localnetwork': { - category: 'sophos', - description: 'Localnetwork ', - name: 'sophos.xg.localnetwork', + 'bucket.arn': { + category: 'bucket', + description: 'ARN of the S3 bucket that this log retrieved from. ', + name: 'bucket.arn', type: 'keyword', }, - 'sophos.xg.connectiontype': { - category: 'sophos', - description: 'Connectiontype ', - name: 'sophos.xg.connectiontype', + 'object.key': { + category: 'object', + description: 'Name of the S3 object that this log retrieved from. ', + name: 'object.key', type: 'keyword', }, - 'sophos.xg.oldversion': { - category: 'sophos', - description: 'Oldversion ', - name: 'sophos.xg.oldversion', + metadata: { + category: 'base', + description: 'AWS S3 object metadata values.', + name: 'metadata', + type: 'flattened', + }, + 'netflow.type': { + category: 'netflow', + description: 'The type of NetFlow record described by this event. ', + name: 'netflow.type', type: 'keyword', }, - 'sophos.xg.newversion': { - category: 'sophos', - description: 'Newversion ', - name: 'sophos.xg.newversion', + 'netflow.exporter.address': { + category: 'netflow', + description: "Exporter's network address in IP:port format. ", + name: 'netflow.exporter.address', type: 'keyword', }, - 'sophos.xg.ipaddress': { - category: 'sophos', - description: 'Ipaddress ', - name: 'sophos.xg.ipaddress', + 'netflow.exporter.source_id': { + category: 'netflow', + description: 'Observation domain ID to which this record belongs. ', + name: 'netflow.exporter.source_id', + type: 'long', + }, + 'netflow.exporter.timestamp': { + category: 'netflow', + description: 'Time and date of export. ', + name: 'netflow.exporter.timestamp', + type: 'date', + }, + 'netflow.exporter.uptime_millis': { + category: 'netflow', + description: 'How long the exporter process has been running, in milliseconds. ', + name: 'netflow.exporter.uptime_millis', + type: 'long', + }, + 'netflow.exporter.version': { + category: 'netflow', + description: 'NetFlow version used. ', + name: 'netflow.exporter.version', + type: 'integer', + }, + 'netflow.absolute_error': { + category: 'netflow', + name: 'netflow.absolute_error', + type: 'double', + }, + 'netflow.address_pool_high_threshold': { + category: 'netflow', + name: 'netflow.address_pool_high_threshold', + type: 'long', + }, + 'netflow.address_pool_low_threshold': { + category: 'netflow', + name: 'netflow.address_pool_low_threshold', + type: 'long', + }, + 'netflow.address_port_mapping_high_threshold': { + category: 'netflow', + name: 'netflow.address_port_mapping_high_threshold', + type: 'long', + }, + 'netflow.address_port_mapping_low_threshold': { + category: 'netflow', + name: 'netflow.address_port_mapping_low_threshold', + type: 'long', + }, + 'netflow.address_port_mapping_per_user_high_threshold': { + category: 'netflow', + name: 'netflow.address_port_mapping_per_user_high_threshold', + type: 'long', + }, + 'netflow.afc_protocol': { + category: 'netflow', + name: 'netflow.afc_protocol', + type: 'integer', + }, + 'netflow.afc_protocol_name': { + category: 'netflow', + name: 'netflow.afc_protocol_name', type: 'keyword', }, - 'sophos.xg.client_physical_address': { - category: 'sophos', - description: 'Client physical address ', - name: 'sophos.xg.client_physical_address', + 'netflow.anonymization_flags': { + category: 'netflow', + name: 'netflow.anonymization_flags', + type: 'integer', + }, + 'netflow.anonymization_technique': { + category: 'netflow', + name: 'netflow.anonymization_technique', + type: 'integer', + }, + 'netflow.application_business-relevance': { + category: 'netflow', + name: 'netflow.application_business-relevance', + type: 'long', + }, + 'netflow.application_category_name': { + category: 'netflow', + name: 'netflow.application_category_name', type: 'keyword', }, - 'sophos.xg.client_host_name': { - category: 'sophos', - description: 'Client host name ', - name: 'sophos.xg.client_host_name', + 'netflow.application_description': { + category: 'netflow', + name: 'netflow.application_description', type: 'keyword', }, - 'sophos.xg.raw_data': { - category: 'sophos', - description: 'Raw data ', - name: 'sophos.xg.raw_data', + 'netflow.application_group_name': { + category: 'netflow', + name: 'netflow.application_group_name', type: 'keyword', }, - 'sophos.xg.Mode': { - category: 'sophos', - description: 'Mode ', - name: 'sophos.xg.Mode', + 'netflow.application_http_uri_statistics': { + category: 'netflow', + name: 'netflow.application_http_uri_statistics', + type: 'short', + }, + 'netflow.application_http_user-agent': { + category: 'netflow', + name: 'netflow.application_http_user-agent', + type: 'short', + }, + 'netflow.application_id': { + category: 'netflow', + name: 'netflow.application_id', + type: 'short', + }, + 'netflow.application_name': { + category: 'netflow', + name: 'netflow.application_name', type: 'keyword', }, - 'sophos.xg.sessionid': { - category: 'sophos', - description: 'Sessionid ', - name: 'sophos.xg.sessionid', + 'netflow.application_sub_category_name': { + category: 'netflow', + name: 'netflow.application_sub_category_name', type: 'keyword', }, - 'sophos.xg.starttime': { - category: 'sophos', - description: 'Starttime ', - name: 'sophos.xg.starttime', - type: 'date', + 'netflow.application_traffic-class': { + category: 'netflow', + name: 'netflow.application_traffic-class', + type: 'long', + }, + 'netflow.art_client_network_time_maximum': { + category: 'netflow', + name: 'netflow.art_client_network_time_maximum', + type: 'long', + }, + 'netflow.art_client_network_time_minimum': { + category: 'netflow', + name: 'netflow.art_client_network_time_minimum', + type: 'long', + }, + 'netflow.art_client_network_time_sum': { + category: 'netflow', + name: 'netflow.art_client_network_time_sum', + type: 'long', + }, + 'netflow.art_clientpackets': { + category: 'netflow', + name: 'netflow.art_clientpackets', + type: 'long', + }, + 'netflow.art_count_late_responses': { + category: 'netflow', + name: 'netflow.art_count_late_responses', + type: 'long', + }, + 'netflow.art_count_new_connections': { + category: 'netflow', + name: 'netflow.art_count_new_connections', + type: 'long', + }, + 'netflow.art_count_responses': { + category: 'netflow', + name: 'netflow.art_count_responses', + type: 'long', + }, + 'netflow.art_count_responses_histogram_bucket1': { + category: 'netflow', + name: 'netflow.art_count_responses_histogram_bucket1', + type: 'long', + }, + 'netflow.art_count_responses_histogram_bucket2': { + category: 'netflow', + name: 'netflow.art_count_responses_histogram_bucket2', + type: 'long', }, - 'sophos.xg.remote_ip': { - category: 'sophos', - description: 'Remote IP ', - name: 'sophos.xg.remote_ip', - type: 'ip', + 'netflow.art_count_responses_histogram_bucket3': { + category: 'netflow', + name: 'netflow.art_count_responses_histogram_bucket3', + type: 'long', }, - 'sophos.xg.timestamp': { - category: 'sophos', - description: 'timestamp ', - name: 'sophos.xg.timestamp', - type: 'date', + 'netflow.art_count_responses_histogram_bucket4': { + category: 'netflow', + name: 'netflow.art_count_responses_histogram_bucket4', + type: 'long', }, - 'sophos.xg.SysLog_SERVER_NAME': { - category: 'sophos', - description: 'SysLog SERVER NAME ', - name: 'sophos.xg.SysLog_SERVER_NAME', - type: 'keyword', + 'netflow.art_count_responses_histogram_bucket5': { + category: 'netflow', + name: 'netflow.art_count_responses_histogram_bucket5', + type: 'long', }, - 'sophos.xg.backup_mode': { - category: 'sophos', - description: 'Backup mode ', - name: 'sophos.xg.backup_mode', - type: 'keyword', + 'netflow.art_count_responses_histogram_bucket6': { + category: 'netflow', + name: 'netflow.art_count_responses_histogram_bucket6', + type: 'long', }, - 'sophos.xg.source': { - category: 'sophos', - description: 'Source ', - name: 'sophos.xg.source', - type: 'keyword', + 'netflow.art_count_responses_histogram_bucket7': { + category: 'netflow', + name: 'netflow.art_count_responses_histogram_bucket7', + type: 'long', }, - 'sophos.xg.server': { - category: 'sophos', - description: 'Server ', - name: 'sophos.xg.server', - type: 'keyword', + 'netflow.art_count_retransmissions': { + category: 'netflow', + name: 'netflow.art_count_retransmissions', + type: 'long', }, - 'sophos.xg.host': { - category: 'sophos', - description: 'Host ', - name: 'sophos.xg.host', - type: 'keyword', + 'netflow.art_count_transactions': { + category: 'netflow', + name: 'netflow.art_count_transactions', + type: 'long', }, - 'sophos.xg.responsetime': { - category: 'sophos', - description: 'Responsetime ', - name: 'sophos.xg.responsetime', + 'netflow.art_network_time_maximum': { + category: 'netflow', + name: 'netflow.art_network_time_maximum', type: 'long', }, - 'sophos.xg.cookie': { - category: 'sophos', - description: 'cookie ', - name: 'sophos.xg.cookie', - type: 'keyword', + 'netflow.art_network_time_minimum': { + category: 'netflow', + name: 'netflow.art_network_time_minimum', + type: 'long', }, - 'sophos.xg.querystring': { - category: 'sophos', - description: 'querystring ', - name: 'sophos.xg.querystring', - type: 'keyword', + 'netflow.art_network_time_sum': { + category: 'netflow', + name: 'netflow.art_network_time_sum', + type: 'long', }, - 'sophos.xg.extra': { - category: 'sophos', - description: 'extra ', - name: 'sophos.xg.extra', - type: 'keyword', + 'netflow.art_response_time_maximum': { + category: 'netflow', + name: 'netflow.art_response_time_maximum', + type: 'long', }, - 'sophos.xg.PHPSESSID': { - category: 'sophos', - description: 'PHPSESSID ', - name: 'sophos.xg.PHPSESSID', - type: 'keyword', + 'netflow.art_response_time_minimum': { + category: 'netflow', + name: 'netflow.art_response_time_minimum', + type: 'long', }, - 'sophos.xg.start_time': { - category: 'sophos', - description: 'Start time ', - name: 'sophos.xg.start_time', - type: 'date', + 'netflow.art_response_time_sum': { + category: 'netflow', + name: 'netflow.art_response_time_sum', + type: 'long', }, - 'sophos.xg.eventtime': { - category: 'sophos', - description: 'Event time ', - name: 'sophos.xg.eventtime', - type: 'date', + 'netflow.art_server_network_time_maximum': { + category: 'netflow', + name: 'netflow.art_server_network_time_maximum', + type: 'long', }, - 'sophos.xg.red_id': { - category: 'sophos', - description: 'RED ID ', - name: 'sophos.xg.red_id', - type: 'keyword', + 'netflow.art_server_network_time_minimum': { + category: 'netflow', + name: 'netflow.art_server_network_time_minimum', + type: 'long', }, - 'sophos.xg.branch_name': { - category: 'sophos', - description: 'Branch Name ', - name: 'sophos.xg.branch_name', - type: 'keyword', + 'netflow.art_server_network_time_sum': { + category: 'netflow', + name: 'netflow.art_server_network_time_sum', + type: 'long', }, - 'sophos.xg.updatedip': { - category: 'sophos', - description: 'updatedip ', - name: 'sophos.xg.updatedip', - type: 'ip', + 'netflow.art_server_response_time_maximum': { + category: 'netflow', + name: 'netflow.art_server_response_time_maximum', + type: 'long', }, - 'sophos.xg.idle_cpu': { - category: 'sophos', - description: 'idle ## ', - name: 'sophos.xg.idle_cpu', - type: 'float', + 'netflow.art_server_response_time_minimum': { + category: 'netflow', + name: 'netflow.art_server_response_time_minimum', + type: 'long', }, - 'sophos.xg.system_cpu': { - category: 'sophos', - description: 'system ', - name: 'sophos.xg.system_cpu', - type: 'float', + 'netflow.art_server_response_time_sum': { + category: 'netflow', + name: 'netflow.art_server_response_time_sum', + type: 'long', }, - 'sophos.xg.user_cpu': { - category: 'sophos', - description: 'system ', - name: 'sophos.xg.user_cpu', - type: 'float', + 'netflow.art_serverpackets': { + category: 'netflow', + name: 'netflow.art_serverpackets', + type: 'long', }, - 'sophos.xg.used': { - category: 'sophos', - description: 'used ', - name: 'sophos.xg.used', - type: 'integer', + 'netflow.art_total_response_time_maximum': { + category: 'netflow', + name: 'netflow.art_total_response_time_maximum', + type: 'long', }, - 'sophos.xg.unit': { - category: 'sophos', - description: 'unit ', - name: 'sophos.xg.unit', - type: 'keyword', + 'netflow.art_total_response_time_minimum': { + category: 'netflow', + name: 'netflow.art_total_response_time_minimum', + type: 'long', }, - 'sophos.xg.total_memory': { - category: 'sophos', - description: 'Total Memory ', - name: 'sophos.xg.total_memory', - type: 'integer', + 'netflow.art_total_response_time_sum': { + category: 'netflow', + name: 'netflow.art_total_response_time_sum', + type: 'long', }, - 'sophos.xg.free': { - category: 'sophos', - description: 'free ', - name: 'sophos.xg.free', - type: 'integer', + 'netflow.art_total_transaction_time_maximum': { + category: 'netflow', + name: 'netflow.art_total_transaction_time_maximum', + type: 'long', }, - 'sophos.xg.transmittederrors': { - category: 'sophos', - description: 'transmitted errors ', - name: 'sophos.xg.transmittederrors', - type: 'keyword', + 'netflow.art_total_transaction_time_minimum': { + category: 'netflow', + name: 'netflow.art_total_transaction_time_minimum', + type: 'long', }, - 'sophos.xg.receivederrors': { - category: 'sophos', - description: 'received errors ', - name: 'sophos.xg.receivederrors', - type: 'keyword', + 'netflow.art_total_transaction_time_sum': { + category: 'netflow', + name: 'netflow.art_total_transaction_time_sum', + type: 'long', }, - 'sophos.xg.receivedkbits': { - category: 'sophos', - description: 'received kbits ', - name: 'sophos.xg.receivedkbits', + 'netflow.assembled_fragment_count': { + category: 'netflow', + name: 'netflow.assembled_fragment_count', type: 'long', }, - 'sophos.xg.transmittedkbits': { - category: 'sophos', - description: 'transmitted kbits ', - name: 'sophos.xg.transmittedkbits', + 'netflow.audit_counter': { + category: 'netflow', + name: 'netflow.audit_counter', type: 'long', }, - 'sophos.xg.transmitteddrops': { - category: 'sophos', - description: 'transmitted drops ', - name: 'sophos.xg.transmitteddrops', + 'netflow.average_interarrival_time': { + category: 'netflow', + name: 'netflow.average_interarrival_time', type: 'long', }, - 'sophos.xg.receiveddrops': { - category: 'sophos', - description: 'received drops ', - name: 'sophos.xg.receiveddrops', + 'netflow.bgp_destination_as_number': { + category: 'netflow', + name: 'netflow.bgp_destination_as_number', type: 'long', }, - 'sophos.xg.collisions': { - category: 'sophos', - description: 'collisions ', - name: 'sophos.xg.collisions', + 'netflow.bgp_next_adjacent_as_number': { + category: 'netflow', + name: 'netflow.bgp_next_adjacent_as_number', type: 'long', }, - 'sophos.xg.interface': { - category: 'sophos', - description: 'interface ', - name: 'sophos.xg.interface', - type: 'keyword', + 'netflow.bgp_next_hop_ipv4_address': { + category: 'netflow', + name: 'netflow.bgp_next_hop_ipv4_address', + type: 'ip', }, - 'sophos.xg.Configuration': { - category: 'sophos', - description: 'Configuration ', - name: 'sophos.xg.Configuration', - type: 'float', + 'netflow.bgp_next_hop_ipv6_address': { + category: 'netflow', + name: 'netflow.bgp_next_hop_ipv6_address', + type: 'ip', }, - 'sophos.xg.Reports': { - category: 'sophos', - description: 'Reports ', - name: 'sophos.xg.Reports', - type: 'float', + 'netflow.bgp_prev_adjacent_as_number': { + category: 'netflow', + name: 'netflow.bgp_prev_adjacent_as_number', + type: 'long', }, - 'sophos.xg.Signature': { - category: 'sophos', - description: 'Signature ', - name: 'sophos.xg.Signature', - type: 'float', + 'netflow.bgp_source_as_number': { + category: 'netflow', + name: 'netflow.bgp_source_as_number', + type: 'long', }, - 'sophos.xg.Temp': { - category: 'sophos', - description: 'Temp ', - name: 'sophos.xg.Temp', - type: 'float', + 'netflow.bgp_validity_state': { + category: 'netflow', + name: 'netflow.bgp_validity_state', + type: 'short', }, - 'sophos.xg.users': { - category: 'sophos', - description: 'users ', - name: 'sophos.xg.users', - type: 'keyword', + 'netflow.biflow_direction': { + category: 'netflow', + name: 'netflow.biflow_direction', + type: 'short', }, - 'sophos.xg.ssid': { - category: 'sophos', - description: 'ssid ', - name: 'sophos.xg.ssid', - type: 'keyword', + 'netflow.bind_ipv4_address': { + category: 'netflow', + name: 'netflow.bind_ipv4_address', + type: 'ip', }, - 'sophos.xg.ap': { - category: 'sophos', - description: 'ap ', - name: 'sophos.xg.ap', - type: 'keyword', + 'netflow.bind_transport_port': { + category: 'netflow', + name: 'netflow.bind_transport_port', + type: 'integer', }, - 'sophos.xg.clients_conn_ssid': { - category: 'sophos', - description: 'clients connection ssid ', - name: 'sophos.xg.clients_conn_ssid', - type: 'keyword', + 'netflow.class_id': { + category: 'netflow', + name: 'netflow.class_id', + type: 'long', }, - 'suricata.eve.event_type': { - category: 'suricata', - name: 'suricata.eve.event_type', + 'netflow.class_name': { + category: 'netflow', + name: 'netflow.class_name', type: 'keyword', }, - 'suricata.eve.app_proto_orig': { - category: 'suricata', - name: 'suricata.eve.app_proto_orig', - type: 'keyword', + 'netflow.classification_engine_id': { + category: 'netflow', + name: 'netflow.classification_engine_id', + type: 'short', }, - 'suricata.eve.tcp.tcp_flags': { - category: 'suricata', - name: 'suricata.eve.tcp.tcp_flags', - type: 'keyword', + 'netflow.collection_time_milliseconds': { + category: 'netflow', + name: 'netflow.collection_time_milliseconds', + type: 'date', }, - 'suricata.eve.tcp.psh': { - category: 'suricata', - name: 'suricata.eve.tcp.psh', - type: 'boolean', + 'netflow.collector_certificate': { + category: 'netflow', + name: 'netflow.collector_certificate', + type: 'short', }, - 'suricata.eve.tcp.tcp_flags_tc': { - category: 'suricata', - name: 'suricata.eve.tcp.tcp_flags_tc', - type: 'keyword', + 'netflow.collector_ipv4_address': { + category: 'netflow', + name: 'netflow.collector_ipv4_address', + type: 'ip', }, - 'suricata.eve.tcp.ack': { - category: 'suricata', - name: 'suricata.eve.tcp.ack', - type: 'boolean', + 'netflow.collector_ipv6_address': { + category: 'netflow', + name: 'netflow.collector_ipv6_address', + type: 'ip', }, - 'suricata.eve.tcp.syn': { - category: 'suricata', - name: 'suricata.eve.tcp.syn', - type: 'boolean', + 'netflow.collector_transport_port': { + category: 'netflow', + name: 'netflow.collector_transport_port', + type: 'integer', }, - 'suricata.eve.tcp.state': { - category: 'suricata', - name: 'suricata.eve.tcp.state', - type: 'keyword', + 'netflow.common_properties_id': { + category: 'netflow', + name: 'netflow.common_properties_id', + type: 'long', }, - 'suricata.eve.tcp.tcp_flags_ts': { - category: 'suricata', - name: 'suricata.eve.tcp.tcp_flags_ts', - type: 'keyword', + 'netflow.confidence_level': { + category: 'netflow', + name: 'netflow.confidence_level', + type: 'double', }, - 'suricata.eve.tcp.rst': { - category: 'suricata', - name: 'suricata.eve.tcp.rst', - type: 'boolean', + 'netflow.conn_ipv4_address': { + category: 'netflow', + name: 'netflow.conn_ipv4_address', + type: 'ip', }, - 'suricata.eve.tcp.fin': { - category: 'suricata', - name: 'suricata.eve.tcp.fin', - type: 'boolean', + 'netflow.conn_transport_port': { + category: 'netflow', + name: 'netflow.conn_transport_port', + type: 'integer', }, - 'suricata.eve.fileinfo.sha1': { - category: 'suricata', - name: 'suricata.eve.fileinfo.sha1', - type: 'keyword', + 'netflow.connection_sum_duration_seconds': { + category: 'netflow', + name: 'netflow.connection_sum_duration_seconds', + type: 'long', }, - 'suricata.eve.fileinfo.filename': { - category: 'suricata', - name: 'suricata.eve.fileinfo.filename', - type: 'alias', + 'netflow.connection_transaction_id': { + category: 'netflow', + name: 'netflow.connection_transaction_id', + type: 'long', }, - 'suricata.eve.fileinfo.tx_id': { - category: 'suricata', - name: 'suricata.eve.fileinfo.tx_id', + 'netflow.conntrack_id': { + category: 'netflow', + name: 'netflow.conntrack_id', type: 'long', }, - 'suricata.eve.fileinfo.state': { - category: 'suricata', - name: 'suricata.eve.fileinfo.state', - type: 'keyword', + 'netflow.data_byte_count': { + category: 'netflow', + name: 'netflow.data_byte_count', + type: 'long', }, - 'suricata.eve.fileinfo.stored': { - category: 'suricata', - name: 'suricata.eve.fileinfo.stored', - type: 'boolean', + 'netflow.data_link_frame_section': { + category: 'netflow', + name: 'netflow.data_link_frame_section', + type: 'short', }, - 'suricata.eve.fileinfo.gaps': { - category: 'suricata', - name: 'suricata.eve.fileinfo.gaps', + 'netflow.data_link_frame_size': { + category: 'netflow', + name: 'netflow.data_link_frame_size', + type: 'integer', + }, + 'netflow.data_link_frame_type': { + category: 'netflow', + name: 'netflow.data_link_frame_type', + type: 'integer', + }, + 'netflow.data_records_reliability': { + category: 'netflow', + name: 'netflow.data_records_reliability', type: 'boolean', }, - 'suricata.eve.fileinfo.sha256': { - category: 'suricata', - name: 'suricata.eve.fileinfo.sha256', - type: 'keyword', + 'netflow.delta_flow_count': { + category: 'netflow', + name: 'netflow.delta_flow_count', + type: 'long', }, - 'suricata.eve.fileinfo.md5': { - category: 'suricata', - name: 'suricata.eve.fileinfo.md5', + 'netflow.destination_ipv4_address': { + category: 'netflow', + name: 'netflow.destination_ipv4_address', + type: 'ip', + }, + 'netflow.destination_ipv4_prefix': { + category: 'netflow', + name: 'netflow.destination_ipv4_prefix', + type: 'ip', + }, + 'netflow.destination_ipv4_prefix_length': { + category: 'netflow', + name: 'netflow.destination_ipv4_prefix_length', + type: 'short', + }, + 'netflow.destination_ipv6_address': { + category: 'netflow', + name: 'netflow.destination_ipv6_address', + type: 'ip', + }, + 'netflow.destination_ipv6_prefix': { + category: 'netflow', + name: 'netflow.destination_ipv6_prefix', + type: 'ip', + }, + 'netflow.destination_ipv6_prefix_length': { + category: 'netflow', + name: 'netflow.destination_ipv6_prefix_length', + type: 'short', + }, + 'netflow.destination_mac_address': { + category: 'netflow', + name: 'netflow.destination_mac_address', type: 'keyword', }, - 'suricata.eve.fileinfo.size': { - category: 'suricata', - name: 'suricata.eve.fileinfo.size', - type: 'alias', + 'netflow.destination_transport_port': { + category: 'netflow', + name: 'netflow.destination_transport_port', + type: 'integer', }, - 'suricata.eve.icmp_type': { - category: 'suricata', - name: 'suricata.eve.icmp_type', + 'netflow.digest_hash_value': { + category: 'netflow', + name: 'netflow.digest_hash_value', type: 'long', }, - 'suricata.eve.dest_port': { - category: 'suricata', - name: 'suricata.eve.dest_port', - type: 'alias', + 'netflow.distinct_count_of_destination_ip_address': { + category: 'netflow', + name: 'netflow.distinct_count_of_destination_ip_address', + type: 'long', }, - 'suricata.eve.src_port': { - category: 'suricata', - name: 'suricata.eve.src_port', - type: 'alias', + 'netflow.distinct_count_of_destination_ipv4_address': { + category: 'netflow', + name: 'netflow.distinct_count_of_destination_ipv4_address', + type: 'long', }, - 'suricata.eve.proto': { - category: 'suricata', - name: 'suricata.eve.proto', - type: 'alias', + 'netflow.distinct_count_of_destination_ipv6_address': { + category: 'netflow', + name: 'netflow.distinct_count_of_destination_ipv6_address', + type: 'long', }, - 'suricata.eve.pcap_cnt': { - category: 'suricata', - name: 'suricata.eve.pcap_cnt', + 'netflow.distinct_count_of_source_ip_address': { + category: 'netflow', + name: 'netflow.distinct_count_of_source_ip_address', + type: 'long', + }, + 'netflow.distinct_count_of_source_ipv4_address': { + category: 'netflow', + name: 'netflow.distinct_count_of_source_ipv4_address', + type: 'long', + }, + 'netflow.distinct_count_of_source_ipv6_address': { + category: 'netflow', + name: 'netflow.distinct_count_of_source_ipv6_address', type: 'long', }, - 'suricata.eve.src_ip': { - category: 'suricata', - name: 'suricata.eve.src_ip', - type: 'alias', + 'netflow.dns_authoritative': { + category: 'netflow', + name: 'netflow.dns_authoritative', + type: 'short', }, - 'suricata.eve.dns.type': { - category: 'suricata', - name: 'suricata.eve.dns.type', + 'netflow.dns_cname': { + category: 'netflow', + name: 'netflow.dns_cname', type: 'keyword', }, - 'suricata.eve.dns.rrtype': { - category: 'suricata', - name: 'suricata.eve.dns.rrtype', - type: 'keyword', + 'netflow.dns_id': { + category: 'netflow', + name: 'netflow.dns_id', + type: 'integer', }, - 'suricata.eve.dns.rrname': { - category: 'suricata', - name: 'suricata.eve.dns.rrname', + 'netflow.dns_mx_exchange': { + category: 'netflow', + name: 'netflow.dns_mx_exchange', type: 'keyword', }, - 'suricata.eve.dns.rdata': { - category: 'suricata', - name: 'suricata.eve.dns.rdata', + 'netflow.dns_mx_preference': { + category: 'netflow', + name: 'netflow.dns_mx_preference', + type: 'integer', + }, + 'netflow.dns_nsd_name': { + category: 'netflow', + name: 'netflow.dns_nsd_name', type: 'keyword', }, - 'suricata.eve.dns.tx_id': { - category: 'suricata', - name: 'suricata.eve.dns.tx_id', - type: 'long', + 'netflow.dns_nx_domain': { + category: 'netflow', + name: 'netflow.dns_nx_domain', + type: 'short', }, - 'suricata.eve.dns.ttl': { - category: 'suricata', - name: 'suricata.eve.dns.ttl', - type: 'long', + 'netflow.dns_ptrd_name': { + category: 'netflow', + name: 'netflow.dns_ptrd_name', + type: 'keyword', }, - 'suricata.eve.dns.rcode': { - category: 'suricata', - name: 'suricata.eve.dns.rcode', + 'netflow.dns_qname': { + category: 'netflow', + name: 'netflow.dns_qname', type: 'keyword', }, - 'suricata.eve.dns.id': { - category: 'suricata', - name: 'suricata.eve.dns.id', - type: 'long', + 'netflow.dns_qr_type': { + category: 'netflow', + name: 'netflow.dns_qr_type', + type: 'integer', }, - 'suricata.eve.flow_id': { - category: 'suricata', - name: 'suricata.eve.flow_id', - type: 'keyword', + 'netflow.dns_query_response': { + category: 'netflow', + name: 'netflow.dns_query_response', + type: 'short', }, - 'suricata.eve.email.status': { - category: 'suricata', - name: 'suricata.eve.email.status', - type: 'keyword', + 'netflow.dns_rr_section': { + category: 'netflow', + name: 'netflow.dns_rr_section', + type: 'short', }, - 'suricata.eve.dest_ip': { - category: 'suricata', - name: 'suricata.eve.dest_ip', - type: 'alias', + 'netflow.dns_soa_expire': { + category: 'netflow', + name: 'netflow.dns_soa_expire', + type: 'long', }, - 'suricata.eve.icmp_code': { - category: 'suricata', - name: 'suricata.eve.icmp_code', + 'netflow.dns_soa_minimum': { + category: 'netflow', + name: 'netflow.dns_soa_minimum', type: 'long', }, - 'suricata.eve.http.status': { - category: 'suricata', - name: 'suricata.eve.http.status', - type: 'alias', + 'netflow.dns_soa_refresh': { + category: 'netflow', + name: 'netflow.dns_soa_refresh', + type: 'long', }, - 'suricata.eve.http.redirect': { - category: 'suricata', - name: 'suricata.eve.http.redirect', - type: 'keyword', + 'netflow.dns_soa_retry': { + category: 'netflow', + name: 'netflow.dns_soa_retry', + type: 'long', }, - 'suricata.eve.http.http_user_agent': { - category: 'suricata', - name: 'suricata.eve.http.http_user_agent', - type: 'alias', + 'netflow.dns_soa_serial': { + category: 'netflow', + name: 'netflow.dns_soa_serial', + type: 'long', }, - 'suricata.eve.http.protocol': { - category: 'suricata', - name: 'suricata.eve.http.protocol', + 'netflow.dns_soam_name': { + category: 'netflow', + name: 'netflow.dns_soam_name', type: 'keyword', }, - 'suricata.eve.http.http_refer': { - category: 'suricata', - name: 'suricata.eve.http.http_refer', - type: 'alias', - }, - 'suricata.eve.http.url': { - category: 'suricata', - name: 'suricata.eve.http.url', - type: 'alias', + 'netflow.dns_soar_name': { + category: 'netflow', + name: 'netflow.dns_soar_name', + type: 'keyword', }, - 'suricata.eve.http.hostname': { - category: 'suricata', - name: 'suricata.eve.http.hostname', - type: 'alias', + 'netflow.dns_srv_port': { + category: 'netflow', + name: 'netflow.dns_srv_port', + type: 'integer', }, - 'suricata.eve.http.length': { - category: 'suricata', - name: 'suricata.eve.http.length', - type: 'alias', + 'netflow.dns_srv_priority': { + category: 'netflow', + name: 'netflow.dns_srv_priority', + type: 'integer', }, - 'suricata.eve.http.http_method': { - category: 'suricata', - name: 'suricata.eve.http.http_method', - type: 'alias', + 'netflow.dns_srv_target': { + category: 'netflow', + name: 'netflow.dns_srv_target', + type: 'integer', }, - 'suricata.eve.http.http_content_type': { - category: 'suricata', - name: 'suricata.eve.http.http_content_type', - type: 'keyword', + 'netflow.dns_srv_weight': { + category: 'netflow', + name: 'netflow.dns_srv_weight', + type: 'integer', }, - 'suricata.eve.timestamp': { - category: 'suricata', - name: 'suricata.eve.timestamp', - type: 'alias', + 'netflow.dns_ttl': { + category: 'netflow', + name: 'netflow.dns_ttl', + type: 'long', }, - 'suricata.eve.in_iface': { - category: 'suricata', - name: 'suricata.eve.in_iface', + 'netflow.dns_txt_data': { + category: 'netflow', + name: 'netflow.dns_txt_data', type: 'keyword', }, - 'suricata.eve.alert.category': { - category: 'suricata', - name: 'suricata.eve.alert.category', + 'netflow.dot1q_customer_dei': { + category: 'netflow', + name: 'netflow.dot1q_customer_dei', + type: 'boolean', + }, + 'netflow.dot1q_customer_destination_mac_address': { + category: 'netflow', + name: 'netflow.dot1q_customer_destination_mac_address', type: 'keyword', }, - 'suricata.eve.alert.severity': { - category: 'suricata', - name: 'suricata.eve.alert.severity', - type: 'alias', + 'netflow.dot1q_customer_priority': { + category: 'netflow', + name: 'netflow.dot1q_customer_priority', + type: 'short', }, - 'suricata.eve.alert.rev': { - category: 'suricata', - name: 'suricata.eve.alert.rev', - type: 'long', + 'netflow.dot1q_customer_source_mac_address': { + category: 'netflow', + name: 'netflow.dot1q_customer_source_mac_address', + type: 'keyword', }, - 'suricata.eve.alert.gid': { - category: 'suricata', - name: 'suricata.eve.alert.gid', - type: 'long', + 'netflow.dot1q_customer_vlan_id': { + category: 'netflow', + name: 'netflow.dot1q_customer_vlan_id', + type: 'integer', }, - 'suricata.eve.alert.signature': { - category: 'suricata', - name: 'suricata.eve.alert.signature', - type: 'keyword', + 'netflow.dot1q_dei': { + category: 'netflow', + name: 'netflow.dot1q_dei', + type: 'boolean', }, - 'suricata.eve.alert.action': { - category: 'suricata', - name: 'suricata.eve.alert.action', - type: 'alias', + 'netflow.dot1q_priority': { + category: 'netflow', + name: 'netflow.dot1q_priority', + type: 'short', }, - 'suricata.eve.alert.signature_id': { - category: 'suricata', - name: 'suricata.eve.alert.signature_id', + 'netflow.dot1q_service_instance_id': { + category: 'netflow', + name: 'netflow.dot1q_service_instance_id', type: 'long', }, - 'suricata.eve.ssh.client.proto_version': { - category: 'suricata', - name: 'suricata.eve.ssh.client.proto_version', - type: 'keyword', - }, - 'suricata.eve.ssh.client.software_version': { - category: 'suricata', - name: 'suricata.eve.ssh.client.software_version', - type: 'keyword', + 'netflow.dot1q_service_instance_priority': { + category: 'netflow', + name: 'netflow.dot1q_service_instance_priority', + type: 'short', }, - 'suricata.eve.ssh.server.proto_version': { - category: 'suricata', - name: 'suricata.eve.ssh.server.proto_version', - type: 'keyword', + 'netflow.dot1q_service_instance_tag': { + category: 'netflow', + name: 'netflow.dot1q_service_instance_tag', + type: 'short', }, - 'suricata.eve.ssh.server.software_version': { - category: 'suricata', - name: 'suricata.eve.ssh.server.software_version', - type: 'keyword', + 'netflow.dot1q_vlan_id': { + category: 'netflow', + name: 'netflow.dot1q_vlan_id', + type: 'integer', }, - 'suricata.eve.stats.capture.kernel_packets': { - category: 'suricata', - name: 'suricata.eve.stats.capture.kernel_packets', + 'netflow.dropped_layer2_octet_delta_count': { + category: 'netflow', + name: 'netflow.dropped_layer2_octet_delta_count', type: 'long', }, - 'suricata.eve.stats.capture.kernel_drops': { - category: 'suricata', - name: 'suricata.eve.stats.capture.kernel_drops', + 'netflow.dropped_layer2_octet_total_count': { + category: 'netflow', + name: 'netflow.dropped_layer2_octet_total_count', type: 'long', }, - 'suricata.eve.stats.capture.kernel_ifdrops': { - category: 'suricata', - name: 'suricata.eve.stats.capture.kernel_ifdrops', + 'netflow.dropped_octet_delta_count': { + category: 'netflow', + name: 'netflow.dropped_octet_delta_count', type: 'long', }, - 'suricata.eve.stats.uptime': { - category: 'suricata', - name: 'suricata.eve.stats.uptime', + 'netflow.dropped_octet_total_count': { + category: 'netflow', + name: 'netflow.dropped_octet_total_count', type: 'long', }, - 'suricata.eve.stats.detect.alert': { - category: 'suricata', - name: 'suricata.eve.stats.detect.alert', + 'netflow.dropped_packet_delta_count': { + category: 'netflow', + name: 'netflow.dropped_packet_delta_count', type: 'long', }, - 'suricata.eve.stats.http.memcap': { - category: 'suricata', - name: 'suricata.eve.stats.http.memcap', + 'netflow.dropped_packet_total_count': { + category: 'netflow', + name: 'netflow.dropped_packet_total_count', type: 'long', }, - 'suricata.eve.stats.http.memuse': { - category: 'suricata', - name: 'suricata.eve.stats.http.memuse', + 'netflow.dst_traffic_index': { + category: 'netflow', + name: 'netflow.dst_traffic_index', type: 'long', }, - 'suricata.eve.stats.file_store.open_files': { - category: 'suricata', - name: 'suricata.eve.stats.file_store.open_files', + 'netflow.egress_broadcast_packet_total_count': { + category: 'netflow', + name: 'netflow.egress_broadcast_packet_total_count', type: 'long', }, - 'suricata.eve.stats.defrag.max_frag_hits': { - category: 'suricata', - name: 'suricata.eve.stats.defrag.max_frag_hits', + 'netflow.egress_interface': { + category: 'netflow', + name: 'netflow.egress_interface', type: 'long', }, - 'suricata.eve.stats.defrag.ipv4.timeouts': { - category: 'suricata', - name: 'suricata.eve.stats.defrag.ipv4.timeouts', + 'netflow.egress_interface_type': { + category: 'netflow', + name: 'netflow.egress_interface_type', type: 'long', }, - 'suricata.eve.stats.defrag.ipv4.fragments': { - category: 'suricata', - name: 'suricata.eve.stats.defrag.ipv4.fragments', + 'netflow.egress_physical_interface': { + category: 'netflow', + name: 'netflow.egress_physical_interface', type: 'long', }, - 'suricata.eve.stats.defrag.ipv4.reassembled': { - category: 'suricata', - name: 'suricata.eve.stats.defrag.ipv4.reassembled', + 'netflow.egress_unicast_packet_total_count': { + category: 'netflow', + name: 'netflow.egress_unicast_packet_total_count', type: 'long', }, - 'suricata.eve.stats.defrag.ipv6.timeouts': { - category: 'suricata', - name: 'suricata.eve.stats.defrag.ipv6.timeouts', + 'netflow.egress_vrfid': { + category: 'netflow', + name: 'netflow.egress_vrfid', type: 'long', }, - 'suricata.eve.stats.defrag.ipv6.fragments': { - category: 'suricata', - name: 'suricata.eve.stats.defrag.ipv6.fragments', - type: 'long', + 'netflow.encrypted_technology': { + category: 'netflow', + name: 'netflow.encrypted_technology', + type: 'keyword', }, - 'suricata.eve.stats.defrag.ipv6.reassembled': { - category: 'suricata', - name: 'suricata.eve.stats.defrag.ipv6.reassembled', - type: 'long', + 'netflow.engine_id': { + category: 'netflow', + name: 'netflow.engine_id', + type: 'short', }, - 'suricata.eve.stats.flow.tcp_reuse': { - category: 'suricata', - name: 'suricata.eve.stats.flow.tcp_reuse', - type: 'long', + 'netflow.engine_type': { + category: 'netflow', + name: 'netflow.engine_type', + type: 'short', }, - 'suricata.eve.stats.flow.udp': { - category: 'suricata', - name: 'suricata.eve.stats.flow.udp', - type: 'long', + 'netflow.ethernet_header_length': { + category: 'netflow', + name: 'netflow.ethernet_header_length', + type: 'short', }, - 'suricata.eve.stats.flow.memcap': { - category: 'suricata', - name: 'suricata.eve.stats.flow.memcap', - type: 'long', + 'netflow.ethernet_payload_length': { + category: 'netflow', + name: 'netflow.ethernet_payload_length', + type: 'integer', }, - 'suricata.eve.stats.flow.emerg_mode_entered': { - category: 'suricata', - name: 'suricata.eve.stats.flow.emerg_mode_entered', - type: 'long', + 'netflow.ethernet_total_length': { + category: 'netflow', + name: 'netflow.ethernet_total_length', + type: 'integer', }, - 'suricata.eve.stats.flow.emerg_mode_over': { - category: 'suricata', - name: 'suricata.eve.stats.flow.emerg_mode_over', - type: 'long', + 'netflow.ethernet_type': { + category: 'netflow', + name: 'netflow.ethernet_type', + type: 'integer', }, - 'suricata.eve.stats.flow.tcp': { - category: 'suricata', - name: 'suricata.eve.stats.flow.tcp', + 'netflow.expired_fragment_count': { + category: 'netflow', + name: 'netflow.expired_fragment_count', type: 'long', }, - 'suricata.eve.stats.flow.icmpv6': { - category: 'suricata', - name: 'suricata.eve.stats.flow.icmpv6', + 'netflow.export_interface': { + category: 'netflow', + name: 'netflow.export_interface', type: 'long', }, - 'suricata.eve.stats.flow.icmpv4': { - category: 'suricata', - name: 'suricata.eve.stats.flow.icmpv4', - type: 'long', + 'netflow.export_protocol_version': { + category: 'netflow', + name: 'netflow.export_protocol_version', + type: 'short', }, - 'suricata.eve.stats.flow.spare': { - category: 'suricata', - name: 'suricata.eve.stats.flow.spare', + 'netflow.export_sctp_stream_id': { + category: 'netflow', + name: 'netflow.export_sctp_stream_id', + type: 'integer', + }, + 'netflow.export_transport_protocol': { + category: 'netflow', + name: 'netflow.export_transport_protocol', + type: 'short', + }, + 'netflow.exported_flow_record_total_count': { + category: 'netflow', + name: 'netflow.exported_flow_record_total_count', type: 'long', }, - 'suricata.eve.stats.flow.memuse': { - category: 'suricata', - name: 'suricata.eve.stats.flow.memuse', + 'netflow.exported_message_total_count': { + category: 'netflow', + name: 'netflow.exported_message_total_count', type: 'long', }, - 'suricata.eve.stats.tcp.pseudo_failed': { - category: 'suricata', - name: 'suricata.eve.stats.tcp.pseudo_failed', + 'netflow.exported_octet_total_count': { + category: 'netflow', + name: 'netflow.exported_octet_total_count', type: 'long', }, - 'suricata.eve.stats.tcp.ssn_memcap_drop': { - category: 'suricata', - name: 'suricata.eve.stats.tcp.ssn_memcap_drop', + 'netflow.exporter_certificate': { + category: 'netflow', + name: 'netflow.exporter_certificate', + type: 'short', + }, + 'netflow.exporter_ipv4_address': { + category: 'netflow', + name: 'netflow.exporter_ipv4_address', + type: 'ip', + }, + 'netflow.exporter_ipv6_address': { + category: 'netflow', + name: 'netflow.exporter_ipv6_address', + type: 'ip', + }, + 'netflow.exporter_transport_port': { + category: 'netflow', + name: 'netflow.exporter_transport_port', + type: 'integer', + }, + 'netflow.exporting_process_id': { + category: 'netflow', + name: 'netflow.exporting_process_id', type: 'long', }, - 'suricata.eve.stats.tcp.insert_data_overlap_fail': { - category: 'suricata', - name: 'suricata.eve.stats.tcp.insert_data_overlap_fail', + 'netflow.external_address_realm': { + category: 'netflow', + name: 'netflow.external_address_realm', + type: 'short', + }, + 'netflow.firewall_event': { + category: 'netflow', + name: 'netflow.firewall_event', + type: 'short', + }, + 'netflow.first_eight_non_empty_packet_directions': { + category: 'netflow', + name: 'netflow.first_eight_non_empty_packet_directions', + type: 'short', + }, + 'netflow.first_non_empty_packet_size': { + category: 'netflow', + name: 'netflow.first_non_empty_packet_size', + type: 'integer', + }, + 'netflow.first_packet_banner': { + category: 'netflow', + name: 'netflow.first_packet_banner', + type: 'keyword', + }, + 'netflow.flags_and_sampler_id': { + category: 'netflow', + name: 'netflow.flags_and_sampler_id', type: 'long', }, - 'suricata.eve.stats.tcp.sessions': { - category: 'suricata', - name: 'suricata.eve.stats.tcp.sessions', + 'netflow.flow_active_timeout': { + category: 'netflow', + name: 'netflow.flow_active_timeout', + type: 'integer', + }, + 'netflow.flow_attributes': { + category: 'netflow', + name: 'netflow.flow_attributes', + type: 'integer', + }, + 'netflow.flow_direction': { + category: 'netflow', + name: 'netflow.flow_direction', + type: 'short', + }, + 'netflow.flow_duration_microseconds': { + category: 'netflow', + name: 'netflow.flow_duration_microseconds', type: 'long', }, - 'suricata.eve.stats.tcp.pseudo': { - category: 'suricata', - name: 'suricata.eve.stats.tcp.pseudo', + 'netflow.flow_duration_milliseconds': { + category: 'netflow', + name: 'netflow.flow_duration_milliseconds', type: 'long', }, - 'suricata.eve.stats.tcp.synack': { - category: 'suricata', - name: 'suricata.eve.stats.tcp.synack', + 'netflow.flow_end_delta_microseconds': { + category: 'netflow', + name: 'netflow.flow_end_delta_microseconds', type: 'long', }, - 'suricata.eve.stats.tcp.insert_data_normal_fail': { - category: 'suricata', - name: 'suricata.eve.stats.tcp.insert_data_normal_fail', + 'netflow.flow_end_microseconds': { + category: 'netflow', + name: 'netflow.flow_end_microseconds', + type: 'date', + }, + 'netflow.flow_end_milliseconds': { + category: 'netflow', + name: 'netflow.flow_end_milliseconds', + type: 'date', + }, + 'netflow.flow_end_nanoseconds': { + category: 'netflow', + name: 'netflow.flow_end_nanoseconds', + type: 'date', + }, + 'netflow.flow_end_reason': { + category: 'netflow', + name: 'netflow.flow_end_reason', + type: 'short', + }, + 'netflow.flow_end_seconds': { + category: 'netflow', + name: 'netflow.flow_end_seconds', + type: 'date', + }, + 'netflow.flow_end_sys_up_time': { + category: 'netflow', + name: 'netflow.flow_end_sys_up_time', type: 'long', }, - 'suricata.eve.stats.tcp.syn': { - category: 'suricata', - name: 'suricata.eve.stats.tcp.syn', + 'netflow.flow_id': { + category: 'netflow', + name: 'netflow.flow_id', type: 'long', }, - 'suricata.eve.stats.tcp.memuse': { - category: 'suricata', - name: 'suricata.eve.stats.tcp.memuse', + 'netflow.flow_idle_timeout': { + category: 'netflow', + name: 'netflow.flow_idle_timeout', + type: 'integer', + }, + 'netflow.flow_key_indicator': { + category: 'netflow', + name: 'netflow.flow_key_indicator', type: 'long', }, - 'suricata.eve.stats.tcp.invalid_checksum': { - category: 'suricata', - name: 'suricata.eve.stats.tcp.invalid_checksum', + 'netflow.flow_label_ipv6': { + category: 'netflow', + name: 'netflow.flow_label_ipv6', type: 'long', }, - 'suricata.eve.stats.tcp.segment_memcap_drop': { - category: 'suricata', - name: 'suricata.eve.stats.tcp.segment_memcap_drop', + 'netflow.flow_sampling_time_interval': { + category: 'netflow', + name: 'netflow.flow_sampling_time_interval', type: 'long', }, - 'suricata.eve.stats.tcp.overlap': { - category: 'suricata', - name: 'suricata.eve.stats.tcp.overlap', + 'netflow.flow_sampling_time_spacing': { + category: 'netflow', + name: 'netflow.flow_sampling_time_spacing', type: 'long', }, - 'suricata.eve.stats.tcp.insert_list_fail': { - category: 'suricata', - name: 'suricata.eve.stats.tcp.insert_list_fail', + 'netflow.flow_selected_flow_delta_count': { + category: 'netflow', + name: 'netflow.flow_selected_flow_delta_count', type: 'long', }, - 'suricata.eve.stats.tcp.rst': { - category: 'suricata', - name: 'suricata.eve.stats.tcp.rst', + 'netflow.flow_selected_octet_delta_count': { + category: 'netflow', + name: 'netflow.flow_selected_octet_delta_count', type: 'long', }, - 'suricata.eve.stats.tcp.stream_depth_reached': { - category: 'suricata', - name: 'suricata.eve.stats.tcp.stream_depth_reached', + 'netflow.flow_selected_packet_delta_count': { + category: 'netflow', + name: 'netflow.flow_selected_packet_delta_count', type: 'long', }, - 'suricata.eve.stats.tcp.reassembly_memuse': { - category: 'suricata', - name: 'suricata.eve.stats.tcp.reassembly_memuse', - type: 'long', + 'netflow.flow_selector_algorithm': { + category: 'netflow', + name: 'netflow.flow_selector_algorithm', + type: 'integer', }, - 'suricata.eve.stats.tcp.reassembly_gap': { - category: 'suricata', - name: 'suricata.eve.stats.tcp.reassembly_gap', + 'netflow.flow_start_delta_microseconds': { + category: 'netflow', + name: 'netflow.flow_start_delta_microseconds', type: 'long', }, - 'suricata.eve.stats.tcp.overlap_diff_data': { - category: 'suricata', - name: 'suricata.eve.stats.tcp.overlap_diff_data', - type: 'long', + 'netflow.flow_start_microseconds': { + category: 'netflow', + name: 'netflow.flow_start_microseconds', + type: 'date', }, - 'suricata.eve.stats.tcp.no_flow': { - category: 'suricata', - name: 'suricata.eve.stats.tcp.no_flow', - type: 'long', + 'netflow.flow_start_milliseconds': { + category: 'netflow', + name: 'netflow.flow_start_milliseconds', + type: 'date', }, - 'suricata.eve.stats.decoder.avg_pkt_size': { - category: 'suricata', - name: 'suricata.eve.stats.decoder.avg_pkt_size', - type: 'long', + 'netflow.flow_start_nanoseconds': { + category: 'netflow', + name: 'netflow.flow_start_nanoseconds', + type: 'date', }, - 'suricata.eve.stats.decoder.bytes': { - category: 'suricata', - name: 'suricata.eve.stats.decoder.bytes', - type: 'long', + 'netflow.flow_start_seconds': { + category: 'netflow', + name: 'netflow.flow_start_seconds', + type: 'date', }, - 'suricata.eve.stats.decoder.tcp': { - category: 'suricata', - name: 'suricata.eve.stats.decoder.tcp', + 'netflow.flow_start_sys_up_time': { + category: 'netflow', + name: 'netflow.flow_start_sys_up_time', type: 'long', }, - 'suricata.eve.stats.decoder.raw': { - category: 'suricata', - name: 'suricata.eve.stats.decoder.raw', + 'netflow.flow_table_flush_event_count': { + category: 'netflow', + name: 'netflow.flow_table_flush_event_count', type: 'long', }, - 'suricata.eve.stats.decoder.ppp': { - category: 'suricata', - name: 'suricata.eve.stats.decoder.ppp', + 'netflow.flow_table_peak_count': { + category: 'netflow', + name: 'netflow.flow_table_peak_count', type: 'long', }, - 'suricata.eve.stats.decoder.vlan_qinq': { - category: 'suricata', - name: 'suricata.eve.stats.decoder.vlan_qinq', - type: 'long', + 'netflow.forwarding_status': { + category: 'netflow', + name: 'netflow.forwarding_status', + type: 'short', }, - 'suricata.eve.stats.decoder.null': { - category: 'suricata', - name: 'suricata.eve.stats.decoder.null', - type: 'long', + 'netflow.fragment_flags': { + category: 'netflow', + name: 'netflow.fragment_flags', + type: 'short', }, - 'suricata.eve.stats.decoder.ltnull.unsupported_type': { - category: 'suricata', - name: 'suricata.eve.stats.decoder.ltnull.unsupported_type', + 'netflow.fragment_identification': { + category: 'netflow', + name: 'netflow.fragment_identification', type: 'long', }, - 'suricata.eve.stats.decoder.ltnull.pkt_too_small': { - category: 'suricata', - name: 'suricata.eve.stats.decoder.ltnull.pkt_too_small', - type: 'long', + 'netflow.fragment_offset': { + category: 'netflow', + name: 'netflow.fragment_offset', + type: 'integer', }, - 'suricata.eve.stats.decoder.invalid': { - category: 'suricata', - name: 'suricata.eve.stats.decoder.invalid', + 'netflow.fw_blackout_secs': { + category: 'netflow', + name: 'netflow.fw_blackout_secs', type: 'long', }, - 'suricata.eve.stats.decoder.gre': { - category: 'suricata', - name: 'suricata.eve.stats.decoder.gre', + 'netflow.fw_configured_value': { + category: 'netflow', + name: 'netflow.fw_configured_value', type: 'long', }, - 'suricata.eve.stats.decoder.ipv4': { - category: 'suricata', - name: 'suricata.eve.stats.decoder.ipv4', + 'netflow.fw_cts_src_sgt': { + category: 'netflow', + name: 'netflow.fw_cts_src_sgt', type: 'long', }, - 'suricata.eve.stats.decoder.ipv6': { - category: 'suricata', - name: 'suricata.eve.stats.decoder.ipv6', + 'netflow.fw_event_level': { + category: 'netflow', + name: 'netflow.fw_event_level', type: 'long', }, - 'suricata.eve.stats.decoder.pkts': { - category: 'suricata', - name: 'suricata.eve.stats.decoder.pkts', + 'netflow.fw_event_level_id': { + category: 'netflow', + name: 'netflow.fw_event_level_id', type: 'long', }, - 'suricata.eve.stats.decoder.ipv6_in_ipv6': { - category: 'suricata', - name: 'suricata.eve.stats.decoder.ipv6_in_ipv6', - type: 'long', + 'netflow.fw_ext_event': { + category: 'netflow', + name: 'netflow.fw_ext_event', + type: 'integer', }, - 'suricata.eve.stats.decoder.ipraw.invalid_ip_version': { - category: 'suricata', - name: 'suricata.eve.stats.decoder.ipraw.invalid_ip_version', + 'netflow.fw_ext_event_alt': { + category: 'netflow', + name: 'netflow.fw_ext_event_alt', type: 'long', }, - 'suricata.eve.stats.decoder.pppoe': { - category: 'suricata', - name: 'suricata.eve.stats.decoder.pppoe', - type: 'long', + 'netflow.fw_ext_event_desc': { + category: 'netflow', + name: 'netflow.fw_ext_event_desc', + type: 'keyword', }, - 'suricata.eve.stats.decoder.udp': { - category: 'suricata', - name: 'suricata.eve.stats.decoder.udp', + 'netflow.fw_half_open_count': { + category: 'netflow', + name: 'netflow.fw_half_open_count', type: 'long', }, - 'suricata.eve.stats.decoder.dce.pkt_too_small': { - category: 'suricata', - name: 'suricata.eve.stats.decoder.dce.pkt_too_small', + 'netflow.fw_half_open_high': { + category: 'netflow', + name: 'netflow.fw_half_open_high', type: 'long', }, - 'suricata.eve.stats.decoder.vlan': { - category: 'suricata', - name: 'suricata.eve.stats.decoder.vlan', + 'netflow.fw_half_open_rate': { + category: 'netflow', + name: 'netflow.fw_half_open_rate', type: 'long', }, - 'suricata.eve.stats.decoder.sctp': { - category: 'suricata', - name: 'suricata.eve.stats.decoder.sctp', + 'netflow.fw_max_sessions': { + category: 'netflow', + name: 'netflow.fw_max_sessions', type: 'long', }, - 'suricata.eve.stats.decoder.max_pkt_size': { - category: 'suricata', - name: 'suricata.eve.stats.decoder.max_pkt_size', - type: 'long', + 'netflow.fw_rule': { + category: 'netflow', + name: 'netflow.fw_rule', + type: 'keyword', }, - 'suricata.eve.stats.decoder.teredo': { - category: 'suricata', - name: 'suricata.eve.stats.decoder.teredo', + 'netflow.fw_summary_pkt_count': { + category: 'netflow', + name: 'netflow.fw_summary_pkt_count', type: 'long', }, - 'suricata.eve.stats.decoder.mpls': { - category: 'suricata', - name: 'suricata.eve.stats.decoder.mpls', + 'netflow.fw_zone_pair_id': { + category: 'netflow', + name: 'netflow.fw_zone_pair_id', type: 'long', }, - 'suricata.eve.stats.decoder.sll': { - category: 'suricata', - name: 'suricata.eve.stats.decoder.sll', + 'netflow.fw_zone_pair_name': { + category: 'netflow', + name: 'netflow.fw_zone_pair_name', type: 'long', }, - 'suricata.eve.stats.decoder.icmpv6': { - category: 'suricata', - name: 'suricata.eve.stats.decoder.icmpv6', + 'netflow.global_address_mapping_high_threshold': { + category: 'netflow', + name: 'netflow.global_address_mapping_high_threshold', type: 'long', }, - 'suricata.eve.stats.decoder.icmpv4': { - category: 'suricata', - name: 'suricata.eve.stats.decoder.icmpv4', + 'netflow.gre_key': { + category: 'netflow', + name: 'netflow.gre_key', type: 'long', }, - 'suricata.eve.stats.decoder.erspan': { - category: 'suricata', - name: 'suricata.eve.stats.decoder.erspan', - type: 'long', + 'netflow.hash_digest_output': { + category: 'netflow', + name: 'netflow.hash_digest_output', + type: 'boolean', }, - 'suricata.eve.stats.decoder.ethernet': { - category: 'suricata', - name: 'suricata.eve.stats.decoder.ethernet', - type: 'long', + 'netflow.hash_flow_domain': { + category: 'netflow', + name: 'netflow.hash_flow_domain', + type: 'integer', }, - 'suricata.eve.stats.decoder.ipv4_in_ipv6': { - category: 'suricata', - name: 'suricata.eve.stats.decoder.ipv4_in_ipv6', + 'netflow.hash_initialiser_value': { + category: 'netflow', + name: 'netflow.hash_initialiser_value', type: 'long', }, - 'suricata.eve.stats.decoder.ieee8021ah': { - category: 'suricata', - name: 'suricata.eve.stats.decoder.ieee8021ah', + 'netflow.hash_ip_payload_offset': { + category: 'netflow', + name: 'netflow.hash_ip_payload_offset', type: 'long', }, - 'suricata.eve.stats.dns.memcap_global': { - category: 'suricata', - name: 'suricata.eve.stats.dns.memcap_global', + 'netflow.hash_ip_payload_size': { + category: 'netflow', + name: 'netflow.hash_ip_payload_size', type: 'long', }, - 'suricata.eve.stats.dns.memcap_state': { - category: 'suricata', - name: 'suricata.eve.stats.dns.memcap_state', + 'netflow.hash_output_range_max': { + category: 'netflow', + name: 'netflow.hash_output_range_max', type: 'long', }, - 'suricata.eve.stats.dns.memuse': { - category: 'suricata', - name: 'suricata.eve.stats.dns.memuse', + 'netflow.hash_output_range_min': { + category: 'netflow', + name: 'netflow.hash_output_range_min', type: 'long', }, - 'suricata.eve.stats.flow_mgr.rows_busy': { - category: 'suricata', - name: 'suricata.eve.stats.flow_mgr.rows_busy', + 'netflow.hash_selected_range_max': { + category: 'netflow', + name: 'netflow.hash_selected_range_max', type: 'long', }, - 'suricata.eve.stats.flow_mgr.flows_timeout': { - category: 'suricata', - name: 'suricata.eve.stats.flow_mgr.flows_timeout', + 'netflow.hash_selected_range_min': { + category: 'netflow', + name: 'netflow.hash_selected_range_min', type: 'long', }, - 'suricata.eve.stats.flow_mgr.flows_notimeout': { - category: 'suricata', - name: 'suricata.eve.stats.flow_mgr.flows_notimeout', - type: 'long', + 'netflow.http_content_type': { + category: 'netflow', + name: 'netflow.http_content_type', + type: 'keyword', }, - 'suricata.eve.stats.flow_mgr.rows_skipped': { - category: 'suricata', - name: 'suricata.eve.stats.flow_mgr.rows_skipped', - type: 'long', + 'netflow.http_message_version': { + category: 'netflow', + name: 'netflow.http_message_version', + type: 'keyword', }, - 'suricata.eve.stats.flow_mgr.closed_pruned': { - category: 'suricata', - name: 'suricata.eve.stats.flow_mgr.closed_pruned', - type: 'long', + 'netflow.http_reason_phrase': { + category: 'netflow', + name: 'netflow.http_reason_phrase', + type: 'keyword', }, - 'suricata.eve.stats.flow_mgr.new_pruned': { - category: 'suricata', - name: 'suricata.eve.stats.flow_mgr.new_pruned', - type: 'long', + 'netflow.http_request_host': { + category: 'netflow', + name: 'netflow.http_request_host', + type: 'keyword', }, - 'suricata.eve.stats.flow_mgr.flows_removed': { - category: 'suricata', - name: 'suricata.eve.stats.flow_mgr.flows_removed', - type: 'long', + 'netflow.http_request_method': { + category: 'netflow', + name: 'netflow.http_request_method', + type: 'keyword', }, - 'suricata.eve.stats.flow_mgr.bypassed_pruned': { - category: 'suricata', - name: 'suricata.eve.stats.flow_mgr.bypassed_pruned', - type: 'long', + 'netflow.http_request_target': { + category: 'netflow', + name: 'netflow.http_request_target', + type: 'keyword', }, - 'suricata.eve.stats.flow_mgr.est_pruned': { - category: 'suricata', - name: 'suricata.eve.stats.flow_mgr.est_pruned', - type: 'long', + 'netflow.http_status_code': { + category: 'netflow', + name: 'netflow.http_status_code', + type: 'integer', }, - 'suricata.eve.stats.flow_mgr.flows_timeout_inuse': { - category: 'suricata', - name: 'suricata.eve.stats.flow_mgr.flows_timeout_inuse', - type: 'long', + 'netflow.http_user_agent': { + category: 'netflow', + name: 'netflow.http_user_agent', + type: 'keyword', }, - 'suricata.eve.stats.flow_mgr.flows_checked': { - category: 'suricata', - name: 'suricata.eve.stats.flow_mgr.flows_checked', - type: 'long', + 'netflow.icmp_code_ipv4': { + category: 'netflow', + name: 'netflow.icmp_code_ipv4', + type: 'short', }, - 'suricata.eve.stats.flow_mgr.rows_maxlen': { - category: 'suricata', - name: 'suricata.eve.stats.flow_mgr.rows_maxlen', - type: 'long', + 'netflow.icmp_code_ipv6': { + category: 'netflow', + name: 'netflow.icmp_code_ipv6', + type: 'short', }, - 'suricata.eve.stats.flow_mgr.rows_checked': { - category: 'suricata', - name: 'suricata.eve.stats.flow_mgr.rows_checked', - type: 'long', + 'netflow.icmp_type_code_ipv4': { + category: 'netflow', + name: 'netflow.icmp_type_code_ipv4', + type: 'integer', }, - 'suricata.eve.stats.flow_mgr.rows_empty': { - category: 'suricata', - name: 'suricata.eve.stats.flow_mgr.rows_empty', - type: 'long', + 'netflow.icmp_type_code_ipv6': { + category: 'netflow', + name: 'netflow.icmp_type_code_ipv6', + type: 'integer', }, - 'suricata.eve.stats.app_layer.flow.tls': { - category: 'suricata', - name: 'suricata.eve.stats.app_layer.flow.tls', - type: 'long', + 'netflow.icmp_type_ipv4': { + category: 'netflow', + name: 'netflow.icmp_type_ipv4', + type: 'short', }, - 'suricata.eve.stats.app_layer.flow.ftp': { - category: 'suricata', - name: 'suricata.eve.stats.app_layer.flow.ftp', - type: 'long', + 'netflow.icmp_type_ipv6': { + category: 'netflow', + name: 'netflow.icmp_type_ipv6', + type: 'short', }, - 'suricata.eve.stats.app_layer.flow.http': { - category: 'suricata', - name: 'suricata.eve.stats.app_layer.flow.http', - type: 'long', + 'netflow.igmp_type': { + category: 'netflow', + name: 'netflow.igmp_type', + type: 'short', }, - 'suricata.eve.stats.app_layer.flow.failed_udp': { - category: 'suricata', - name: 'suricata.eve.stats.app_layer.flow.failed_udp', + 'netflow.ignored_data_record_total_count': { + category: 'netflow', + name: 'netflow.ignored_data_record_total_count', type: 'long', }, - 'suricata.eve.stats.app_layer.flow.dns_udp': { - category: 'suricata', - name: 'suricata.eve.stats.app_layer.flow.dns_udp', + 'netflow.ignored_layer2_frame_total_count': { + category: 'netflow', + name: 'netflow.ignored_layer2_frame_total_count', type: 'long', }, - 'suricata.eve.stats.app_layer.flow.dns_tcp': { - category: 'suricata', - name: 'suricata.eve.stats.app_layer.flow.dns_tcp', + 'netflow.ignored_layer2_octet_total_count': { + category: 'netflow', + name: 'netflow.ignored_layer2_octet_total_count', type: 'long', }, - 'suricata.eve.stats.app_layer.flow.smtp': { - category: 'suricata', - name: 'suricata.eve.stats.app_layer.flow.smtp', + 'netflow.ignored_octet_total_count': { + category: 'netflow', + name: 'netflow.ignored_octet_total_count', type: 'long', }, - 'suricata.eve.stats.app_layer.flow.failed_tcp': { - category: 'suricata', - name: 'suricata.eve.stats.app_layer.flow.failed_tcp', + 'netflow.ignored_packet_total_count': { + category: 'netflow', + name: 'netflow.ignored_packet_total_count', type: 'long', }, - 'suricata.eve.stats.app_layer.flow.msn': { - category: 'suricata', - name: 'suricata.eve.stats.app_layer.flow.msn', - type: 'long', + 'netflow.information_element_data_type': { + category: 'netflow', + name: 'netflow.information_element_data_type', + type: 'short', }, - 'suricata.eve.stats.app_layer.flow.ssh': { - category: 'suricata', - name: 'suricata.eve.stats.app_layer.flow.ssh', - type: 'long', + 'netflow.information_element_description': { + category: 'netflow', + name: 'netflow.information_element_description', + type: 'keyword', }, - 'suricata.eve.stats.app_layer.flow.imap': { - category: 'suricata', - name: 'suricata.eve.stats.app_layer.flow.imap', - type: 'long', + 'netflow.information_element_id': { + category: 'netflow', + name: 'netflow.information_element_id', + type: 'integer', }, - 'suricata.eve.stats.app_layer.flow.dcerpc_udp': { - category: 'suricata', - name: 'suricata.eve.stats.app_layer.flow.dcerpc_udp', - type: 'long', + 'netflow.information_element_index': { + category: 'netflow', + name: 'netflow.information_element_index', + type: 'integer', }, - 'suricata.eve.stats.app_layer.flow.dcerpc_tcp': { - category: 'suricata', - name: 'suricata.eve.stats.app_layer.flow.dcerpc_tcp', - type: 'long', + 'netflow.information_element_name': { + category: 'netflow', + name: 'netflow.information_element_name', + type: 'keyword', }, - 'suricata.eve.stats.app_layer.flow.smb': { - category: 'suricata', - name: 'suricata.eve.stats.app_layer.flow.smb', + 'netflow.information_element_range_begin': { + category: 'netflow', + name: 'netflow.information_element_range_begin', type: 'long', }, - 'suricata.eve.stats.app_layer.tx.tls': { - category: 'suricata', - name: 'suricata.eve.stats.app_layer.tx.tls', + 'netflow.information_element_range_end': { + category: 'netflow', + name: 'netflow.information_element_range_end', type: 'long', }, - 'suricata.eve.stats.app_layer.tx.ftp': { - category: 'suricata', - name: 'suricata.eve.stats.app_layer.tx.ftp', - type: 'long', + 'netflow.information_element_semantics': { + category: 'netflow', + name: 'netflow.information_element_semantics', + type: 'short', }, - 'suricata.eve.stats.app_layer.tx.http': { - category: 'suricata', - name: 'suricata.eve.stats.app_layer.tx.http', + 'netflow.information_element_units': { + category: 'netflow', + name: 'netflow.information_element_units', + type: 'integer', + }, + 'netflow.ingress_broadcast_packet_total_count': { + category: 'netflow', + name: 'netflow.ingress_broadcast_packet_total_count', type: 'long', }, - 'suricata.eve.stats.app_layer.tx.dns_udp': { - category: 'suricata', - name: 'suricata.eve.stats.app_layer.tx.dns_udp', + 'netflow.ingress_interface': { + category: 'netflow', + name: 'netflow.ingress_interface', type: 'long', }, - 'suricata.eve.stats.app_layer.tx.dns_tcp': { - category: 'suricata', - name: 'suricata.eve.stats.app_layer.tx.dns_tcp', + 'netflow.ingress_interface_type': { + category: 'netflow', + name: 'netflow.ingress_interface_type', type: 'long', }, - 'suricata.eve.stats.app_layer.tx.smtp': { - category: 'suricata', - name: 'suricata.eve.stats.app_layer.tx.smtp', + 'netflow.ingress_multicast_packet_total_count': { + category: 'netflow', + name: 'netflow.ingress_multicast_packet_total_count', type: 'long', }, - 'suricata.eve.stats.app_layer.tx.ssh': { - category: 'suricata', - name: 'suricata.eve.stats.app_layer.tx.ssh', + 'netflow.ingress_physical_interface': { + category: 'netflow', + name: 'netflow.ingress_physical_interface', type: 'long', }, - 'suricata.eve.stats.app_layer.tx.dcerpc_udp': { - category: 'suricata', - name: 'suricata.eve.stats.app_layer.tx.dcerpc_udp', + 'netflow.ingress_unicast_packet_total_count': { + category: 'netflow', + name: 'netflow.ingress_unicast_packet_total_count', type: 'long', }, - 'suricata.eve.stats.app_layer.tx.dcerpc_tcp': { - category: 'suricata', - name: 'suricata.eve.stats.app_layer.tx.dcerpc_tcp', + 'netflow.ingress_vrfid': { + category: 'netflow', + name: 'netflow.ingress_vrfid', type: 'long', }, - 'suricata.eve.stats.app_layer.tx.smb': { - category: 'suricata', - name: 'suricata.eve.stats.app_layer.tx.smb', + 'netflow.initial_tcp_flags': { + category: 'netflow', + name: 'netflow.initial_tcp_flags', + type: 'short', + }, + 'netflow.initiator_octets': { + category: 'netflow', + name: 'netflow.initiator_octets', type: 'long', }, - 'suricata.eve.tls.notbefore': { - category: 'suricata', - name: 'suricata.eve.tls.notbefore', - type: 'date', + 'netflow.initiator_packets': { + category: 'netflow', + name: 'netflow.initiator_packets', + type: 'long', }, - 'suricata.eve.tls.issuerdn': { - category: 'suricata', - name: 'suricata.eve.tls.issuerdn', + 'netflow.interface_description': { + category: 'netflow', + name: 'netflow.interface_description', type: 'keyword', }, - 'suricata.eve.tls.sni': { - category: 'suricata', - name: 'suricata.eve.tls.sni', + 'netflow.interface_name': { + category: 'netflow', + name: 'netflow.interface_name', type: 'keyword', }, - 'suricata.eve.tls.version': { - category: 'suricata', - name: 'suricata.eve.tls.version', - type: 'keyword', + 'netflow.intermediate_process_id': { + category: 'netflow', + name: 'netflow.intermediate_process_id', + type: 'long', }, - 'suricata.eve.tls.session_resumed': { - category: 'suricata', - name: 'suricata.eve.tls.session_resumed', - type: 'boolean', + 'netflow.internal_address_realm': { + category: 'netflow', + name: 'netflow.internal_address_realm', + type: 'short', }, - 'suricata.eve.tls.fingerprint': { - category: 'suricata', - name: 'suricata.eve.tls.fingerprint', - type: 'keyword', + 'netflow.ip_class_of_service': { + category: 'netflow', + name: 'netflow.ip_class_of_service', + type: 'short', }, - 'suricata.eve.tls.serial': { - category: 'suricata', - name: 'suricata.eve.tls.serial', - type: 'keyword', + 'netflow.ip_diff_serv_code_point': { + category: 'netflow', + name: 'netflow.ip_diff_serv_code_point', + type: 'short', }, - 'suricata.eve.tls.notafter': { - category: 'suricata', - name: 'suricata.eve.tls.notafter', - type: 'date', + 'netflow.ip_header_length': { + category: 'netflow', + name: 'netflow.ip_header_length', + type: 'short', }, - 'suricata.eve.tls.subject': { - category: 'suricata', - name: 'suricata.eve.tls.subject', - type: 'keyword', + 'netflow.ip_header_packet_section': { + category: 'netflow', + name: 'netflow.ip_header_packet_section', + type: 'short', }, - 'suricata.eve.tls.ja3s.string': { - category: 'suricata', - name: 'suricata.eve.tls.ja3s.string', - type: 'keyword', + 'netflow.ip_next_hop_ipv4_address': { + category: 'netflow', + name: 'netflow.ip_next_hop_ipv4_address', + type: 'ip', }, - 'suricata.eve.tls.ja3s.hash': { - category: 'suricata', - name: 'suricata.eve.tls.ja3s.hash', - type: 'keyword', + 'netflow.ip_next_hop_ipv6_address': { + category: 'netflow', + name: 'netflow.ip_next_hop_ipv6_address', + type: 'ip', }, - 'suricata.eve.tls.ja3.string': { - category: 'suricata', - name: 'suricata.eve.tls.ja3.string', - type: 'keyword', + 'netflow.ip_payload_length': { + category: 'netflow', + name: 'netflow.ip_payload_length', + type: 'long', }, - 'suricata.eve.tls.ja3.hash': { - category: 'suricata', - name: 'suricata.eve.tls.ja3.hash', - type: 'keyword', + 'netflow.ip_payload_packet_section': { + category: 'netflow', + name: 'netflow.ip_payload_packet_section', + type: 'short', }, - 'suricata.eve.app_proto_ts': { - category: 'suricata', - name: 'suricata.eve.app_proto_ts', - type: 'keyword', + 'netflow.ip_precedence': { + category: 'netflow', + name: 'netflow.ip_precedence', + type: 'short', }, - 'suricata.eve.flow.bytes_toclient': { - category: 'suricata', - name: 'suricata.eve.flow.bytes_toclient', - type: 'alias', + 'netflow.ip_sec_spi': { + category: 'netflow', + name: 'netflow.ip_sec_spi', + type: 'long', }, - 'suricata.eve.flow.start': { - category: 'suricata', - name: 'suricata.eve.flow.start', - type: 'alias', + 'netflow.ip_total_length': { + category: 'netflow', + name: 'netflow.ip_total_length', + type: 'long', }, - 'suricata.eve.flow.pkts_toclient': { - category: 'suricata', - name: 'suricata.eve.flow.pkts_toclient', - type: 'alias', + 'netflow.ip_ttl': { + category: 'netflow', + name: 'netflow.ip_ttl', + type: 'short', }, - 'suricata.eve.flow.age': { - category: 'suricata', - name: 'suricata.eve.flow.age', - type: 'long', + 'netflow.ip_version': { + category: 'netflow', + name: 'netflow.ip_version', + type: 'short', }, - 'suricata.eve.flow.state': { - category: 'suricata', - name: 'suricata.eve.flow.state', - type: 'keyword', + 'netflow.ipv4_ihl': { + category: 'netflow', + name: 'netflow.ipv4_ihl', + type: 'short', }, - 'suricata.eve.flow.bytes_toserver': { - category: 'suricata', - name: 'suricata.eve.flow.bytes_toserver', - type: 'alias', + 'netflow.ipv4_options': { + category: 'netflow', + name: 'netflow.ipv4_options', + type: 'long', }, - 'suricata.eve.flow.reason': { - category: 'suricata', - name: 'suricata.eve.flow.reason', - type: 'keyword', + 'netflow.ipv4_router_sc': { + category: 'netflow', + name: 'netflow.ipv4_router_sc', + type: 'ip', }, - 'suricata.eve.flow.pkts_toserver': { - category: 'suricata', - name: 'suricata.eve.flow.pkts_toserver', - type: 'alias', + 'netflow.ipv6_extension_headers': { + category: 'netflow', + name: 'netflow.ipv6_extension_headers', + type: 'long', }, - 'suricata.eve.flow.end': { - category: 'suricata', - name: 'suricata.eve.flow.end', - type: 'date', + 'netflow.is_multicast': { + category: 'netflow', + name: 'netflow.is_multicast', + type: 'short', }, - 'suricata.eve.flow.alerted': { - category: 'suricata', - name: 'suricata.eve.flow.alerted', - type: 'boolean', + 'netflow.ixia_browser_id': { + category: 'netflow', + name: 'netflow.ixia_browser_id', + type: 'short', }, - 'suricata.eve.app_proto': { - category: 'suricata', - name: 'suricata.eve.app_proto', - type: 'alias', + 'netflow.ixia_browser_name': { + category: 'netflow', + name: 'netflow.ixia_browser_name', + type: 'keyword', }, - 'suricata.eve.tx_id': { - category: 'suricata', - name: 'suricata.eve.tx_id', - type: 'long', + 'netflow.ixia_device_id': { + category: 'netflow', + name: 'netflow.ixia_device_id', + type: 'short', }, - 'suricata.eve.app_proto_tc': { - category: 'suricata', - name: 'suricata.eve.app_proto_tc', + 'netflow.ixia_device_name': { + category: 'netflow', + name: 'netflow.ixia_device_name', type: 'keyword', }, - 'suricata.eve.smtp.rcpt_to': { - category: 'suricata', - name: 'suricata.eve.smtp.rcpt_to', + 'netflow.ixia_dns_answer': { + category: 'netflow', + name: 'netflow.ixia_dns_answer', type: 'keyword', }, - 'suricata.eve.smtp.mail_from': { - category: 'suricata', - name: 'suricata.eve.smtp.mail_from', + 'netflow.ixia_dns_classes': { + category: 'netflow', + name: 'netflow.ixia_dns_classes', type: 'keyword', }, - 'suricata.eve.smtp.helo': { - category: 'suricata', - name: 'suricata.eve.smtp.helo', + 'netflow.ixia_dns_query': { + category: 'netflow', + name: 'netflow.ixia_dns_query', type: 'keyword', }, - 'suricata.eve.app_proto_expected': { - category: 'suricata', - name: 'suricata.eve.app_proto_expected', + 'netflow.ixia_dns_record_txt': { + category: 'netflow', + name: 'netflow.ixia_dns_record_txt', type: 'keyword', }, - 'suricata.eve.flags': { - category: 'suricata', - name: 'suricata.eve.flags', - type: 'group', + 'netflow.ixia_dst_as_name': { + category: 'netflow', + name: 'netflow.ixia_dst_as_name', + type: 'keyword', }, - 'zeek.session_id': { - category: 'zeek', - description: 'A unique identifier of the session ', - name: 'zeek.session_id', + 'netflow.ixia_dst_city_name': { + category: 'netflow', + name: 'netflow.ixia_dst_city_name', type: 'keyword', }, - 'zeek.capture_loss.ts_delta': { - category: 'zeek', - description: 'The time delay between this measurement and the last. ', - name: 'zeek.capture_loss.ts_delta', - type: 'integer', + 'netflow.ixia_dst_country_code': { + category: 'netflow', + name: 'netflow.ixia_dst_country_code', + type: 'keyword', }, - 'zeek.capture_loss.peer': { - category: 'zeek', - description: - 'In the event that there are multiple Bro instances logging to the same host, this distinguishes each peer with its individual name. ', - name: 'zeek.capture_loss.peer', + 'netflow.ixia_dst_country_name': { + category: 'netflow', + name: 'netflow.ixia_dst_country_name', type: 'keyword', }, - 'zeek.capture_loss.gaps': { - category: 'zeek', - description: 'Number of missed ACKs from the previous measurement interval. ', - name: 'zeek.capture_loss.gaps', - type: 'integer', + 'netflow.ixia_dst_latitude': { + category: 'netflow', + name: 'netflow.ixia_dst_latitude', + type: 'float', }, - 'zeek.capture_loss.acks': { - category: 'zeek', - description: 'Total number of ACKs seen in the previous measurement interval. ', - name: 'zeek.capture_loss.acks', - type: 'integer', + 'netflow.ixia_dst_longitude': { + category: 'netflow', + name: 'netflow.ixia_dst_longitude', + type: 'float', }, - 'zeek.capture_loss.percent_lost': { - category: 'zeek', - description: "Percentage of ACKs seen where the data being ACKed wasn't seen. ", - name: 'zeek.capture_loss.percent_lost', - type: 'double', + 'netflow.ixia_dst_region_code': { + category: 'netflow', + name: 'netflow.ixia_dst_region_code', + type: 'keyword', }, - 'zeek.connection.local_orig': { - category: 'zeek', - description: 'Indicates whether the session is originated locally. ', - name: 'zeek.connection.local_orig', - type: 'boolean', + 'netflow.ixia_dst_region_node': { + category: 'netflow', + name: 'netflow.ixia_dst_region_node', + type: 'keyword', }, - 'zeek.connection.local_resp': { - category: 'zeek', - description: 'Indicates whether the session is responded locally. ', - name: 'zeek.connection.local_resp', - type: 'boolean', + 'netflow.ixia_encrypt_cipher': { + category: 'netflow', + name: 'netflow.ixia_encrypt_cipher', + type: 'keyword', }, - 'zeek.connection.missed_bytes': { - category: 'zeek', - description: 'Missed bytes for the session. ', - name: 'zeek.connection.missed_bytes', - type: 'long', + 'netflow.ixia_encrypt_key_length': { + category: 'netflow', + name: 'netflow.ixia_encrypt_key_length', + type: 'integer', }, - 'zeek.connection.state': { - category: 'zeek', - description: 'Code indicating the state of the session. ', - name: 'zeek.connection.state', + 'netflow.ixia_encrypt_type': { + category: 'netflow', + name: 'netflow.ixia_encrypt_type', type: 'keyword', }, - 'zeek.connection.state_message': { - category: 'zeek', - description: 'The state of the session. ', - name: 'zeek.connection.state_message', + 'netflow.ixia_http_host_name': { + category: 'netflow', + name: 'netflow.ixia_http_host_name', type: 'keyword', }, - 'zeek.connection.icmp.type': { - category: 'zeek', - description: 'ICMP message type. ', - name: 'zeek.connection.icmp.type', - type: 'integer', + 'netflow.ixia_http_uri': { + category: 'netflow', + name: 'netflow.ixia_http_uri', + type: 'keyword', }, - 'zeek.connection.icmp.code': { - category: 'zeek', - description: 'ICMP message code. ', - name: 'zeek.connection.icmp.code', - type: 'integer', + 'netflow.ixia_http_user_agent': { + category: 'netflow', + name: 'netflow.ixia_http_user_agent', + type: 'keyword', }, - 'zeek.connection.history': { - category: 'zeek', - description: 'Flags indicating the history of the session. ', - name: 'zeek.connection.history', + 'netflow.ixia_imsi_subscriber': { + category: 'netflow', + name: 'netflow.ixia_imsi_subscriber', type: 'keyword', }, - 'zeek.connection.vlan': { - category: 'zeek', - description: 'VLAN identifier. ', - name: 'zeek.connection.vlan', - type: 'integer', + 'netflow.ixia_l7_app_id': { + category: 'netflow', + name: 'netflow.ixia_l7_app_id', + type: 'long', }, - 'zeek.connection.inner_vlan': { - category: 'zeek', - description: 'VLAN identifier. ', - name: 'zeek.connection.inner_vlan', - type: 'integer', + 'netflow.ixia_l7_app_name': { + category: 'netflow', + name: 'netflow.ixia_l7_app_name', + type: 'keyword', }, - 'zeek.dce_rpc.rtt': { - category: 'zeek', - description: - "Round trip time from the request to the response. If either the request or response wasn't seen, this will be null. ", - name: 'zeek.dce_rpc.rtt', - type: 'integer', + 'netflow.ixia_latency': { + category: 'netflow', + name: 'netflow.ixia_latency', + type: 'long', }, - 'zeek.dce_rpc.named_pipe': { - category: 'zeek', - description: 'Remote pipe name. ', - name: 'zeek.dce_rpc.named_pipe', - type: 'keyword', + 'netflow.ixia_rev_octet_delta_count': { + category: 'netflow', + name: 'netflow.ixia_rev_octet_delta_count', + type: 'long', }, - 'zeek.dce_rpc.endpoint': { - category: 'zeek', - description: 'Endpoint name looked up from the uuid. ', - name: 'zeek.dce_rpc.endpoint', - type: 'keyword', + 'netflow.ixia_rev_packet_delta_count': { + category: 'netflow', + name: 'netflow.ixia_rev_packet_delta_count', + type: 'long', }, - 'zeek.dce_rpc.operation': { - category: 'zeek', - description: 'Operation seen in the call. ', - name: 'zeek.dce_rpc.operation', + 'netflow.ixia_src_as_name': { + category: 'netflow', + name: 'netflow.ixia_src_as_name', type: 'keyword', }, - 'zeek.dhcp.domain': { - category: 'zeek', - description: 'Domain given by the server in option 15. ', - name: 'zeek.dhcp.domain', + 'netflow.ixia_src_city_name': { + category: 'netflow', + name: 'netflow.ixia_src_city_name', type: 'keyword', }, - 'zeek.dhcp.duration': { - category: 'zeek', - description: - 'Duration of the DHCP session representing the time from the first message to the last, in seconds. ', - name: 'zeek.dhcp.duration', - type: 'double', - }, - 'zeek.dhcp.hostname': { - category: 'zeek', - description: 'Name given by client in Hostname option 12. ', - name: 'zeek.dhcp.hostname', + 'netflow.ixia_src_country_code': { + category: 'netflow', + name: 'netflow.ixia_src_country_code', type: 'keyword', }, - 'zeek.dhcp.client_fqdn': { - category: 'zeek', - description: 'FQDN given by client in Client FQDN option 81. ', - name: 'zeek.dhcp.client_fqdn', + 'netflow.ixia_src_country_name': { + category: 'netflow', + name: 'netflow.ixia_src_country_name', type: 'keyword', }, - 'zeek.dhcp.lease_time': { - category: 'zeek', - description: 'IP address lease interval in seconds. ', - name: 'zeek.dhcp.lease_time', - type: 'integer', + 'netflow.ixia_src_latitude': { + category: 'netflow', + name: 'netflow.ixia_src_latitude', + type: 'float', }, - 'zeek.dhcp.address.assigned': { - category: 'zeek', - description: 'IP address assigned by the server. ', - name: 'zeek.dhcp.address.assigned', - type: 'ip', + 'netflow.ixia_src_longitude': { + category: 'netflow', + name: 'netflow.ixia_src_longitude', + type: 'float', }, - 'zeek.dhcp.address.client': { - category: 'zeek', - description: - 'IP address of the client. If a transaction is only a client sending INFORM messages then there is no lease information exchanged so this is helpful to know who sent the messages. Getting an address in this field does require that the client sources at least one DHCP message using a non-broadcast address. ', - name: 'zeek.dhcp.address.client', - type: 'ip', + 'netflow.ixia_src_region_code': { + category: 'netflow', + name: 'netflow.ixia_src_region_code', + type: 'keyword', }, - 'zeek.dhcp.address.mac': { - category: 'zeek', - description: "Client's hardware address. ", - name: 'zeek.dhcp.address.mac', + 'netflow.ixia_src_region_name': { + category: 'netflow', + name: 'netflow.ixia_src_region_name', type: 'keyword', }, - 'zeek.dhcp.address.requested': { - category: 'zeek', - description: 'IP address requested by the client. ', - name: 'zeek.dhcp.address.requested', + 'netflow.ixia_threat_ipv4': { + category: 'netflow', + name: 'netflow.ixia_threat_ipv4', type: 'ip', }, - 'zeek.dhcp.address.server': { - category: 'zeek', - description: 'IP address of the DHCP server. ', - name: 'zeek.dhcp.address.server', + 'netflow.ixia_threat_ipv6': { + category: 'netflow', + name: 'netflow.ixia_threat_ipv6', type: 'ip', }, - 'zeek.dhcp.msg.types': { - category: 'zeek', - description: 'List of DHCP message types seen in this exchange. ', - name: 'zeek.dhcp.msg.types', + 'netflow.ixia_threat_type': { + category: 'netflow', + name: 'netflow.ixia_threat_type', type: 'keyword', }, - 'zeek.dhcp.msg.origin': { - category: 'zeek', - description: - '(present if policy/protocols/dhcp/msg-orig.bro is loaded) The address that originated each message from the msg.types field. ', - name: 'zeek.dhcp.msg.origin', - type: 'ip', + 'netflow.large_packet_count': { + category: 'netflow', + name: 'netflow.large_packet_count', + type: 'long', }, - 'zeek.dhcp.msg.client': { - category: 'zeek', - description: - 'Message typically accompanied with a DHCP_DECLINE so the client can tell the server why it rejected an address. ', - name: 'zeek.dhcp.msg.client', - type: 'keyword', + 'netflow.layer2_frame_delta_count': { + category: 'netflow', + name: 'netflow.layer2_frame_delta_count', + type: 'long', }, - 'zeek.dhcp.msg.server': { - category: 'zeek', - description: - 'Message typically accompanied with a DHCP_NAK to let the client know why it rejected the request. ', - name: 'zeek.dhcp.msg.server', - type: 'keyword', + 'netflow.layer2_frame_total_count': { + category: 'netflow', + name: 'netflow.layer2_frame_total_count', + type: 'long', }, - 'zeek.dhcp.software.client': { - category: 'zeek', - description: - '(present if policy/protocols/dhcp/software.bro is loaded) Software reported by the client in the vendor_class option. ', - name: 'zeek.dhcp.software.client', - type: 'keyword', + 'netflow.layer2_octet_delta_count': { + category: 'netflow', + name: 'netflow.layer2_octet_delta_count', + type: 'long', }, - 'zeek.dhcp.software.server': { - category: 'zeek', - description: - '(present if policy/protocols/dhcp/software.bro is loaded) Software reported by the client in the vendor_class option. ', - name: 'zeek.dhcp.software.server', - type: 'keyword', + 'netflow.layer2_octet_delta_sum_of_squares': { + category: 'netflow', + name: 'netflow.layer2_octet_delta_sum_of_squares', + type: 'long', }, - 'zeek.dhcp.id.circuit': { - category: 'zeek', - description: - '(present if policy/protocols/dhcp/sub-opts.bro is loaded) Added by DHCP relay agents which terminate switched or permanent circuits. It encodes an agent-local identifier of the circuit from which a DHCP client-to-server packet was received. Typically it should represent a router or switch interface number. ', - name: 'zeek.dhcp.id.circuit', - type: 'keyword', + 'netflow.layer2_octet_total_count': { + category: 'netflow', + name: 'netflow.layer2_octet_total_count', + type: 'long', }, - 'zeek.dhcp.id.remote_agent': { - category: 'zeek', - description: - '(present if policy/protocols/dhcp/sub-opts.bro is loaded) A globally unique identifier added by relay agents to identify the remote host end of the circuit. ', - name: 'zeek.dhcp.id.remote_agent', - type: 'keyword', + 'netflow.layer2_octet_total_sum_of_squares': { + category: 'netflow', + name: 'netflow.layer2_octet_total_sum_of_squares', + type: 'long', }, - 'zeek.dhcp.id.subscriber': { - category: 'zeek', - description: - "(present if policy/protocols/dhcp/sub-opts.bro is loaded) The subscriber ID is a value independent of the physical network configuration so that a customer's DHCP configuration can be given to them correctly no matter where they are physically connected. ", - name: 'zeek.dhcp.id.subscriber', - type: 'keyword', + 'netflow.layer2_segment_id': { + category: 'netflow', + name: 'netflow.layer2_segment_id', + type: 'long', }, - 'zeek.dnp3.function.request': { - category: 'zeek', - description: 'The name of the function message in the request. ', - name: 'zeek.dnp3.function.request', - type: 'keyword', + 'netflow.layer2packet_section_data': { + category: 'netflow', + name: 'netflow.layer2packet_section_data', + type: 'short', }, - 'zeek.dnp3.function.reply': { - category: 'zeek', - description: 'The name of the function message in the reply. ', - name: 'zeek.dnp3.function.reply', - type: 'keyword', + 'netflow.layer2packet_section_offset': { + category: 'netflow', + name: 'netflow.layer2packet_section_offset', + type: 'integer', }, - 'zeek.dnp3.id': { - category: 'zeek', - description: "The response's internal indication number. ", - name: 'zeek.dnp3.id', + 'netflow.layer2packet_section_size': { + category: 'netflow', + name: 'netflow.layer2packet_section_size', type: 'integer', }, - 'zeek.dns.trans_id': { - category: 'zeek', - description: 'DNS transaction identifier. ', - name: 'zeek.dns.trans_id', - type: 'keyword', + 'netflow.line_card_id': { + category: 'netflow', + name: 'netflow.line_card_id', + type: 'long', }, - 'zeek.dns.rtt': { - category: 'zeek', - description: 'Round trip time for the query and response. ', - name: 'zeek.dns.rtt', - type: 'double', + 'netflow.log_op': { + category: 'netflow', + name: 'netflow.log_op', + type: 'short', }, - 'zeek.dns.query': { - category: 'zeek', - description: 'The domain name that is the subject of the DNS query. ', - name: 'zeek.dns.query', - type: 'keyword', + 'netflow.lower_ci_limit': { + category: 'netflow', + name: 'netflow.lower_ci_limit', + type: 'double', }, - 'zeek.dns.qclass': { - category: 'zeek', - description: 'The QCLASS value specifying the class of the query. ', - name: 'zeek.dns.qclass', + 'netflow.mark': { + category: 'netflow', + name: 'netflow.mark', type: 'long', }, - 'zeek.dns.qclass_name': { - category: 'zeek', - description: 'A descriptive name for the class of the query. ', - name: 'zeek.dns.qclass_name', - type: 'keyword', + 'netflow.max_bib_entries': { + category: 'netflow', + name: 'netflow.max_bib_entries', + type: 'long', }, - 'zeek.dns.qtype': { - category: 'zeek', - description: 'A QTYPE value specifying the type of the query. ', - name: 'zeek.dns.qtype', + 'netflow.max_entries_per_user': { + category: 'netflow', + name: 'netflow.max_entries_per_user', type: 'long', }, - 'zeek.dns.qtype_name': { - category: 'zeek', - description: 'A descriptive name for the type of the query. ', - name: 'zeek.dns.qtype_name', - type: 'keyword', + 'netflow.max_export_seconds': { + category: 'netflow', + name: 'netflow.max_export_seconds', + type: 'date', }, - 'zeek.dns.rcode': { - category: 'zeek', - description: 'The response code value in DNS response messages. ', - name: 'zeek.dns.rcode', - type: 'long', + 'netflow.max_flow_end_microseconds': { + category: 'netflow', + name: 'netflow.max_flow_end_microseconds', + type: 'date', }, - 'zeek.dns.rcode_name': { - category: 'zeek', - description: 'A descriptive name for the response code value. ', - name: 'zeek.dns.rcode_name', - type: 'keyword', + 'netflow.max_flow_end_milliseconds': { + category: 'netflow', + name: 'netflow.max_flow_end_milliseconds', + type: 'date', }, - 'zeek.dns.AA': { - category: 'zeek', - description: - 'The Authoritative Answer bit for response messages specifies that the responding name server is an authority for the domain name in the question section. ', - name: 'zeek.dns.AA', - type: 'boolean', + 'netflow.max_flow_end_nanoseconds': { + category: 'netflow', + name: 'netflow.max_flow_end_nanoseconds', + type: 'date', }, - 'zeek.dns.TC': { - category: 'zeek', - description: 'The Truncation bit specifies that the message was truncated. ', - name: 'zeek.dns.TC', - type: 'boolean', + 'netflow.max_flow_end_seconds': { + category: 'netflow', + name: 'netflow.max_flow_end_seconds', + type: 'date', }, - 'zeek.dns.RD': { - category: 'zeek', - description: - 'The Recursion Desired bit in a request message indicates that the client wants recursive service for this query. ', - name: 'zeek.dns.RD', - type: 'boolean', + 'netflow.max_fragments_pending_reassembly': { + category: 'netflow', + name: 'netflow.max_fragments_pending_reassembly', + type: 'long', }, - 'zeek.dns.RA': { - category: 'zeek', - description: - 'The Recursion Available bit in a response message indicates that the name server supports recursive queries. ', - name: 'zeek.dns.RA', - type: 'boolean', + 'netflow.max_packet_size': { + category: 'netflow', + name: 'netflow.max_packet_size', + type: 'integer', }, - 'zeek.dns.answers': { - category: 'zeek', - description: 'The set of resource descriptions in the query answer. ', - name: 'zeek.dns.answers', - type: 'keyword', + 'netflow.max_session_entries': { + category: 'netflow', + name: 'netflow.max_session_entries', + type: 'long', }, - 'zeek.dns.TTLs': { - category: 'zeek', - description: 'The caching intervals of the associated RRs described by the answers field. ', - name: 'zeek.dns.TTLs', - type: 'double', + 'netflow.max_subscribers': { + category: 'netflow', + name: 'netflow.max_subscribers', + type: 'long', }, - 'zeek.dns.rejected': { - category: 'zeek', - description: 'Indicates whether the DNS query was rejected by the server. ', - name: 'zeek.dns.rejected', - type: 'boolean', + 'netflow.maximum_ip_total_length': { + category: 'netflow', + name: 'netflow.maximum_ip_total_length', + type: 'long', }, - 'zeek.dns.total_answers': { - category: 'zeek', - description: 'The total number of resource records in the reply. ', - name: 'zeek.dns.total_answers', - type: 'integer', + 'netflow.maximum_layer2_total_length': { + category: 'netflow', + name: 'netflow.maximum_layer2_total_length', + type: 'long', }, - 'zeek.dns.total_replies': { - category: 'zeek', - description: 'The total number of resource records in the reply message. ', - name: 'zeek.dns.total_replies', - type: 'integer', + 'netflow.maximum_ttl': { + category: 'netflow', + name: 'netflow.maximum_ttl', + type: 'short', }, - 'zeek.dns.saw_query': { - category: 'zeek', - description: 'Whether the full DNS query has been seen. ', - name: 'zeek.dns.saw_query', - type: 'boolean', + 'netflow.mean_flow_rate': { + category: 'netflow', + name: 'netflow.mean_flow_rate', + type: 'long', }, - 'zeek.dns.saw_reply': { - category: 'zeek', - description: 'Whether the full DNS reply has been seen. ', - name: 'zeek.dns.saw_reply', - type: 'boolean', + 'netflow.mean_packet_rate': { + category: 'netflow', + name: 'netflow.mean_packet_rate', + type: 'long', }, - 'zeek.dpd.analyzer': { - category: 'zeek', - description: 'The analyzer that generated the violation. ', - name: 'zeek.dpd.analyzer', - type: 'keyword', + 'netflow.message_md5_checksum': { + category: 'netflow', + name: 'netflow.message_md5_checksum', + type: 'short', }, - 'zeek.dpd.failure_reason': { - category: 'zeek', - description: 'The textual reason for the analysis failure. ', - name: 'zeek.dpd.failure_reason', - type: 'keyword', + 'netflow.message_scope': { + category: 'netflow', + name: 'netflow.message_scope', + type: 'short', }, - 'zeek.dpd.packet_segment': { - category: 'zeek', - description: - '(present if policy/frameworks/dpd/packet-segment-logging.bro is loaded) A chunk of the payload that most likely resulted in the protocol violation. ', - name: 'zeek.dpd.packet_segment', - type: 'keyword', + 'netflow.metering_process_id': { + category: 'netflow', + name: 'netflow.metering_process_id', + type: 'long', }, - 'zeek.files.fuid': { - category: 'zeek', - description: 'A file unique identifier. ', - name: 'zeek.files.fuid', + 'netflow.metro_evc_id': { + category: 'netflow', + name: 'netflow.metro_evc_id', type: 'keyword', }, - 'zeek.files.tx_host': { - category: 'zeek', - description: 'The host that transferred the file. ', - name: 'zeek.files.tx_host', - type: 'ip', + 'netflow.metro_evc_type': { + category: 'netflow', + name: 'netflow.metro_evc_type', + type: 'short', }, - 'zeek.files.rx_host': { - category: 'zeek', - description: 'The host that received the file. ', - name: 'zeek.files.rx_host', - type: 'ip', + 'netflow.mib_capture_time_semantics': { + category: 'netflow', + name: 'netflow.mib_capture_time_semantics', + type: 'short', }, - 'zeek.files.session_ids': { - category: 'zeek', - description: 'The sessions that have this file. ', - name: 'zeek.files.session_ids', - type: 'keyword', + 'netflow.mib_context_engine_id': { + category: 'netflow', + name: 'netflow.mib_context_engine_id', + type: 'short', }, - 'zeek.files.source': { - category: 'zeek', - description: - 'An identification of the source of the file data. E.g. it may be a network protocol over which it was transferred, or a local file path which was read, or some other input source. ', - name: 'zeek.files.source', + 'netflow.mib_context_name': { + category: 'netflow', + name: 'netflow.mib_context_name', type: 'keyword', }, - 'zeek.files.depth': { - category: 'zeek', - description: - 'A value to represent the depth of this file in relation to its source. In SMTP, it is the depth of the MIME attachment on the message. In HTTP, it is the depth of the request within the TCP connection. ', - name: 'zeek.files.depth', + 'netflow.mib_index_indicator': { + category: 'netflow', + name: 'netflow.mib_index_indicator', type: 'long', }, - 'zeek.files.analyzers': { - category: 'zeek', - description: 'A set of analysis types done during the file analysis. ', - name: 'zeek.files.analyzers', - type: 'keyword', - }, - 'zeek.files.mime_type': { - category: 'zeek', - description: 'Mime type of the file. ', - name: 'zeek.files.mime_type', + 'netflow.mib_module_name': { + category: 'netflow', + name: 'netflow.mib_module_name', type: 'keyword', }, - 'zeek.files.filename': { - category: 'zeek', - description: 'Name of the file if available. ', - name: 'zeek.files.filename', + 'netflow.mib_object_description': { + category: 'netflow', + name: 'netflow.mib_object_description', type: 'keyword', }, - 'zeek.files.local_orig': { - category: 'zeek', - description: - 'If the source of this file is a network connection, this field indicates if the data originated from the local network or not. ', - name: 'zeek.files.local_orig', - type: 'boolean', - }, - 'zeek.files.is_orig': { - category: 'zeek', - description: - 'If the source of this file is a network connection, this field indicates if the file is being sent by the originator of the connection or the responder. ', - name: 'zeek.files.is_orig', - type: 'boolean', + 'netflow.mib_object_identifier': { + category: 'netflow', + name: 'netflow.mib_object_identifier', + type: 'short', }, - 'zeek.files.duration': { - category: 'zeek', - description: 'The duration the file was analyzed for. Not the duration of the session. ', - name: 'zeek.files.duration', - type: 'double', + 'netflow.mib_object_name': { + category: 'netflow', + name: 'netflow.mib_object_name', + type: 'keyword', }, - 'zeek.files.seen_bytes': { - category: 'zeek', - description: 'Number of bytes provided to the file analysis engine for the file. ', - name: 'zeek.files.seen_bytes', - type: 'long', + 'netflow.mib_object_syntax': { + category: 'netflow', + name: 'netflow.mib_object_syntax', + type: 'keyword', }, - 'zeek.files.total_bytes': { - category: 'zeek', - description: 'Total number of bytes that are supposed to comprise the full file. ', - name: 'zeek.files.total_bytes', - type: 'long', + 'netflow.mib_object_value_bits': { + category: 'netflow', + name: 'netflow.mib_object_value_bits', + type: 'short', }, - 'zeek.files.missing_bytes': { - category: 'zeek', - description: - 'The number of bytes in the file stream that were completely missed during the process of analysis. ', - name: 'zeek.files.missing_bytes', + 'netflow.mib_object_value_counter': { + category: 'netflow', + name: 'netflow.mib_object_value_counter', type: 'long', }, - 'zeek.files.overflow_bytes': { - category: 'zeek', - description: - "The number of bytes in the file stream that were not delivered to stream file analyzers. This could be overlapping bytes or bytes that couldn't be reassembled. ", - name: 'zeek.files.overflow_bytes', + 'netflow.mib_object_value_gauge': { + category: 'netflow', + name: 'netflow.mib_object_value_gauge', type: 'long', }, - 'zeek.files.timedout': { - category: 'zeek', - description: 'Whether the file analysis timed out at least once for the file. ', - name: 'zeek.files.timedout', - type: 'boolean', - }, - 'zeek.files.parent_fuid': { - category: 'zeek', - description: - 'Identifier associated with a container file from which this one was extracted as part of the file analysis. ', - name: 'zeek.files.parent_fuid', - type: 'keyword', + 'netflow.mib_object_value_integer': { + category: 'netflow', + name: 'netflow.mib_object_value_integer', + type: 'integer', }, - 'zeek.files.md5': { - category: 'zeek', - description: 'An MD5 digest of the file contents. ', - name: 'zeek.files.md5', - type: 'keyword', + 'netflow.mib_object_value_ip_address': { + category: 'netflow', + name: 'netflow.mib_object_value_ip_address', + type: 'ip', }, - 'zeek.files.sha1': { - category: 'zeek', - description: 'A SHA1 digest of the file contents. ', - name: 'zeek.files.sha1', - type: 'keyword', + 'netflow.mib_object_value_octet_string': { + category: 'netflow', + name: 'netflow.mib_object_value_octet_string', + type: 'short', }, - 'zeek.files.sha256': { - category: 'zeek', - description: 'A SHA256 digest of the file contents. ', - name: 'zeek.files.sha256', - type: 'keyword', + 'netflow.mib_object_value_oid': { + category: 'netflow', + name: 'netflow.mib_object_value_oid', + type: 'short', }, - 'zeek.files.extracted': { - category: 'zeek', - description: 'Local filename of extracted file. ', - name: 'zeek.files.extracted', - type: 'keyword', + 'netflow.mib_object_value_time_ticks': { + category: 'netflow', + name: 'netflow.mib_object_value_time_ticks', + type: 'long', }, - 'zeek.files.extracted_cutoff': { - category: 'zeek', - description: - 'Indicate whether the file being extracted was cut off hence not extracted completely. ', - name: 'zeek.files.extracted_cutoff', - type: 'boolean', + 'netflow.mib_object_value_unsigned': { + category: 'netflow', + name: 'netflow.mib_object_value_unsigned', + type: 'long', }, - 'zeek.files.extracted_size': { - category: 'zeek', - description: 'The number of bytes extracted to disk. ', - name: 'zeek.files.extracted_size', + 'netflow.mib_sub_identifier': { + category: 'netflow', + name: 'netflow.mib_sub_identifier', type: 'long', }, - 'zeek.files.entropy': { - category: 'zeek', - description: 'The information density of the contents of the file. ', - name: 'zeek.files.entropy', - type: 'double', + 'netflow.min_export_seconds': { + category: 'netflow', + name: 'netflow.min_export_seconds', + type: 'date', }, - 'zeek.ftp.user': { - category: 'zeek', - description: 'User name for the current FTP session. ', - name: 'zeek.ftp.user', - type: 'keyword', + 'netflow.min_flow_start_microseconds': { + category: 'netflow', + name: 'netflow.min_flow_start_microseconds', + type: 'date', }, - 'zeek.ftp.password': { - category: 'zeek', - description: 'Password for the current FTP session if captured. ', - name: 'zeek.ftp.password', - type: 'keyword', + 'netflow.min_flow_start_milliseconds': { + category: 'netflow', + name: 'netflow.min_flow_start_milliseconds', + type: 'date', }, - 'zeek.ftp.command': { - category: 'zeek', - description: 'Command given by the client. ', - name: 'zeek.ftp.command', - type: 'keyword', + 'netflow.min_flow_start_nanoseconds': { + category: 'netflow', + name: 'netflow.min_flow_start_nanoseconds', + type: 'date', }, - 'zeek.ftp.arg': { - category: 'zeek', - description: 'Argument for the command if one is given. ', - name: 'zeek.ftp.arg', - type: 'keyword', + 'netflow.min_flow_start_seconds': { + category: 'netflow', + name: 'netflow.min_flow_start_seconds', + type: 'date', }, - 'zeek.ftp.file.size': { - category: 'zeek', - description: 'Size of the file if the command indicates a file transfer. ', - name: 'zeek.ftp.file.size', + 'netflow.minimum_ip_total_length': { + category: 'netflow', + name: 'netflow.minimum_ip_total_length', type: 'long', }, - 'zeek.ftp.file.mime_type': { - category: 'zeek', - description: 'Sniffed mime type of file. ', - name: 'zeek.ftp.file.mime_type', - type: 'keyword', + 'netflow.minimum_layer2_total_length': { + category: 'netflow', + name: 'netflow.minimum_layer2_total_length', + type: 'long', }, - 'zeek.ftp.file.fuid': { - category: 'zeek', - description: '(present if base/protocols/ftp/files.bro is loaded) File unique ID. ', - name: 'zeek.ftp.file.fuid', - type: 'keyword', + 'netflow.minimum_ttl': { + category: 'netflow', + name: 'netflow.minimum_ttl', + type: 'short', }, - 'zeek.ftp.reply.code': { - category: 'zeek', - description: 'Reply code from the server in response to the command. ', - name: 'zeek.ftp.reply.code', - type: 'integer', + 'netflow.mobile_imsi': { + category: 'netflow', + name: 'netflow.mobile_imsi', + type: 'keyword', }, - 'zeek.ftp.reply.msg': { - category: 'zeek', - description: 'Reply message from the server in response to the command. ', - name: 'zeek.ftp.reply.msg', + 'netflow.mobile_msisdn': { + category: 'netflow', + name: 'netflow.mobile_msisdn', type: 'keyword', }, - 'zeek.ftp.data_channel.passive': { - category: 'zeek', - description: 'Whether PASV mode is toggled for control channel. ', - name: 'zeek.ftp.data_channel.passive', - type: 'boolean', + 'netflow.monitoring_interval_end_milli_seconds': { + category: 'netflow', + name: 'netflow.monitoring_interval_end_milli_seconds', + type: 'date', + }, + 'netflow.monitoring_interval_start_milli_seconds': { + category: 'netflow', + name: 'netflow.monitoring_interval_start_milli_seconds', + type: 'date', }, - 'zeek.ftp.data_channel.originating_host': { - category: 'zeek', - description: 'The host that will be initiating the data connection. ', - name: 'zeek.ftp.data_channel.originating_host', - type: 'ip', + 'netflow.mpls_label_stack_depth': { + category: 'netflow', + name: 'netflow.mpls_label_stack_depth', + type: 'long', }, - 'zeek.ftp.data_channel.response_host': { - category: 'zeek', - description: 'The host that will be accepting the data connection. ', - name: 'zeek.ftp.data_channel.response_host', - type: 'ip', + 'netflow.mpls_label_stack_length': { + category: 'netflow', + name: 'netflow.mpls_label_stack_length', + type: 'long', }, - 'zeek.ftp.data_channel.response_port': { - category: 'zeek', - description: 'The port at which the acceptor is listening for the data connection. ', - name: 'zeek.ftp.data_channel.response_port', - type: 'integer', + 'netflow.mpls_label_stack_section': { + category: 'netflow', + name: 'netflow.mpls_label_stack_section', + type: 'short', }, - 'zeek.ftp.cwd': { - category: 'zeek', - description: - "Current working directory that this session is in. By making the default value '.', we can indicate that unless something more concrete is discovered that the existing but unknown directory is ok to use. ", - name: 'zeek.ftp.cwd', - type: 'keyword', + 'netflow.mpls_label_stack_section10': { + category: 'netflow', + name: 'netflow.mpls_label_stack_section10', + type: 'short', }, - 'zeek.ftp.cmdarg.cmd': { - category: 'zeek', - description: 'Command. ', - name: 'zeek.ftp.cmdarg.cmd', - type: 'keyword', + 'netflow.mpls_label_stack_section2': { + category: 'netflow', + name: 'netflow.mpls_label_stack_section2', + type: 'short', }, - 'zeek.ftp.cmdarg.arg': { - category: 'zeek', - description: 'Argument for the command if one was given. ', - name: 'zeek.ftp.cmdarg.arg', - type: 'keyword', + 'netflow.mpls_label_stack_section3': { + category: 'netflow', + name: 'netflow.mpls_label_stack_section3', + type: 'short', }, - 'zeek.ftp.cmdarg.seq': { - category: 'zeek', - description: 'Counter to track how many commands have been executed. ', - name: 'zeek.ftp.cmdarg.seq', - type: 'integer', + 'netflow.mpls_label_stack_section4': { + category: 'netflow', + name: 'netflow.mpls_label_stack_section4', + type: 'short', }, - 'zeek.ftp.pending_commands': { - category: 'zeek', - description: - 'Queue for commands that have been sent but not yet responded to are tracked here. ', - name: 'zeek.ftp.pending_commands', - type: 'integer', + 'netflow.mpls_label_stack_section5': { + category: 'netflow', + name: 'netflow.mpls_label_stack_section5', + type: 'short', }, - 'zeek.ftp.passive': { - category: 'zeek', - description: 'Indicates if the session is in active or passive mode. ', - name: 'zeek.ftp.passive', - type: 'boolean', + 'netflow.mpls_label_stack_section6': { + category: 'netflow', + name: 'netflow.mpls_label_stack_section6', + type: 'short', }, - 'zeek.ftp.capture_password': { - category: 'zeek', - description: 'Determines if the password will be captured for this request. ', - name: 'zeek.ftp.capture_password', - type: 'boolean', + 'netflow.mpls_label_stack_section7': { + category: 'netflow', + name: 'netflow.mpls_label_stack_section7', + type: 'short', }, - 'zeek.ftp.last_auth_requested': { - category: 'zeek', - description: - 'present if base/protocols/ftp/gridftp.bro is loaded. Last authentication/security mechanism that was used. ', - name: 'zeek.ftp.last_auth_requested', - type: 'keyword', + 'netflow.mpls_label_stack_section8': { + category: 'netflow', + name: 'netflow.mpls_label_stack_section8', + type: 'short', }, - 'zeek.http.trans_depth': { - category: 'zeek', - description: - 'Represents the pipelined depth into the connection of this request/response transaction. ', - name: 'zeek.http.trans_depth', - type: 'integer', + 'netflow.mpls_label_stack_section9': { + category: 'netflow', + name: 'netflow.mpls_label_stack_section9', + type: 'short', }, - 'zeek.http.status_msg': { - category: 'zeek', - description: 'Status message returned by the server. ', - name: 'zeek.http.status_msg', - type: 'keyword', + 'netflow.mpls_payload_length': { + category: 'netflow', + name: 'netflow.mpls_payload_length', + type: 'long', }, - 'zeek.http.info_code': { - category: 'zeek', - description: 'Last seen 1xx informational reply code returned by the server. ', - name: 'zeek.http.info_code', - type: 'integer', + 'netflow.mpls_payload_packet_section': { + category: 'netflow', + name: 'netflow.mpls_payload_packet_section', + type: 'short', }, - 'zeek.http.info_msg': { - category: 'zeek', - description: 'Last seen 1xx informational reply message returned by the server. ', - name: 'zeek.http.info_msg', - type: 'keyword', + 'netflow.mpls_top_label_exp': { + category: 'netflow', + name: 'netflow.mpls_top_label_exp', + type: 'short', }, - 'zeek.http.tags': { - category: 'zeek', - description: - 'A set of indicators of various attributes discovered and related to a particular request/response pair. ', - name: 'zeek.http.tags', - type: 'keyword', + 'netflow.mpls_top_label_ipv4_address': { + category: 'netflow', + name: 'netflow.mpls_top_label_ipv4_address', + type: 'ip', }, - 'zeek.http.password': { - category: 'zeek', - description: 'Password if basic-auth is performed for the request. ', - name: 'zeek.http.password', - type: 'keyword', + 'netflow.mpls_top_label_ipv6_address': { + category: 'netflow', + name: 'netflow.mpls_top_label_ipv6_address', + type: 'ip', }, - 'zeek.http.captured_password': { - category: 'zeek', - description: 'Determines if the password will be captured for this request. ', - name: 'zeek.http.captured_password', - type: 'boolean', + 'netflow.mpls_top_label_prefix_length': { + category: 'netflow', + name: 'netflow.mpls_top_label_prefix_length', + type: 'short', }, - 'zeek.http.proxied': { - category: 'zeek', - description: 'All of the headers that may indicate if the HTTP request was proxied. ', - name: 'zeek.http.proxied', - type: 'keyword', + 'netflow.mpls_top_label_stack_section': { + category: 'netflow', + name: 'netflow.mpls_top_label_stack_section', + type: 'short', }, - 'zeek.http.range_request': { - category: 'zeek', - description: 'Indicates if this request can assume 206 partial content in response. ', - name: 'zeek.http.range_request', - type: 'boolean', + 'netflow.mpls_top_label_ttl': { + category: 'netflow', + name: 'netflow.mpls_top_label_ttl', + type: 'short', }, - 'zeek.http.client_header_names': { - category: 'zeek', - description: - 'The vector of HTTP header names sent by the client. No header values are included here, just the header names. ', - name: 'zeek.http.client_header_names', - type: 'keyword', + 'netflow.mpls_top_label_type': { + category: 'netflow', + name: 'netflow.mpls_top_label_type', + type: 'short', }, - 'zeek.http.server_header_names': { - category: 'zeek', - description: - 'The vector of HTTP header names sent by the server. No header values are included here, just the header names. ', - name: 'zeek.http.server_header_names', - type: 'keyword', + 'netflow.mpls_vpn_route_distinguisher': { + category: 'netflow', + name: 'netflow.mpls_vpn_route_distinguisher', + type: 'short', }, - 'zeek.http.orig_fuids': { - category: 'zeek', - description: 'An ordered vector of file unique IDs from the originator. ', - name: 'zeek.http.orig_fuids', - type: 'keyword', + 'netflow.mptcp_address_id': { + category: 'netflow', + name: 'netflow.mptcp_address_id', + type: 'short', }, - 'zeek.http.orig_mime_types': { - category: 'zeek', - description: 'An ordered vector of mime types from the originator. ', - name: 'zeek.http.orig_mime_types', - type: 'keyword', + 'netflow.mptcp_flags': { + category: 'netflow', + name: 'netflow.mptcp_flags', + type: 'short', }, - 'zeek.http.orig_filenames': { - category: 'zeek', - description: 'An ordered vector of filenames from the originator. ', - name: 'zeek.http.orig_filenames', - type: 'keyword', + 'netflow.mptcp_initial_data_sequence_number': { + category: 'netflow', + name: 'netflow.mptcp_initial_data_sequence_number', + type: 'long', }, - 'zeek.http.resp_fuids': { - category: 'zeek', - description: 'An ordered vector of file unique IDs from the responder. ', - name: 'zeek.http.resp_fuids', - type: 'keyword', + 'netflow.mptcp_maximum_segment_size': { + category: 'netflow', + name: 'netflow.mptcp_maximum_segment_size', + type: 'integer', }, - 'zeek.http.resp_mime_types': { - category: 'zeek', - description: 'An ordered vector of mime types from the responder. ', - name: 'zeek.http.resp_mime_types', - type: 'keyword', + 'netflow.mptcp_receiver_token': { + category: 'netflow', + name: 'netflow.mptcp_receiver_token', + type: 'long', }, - 'zeek.http.resp_filenames': { - category: 'zeek', - description: 'An ordered vector of filenames from the responder. ', - name: 'zeek.http.resp_filenames', - type: 'keyword', + 'netflow.multicast_replication_factor': { + category: 'netflow', + name: 'netflow.multicast_replication_factor', + type: 'long', }, - 'zeek.http.orig_mime_depth': { - category: 'zeek', - description: 'Current number of MIME entities in the HTTP request message body. ', - name: 'zeek.http.orig_mime_depth', - type: 'integer', + 'netflow.nat_event': { + category: 'netflow', + name: 'netflow.nat_event', + type: 'short', }, - 'zeek.http.resp_mime_depth': { - category: 'zeek', - description: 'Current number of MIME entities in the HTTP response message body. ', - name: 'zeek.http.resp_mime_depth', + 'netflow.nat_inside_svcid': { + category: 'netflow', + name: 'netflow.nat_inside_svcid', type: 'integer', }, - 'zeek.intel.seen.indicator': { - category: 'zeek', - description: 'The intelligence indicator. ', - name: 'zeek.intel.seen.indicator', - type: 'keyword', + 'netflow.nat_instance_id': { + category: 'netflow', + name: 'netflow.nat_instance_id', + type: 'long', }, - 'zeek.intel.seen.indicator_type': { - category: 'zeek', - description: 'The type of data the indicator represents. ', - name: 'zeek.intel.seen.indicator_type', - type: 'keyword', + 'netflow.nat_originating_address_realm': { + category: 'netflow', + name: 'netflow.nat_originating_address_realm', + type: 'short', }, - 'zeek.intel.seen.host': { - category: 'zeek', - description: 'If the indicator type was Intel::ADDR, then this field will be present. ', - name: 'zeek.intel.seen.host', - type: 'keyword', + 'netflow.nat_outside_svcid': { + category: 'netflow', + name: 'netflow.nat_outside_svcid', + type: 'integer', }, - 'zeek.intel.seen.conn': { - category: 'zeek', - description: - 'If the data was discovered within a connection, the connection record should go here to give context to the data. ', - name: 'zeek.intel.seen.conn', - type: 'keyword', + 'netflow.nat_pool_id': { + category: 'netflow', + name: 'netflow.nat_pool_id', + type: 'long', }, - 'zeek.intel.seen.where': { - category: 'zeek', - description: 'Where the data was discovered. ', - name: 'zeek.intel.seen.where', + 'netflow.nat_pool_name': { + category: 'netflow', + name: 'netflow.nat_pool_name', type: 'keyword', }, - 'zeek.intel.seen.node': { - category: 'zeek', - description: 'The name of the node where the match was discovered. ', - name: 'zeek.intel.seen.node', - type: 'keyword', + 'netflow.nat_quota_exceeded_event': { + category: 'netflow', + name: 'netflow.nat_quota_exceeded_event', + type: 'long', }, - 'zeek.intel.seen.uid': { - category: 'zeek', - description: - 'If the data was discovered within a connection, the connection uid should go here to give context to the data. If the conn field is provided, this will be automatically filled out. ', - name: 'zeek.intel.seen.uid', + 'netflow.nat_sub_string': { + category: 'netflow', + name: 'netflow.nat_sub_string', type: 'keyword', }, - 'zeek.intel.seen.f': { - category: 'zeek', - description: - 'If the data was discovered within a file, the file record should go here to provide context to the data. ', - name: 'zeek.intel.seen.f', - type: 'object', + 'netflow.nat_threshold_event': { + category: 'netflow', + name: 'netflow.nat_threshold_event', + type: 'long', }, - 'zeek.intel.seen.fuid': { - category: 'zeek', - description: - 'If the data was discovered within a file, the file uid should go here to provide context to the data. If the file record f is provided, this will be automatically filled out. ', - name: 'zeek.intel.seen.fuid', - type: 'keyword', + 'netflow.nat_type': { + category: 'netflow', + name: 'netflow.nat_type', + type: 'short', }, - 'zeek.intel.matched': { - category: 'zeek', - description: 'Event to represent a match in the intelligence data from data that was seen. ', - name: 'zeek.intel.matched', + 'netflow.netscale_ica_client_version': { + category: 'netflow', + name: 'netflow.netscale_ica_client_version', type: 'keyword', }, - 'zeek.intel.sources': { - category: 'zeek', - description: 'Sources which supplied data for this match. ', - name: 'zeek.intel.sources', + 'netflow.netscaler_aaa_username': { + category: 'netflow', + name: 'netflow.netscaler_aaa_username', type: 'keyword', }, - 'zeek.intel.fuid': { - category: 'zeek', - description: - 'If a file was associated with this intelligence hit, this is the uid for the file. ', - name: 'zeek.intel.fuid', + 'netflow.netscaler_app_name': { + category: 'netflow', + name: 'netflow.netscaler_app_name', type: 'keyword', }, - 'zeek.intel.file_mime_type': { - category: 'zeek', - description: - 'A mime type if the intelligence hit is related to a file. If the $f field is provided this will be automatically filled out. ', - name: 'zeek.intel.file_mime_type', - type: 'keyword', + 'netflow.netscaler_app_name_app_id': { + category: 'netflow', + name: 'netflow.netscaler_app_name_app_id', + type: 'long', }, - 'zeek.intel.file_desc': { - category: 'zeek', - description: - 'Frequently files can be described to give a bit more context. If the $f field is provided this field will be automatically filled out. ', - name: 'zeek.intel.file_desc', - type: 'keyword', + 'netflow.netscaler_app_name_incarnation_number': { + category: 'netflow', + name: 'netflow.netscaler_app_name_incarnation_number', + type: 'long', }, - 'zeek.irc.nick': { - category: 'zeek', - description: 'Nickname given for the connection. ', - name: 'zeek.irc.nick', + 'netflow.netscaler_app_template_name': { + category: 'netflow', + name: 'netflow.netscaler_app_template_name', type: 'keyword', }, - 'zeek.irc.user': { - category: 'zeek', - description: 'Username given for the connection. ', - name: 'zeek.irc.user', - type: 'keyword', + 'netflow.netscaler_app_unit_name_app_id': { + category: 'netflow', + name: 'netflow.netscaler_app_unit_name_app_id', + type: 'long', }, - 'zeek.irc.command': { - category: 'zeek', - description: 'Command given by the client. ', - name: 'zeek.irc.command', - type: 'keyword', + 'netflow.netscaler_application_startup_duration': { + category: 'netflow', + name: 'netflow.netscaler_application_startup_duration', + type: 'long', }, - 'zeek.irc.value': { - category: 'zeek', - description: 'Value for the command given by the client. ', - name: 'zeek.irc.value', - type: 'keyword', + 'netflow.netscaler_application_startup_time': { + category: 'netflow', + name: 'netflow.netscaler_application_startup_time', + type: 'long', }, - 'zeek.irc.addl': { - category: 'zeek', - description: 'Any additional data for the command. ', - name: 'zeek.irc.addl', - type: 'keyword', + 'netflow.netscaler_cache_redir_client_connection_core_id': { + category: 'netflow', + name: 'netflow.netscaler_cache_redir_client_connection_core_id', + type: 'long', }, - 'zeek.irc.dcc.file.name': { - category: 'zeek', - description: 'Present if base/protocols/irc/dcc-send.bro is loaded. DCC filename requested. ', - name: 'zeek.irc.dcc.file.name', - type: 'keyword', + 'netflow.netscaler_cache_redir_client_connection_transaction_id': { + category: 'netflow', + name: 'netflow.netscaler_cache_redir_client_connection_transaction_id', + type: 'long', }, - 'zeek.irc.dcc.file.size': { - category: 'zeek', - description: - 'Present if base/protocols/irc/dcc-send.bro is loaded. Size of the DCC transfer as indicated by the sender. ', - name: 'zeek.irc.dcc.file.size', + 'netflow.netscaler_client_rtt': { + category: 'netflow', + name: 'netflow.netscaler_client_rtt', type: 'long', }, - 'zeek.irc.dcc.mime_type': { - category: 'zeek', - description: - 'present if base/protocols/irc/dcc-send.bro is loaded. Sniffed mime type of the file. ', - name: 'zeek.irc.dcc.mime_type', - type: 'keyword', + 'netflow.netscaler_connection_chain_hop_count': { + category: 'netflow', + name: 'netflow.netscaler_connection_chain_hop_count', + type: 'long', }, - 'zeek.irc.fuid': { - category: 'zeek', - description: 'present if base/protocols/irc/files.bro is loaded. File unique ID. ', - name: 'zeek.irc.fuid', - type: 'keyword', + 'netflow.netscaler_connection_chain_id': { + category: 'netflow', + name: 'netflow.netscaler_connection_chain_id', + type: 'short', }, - 'zeek.kerberos.request_type': { - category: 'zeek', - description: 'Request type - Authentication Service (AS) or Ticket Granting Service (TGS). ', - name: 'zeek.kerberos.request_type', - type: 'keyword', + 'netflow.netscaler_connection_id': { + category: 'netflow', + name: 'netflow.netscaler_connection_id', + type: 'long', }, - 'zeek.kerberos.client': { - category: 'zeek', - description: 'Client name. ', - name: 'zeek.kerberos.client', + 'netflow.netscaler_current_license_consumed': { + category: 'netflow', + name: 'netflow.netscaler_current_license_consumed', + type: 'long', + }, + 'netflow.netscaler_db_clt_host_name': { + category: 'netflow', + name: 'netflow.netscaler_db_clt_host_name', type: 'keyword', }, - 'zeek.kerberos.service': { - category: 'zeek', - description: 'Service name. ', - name: 'zeek.kerberos.service', + 'netflow.netscaler_db_database_name': { + category: 'netflow', + name: 'netflow.netscaler_db_database_name', type: 'keyword', }, - 'zeek.kerberos.success': { - category: 'zeek', - description: 'Request result. ', - name: 'zeek.kerberos.success', - type: 'boolean', + 'netflow.netscaler_db_login_flags': { + category: 'netflow', + name: 'netflow.netscaler_db_login_flags', + type: 'long', }, - 'zeek.kerberos.error.code': { - category: 'zeek', - description: 'Error code. ', - name: 'zeek.kerberos.error.code', - type: 'integer', + 'netflow.netscaler_db_protocol_name': { + category: 'netflow', + name: 'netflow.netscaler_db_protocol_name', + type: 'short', }, - 'zeek.kerberos.error.msg': { - category: 'zeek', - description: 'Error message. ', - name: 'zeek.kerberos.error.msg', + 'netflow.netscaler_db_req_string': { + category: 'netflow', + name: 'netflow.netscaler_db_req_string', type: 'keyword', }, - 'zeek.kerberos.valid.from': { - category: 'zeek', - description: 'Ticket valid from. ', - name: 'zeek.kerberos.valid.from', - type: 'date', + 'netflow.netscaler_db_req_type': { + category: 'netflow', + name: 'netflow.netscaler_db_req_type', + type: 'short', }, - 'zeek.kerberos.valid.until': { - category: 'zeek', - description: 'Ticket valid until. ', - name: 'zeek.kerberos.valid.until', - type: 'date', + 'netflow.netscaler_db_resp_length': { + category: 'netflow', + name: 'netflow.netscaler_db_resp_length', + type: 'long', }, - 'zeek.kerberos.valid.days': { - category: 'zeek', - description: 'Number of days the ticket is valid for. ', - name: 'zeek.kerberos.valid.days', - type: 'integer', + 'netflow.netscaler_db_resp_status': { + category: 'netflow', + name: 'netflow.netscaler_db_resp_status', + type: 'long', }, - 'zeek.kerberos.cipher': { - category: 'zeek', - description: 'Ticket encryption type. ', - name: 'zeek.kerberos.cipher', + 'netflow.netscaler_db_resp_status_string': { + category: 'netflow', + name: 'netflow.netscaler_db_resp_status_string', type: 'keyword', }, - 'zeek.kerberos.forwardable': { - category: 'zeek', - description: 'Forwardable ticket requested. ', - name: 'zeek.kerberos.forwardable', - type: 'boolean', + 'netflow.netscaler_db_user_name': { + category: 'netflow', + name: 'netflow.netscaler_db_user_name', + type: 'keyword', }, - 'zeek.kerberos.renewable': { - category: 'zeek', - description: 'Renewable ticket requested. ', - name: 'zeek.kerberos.renewable', - type: 'boolean', + 'netflow.netscaler_flow_flags': { + category: 'netflow', + name: 'netflow.netscaler_flow_flags', + type: 'long', }, - 'zeek.kerberos.ticket.auth': { - category: 'zeek', - description: 'Hash of ticket used to authorize request/transaction. ', - name: 'zeek.kerberos.ticket.auth', + 'netflow.netscaler_http_client_interaction_end_time': { + category: 'netflow', + name: 'netflow.netscaler_http_client_interaction_end_time', type: 'keyword', }, - 'zeek.kerberos.ticket.new': { - category: 'zeek', - description: 'Hash of ticket returned by the KDC. ', - name: 'zeek.kerberos.ticket.new', + 'netflow.netscaler_http_client_interaction_start_time': { + category: 'netflow', + name: 'netflow.netscaler_http_client_interaction_start_time', type: 'keyword', }, - 'zeek.kerberos.cert.client.value': { - category: 'zeek', - description: 'Client certificate. ', - name: 'zeek.kerberos.cert.client.value', + 'netflow.netscaler_http_client_render_end_time': { + category: 'netflow', + name: 'netflow.netscaler_http_client_render_end_time', type: 'keyword', }, - 'zeek.kerberos.cert.client.fuid': { - category: 'zeek', - description: 'File unique ID of client cert. ', - name: 'zeek.kerberos.cert.client.fuid', + 'netflow.netscaler_http_client_render_start_time': { + category: 'netflow', + name: 'netflow.netscaler_http_client_render_start_time', type: 'keyword', }, - 'zeek.kerberos.cert.client.subject': { - category: 'zeek', - description: 'Subject of client certificate. ', - name: 'zeek.kerberos.cert.client.subject', + 'netflow.netscaler_http_content_type': { + category: 'netflow', + name: 'netflow.netscaler_http_content_type', type: 'keyword', }, - 'zeek.kerberos.cert.server.value': { - category: 'zeek', - description: 'Server certificate. ', - name: 'zeek.kerberos.cert.server.value', + 'netflow.netscaler_http_domain_name': { + category: 'netflow', + name: 'netflow.netscaler_http_domain_name', type: 'keyword', }, - 'zeek.kerberos.cert.server.fuid': { - category: 'zeek', - description: 'File unique ID of server certificate. ', - name: 'zeek.kerberos.cert.server.fuid', + 'netflow.netscaler_http_req_authorization': { + category: 'netflow', + name: 'netflow.netscaler_http_req_authorization', type: 'keyword', }, - 'zeek.kerberos.cert.server.subject': { - category: 'zeek', - description: 'Subject of server certificate. ', - name: 'zeek.kerberos.cert.server.subject', + 'netflow.netscaler_http_req_cookie': { + category: 'netflow', + name: 'netflow.netscaler_http_req_cookie', type: 'keyword', }, - 'zeek.modbus.function': { - category: 'zeek', - description: 'The name of the function message that was sent. ', - name: 'zeek.modbus.function', + 'netflow.netscaler_http_req_forw_fb': { + category: 'netflow', + name: 'netflow.netscaler_http_req_forw_fb', + type: 'long', + }, + 'netflow.netscaler_http_req_forw_lb': { + category: 'netflow', + name: 'netflow.netscaler_http_req_forw_lb', + type: 'long', + }, + 'netflow.netscaler_http_req_host': { + category: 'netflow', + name: 'netflow.netscaler_http_req_host', type: 'keyword', }, - 'zeek.modbus.exception': { - category: 'zeek', - description: 'The exception if the response was a failure. ', - name: 'zeek.modbus.exception', + 'netflow.netscaler_http_req_method': { + category: 'netflow', + name: 'netflow.netscaler_http_req_method', type: 'keyword', }, - 'zeek.modbus.track_address': { - category: 'zeek', - description: - 'Present if policy/protocols/modbus/track-memmap.bro is loaded. Modbus track address. ', - name: 'zeek.modbus.track_address', - type: 'integer', + 'netflow.netscaler_http_req_rcv_fb': { + category: 'netflow', + name: 'netflow.netscaler_http_req_rcv_fb', + type: 'long', }, - 'zeek.mysql.cmd': { - category: 'zeek', - description: 'The command that was issued. ', - name: 'zeek.mysql.cmd', - type: 'keyword', + 'netflow.netscaler_http_req_rcv_lb': { + category: 'netflow', + name: 'netflow.netscaler_http_req_rcv_lb', + type: 'long', }, - 'zeek.mysql.arg': { - category: 'zeek', - description: 'The argument issued to the command. ', - name: 'zeek.mysql.arg', + 'netflow.netscaler_http_req_referer': { + category: 'netflow', + name: 'netflow.netscaler_http_req_referer', type: 'keyword', }, - 'zeek.mysql.success': { - category: 'zeek', - description: 'Whether the command succeeded. ', - name: 'zeek.mysql.success', - type: 'boolean', + 'netflow.netscaler_http_req_url': { + category: 'netflow', + name: 'netflow.netscaler_http_req_url', + type: 'keyword', }, - 'zeek.mysql.rows': { - category: 'zeek', - description: 'The number of affected rows, if any. ', - name: 'zeek.mysql.rows', - type: 'integer', + 'netflow.netscaler_http_req_user_agent': { + category: 'netflow', + name: 'netflow.netscaler_http_req_user_agent', + type: 'keyword', }, - 'zeek.mysql.response': { - category: 'zeek', - description: 'Server message, if any. ', - name: 'zeek.mysql.response', + 'netflow.netscaler_http_req_via': { + category: 'netflow', + name: 'netflow.netscaler_http_req_via', type: 'keyword', }, - 'zeek.notice.connection_id': { - category: 'zeek', - description: 'Identifier of the related connection session. ', - name: 'zeek.notice.connection_id', + 'netflow.netscaler_http_req_xforwarded_for': { + category: 'netflow', + name: 'netflow.netscaler_http_req_xforwarded_for', type: 'keyword', }, - 'zeek.notice.icmp_id': { - category: 'zeek', - description: 'Identifier of the related ICMP session. ', - name: 'zeek.notice.icmp_id', + 'netflow.netscaler_http_res_forw_fb': { + category: 'netflow', + name: 'netflow.netscaler_http_res_forw_fb', + type: 'long', + }, + 'netflow.netscaler_http_res_forw_lb': { + category: 'netflow', + name: 'netflow.netscaler_http_res_forw_lb', + type: 'long', + }, + 'netflow.netscaler_http_res_location': { + category: 'netflow', + name: 'netflow.netscaler_http_res_location', type: 'keyword', }, - 'zeek.notice.file.id': { - category: 'zeek', - description: 'An identifier associated with a single file that is related to this notice. ', - name: 'zeek.notice.file.id', + 'netflow.netscaler_http_res_rcv_fb': { + category: 'netflow', + name: 'netflow.netscaler_http_res_rcv_fb', + type: 'long', + }, + 'netflow.netscaler_http_res_rcv_lb': { + category: 'netflow', + name: 'netflow.netscaler_http_res_rcv_lb', + type: 'long', + }, + 'netflow.netscaler_http_res_set_cookie': { + category: 'netflow', + name: 'netflow.netscaler_http_res_set_cookie', type: 'keyword', }, - 'zeek.notice.file.parent_id': { - category: 'zeek', - description: 'Identifier associated with a container file from which this one was extracted. ', - name: 'zeek.notice.file.parent_id', + 'netflow.netscaler_http_res_set_cookie2': { + category: 'netflow', + name: 'netflow.netscaler_http_res_set_cookie2', type: 'keyword', }, - 'zeek.notice.file.source': { - category: 'zeek', - description: - 'An identification of the source of the file data. E.g. it may be a network protocol over which it was transferred, or a local file path which was read, or some other input source. ', - name: 'zeek.notice.file.source', + 'netflow.netscaler_http_rsp_len': { + category: 'netflow', + name: 'netflow.netscaler_http_rsp_len', + type: 'long', + }, + 'netflow.netscaler_http_rsp_status': { + category: 'netflow', + name: 'netflow.netscaler_http_rsp_status', + type: 'integer', + }, + 'netflow.netscaler_ica_app_module_path': { + category: 'netflow', + name: 'netflow.netscaler_ica_app_module_path', type: 'keyword', }, - 'zeek.notice.file.mime_type': { - category: 'zeek', - description: 'A mime type if the notice is related to a file. ', - name: 'zeek.notice.file.mime_type', + 'netflow.netscaler_ica_app_process_id': { + category: 'netflow', + name: 'netflow.netscaler_ica_app_process_id', + type: 'long', + }, + 'netflow.netscaler_ica_application_name': { + category: 'netflow', + name: 'netflow.netscaler_ica_application_name', type: 'keyword', }, - 'zeek.notice.file.is_orig': { - category: 'zeek', - description: - 'If the source of this file is a network connection, this field indicates if the file is being sent by the originator of the connection or the responder. ', - name: 'zeek.notice.file.is_orig', - type: 'boolean', + 'netflow.netscaler_ica_application_termination_time': { + category: 'netflow', + name: 'netflow.netscaler_ica_application_termination_time', + type: 'long', }, - 'zeek.notice.file.seen_bytes': { - category: 'zeek', - description: 'Number of bytes provided to the file analysis engine for the file. ', - name: 'zeek.notice.file.seen_bytes', + 'netflow.netscaler_ica_application_termination_type': { + category: 'netflow', + name: 'netflow.netscaler_ica_application_termination_type', + type: 'integer', + }, + 'netflow.netscaler_ica_channel_id1': { + category: 'netflow', + name: 'netflow.netscaler_ica_channel_id1', type: 'long', }, - 'zeek.notice.ffile.total_bytes': { - category: 'zeek', - description: 'Total number of bytes that are supposed to comprise the full file. ', - name: 'zeek.notice.ffile.total_bytes', + 'netflow.netscaler_ica_channel_id1_bytes': { + category: 'netflow', + name: 'netflow.netscaler_ica_channel_id1_bytes', type: 'long', }, - 'zeek.notice.file.missing_bytes': { - category: 'zeek', - description: - 'The number of bytes in the file stream that were completely missed during the process of analysis. ', - name: 'zeek.notice.file.missing_bytes', + 'netflow.netscaler_ica_channel_id2': { + category: 'netflow', + name: 'netflow.netscaler_ica_channel_id2', type: 'long', }, - 'zeek.notice.file.overflow_bytes': { - category: 'zeek', - description: - "The number of bytes in the file stream that were not delivered to stream file analyzers. This could be overlapping bytes or bytes that couldn't be reassembled. ", - name: 'zeek.notice.file.overflow_bytes', + 'netflow.netscaler_ica_channel_id2_bytes': { + category: 'netflow', + name: 'netflow.netscaler_ica_channel_id2_bytes', type: 'long', }, - 'zeek.notice.fuid': { - category: 'zeek', - description: 'A file unique ID if this notice is related to a file. ', - name: 'zeek.notice.fuid', - type: 'keyword', + 'netflow.netscaler_ica_channel_id3': { + category: 'netflow', + name: 'netflow.netscaler_ica_channel_id3', + type: 'long', }, - 'zeek.notice.note': { - category: 'zeek', - description: 'The type of the notice. ', - name: 'zeek.notice.note', - type: 'keyword', + 'netflow.netscaler_ica_channel_id3_bytes': { + category: 'netflow', + name: 'netflow.netscaler_ica_channel_id3_bytes', + type: 'long', }, - 'zeek.notice.msg': { - category: 'zeek', - description: 'The human readable message for the notice. ', - name: 'zeek.notice.msg', - type: 'keyword', + 'netflow.netscaler_ica_channel_id4': { + category: 'netflow', + name: 'netflow.netscaler_ica_channel_id4', + type: 'long', }, - 'zeek.notice.sub': { - category: 'zeek', - description: 'The human readable sub-message. ', - name: 'zeek.notice.sub', - type: 'keyword', + 'netflow.netscaler_ica_channel_id4_bytes': { + category: 'netflow', + name: 'netflow.netscaler_ica_channel_id4_bytes', + type: 'long', }, - 'zeek.notice.n': { - category: 'zeek', - description: 'Associated count, or a status code. ', - name: 'zeek.notice.n', + 'netflow.netscaler_ica_channel_id5': { + category: 'netflow', + name: 'netflow.netscaler_ica_channel_id5', type: 'long', }, - 'zeek.notice.peer_name': { - category: 'zeek', - description: 'Name of remote peer that raised this notice. ', - name: 'zeek.notice.peer_name', + 'netflow.netscaler_ica_channel_id5_bytes': { + category: 'netflow', + name: 'netflow.netscaler_ica_channel_id5_bytes', + type: 'long', + }, + 'netflow.netscaler_ica_client_host_name': { + category: 'netflow', + name: 'netflow.netscaler_ica_client_host_name', type: 'keyword', }, - 'zeek.notice.peer_descr': { - category: 'zeek', - description: 'Textual description for the peer that raised this notice. ', - name: 'zeek.notice.peer_descr', - type: 'text', + 'netflow.netscaler_ica_client_ip': { + category: 'netflow', + name: 'netflow.netscaler_ica_client_ip', + type: 'ip', }, - 'zeek.notice.actions': { - category: 'zeek', - description: 'The actions which have been applied to this notice. ', - name: 'zeek.notice.actions', - type: 'keyword', + 'netflow.netscaler_ica_client_launcher': { + category: 'netflow', + name: 'netflow.netscaler_ica_client_launcher', + type: 'integer', }, - 'zeek.notice.email_body_sections': { - category: 'zeek', - description: - 'By adding chunks of text into this element, other scripts can expand on notices that are being emailed. ', - name: 'zeek.notice.email_body_sections', - type: 'text', + 'netflow.netscaler_ica_client_side_rto_count': { + category: 'netflow', + name: 'netflow.netscaler_ica_client_side_rto_count', + type: 'integer', }, - 'zeek.notice.email_delay_tokens': { - category: 'zeek', - description: - 'Adding a string token to this set will cause the built-in emailing functionality to delay sending the email either the token has been removed or the email has been delayed for the specified time duration. ', - name: 'zeek.notice.email_delay_tokens', - type: 'keyword', + 'netflow.netscaler_ica_client_side_window_size': { + category: 'netflow', + name: 'netflow.netscaler_ica_client_side_window_size', + type: 'integer', }, - 'zeek.notice.identifier': { - category: 'zeek', - description: - 'This field is provided when a notice is generated for the purpose of deduplicating notices. ', - name: 'zeek.notice.identifier', - type: 'keyword', + 'netflow.netscaler_ica_client_type': { + category: 'netflow', + name: 'netflow.netscaler_ica_client_type', + type: 'integer', }, - 'zeek.notice.suppress_for': { - category: 'zeek', - description: - 'This field indicates the length of time that this unique notice should be suppressed. ', - name: 'zeek.notice.suppress_for', - type: 'double', + 'netflow.netscaler_ica_clientside_delay': { + category: 'netflow', + name: 'netflow.netscaler_ica_clientside_delay', + type: 'long', }, - 'zeek.notice.dropped': { - category: 'zeek', - description: 'Indicate if the source IP address was dropped and denied network access. ', - name: 'zeek.notice.dropped', - type: 'boolean', + 'netflow.netscaler_ica_clientside_jitter': { + category: 'netflow', + name: 'netflow.netscaler_ica_clientside_jitter', + type: 'long', }, - 'zeek.ntlm.domain': { - category: 'zeek', - description: 'Domain name given by the client. ', - name: 'zeek.ntlm.domain', - type: 'keyword', + 'netflow.netscaler_ica_clientside_packets_retransmit': { + category: 'netflow', + name: 'netflow.netscaler_ica_clientside_packets_retransmit', + type: 'integer', }, - 'zeek.ntlm.hostname': { - category: 'zeek', - description: 'Hostname given by the client. ', - name: 'zeek.ntlm.hostname', - type: 'keyword', + 'netflow.netscaler_ica_clientside_rtt': { + category: 'netflow', + name: 'netflow.netscaler_ica_clientside_rtt', + type: 'long', }, - 'zeek.ntlm.success': { - category: 'zeek', - description: 'Indicate whether or not the authentication was successful. ', - name: 'zeek.ntlm.success', - type: 'boolean', + 'netflow.netscaler_ica_clientside_rx_bytes': { + category: 'netflow', + name: 'netflow.netscaler_ica_clientside_rx_bytes', + type: 'long', }, - 'zeek.ntlm.username': { - category: 'zeek', - description: 'Username given by the client. ', - name: 'zeek.ntlm.username', - type: 'keyword', + 'netflow.netscaler_ica_clientside_srtt': { + category: 'netflow', + name: 'netflow.netscaler_ica_clientside_srtt', + type: 'long', }, - 'zeek.ntlm.server.name.dns': { - category: 'zeek', - description: 'DNS name given by the server in a CHALLENGE. ', - name: 'zeek.ntlm.server.name.dns', - type: 'keyword', + 'netflow.netscaler_ica_clientside_tx_bytes': { + category: 'netflow', + name: 'netflow.netscaler_ica_clientside_tx_bytes', + type: 'long', }, - 'zeek.ntlm.server.name.netbios': { - category: 'zeek', - description: 'NetBIOS name given by the server in a CHALLENGE. ', - name: 'zeek.ntlm.server.name.netbios', - type: 'keyword', + 'netflow.netscaler_ica_connection_priority': { + category: 'netflow', + name: 'netflow.netscaler_ica_connection_priority', + type: 'integer', }, - 'zeek.ntlm.server.name.tree': { - category: 'zeek', - description: 'Tree name given by the server in a CHALLENGE. ', - name: 'zeek.ntlm.server.name.tree', - type: 'keyword', + 'netflow.netscaler_ica_device_serial_no': { + category: 'netflow', + name: 'netflow.netscaler_ica_device_serial_no', + type: 'long', }, - 'zeek.ocsp.file_id': { - category: 'zeek', - description: 'File id of the OCSP reply. ', - name: 'zeek.ocsp.file_id', + 'netflow.netscaler_ica_domain_name': { + category: 'netflow', + name: 'netflow.netscaler_ica_domain_name', type: 'keyword', }, - 'zeek.ocsp.hash.algorithm': { - category: 'zeek', - description: 'Hash algorithm used to generate issuerNameHash and issuerKeyHash. ', - name: 'zeek.ocsp.hash.algorithm', - type: 'keyword', + 'netflow.netscaler_ica_flags': { + category: 'netflow', + name: 'netflow.netscaler_ica_flags', + type: 'long', }, - 'zeek.ocsp.hash.issuer.name': { - category: 'zeek', - description: "Hash of the issuer's distingueshed name. ", - name: 'zeek.ocsp.hash.issuer.name', - type: 'keyword', + 'netflow.netscaler_ica_host_delay': { + category: 'netflow', + name: 'netflow.netscaler_ica_host_delay', + type: 'long', }, - 'zeek.ocsp.hash.issuer.key': { - category: 'zeek', - description: "Hash of the issuer's public key. ", - name: 'zeek.ocsp.hash.issuer.key', - type: 'keyword', + 'netflow.netscaler_ica_l7_client_latency': { + category: 'netflow', + name: 'netflow.netscaler_ica_l7_client_latency', + type: 'long', }, - 'zeek.ocsp.serial_number': { - category: 'zeek', - description: 'Serial number of the affected certificate. ', - name: 'zeek.ocsp.serial_number', - type: 'keyword', + 'netflow.netscaler_ica_l7_server_latency': { + category: 'netflow', + name: 'netflow.netscaler_ica_l7_server_latency', + type: 'long', }, - 'zeek.ocsp.status': { - category: 'zeek', - description: 'Status of the affected certificate. ', - name: 'zeek.ocsp.status', - type: 'keyword', + 'netflow.netscaler_ica_launch_mechanism': { + category: 'netflow', + name: 'netflow.netscaler_ica_launch_mechanism', + type: 'integer', }, - 'zeek.ocsp.revoke.time': { - category: 'zeek', - description: 'Time at which the certificate was revoked. ', - name: 'zeek.ocsp.revoke.time', - type: 'date', + 'netflow.netscaler_ica_network_update_end_time': { + category: 'netflow', + name: 'netflow.netscaler_ica_network_update_end_time', + type: 'long', }, - 'zeek.ocsp.revoke.reason': { - category: 'zeek', - description: 'Reason for which the certificate was revoked. ', - name: 'zeek.ocsp.revoke.reason', + 'netflow.netscaler_ica_network_update_start_time': { + category: 'netflow', + name: 'netflow.netscaler_ica_network_update_start_time', + type: 'long', + }, + 'netflow.netscaler_ica_rtt': { + category: 'netflow', + name: 'netflow.netscaler_ica_rtt', + type: 'long', + }, + 'netflow.netscaler_ica_server_name': { + category: 'netflow', + name: 'netflow.netscaler_ica_server_name', type: 'keyword', }, - 'zeek.ocsp.update.this': { - category: 'zeek', - description: 'The time at which the status being shows is known to have been correct. ', - name: 'zeek.ocsp.update.this', - type: 'date', + 'netflow.netscaler_ica_server_side_rto_count': { + category: 'netflow', + name: 'netflow.netscaler_ica_server_side_rto_count', + type: 'integer', }, - 'zeek.ocsp.update.next': { - category: 'zeek', - description: - 'The latest time at which new information about the status of the certificate will be available. ', - name: 'zeek.ocsp.update.next', - type: 'date', + 'netflow.netscaler_ica_server_side_window_size': { + category: 'netflow', + name: 'netflow.netscaler_ica_server_side_window_size', + type: 'integer', }, - 'zeek.pe.client': { - category: 'zeek', - description: "The client's version string. ", - name: 'zeek.pe.client', - type: 'keyword', + 'netflow.netscaler_ica_serverside_delay': { + category: 'netflow', + name: 'netflow.netscaler_ica_serverside_delay', + type: 'long', }, - 'zeek.pe.id': { - category: 'zeek', - description: 'File id of this portable executable file. ', - name: 'zeek.pe.id', - type: 'keyword', + 'netflow.netscaler_ica_serverside_jitter': { + category: 'netflow', + name: 'netflow.netscaler_ica_serverside_jitter', + type: 'long', }, - 'zeek.pe.machine': { - category: 'zeek', - description: 'The target machine that the file was compiled for. ', - name: 'zeek.pe.machine', - type: 'keyword', + 'netflow.netscaler_ica_serverside_packets_retransmit': { + category: 'netflow', + name: 'netflow.netscaler_ica_serverside_packets_retransmit', + type: 'integer', }, - 'zeek.pe.compile_time': { - category: 'zeek', - description: 'The time that the file was created at. ', - name: 'zeek.pe.compile_time', - type: 'date', + 'netflow.netscaler_ica_serverside_rtt': { + category: 'netflow', + name: 'netflow.netscaler_ica_serverside_rtt', + type: 'long', }, - 'zeek.pe.os': { - category: 'zeek', - description: 'The required operating system. ', - name: 'zeek.pe.os', - type: 'keyword', + 'netflow.netscaler_ica_serverside_srtt': { + category: 'netflow', + name: 'netflow.netscaler_ica_serverside_srtt', + type: 'long', }, - 'zeek.pe.subsystem': { - category: 'zeek', - description: 'The subsystem that is required to run this file. ', - name: 'zeek.pe.subsystem', - type: 'keyword', + 'netflow.netscaler_ica_session_end_time': { + category: 'netflow', + name: 'netflow.netscaler_ica_session_end_time', + type: 'long', }, - 'zeek.pe.is_exe': { - category: 'zeek', - description: 'Is the file an executable, or just an object file? ', - name: 'zeek.pe.is_exe', - type: 'boolean', + 'netflow.netscaler_ica_session_guid': { + category: 'netflow', + name: 'netflow.netscaler_ica_session_guid', + type: 'short', }, - 'zeek.pe.is_64bit': { - category: 'zeek', - description: 'Is the file a 64-bit executable? ', - name: 'zeek.pe.is_64bit', - type: 'boolean', + 'netflow.netscaler_ica_session_reconnects': { + category: 'netflow', + name: 'netflow.netscaler_ica_session_reconnects', + type: 'short', }, - 'zeek.pe.uses_aslr': { - category: 'zeek', - description: 'Does the file support Address Space Layout Randomization? ', - name: 'zeek.pe.uses_aslr', - type: 'boolean', + 'netflow.netscaler_ica_session_setup_time': { + category: 'netflow', + name: 'netflow.netscaler_ica_session_setup_time', + type: 'long', }, - 'zeek.pe.uses_dep': { - category: 'zeek', - description: 'Does the file support Data Execution Prevention? ', - name: 'zeek.pe.uses_dep', - type: 'boolean', + 'netflow.netscaler_ica_session_update_begin_sec': { + category: 'netflow', + name: 'netflow.netscaler_ica_session_update_begin_sec', + type: 'long', }, - 'zeek.pe.uses_code_integrity': { - category: 'zeek', - description: 'Does the file enforce code integrity checks? ', - name: 'zeek.pe.uses_code_integrity', - type: 'boolean', + 'netflow.netscaler_ica_session_update_end_sec': { + category: 'netflow', + name: 'netflow.netscaler_ica_session_update_end_sec', + type: 'long', }, - 'zeek.pe.uses_seh': { - category: 'zeek', - description: 'Does the file use structured exception handing? ', - name: 'zeek.pe.uses_seh', - type: 'boolean', + 'netflow.netscaler_ica_username': { + category: 'netflow', + name: 'netflow.netscaler_ica_username', + type: 'keyword', }, - 'zeek.pe.has_import_table': { - category: 'zeek', - description: 'Does the file have an import table? ', - name: 'zeek.pe.has_import_table', - type: 'boolean', + 'netflow.netscaler_license_type': { + category: 'netflow', + name: 'netflow.netscaler_license_type', + type: 'short', }, - 'zeek.pe.has_export_table': { - category: 'zeek', - description: 'Does the file have an export table? ', - name: 'zeek.pe.has_export_table', - type: 'boolean', + 'netflow.netscaler_main_page_core_id': { + category: 'netflow', + name: 'netflow.netscaler_main_page_core_id', + type: 'long', }, - 'zeek.pe.has_cert_table': { - category: 'zeek', - description: 'Does the file have an attribute certificate table? ', - name: 'zeek.pe.has_cert_table', - type: 'boolean', + 'netflow.netscaler_main_page_id': { + category: 'netflow', + name: 'netflow.netscaler_main_page_id', + type: 'long', + }, + 'netflow.netscaler_max_license_count': { + category: 'netflow', + name: 'netflow.netscaler_max_license_count', + type: 'long', + }, + 'netflow.netscaler_msi_client_cookie': { + category: 'netflow', + name: 'netflow.netscaler_msi_client_cookie', + type: 'short', + }, + 'netflow.netscaler_round_trip_time': { + category: 'netflow', + name: 'netflow.netscaler_round_trip_time', + type: 'long', + }, + 'netflow.netscaler_server_ttfb': { + category: 'netflow', + name: 'netflow.netscaler_server_ttfb', + type: 'long', }, - 'zeek.pe.has_debug_data': { - category: 'zeek', - description: 'Does the file have a debug table? ', - name: 'zeek.pe.has_debug_data', - type: 'boolean', + 'netflow.netscaler_server_ttlb': { + category: 'netflow', + name: 'netflow.netscaler_server_ttlb', + type: 'long', }, - 'zeek.pe.section_names': { - category: 'zeek', - description: 'The names of the sections, in order. ', - name: 'zeek.pe.section_names', + 'netflow.netscaler_syslog_message': { + category: 'netflow', + name: 'netflow.netscaler_syslog_message', type: 'keyword', }, - 'zeek.radius.username': { - category: 'zeek', - description: 'The username, if present. ', - name: 'zeek.radius.username', - type: 'keyword', + 'netflow.netscaler_syslog_priority': { + category: 'netflow', + name: 'netflow.netscaler_syslog_priority', + type: 'short', }, - 'zeek.radius.mac': { - category: 'zeek', - description: 'MAC address, if present. ', - name: 'zeek.radius.mac', - type: 'keyword', + 'netflow.netscaler_syslog_timestamp': { + category: 'netflow', + name: 'netflow.netscaler_syslog_timestamp', + type: 'long', }, - 'zeek.radius.framed_addr': { - category: 'zeek', - description: - 'The address given to the network access server, if present. This is only a hint from the RADIUS server and the network access server is not required to honor the address. ', - name: 'zeek.radius.framed_addr', - type: 'ip', + 'netflow.netscaler_transaction_id': { + category: 'netflow', + name: 'netflow.netscaler_transaction_id', + type: 'long', }, - 'zeek.radius.remote_ip': { - category: 'zeek', - description: - 'Remote IP address, if present. This is collected from the Tunnel-Client-Endpoint attribute. ', - name: 'zeek.radius.remote_ip', - type: 'ip', + 'netflow.netscaler_unknown270': { + category: 'netflow', + name: 'netflow.netscaler_unknown270', + type: 'long', }, - 'zeek.radius.connect_info': { - category: 'zeek', - description: 'Connect info, if present. ', - name: 'zeek.radius.connect_info', - type: 'keyword', + 'netflow.netscaler_unknown271': { + category: 'netflow', + name: 'netflow.netscaler_unknown271', + type: 'long', }, - 'zeek.radius.reply_msg': { - category: 'zeek', - description: - 'Reply message from the server challenge. This is frequently shown to the user authenticating. ', - name: 'zeek.radius.reply_msg', - type: 'keyword', + 'netflow.netscaler_unknown272': { + category: 'netflow', + name: 'netflow.netscaler_unknown272', + type: 'long', }, - 'zeek.radius.result': { - category: 'zeek', - description: 'Successful or failed authentication. ', - name: 'zeek.radius.result', - type: 'keyword', + 'netflow.netscaler_unknown273': { + category: 'netflow', + name: 'netflow.netscaler_unknown273', + type: 'long', }, - 'zeek.radius.ttl': { - category: 'zeek', - description: - 'The duration between the first request and either the "Access-Accept" message or an error. If the field is empty, it means that either the request or response was not seen. ', - name: 'zeek.radius.ttl', - type: 'integer', + 'netflow.netscaler_unknown274': { + category: 'netflow', + name: 'netflow.netscaler_unknown274', + type: 'long', }, - 'zeek.radius.logged': { - category: 'zeek', - description: 'Whether this has already been logged and can be ignored. ', - name: 'zeek.radius.logged', - type: 'boolean', + 'netflow.netscaler_unknown275': { + category: 'netflow', + name: 'netflow.netscaler_unknown275', + type: 'long', }, - 'zeek.rdp.cookie': { - category: 'zeek', - description: 'Cookie value used by the client machine. This is typically a username. ', - name: 'zeek.rdp.cookie', - type: 'keyword', + 'netflow.netscaler_unknown276': { + category: 'netflow', + name: 'netflow.netscaler_unknown276', + type: 'long', }, - 'zeek.rdp.result': { - category: 'zeek', - description: - "Status result for the connection. It's a mix between RDP negotation failure messages and GCC server create response messages. ", - name: 'zeek.rdp.result', - type: 'keyword', + 'netflow.netscaler_unknown277': { + category: 'netflow', + name: 'netflow.netscaler_unknown277', + type: 'long', }, - 'zeek.rdp.security_protocol': { - category: 'zeek', - description: 'Security protocol chosen by the server. ', - name: 'zeek.rdp.security_protocol', - type: 'keyword', + 'netflow.netscaler_unknown278': { + category: 'netflow', + name: 'netflow.netscaler_unknown278', + type: 'long', }, - 'zeek.rdp.keyboard_layout': { - category: 'zeek', - description: 'Keyboard layout (language) of the client machine. ', - name: 'zeek.rdp.keyboard_layout', - type: 'keyword', + 'netflow.netscaler_unknown279': { + category: 'netflow', + name: 'netflow.netscaler_unknown279', + type: 'long', }, - 'zeek.rdp.client.build': { - category: 'zeek', - description: 'RDP client version used by the client machine. ', - name: 'zeek.rdp.client.build', - type: 'keyword', + 'netflow.netscaler_unknown280': { + category: 'netflow', + name: 'netflow.netscaler_unknown280', + type: 'long', }, - 'zeek.rdp.client.client_name': { - category: 'zeek', - description: 'Name of the client machine. ', - name: 'zeek.rdp.client.client_name', - type: 'keyword', + 'netflow.netscaler_unknown281': { + category: 'netflow', + name: 'netflow.netscaler_unknown281', + type: 'long', }, - 'zeek.rdp.client.product_id': { - category: 'zeek', - description: 'Product ID of the client machine. ', - name: 'zeek.rdp.client.product_id', - type: 'keyword', + 'netflow.netscaler_unknown282': { + category: 'netflow', + name: 'netflow.netscaler_unknown282', + type: 'long', }, - 'zeek.rdp.desktop.width': { - category: 'zeek', - description: 'Desktop width of the client machine. ', - name: 'zeek.rdp.desktop.width', - type: 'integer', + 'netflow.netscaler_unknown283': { + category: 'netflow', + name: 'netflow.netscaler_unknown283', + type: 'long', }, - 'zeek.rdp.desktop.height': { - category: 'zeek', - description: 'Desktop height of the client machine. ', - name: 'zeek.rdp.desktop.height', - type: 'integer', + 'netflow.netscaler_unknown284': { + category: 'netflow', + name: 'netflow.netscaler_unknown284', + type: 'long', }, - 'zeek.rdp.desktop.color_depth': { - category: 'zeek', - description: 'The color depth requested by the client in the high_color_depth field. ', - name: 'zeek.rdp.desktop.color_depth', - type: 'keyword', + 'netflow.netscaler_unknown285': { + category: 'netflow', + name: 'netflow.netscaler_unknown285', + type: 'long', }, - 'zeek.rdp.cert.type': { - category: 'zeek', - description: - 'If the connection is being encrypted with native RDP encryption, this is the type of cert being used. ', - name: 'zeek.rdp.cert.type', - type: 'keyword', + 'netflow.netscaler_unknown286': { + category: 'netflow', + name: 'netflow.netscaler_unknown286', + type: 'long', }, - 'zeek.rdp.cert.count': { - category: 'zeek', - description: 'The number of certs seen. X.509 can transfer an entire certificate chain. ', - name: 'zeek.rdp.cert.count', - type: 'integer', + 'netflow.netscaler_unknown287': { + category: 'netflow', + name: 'netflow.netscaler_unknown287', + type: 'long', }, - 'zeek.rdp.cert.permanent': { - category: 'zeek', - description: - 'Indicates if the provided certificate or certificate chain is permanent or temporary. ', - name: 'zeek.rdp.cert.permanent', - type: 'boolean', + 'netflow.netscaler_unknown288': { + category: 'netflow', + name: 'netflow.netscaler_unknown288', + type: 'long', }, - 'zeek.rdp.encryption.level': { - category: 'zeek', - description: 'Encryption level of the connection. ', - name: 'zeek.rdp.encryption.level', - type: 'keyword', + 'netflow.netscaler_unknown289': { + category: 'netflow', + name: 'netflow.netscaler_unknown289', + type: 'long', }, - 'zeek.rdp.encryption.method': { - category: 'zeek', - description: 'Encryption method of the connection. ', - name: 'zeek.rdp.encryption.method', - type: 'keyword', + 'netflow.netscaler_unknown290': { + category: 'netflow', + name: 'netflow.netscaler_unknown290', + type: 'long', }, - 'zeek.rdp.done': { - category: 'zeek', - description: 'Track status of logging RDP connections. ', - name: 'zeek.rdp.done', - type: 'boolean', + 'netflow.netscaler_unknown291': { + category: 'netflow', + name: 'netflow.netscaler_unknown291', + type: 'long', }, - 'zeek.rdp.ssl': { - category: 'zeek', - description: - '(present if policy/protocols/rdp/indicate_ssl.bro is loaded) Flag the connection if it was seen over SSL. ', - name: 'zeek.rdp.ssl', - type: 'boolean', + 'netflow.netscaler_unknown292': { + category: 'netflow', + name: 'netflow.netscaler_unknown292', + type: 'long', }, - 'zeek.rfb.version.client.major': { - category: 'zeek', - description: 'Major version of the client. ', - name: 'zeek.rfb.version.client.major', - type: 'keyword', + 'netflow.netscaler_unknown293': { + category: 'netflow', + name: 'netflow.netscaler_unknown293', + type: 'long', }, - 'zeek.rfb.version.client.minor': { - category: 'zeek', - description: 'Minor version of the client. ', - name: 'zeek.rfb.version.client.minor', - type: 'keyword', + 'netflow.netscaler_unknown294': { + category: 'netflow', + name: 'netflow.netscaler_unknown294', + type: 'long', }, - 'zeek.rfb.version.server.major': { - category: 'zeek', - description: 'Major version of the server. ', - name: 'zeek.rfb.version.server.major', - type: 'keyword', + 'netflow.netscaler_unknown295': { + category: 'netflow', + name: 'netflow.netscaler_unknown295', + type: 'long', }, - 'zeek.rfb.version.server.minor': { - category: 'zeek', - description: 'Minor version of the server. ', - name: 'zeek.rfb.version.server.minor', - type: 'keyword', + 'netflow.netscaler_unknown296': { + category: 'netflow', + name: 'netflow.netscaler_unknown296', + type: 'long', }, - 'zeek.rfb.auth.success': { - category: 'zeek', - description: 'Whether or not authentication was successful. ', - name: 'zeek.rfb.auth.success', - type: 'boolean', + 'netflow.netscaler_unknown297': { + category: 'netflow', + name: 'netflow.netscaler_unknown297', + type: 'long', }, - 'zeek.rfb.auth.method': { - category: 'zeek', - description: 'Identifier of authentication method used. ', - name: 'zeek.rfb.auth.method', - type: 'keyword', + 'netflow.netscaler_unknown298': { + category: 'netflow', + name: 'netflow.netscaler_unknown298', + type: 'long', }, - 'zeek.rfb.share_flag': { - category: 'zeek', - description: 'Whether the client has an exclusive or a shared session. ', - name: 'zeek.rfb.share_flag', - type: 'boolean', + 'netflow.netscaler_unknown299': { + category: 'netflow', + name: 'netflow.netscaler_unknown299', + type: 'long', }, - 'zeek.rfb.desktop_name': { - category: 'zeek', - description: 'Name of the screen that is being shared. ', - name: 'zeek.rfb.desktop_name', - type: 'keyword', + 'netflow.netscaler_unknown300': { + category: 'netflow', + name: 'netflow.netscaler_unknown300', + type: 'long', }, - 'zeek.rfb.width': { - category: 'zeek', - description: 'Width of the screen that is being shared. ', - name: 'zeek.rfb.width', - type: 'integer', + 'netflow.netscaler_unknown301': { + category: 'netflow', + name: 'netflow.netscaler_unknown301', + type: 'long', }, - 'zeek.rfb.height': { - category: 'zeek', - description: 'Height of the screen that is being shared. ', - name: 'zeek.rfb.height', - type: 'integer', + 'netflow.netscaler_unknown302': { + category: 'netflow', + name: 'netflow.netscaler_unknown302', + type: 'long', }, - 'zeek.sip.transaction_depth': { - category: 'zeek', - description: - 'Represents the pipelined depth into the connection of this request/response transaction. ', - name: 'zeek.sip.transaction_depth', - type: 'integer', + 'netflow.netscaler_unknown303': { + category: 'netflow', + name: 'netflow.netscaler_unknown303', + type: 'long', }, - 'zeek.sip.sequence.method': { - category: 'zeek', - description: 'Verb used in the SIP request (INVITE, REGISTER etc.). ', - name: 'zeek.sip.sequence.method', - type: 'keyword', + 'netflow.netscaler_unknown304': { + category: 'netflow', + name: 'netflow.netscaler_unknown304', + type: 'long', }, - 'zeek.sip.sequence.number': { - category: 'zeek', - description: 'Contents of the CSeq: header from the client. ', - name: 'zeek.sip.sequence.number', - type: 'keyword', + 'netflow.netscaler_unknown305': { + category: 'netflow', + name: 'netflow.netscaler_unknown305', + type: 'long', }, - 'zeek.sip.uri': { - category: 'zeek', - description: 'URI used in the request. ', - name: 'zeek.sip.uri', - type: 'keyword', + 'netflow.netscaler_unknown306': { + category: 'netflow', + name: 'netflow.netscaler_unknown306', + type: 'long', }, - 'zeek.sip.date': { - category: 'zeek', - description: 'Contents of the Date: header from the client. ', - name: 'zeek.sip.date', - type: 'keyword', + 'netflow.netscaler_unknown307': { + category: 'netflow', + name: 'netflow.netscaler_unknown307', + type: 'long', }, - 'zeek.sip.request.from': { - category: 'zeek', - description: - "Contents of the request From: header Note: The tag= value that's usually appended to the sender is stripped off and not logged. ", - name: 'zeek.sip.request.from', - type: 'keyword', + 'netflow.netscaler_unknown308': { + category: 'netflow', + name: 'netflow.netscaler_unknown308', + type: 'long', }, - 'zeek.sip.request.to': { - category: 'zeek', - description: 'Contents of the To: header. ', - name: 'zeek.sip.request.to', - type: 'keyword', + 'netflow.netscaler_unknown309': { + category: 'netflow', + name: 'netflow.netscaler_unknown309', + type: 'long', }, - 'zeek.sip.request.path': { - category: 'zeek', - description: 'The client message transmission path, as extracted from the headers. ', - name: 'zeek.sip.request.path', - type: 'keyword', + 'netflow.netscaler_unknown310': { + category: 'netflow', + name: 'netflow.netscaler_unknown310', + type: 'long', }, - 'zeek.sip.request.body_length': { - category: 'zeek', - description: 'Contents of the Content-Length: header from the client. ', - name: 'zeek.sip.request.body_length', + 'netflow.netscaler_unknown311': { + category: 'netflow', + name: 'netflow.netscaler_unknown311', type: 'long', }, - 'zeek.sip.response.from': { - category: 'zeek', - description: - "Contents of the response From: header Note: The tag= value that's usually appended to the sender is stripped off and not logged. ", - name: 'zeek.sip.response.from', - type: 'keyword', + 'netflow.netscaler_unknown312': { + category: 'netflow', + name: 'netflow.netscaler_unknown312', + type: 'long', }, - 'zeek.sip.response.to': { - category: 'zeek', - description: 'Contents of the response To: header. ', - name: 'zeek.sip.response.to', - type: 'keyword', + 'netflow.netscaler_unknown313': { + category: 'netflow', + name: 'netflow.netscaler_unknown313', + type: 'long', }, - 'zeek.sip.response.path': { - category: 'zeek', - description: 'The server message transmission path, as extracted from the headers. ', - name: 'zeek.sip.response.path', - type: 'keyword', + 'netflow.netscaler_unknown314': { + category: 'netflow', + name: 'netflow.netscaler_unknown314', + type: 'long', }, - 'zeek.sip.response.body_length': { - category: 'zeek', - description: 'Contents of the Content-Length: header from the server. ', - name: 'zeek.sip.response.body_length', + 'netflow.netscaler_unknown315': { + category: 'netflow', + name: 'netflow.netscaler_unknown315', type: 'long', }, - 'zeek.sip.reply_to': { - category: 'zeek', - description: 'Contents of the Reply-To: header. ', - name: 'zeek.sip.reply_to', + 'netflow.netscaler_unknown316': { + category: 'netflow', + name: 'netflow.netscaler_unknown316', type: 'keyword', }, - 'zeek.sip.call_id': { - category: 'zeek', - description: 'Contents of the Call-ID: header from the client. ', - name: 'zeek.sip.call_id', - type: 'keyword', + 'netflow.netscaler_unknown317': { + category: 'netflow', + name: 'netflow.netscaler_unknown317', + type: 'long', }, - 'zeek.sip.subject': { - category: 'zeek', - description: 'Contents of the Subject: header from the client. ', - name: 'zeek.sip.subject', - type: 'keyword', + 'netflow.netscaler_unknown318': { + category: 'netflow', + name: 'netflow.netscaler_unknown318', + type: 'long', }, - 'zeek.sip.user_agent': { - category: 'zeek', - description: 'Contents of the User-Agent: header from the client. ', - name: 'zeek.sip.user_agent', + 'netflow.netscaler_unknown319': { + category: 'netflow', + name: 'netflow.netscaler_unknown319', type: 'keyword', }, - 'zeek.sip.status.code': { - category: 'zeek', - description: 'Status code returned by the server. ', - name: 'zeek.sip.status.code', + 'netflow.netscaler_unknown320': { + category: 'netflow', + name: 'netflow.netscaler_unknown320', type: 'integer', }, - 'zeek.sip.status.msg': { - category: 'zeek', - description: 'Status message returned by the server. ', - name: 'zeek.sip.status.msg', - type: 'keyword', + 'netflow.netscaler_unknown321': { + category: 'netflow', + name: 'netflow.netscaler_unknown321', + type: 'long', }, - 'zeek.sip.warning': { - category: 'zeek', - description: 'Contents of the Warning: header. ', - name: 'zeek.sip.warning', - type: 'keyword', + 'netflow.netscaler_unknown322': { + category: 'netflow', + name: 'netflow.netscaler_unknown322', + type: 'long', }, - 'zeek.sip.content_type': { - category: 'zeek', - description: 'Contents of the Content-Type: header from the server. ', - name: 'zeek.sip.content_type', - type: 'keyword', + 'netflow.netscaler_unknown323': { + category: 'netflow', + name: 'netflow.netscaler_unknown323', + type: 'integer', }, - 'zeek.smb_cmd.command': { - category: 'zeek', - description: 'The command sent by the client. ', - name: 'zeek.smb_cmd.command', - type: 'keyword', + 'netflow.netscaler_unknown324': { + category: 'netflow', + name: 'netflow.netscaler_unknown324', + type: 'integer', }, - 'zeek.smb_cmd.sub_command': { - category: 'zeek', - description: 'The subcommand sent by the client, if present. ', - name: 'zeek.smb_cmd.sub_command', - type: 'keyword', + 'netflow.netscaler_unknown325': { + category: 'netflow', + name: 'netflow.netscaler_unknown325', + type: 'integer', }, - 'zeek.smb_cmd.argument': { - category: 'zeek', - description: 'Command argument sent by the client, if any. ', - name: 'zeek.smb_cmd.argument', - type: 'keyword', + 'netflow.netscaler_unknown326': { + category: 'netflow', + name: 'netflow.netscaler_unknown326', + type: 'integer', }, - 'zeek.smb_cmd.status': { - category: 'zeek', - description: "Server reply to the client's command. ", - name: 'zeek.smb_cmd.status', - type: 'keyword', + 'netflow.netscaler_unknown327': { + category: 'netflow', + name: 'netflow.netscaler_unknown327', + type: 'long', }, - 'zeek.smb_cmd.rtt': { - category: 'zeek', - description: 'Round trip time from the request to the response. ', - name: 'zeek.smb_cmd.rtt', - type: 'double', + 'netflow.netscaler_unknown328': { + category: 'netflow', + name: 'netflow.netscaler_unknown328', + type: 'integer', }, - 'zeek.smb_cmd.version': { - category: 'zeek', - description: 'Version of SMB for the command. ', - name: 'zeek.smb_cmd.version', - type: 'keyword', + 'netflow.netscaler_unknown329': { + category: 'netflow', + name: 'netflow.netscaler_unknown329', + type: 'integer', }, - 'zeek.smb_cmd.username': { - category: 'zeek', - description: 'Authenticated username, if available. ', - name: 'zeek.smb_cmd.username', - type: 'keyword', + 'netflow.netscaler_unknown330': { + category: 'netflow', + name: 'netflow.netscaler_unknown330', + type: 'integer', }, - 'zeek.smb_cmd.tree': { - category: 'zeek', - description: - 'If this is related to a tree, this is the tree that was used for the current command. ', - name: 'zeek.smb_cmd.tree', - type: 'keyword', + 'netflow.netscaler_unknown331': { + category: 'netflow', + name: 'netflow.netscaler_unknown331', + type: 'integer', }, - 'zeek.smb_cmd.tree_service': { - category: 'zeek', - description: 'The type of tree (disk share, printer share, named pipe, etc.). ', - name: 'zeek.smb_cmd.tree_service', - type: 'keyword', + 'netflow.netscaler_unknown332': { + category: 'netflow', + name: 'netflow.netscaler_unknown332', + type: 'long', }, - 'zeek.smb_cmd.file.name': { - category: 'zeek', - description: 'Filename if one was seen. ', - name: 'zeek.smb_cmd.file.name', + 'netflow.netscaler_unknown333': { + category: 'netflow', + name: 'netflow.netscaler_unknown333', type: 'keyword', }, - 'zeek.smb_cmd.file.action': { - category: 'zeek', - description: 'Action this log record represents. ', - name: 'zeek.smb_cmd.file.action', + 'netflow.netscaler_unknown334': { + category: 'netflow', + name: 'netflow.netscaler_unknown334', type: 'keyword', }, - 'zeek.smb_cmd.file.uid': { - category: 'zeek', - description: 'UID of the referenced file. ', - name: 'zeek.smb_cmd.file.uid', - type: 'keyword', + 'netflow.netscaler_unknown335': { + category: 'netflow', + name: 'netflow.netscaler_unknown335', + type: 'long', + }, + 'netflow.netscaler_unknown336': { + category: 'netflow', + name: 'netflow.netscaler_unknown336', + type: 'long', + }, + 'netflow.netscaler_unknown337': { + category: 'netflow', + name: 'netflow.netscaler_unknown337', + type: 'long', + }, + 'netflow.netscaler_unknown338': { + category: 'netflow', + name: 'netflow.netscaler_unknown338', + type: 'long', + }, + 'netflow.netscaler_unknown339': { + category: 'netflow', + name: 'netflow.netscaler_unknown339', + type: 'long', + }, + 'netflow.netscaler_unknown340': { + category: 'netflow', + name: 'netflow.netscaler_unknown340', + type: 'long', + }, + 'netflow.netscaler_unknown341': { + category: 'netflow', + name: 'netflow.netscaler_unknown341', + type: 'long', }, - 'zeek.smb_cmd.file.host.tx': { - category: 'zeek', - description: 'Address of the transmitting host. ', - name: 'zeek.smb_cmd.file.host.tx', - type: 'ip', + 'netflow.netscaler_unknown342': { + category: 'netflow', + name: 'netflow.netscaler_unknown342', + type: 'long', }, - 'zeek.smb_cmd.file.host.rx': { - category: 'zeek', - description: 'Address of the receiving host. ', - name: 'zeek.smb_cmd.file.host.rx', - type: 'ip', + 'netflow.netscaler_unknown343': { + category: 'netflow', + name: 'netflow.netscaler_unknown343', + type: 'long', }, - 'zeek.smb_cmd.smb1_offered_dialects': { - category: 'zeek', - description: - 'Present if base/protocols/smb/smb1-main.bro is loaded. Dialects offered by the client. ', - name: 'zeek.smb_cmd.smb1_offered_dialects', - type: 'keyword', + 'netflow.netscaler_unknown344': { + category: 'netflow', + name: 'netflow.netscaler_unknown344', + type: 'long', }, - 'zeek.smb_cmd.smb2_offered_dialects': { - category: 'zeek', - description: - 'Present if base/protocols/smb/smb2-main.bro is loaded. Dialects offered by the client. ', - name: 'zeek.smb_cmd.smb2_offered_dialects', - type: 'integer', + 'netflow.netscaler_unknown345': { + category: 'netflow', + name: 'netflow.netscaler_unknown345', + type: 'long', }, - 'zeek.smb_files.action': { - category: 'zeek', - description: 'Action this log record represents. ', - name: 'zeek.smb_files.action', - type: 'keyword', + 'netflow.netscaler_unknown346': { + category: 'netflow', + name: 'netflow.netscaler_unknown346', + type: 'long', }, - 'zeek.smb_files.fid': { - category: 'zeek', - description: 'ID referencing this file. ', - name: 'zeek.smb_files.fid', + 'netflow.netscaler_unknown347': { + category: 'netflow', + name: 'netflow.netscaler_unknown347', + type: 'long', + }, + 'netflow.netscaler_unknown348': { + category: 'netflow', + name: 'netflow.netscaler_unknown348', type: 'integer', }, - 'zeek.smb_files.name': { - category: 'zeek', - description: 'Filename if one was seen. ', - name: 'zeek.smb_files.name', + 'netflow.netscaler_unknown349': { + category: 'netflow', + name: 'netflow.netscaler_unknown349', type: 'keyword', }, - 'zeek.smb_files.path': { - category: 'zeek', - description: 'Path pulled from the tree this file was transferred to or from. ', - name: 'zeek.smb_files.path', + 'netflow.netscaler_unknown350': { + category: 'netflow', + name: 'netflow.netscaler_unknown350', type: 'keyword', }, - 'zeek.smb_files.previous_name': { - category: 'zeek', - description: "If the rename action was seen, this will be the file's previous name. ", - name: 'zeek.smb_files.previous_name', + 'netflow.netscaler_unknown351': { + category: 'netflow', + name: 'netflow.netscaler_unknown351', type: 'keyword', }, - 'zeek.smb_files.size': { - category: 'zeek', - description: 'Byte size of the file. ', - name: 'zeek.smb_files.size', + 'netflow.netscaler_unknown352': { + category: 'netflow', + name: 'netflow.netscaler_unknown352', + type: 'integer', + }, + 'netflow.netscaler_unknown353': { + category: 'netflow', + name: 'netflow.netscaler_unknown353', type: 'long', }, - 'zeek.smb_files.times.accessed': { - category: 'zeek', - description: "The file's access time. ", - name: 'zeek.smb_files.times.accessed', - type: 'date', + 'netflow.netscaler_unknown354': { + category: 'netflow', + name: 'netflow.netscaler_unknown354', + type: 'long', }, - 'zeek.smb_files.times.changed': { - category: 'zeek', - description: "The file's change time. ", - name: 'zeek.smb_files.times.changed', - type: 'date', + 'netflow.netscaler_unknown355': { + category: 'netflow', + name: 'netflow.netscaler_unknown355', + type: 'long', }, - 'zeek.smb_files.times.created': { - category: 'zeek', - description: "The file's create time. ", - name: 'zeek.smb_files.times.created', - type: 'date', + 'netflow.netscaler_unknown356': { + category: 'netflow', + name: 'netflow.netscaler_unknown356', + type: 'long', }, - 'zeek.smb_files.times.modified': { - category: 'zeek', - description: "The file's modify time. ", - name: 'zeek.smb_files.times.modified', - type: 'date', + 'netflow.netscaler_unknown357': { + category: 'netflow', + name: 'netflow.netscaler_unknown357', + type: 'long', }, - 'zeek.smb_files.uuid': { - category: 'zeek', - description: 'UUID referencing this file if DCE/RPC. ', - name: 'zeek.smb_files.uuid', - type: 'keyword', + 'netflow.netscaler_unknown363': { + category: 'netflow', + name: 'netflow.netscaler_unknown363', + type: 'short', }, - 'zeek.smb_mapping.path': { - category: 'zeek', - description: 'Name of the tree path. ', - name: 'zeek.smb_mapping.path', - type: 'keyword', + 'netflow.netscaler_unknown383': { + category: 'netflow', + name: 'netflow.netscaler_unknown383', + type: 'short', }, - 'zeek.smb_mapping.service': { - category: 'zeek', - description: 'The type of resource of the tree (disk share, printer share, named pipe, etc.). ', - name: 'zeek.smb_mapping.service', - type: 'keyword', + 'netflow.netscaler_unknown391': { + category: 'netflow', + name: 'netflow.netscaler_unknown391', + type: 'long', }, - 'zeek.smb_mapping.native_file_system': { - category: 'zeek', - description: 'File system of the tree. ', - name: 'zeek.smb_mapping.native_file_system', - type: 'keyword', + 'netflow.netscaler_unknown398': { + category: 'netflow', + name: 'netflow.netscaler_unknown398', + type: 'long', }, - 'zeek.smb_mapping.share_type': { - category: 'zeek', - description: - 'If this is SMB2, a share type will be included. For SMB1, the type of share will be deduced and included as well. ', - name: 'zeek.smb_mapping.share_type', - type: 'keyword', + 'netflow.netscaler_unknown404': { + category: 'netflow', + name: 'netflow.netscaler_unknown404', + type: 'long', }, - 'zeek.smtp.transaction_depth': { - category: 'zeek', - description: - 'A count to represent the depth of this message transaction in a single connection where multiple messages were transferred. ', - name: 'zeek.smtp.transaction_depth', - type: 'integer', + 'netflow.netscaler_unknown405': { + category: 'netflow', + name: 'netflow.netscaler_unknown405', + type: 'long', }, - 'zeek.smtp.helo': { - category: 'zeek', - description: 'Contents of the Helo header. ', - name: 'zeek.smtp.helo', - type: 'keyword', + 'netflow.netscaler_unknown427': { + category: 'netflow', + name: 'netflow.netscaler_unknown427', + type: 'long', }, - 'zeek.smtp.mail_from': { - category: 'zeek', - description: 'Email addresses found in the MAIL FROM header. ', - name: 'zeek.smtp.mail_from', - type: 'keyword', + 'netflow.netscaler_unknown429': { + category: 'netflow', + name: 'netflow.netscaler_unknown429', + type: 'short', }, - 'zeek.smtp.rcpt_to': { - category: 'zeek', - description: 'Email addresses found in the RCPT TO header. ', - name: 'zeek.smtp.rcpt_to', - type: 'keyword', + 'netflow.netscaler_unknown432': { + category: 'netflow', + name: 'netflow.netscaler_unknown432', + type: 'short', }, - 'zeek.smtp.date': { - category: 'zeek', - description: 'Contents of the Date header. ', - name: 'zeek.smtp.date', - type: 'date', + 'netflow.netscaler_unknown433': { + category: 'netflow', + name: 'netflow.netscaler_unknown433', + type: 'short', }, - 'zeek.smtp.from': { - category: 'zeek', - description: 'Contents of the From header. ', - name: 'zeek.smtp.from', - type: 'keyword', + 'netflow.netscaler_unknown453': { + category: 'netflow', + name: 'netflow.netscaler_unknown453', + type: 'long', }, - 'zeek.smtp.to': { - category: 'zeek', - description: 'Contents of the To header. ', - name: 'zeek.smtp.to', - type: 'keyword', + 'netflow.netscaler_unknown465': { + category: 'netflow', + name: 'netflow.netscaler_unknown465', + type: 'long', }, - 'zeek.smtp.cc': { - category: 'zeek', - description: 'Contents of the CC header. ', - name: 'zeek.smtp.cc', - type: 'keyword', + 'netflow.new_connection_delta_count': { + category: 'netflow', + name: 'netflow.new_connection_delta_count', + type: 'long', }, - 'zeek.smtp.reply_to': { - category: 'zeek', - description: 'Contents of the ReplyTo header. ', - name: 'zeek.smtp.reply_to', - type: 'keyword', + 'netflow.next_header_ipv6': { + category: 'netflow', + name: 'netflow.next_header_ipv6', + type: 'short', }, - 'zeek.smtp.msg_id': { - category: 'zeek', - description: 'Contents of the MsgID header. ', - name: 'zeek.smtp.msg_id', - type: 'keyword', + 'netflow.non_empty_packet_count': { + category: 'netflow', + name: 'netflow.non_empty_packet_count', + type: 'long', }, - 'zeek.smtp.in_reply_to': { - category: 'zeek', - description: 'Contents of the In-Reply-To header. ', - name: 'zeek.smtp.in_reply_to', - type: 'keyword', + 'netflow.not_sent_flow_total_count': { + category: 'netflow', + name: 'netflow.not_sent_flow_total_count', + type: 'long', }, - 'zeek.smtp.subject': { - category: 'zeek', - description: 'Contents of the Subject header. ', - name: 'zeek.smtp.subject', - type: 'keyword', + 'netflow.not_sent_layer2_octet_total_count': { + category: 'netflow', + name: 'netflow.not_sent_layer2_octet_total_count', + type: 'long', }, - 'zeek.smtp.x_originating_ip': { - category: 'zeek', - description: 'Contents of the X-Originating-IP header. ', - name: 'zeek.smtp.x_originating_ip', - type: 'keyword', + 'netflow.not_sent_octet_total_count': { + category: 'netflow', + name: 'netflow.not_sent_octet_total_count', + type: 'long', }, - 'zeek.smtp.first_received': { - category: 'zeek', - description: 'Contents of the first Received header. ', - name: 'zeek.smtp.first_received', - type: 'keyword', + 'netflow.not_sent_packet_total_count': { + category: 'netflow', + name: 'netflow.not_sent_packet_total_count', + type: 'long', }, - 'zeek.smtp.second_received': { - category: 'zeek', - description: 'Contents of the second Received header. ', - name: 'zeek.smtp.second_received', - type: 'keyword', + 'netflow.observation_domain_id': { + category: 'netflow', + name: 'netflow.observation_domain_id', + type: 'long', }, - 'zeek.smtp.last_reply': { - category: 'zeek', - description: 'The last message that the server sent to the client. ', - name: 'zeek.smtp.last_reply', + 'netflow.observation_domain_name': { + category: 'netflow', + name: 'netflow.observation_domain_name', type: 'keyword', }, - 'zeek.smtp.path': { - category: 'zeek', - description: 'The message transmission path, as extracted from the headers. ', - name: 'zeek.smtp.path', - type: 'ip', + 'netflow.observation_point_id': { + category: 'netflow', + name: 'netflow.observation_point_id', + type: 'long', }, - 'zeek.smtp.user_agent': { - category: 'zeek', - description: 'Value of the User-Agent header from the client. ', - name: 'zeek.smtp.user_agent', - type: 'keyword', + 'netflow.observation_point_type': { + category: 'netflow', + name: 'netflow.observation_point_type', + type: 'short', }, - 'zeek.smtp.tls': { - category: 'zeek', - description: 'Indicates that the connection has switched to using TLS. ', - name: 'zeek.smtp.tls', - type: 'boolean', + 'netflow.observation_time_microseconds': { + category: 'netflow', + name: 'netflow.observation_time_microseconds', + type: 'date', }, - 'zeek.smtp.process_received_from': { - category: 'zeek', - description: 'Indicates if the "Received: from" headers should still be processed. ', - name: 'zeek.smtp.process_received_from', - type: 'boolean', + 'netflow.observation_time_milliseconds': { + category: 'netflow', + name: 'netflow.observation_time_milliseconds', + type: 'date', }, - 'zeek.smtp.has_client_activity': { - category: 'zeek', - description: 'Indicates if client activity has been seen, but not yet logged. ', - name: 'zeek.smtp.has_client_activity', - type: 'boolean', + 'netflow.observation_time_nanoseconds': { + category: 'netflow', + name: 'netflow.observation_time_nanoseconds', + type: 'date', }, - 'zeek.smtp.fuids': { - category: 'zeek', - description: - '(present if base/protocols/smtp/files.bro is loaded) An ordered vector of file unique IDs seen attached to the message. ', - name: 'zeek.smtp.fuids', - type: 'keyword', + 'netflow.observation_time_seconds': { + category: 'netflow', + name: 'netflow.observation_time_seconds', + type: 'date', }, - 'zeek.smtp.is_webmail': { - category: 'zeek', - description: 'Indicates if the message was sent through a webmail interface. ', - name: 'zeek.smtp.is_webmail', - type: 'boolean', + 'netflow.observed_flow_total_count': { + category: 'netflow', + name: 'netflow.observed_flow_total_count', + type: 'long', }, - 'zeek.snmp.duration': { - category: 'zeek', - description: - 'The amount of time between the first packet beloning to the SNMP session and the latest one seen. ', - name: 'zeek.snmp.duration', - type: 'double', + 'netflow.octet_delta_count': { + category: 'netflow', + name: 'netflow.octet_delta_count', + type: 'long', }, - 'zeek.snmp.version': { - category: 'zeek', - description: 'The version of SNMP being used. ', - name: 'zeek.snmp.version', - type: 'keyword', + 'netflow.octet_delta_sum_of_squares': { + category: 'netflow', + name: 'netflow.octet_delta_sum_of_squares', + type: 'long', }, - 'zeek.snmp.community': { - category: 'zeek', - description: - "The community string of the first SNMP packet associated with the session. This is used as part of SNMP's (v1 and v2c) administrative/security framework. See RFC 1157 or RFC 1901. ", - name: 'zeek.snmp.community', - type: 'keyword', + 'netflow.octet_total_count': { + category: 'netflow', + name: 'netflow.octet_total_count', + type: 'long', }, - 'zeek.snmp.get.requests': { - category: 'zeek', - description: - 'The number of variable bindings in GetRequest/GetNextRequest PDUs seen for the session. ', - name: 'zeek.snmp.get.requests', - type: 'integer', + 'netflow.octet_total_sum_of_squares': { + category: 'netflow', + name: 'netflow.octet_total_sum_of_squares', + type: 'long', }, - 'zeek.snmp.get.bulk_requests': { - category: 'zeek', - description: 'The number of variable bindings in GetBulkRequest PDUs seen for the session. ', - name: 'zeek.snmp.get.bulk_requests', - type: 'integer', + 'netflow.opaque_octets': { + category: 'netflow', + name: 'netflow.opaque_octets', + type: 'short', }, - 'zeek.snmp.get.responses': { - category: 'zeek', - description: - 'The number of variable bindings in GetResponse/Response PDUs seen for the session. ', - name: 'zeek.snmp.get.responses', - type: 'integer', + 'netflow.original_exporter_ipv4_address': { + category: 'netflow', + name: 'netflow.original_exporter_ipv4_address', + type: 'ip', }, - 'zeek.snmp.set.requests': { - category: 'zeek', - description: 'The number of variable bindings in SetRequest PDUs seen for the session. ', - name: 'zeek.snmp.set.requests', - type: 'integer', + 'netflow.original_exporter_ipv6_address': { + category: 'netflow', + name: 'netflow.original_exporter_ipv6_address', + type: 'ip', }, - 'zeek.snmp.display_string': { - category: 'zeek', - description: 'A system description of the SNMP responder endpoint. ', - name: 'zeek.snmp.display_string', - type: 'keyword', + 'netflow.original_flows_completed': { + category: 'netflow', + name: 'netflow.original_flows_completed', + type: 'long', }, - 'zeek.snmp.up_since': { - category: 'zeek', - description: "The time at which the SNMP responder endpoint claims it's been up since. ", - name: 'zeek.snmp.up_since', - type: 'date', + 'netflow.original_flows_initiated': { + category: 'netflow', + name: 'netflow.original_flows_initiated', + type: 'long', }, - 'zeek.socks.version': { - category: 'zeek', - description: 'Protocol version of SOCKS. ', - name: 'zeek.socks.version', - type: 'integer', + 'netflow.original_flows_present': { + category: 'netflow', + name: 'netflow.original_flows_present', + type: 'long', }, - 'zeek.socks.user': { - category: 'zeek', - description: 'Username used to request a login to the proxy. ', - name: 'zeek.socks.user', - type: 'keyword', + 'netflow.original_observation_domain_id': { + category: 'netflow', + name: 'netflow.original_observation_domain_id', + type: 'long', }, - 'zeek.socks.password': { - category: 'zeek', - description: 'Password used to request a login to the proxy. ', - name: 'zeek.socks.password', + 'netflow.os_finger_print': { + category: 'netflow', + name: 'netflow.os_finger_print', type: 'keyword', }, - 'zeek.socks.status': { - category: 'zeek', - description: 'Server status for the attempt at using the proxy. ', - name: 'zeek.socks.status', + 'netflow.os_name': { + category: 'netflow', + name: 'netflow.os_name', type: 'keyword', }, - 'zeek.socks.request.host': { - category: 'zeek', - description: 'Client requested SOCKS address. Could be an address, a name or both. ', - name: 'zeek.socks.request.host', + 'netflow.os_version': { + category: 'netflow', + name: 'netflow.os_version', type: 'keyword', }, - 'zeek.socks.request.port': { - category: 'zeek', - description: 'Client requested port. ', - name: 'zeek.socks.request.port', - type: 'integer', - }, - 'zeek.socks.bound.host': { - category: 'zeek', - description: 'Server bound address. Could be an address, a name or both. ', - name: 'zeek.socks.bound.host', + 'netflow.p2p_technology': { + category: 'netflow', + name: 'netflow.p2p_technology', type: 'keyword', }, - 'zeek.socks.bound.port': { - category: 'zeek', - description: 'Server bound port. ', - name: 'zeek.socks.bound.port', - type: 'integer', + 'netflow.packet_delta_count': { + category: 'netflow', + name: 'netflow.packet_delta_count', + type: 'long', }, - 'zeek.socks.capture_password': { - category: 'zeek', - description: 'Determines if the password will be captured for this request. ', - name: 'zeek.socks.capture_password', - type: 'boolean', + 'netflow.packet_total_count': { + category: 'netflow', + name: 'netflow.packet_total_count', + type: 'long', }, - 'zeek.ssh.client': { - category: 'zeek', - description: "The client's version string. ", - name: 'zeek.ssh.client', - type: 'keyword', + 'netflow.padding_octets': { + category: 'netflow', + name: 'netflow.padding_octets', + type: 'short', }, - 'zeek.ssh.direction': { - category: 'zeek', - description: - 'Direction of the connection. If the client was a local host logging into an external host, this would be OUTBOUND. INBOUND would be set for the opposite situation. ', - name: 'zeek.ssh.direction', + 'netflow.payload': { + category: 'netflow', + name: 'netflow.payload', type: 'keyword', }, - 'zeek.ssh.host_key': { - category: 'zeek', - description: "The server's key thumbprint. ", - name: 'zeek.ssh.host_key', - type: 'keyword', + 'netflow.payload_entropy': { + category: 'netflow', + name: 'netflow.payload_entropy', + type: 'short', }, - 'zeek.ssh.server': { - category: 'zeek', - description: "The server's version string. ", - name: 'zeek.ssh.server', - type: 'keyword', + 'netflow.payload_length_ipv6': { + category: 'netflow', + name: 'netflow.payload_length_ipv6', + type: 'integer', + }, + 'netflow.policy_qos_classification_hierarchy': { + category: 'netflow', + name: 'netflow.policy_qos_classification_hierarchy', + type: 'long', + }, + 'netflow.policy_qos_queue_index': { + category: 'netflow', + name: 'netflow.policy_qos_queue_index', + type: 'long', + }, + 'netflow.policy_qos_queuedrops': { + category: 'netflow', + name: 'netflow.policy_qos_queuedrops', + type: 'long', }, - 'zeek.ssh.version': { - category: 'zeek', - description: 'SSH major version (1 or 2). ', - name: 'zeek.ssh.version', + 'netflow.policy_qos_queueindex': { + category: 'netflow', + name: 'netflow.policy_qos_queueindex', + type: 'long', + }, + 'netflow.port_id': { + category: 'netflow', + name: 'netflow.port_id', + type: 'long', + }, + 'netflow.port_range_end': { + category: 'netflow', + name: 'netflow.port_range_end', type: 'integer', }, - 'zeek.ssh.algorithm.cipher': { - category: 'zeek', - description: 'The encryption algorithm in use. ', - name: 'zeek.ssh.algorithm.cipher', - type: 'keyword', + 'netflow.port_range_num_ports': { + category: 'netflow', + name: 'netflow.port_range_num_ports', + type: 'integer', }, - 'zeek.ssh.algorithm.compression': { - category: 'zeek', - description: 'The compression algorithm in use. ', - name: 'zeek.ssh.algorithm.compression', - type: 'keyword', + 'netflow.port_range_start': { + category: 'netflow', + name: 'netflow.port_range_start', + type: 'integer', }, - 'zeek.ssh.algorithm.host_key': { - category: 'zeek', - description: "The server host key's algorithm. ", - name: 'zeek.ssh.algorithm.host_key', - type: 'keyword', + 'netflow.port_range_step_size': { + category: 'netflow', + name: 'netflow.port_range_step_size', + type: 'integer', }, - 'zeek.ssh.algorithm.key_exchange': { - category: 'zeek', - description: 'The key exchange algorithm in use. ', - name: 'zeek.ssh.algorithm.key_exchange', + 'netflow.post_destination_mac_address': { + category: 'netflow', + name: 'netflow.post_destination_mac_address', type: 'keyword', }, - 'zeek.ssh.algorithm.mac': { - category: 'zeek', - description: 'The signing (MAC) algorithm in use. ', - name: 'zeek.ssh.algorithm.mac', - type: 'keyword', + 'netflow.post_dot1q_customer_vlan_id': { + category: 'netflow', + name: 'netflow.post_dot1q_customer_vlan_id', + type: 'integer', }, - 'zeek.ssh.auth.attempts': { - category: 'zeek', - description: - "The number of authentication attemps we observed. There's always at least one, since some servers might support no authentication at all. It's important to note that not all of these are failures, since some servers require two-factor auth (e.g. password AND pubkey). ", - name: 'zeek.ssh.auth.attempts', + 'netflow.post_dot1q_vlan_id': { + category: 'netflow', + name: 'netflow.post_dot1q_vlan_id', type: 'integer', }, - 'zeek.ssh.auth.success': { - category: 'zeek', - description: 'Authentication result. ', - name: 'zeek.ssh.auth.success', - type: 'boolean', + 'netflow.post_ip_class_of_service': { + category: 'netflow', + name: 'netflow.post_ip_class_of_service', + type: 'short', }, - 'zeek.ssl.version': { - category: 'zeek', - description: 'SSL/TLS version that was logged. ', - name: 'zeek.ssl.version', - type: 'keyword', + 'netflow.post_ip_diff_serv_code_point': { + category: 'netflow', + name: 'netflow.post_ip_diff_serv_code_point', + type: 'short', }, - 'zeek.ssl.cipher': { - category: 'zeek', - description: 'SSL/TLS cipher suite that was logged. ', - name: 'zeek.ssl.cipher', - type: 'keyword', + 'netflow.post_ip_precedence': { + category: 'netflow', + name: 'netflow.post_ip_precedence', + type: 'short', }, - 'zeek.ssl.curve': { - category: 'zeek', - description: 'Elliptic curve that was logged when using ECDH/ECDHE. ', - name: 'zeek.ssl.curve', - type: 'keyword', + 'netflow.post_layer2_octet_delta_count': { + category: 'netflow', + name: 'netflow.post_layer2_octet_delta_count', + type: 'long', }, - 'zeek.ssl.resumed': { - category: 'zeek', - description: - 'Flag to indicate if the session was resumed reusing the key material exchanged in an earlier connection. ', - name: 'zeek.ssl.resumed', - type: 'boolean', + 'netflow.post_layer2_octet_total_count': { + category: 'netflow', + name: 'netflow.post_layer2_octet_total_count', + type: 'long', }, - 'zeek.ssl.next_protocol': { - category: 'zeek', - description: - 'Next protocol the server chose using the application layer next protocol extension. ', - name: 'zeek.ssl.next_protocol', - type: 'keyword', + 'netflow.post_mcast_layer2_octet_delta_count': { + category: 'netflow', + name: 'netflow.post_mcast_layer2_octet_delta_count', + type: 'long', }, - 'zeek.ssl.established': { - category: 'zeek', - description: 'Flag to indicate if this ssl session has been established successfully. ', - name: 'zeek.ssl.established', - type: 'boolean', + 'netflow.post_mcast_layer2_octet_total_count': { + category: 'netflow', + name: 'netflow.post_mcast_layer2_octet_total_count', + type: 'long', }, - 'zeek.ssl.validation.status': { - category: 'zeek', - description: 'Result of certificate validation for this connection. ', - name: 'zeek.ssl.validation.status', - type: 'keyword', + 'netflow.post_mcast_octet_delta_count': { + category: 'netflow', + name: 'netflow.post_mcast_octet_delta_count', + type: 'long', }, - 'zeek.ssl.validation.code': { - category: 'zeek', - description: - 'Result of certificate validation for this connection, given as OpenSSL validation code. ', - name: 'zeek.ssl.validation.code', - type: 'keyword', + 'netflow.post_mcast_octet_total_count': { + category: 'netflow', + name: 'netflow.post_mcast_octet_total_count', + type: 'long', }, - 'zeek.ssl.last_alert': { - category: 'zeek', - description: 'Last alert that was seen during the connection. ', - name: 'zeek.ssl.last_alert', - type: 'keyword', + 'netflow.post_mcast_packet_delta_count': { + category: 'netflow', + name: 'netflow.post_mcast_packet_delta_count', + type: 'long', }, - 'zeek.ssl.server.name': { - category: 'zeek', - description: - 'Value of the Server Name Indicator SSL/TLS extension. It indicates the server name that the client was requesting. ', - name: 'zeek.ssl.server.name', - type: 'keyword', + 'netflow.post_mcast_packet_total_count': { + category: 'netflow', + name: 'netflow.post_mcast_packet_total_count', + type: 'long', }, - 'zeek.ssl.server.cert_chain': { - category: 'zeek', - description: - 'Chain of certificates offered by the server to validate its complete signing chain. ', - name: 'zeek.ssl.server.cert_chain', - type: 'keyword', + 'netflow.post_mpls_top_label_exp': { + category: 'netflow', + name: 'netflow.post_mpls_top_label_exp', + type: 'short', }, - 'zeek.ssl.server.cert_chain_fuids': { - category: 'zeek', - description: - 'An ordered vector of certificate file identifiers for the certificates offered by the server. ', - name: 'zeek.ssl.server.cert_chain_fuids', - type: 'keyword', + 'netflow.post_napt_destination_transport_port': { + category: 'netflow', + name: 'netflow.post_napt_destination_transport_port', + type: 'integer', }, - 'zeek.ssl.server.issuer.common_name': { - category: 'zeek', - description: 'Common name of the signer of the X.509 certificate offered by the server. ', - name: 'zeek.ssl.server.issuer.common_name', - type: 'keyword', + 'netflow.post_napt_source_transport_port': { + category: 'netflow', + name: 'netflow.post_napt_source_transport_port', + type: 'integer', }, - 'zeek.ssl.server.issuer.country': { - category: 'zeek', - description: 'Country code of the signer of the X.509 certificate offered by the server. ', - name: 'zeek.ssl.server.issuer.country', - type: 'keyword', + 'netflow.post_nat_destination_ipv4_address': { + category: 'netflow', + name: 'netflow.post_nat_destination_ipv4_address', + type: 'ip', }, - 'zeek.ssl.server.issuer.locality': { - category: 'zeek', - description: 'Locality of the signer of the X.509 certificate offered by the server. ', - name: 'zeek.ssl.server.issuer.locality', - type: 'keyword', + 'netflow.post_nat_destination_ipv6_address': { + category: 'netflow', + name: 'netflow.post_nat_destination_ipv6_address', + type: 'ip', }, - 'zeek.ssl.server.issuer.organization': { - category: 'zeek', - description: 'Organization of the signer of the X.509 certificate offered by the server. ', - name: 'zeek.ssl.server.issuer.organization', - type: 'keyword', + 'netflow.post_nat_source_ipv4_address': { + category: 'netflow', + name: 'netflow.post_nat_source_ipv4_address', + type: 'ip', }, - 'zeek.ssl.server.issuer.organizational_unit': { - category: 'zeek', - description: - 'Organizational unit of the signer of the X.509 certificate offered by the server. ', - name: 'zeek.ssl.server.issuer.organizational_unit', - type: 'keyword', + 'netflow.post_nat_source_ipv6_address': { + category: 'netflow', + name: 'netflow.post_nat_source_ipv6_address', + type: 'ip', }, - 'zeek.ssl.server.issuer.state': { - category: 'zeek', - description: - 'State or province name of the signer of the X.509 certificate offered by the server. ', - name: 'zeek.ssl.server.issuer.state', - type: 'keyword', + 'netflow.post_octet_delta_count': { + category: 'netflow', + name: 'netflow.post_octet_delta_count', + type: 'long', }, - 'zeek.ssl.server.subject.common_name': { - category: 'zeek', - description: 'Common name of the X.509 certificate offered by the server. ', - name: 'zeek.ssl.server.subject.common_name', - type: 'keyword', + 'netflow.post_octet_total_count': { + category: 'netflow', + name: 'netflow.post_octet_total_count', + type: 'long', }, - 'zeek.ssl.server.subject.country': { - category: 'zeek', - description: 'Country code of the X.509 certificate offered by the server. ', - name: 'zeek.ssl.server.subject.country', - type: 'keyword', + 'netflow.post_packet_delta_count': { + category: 'netflow', + name: 'netflow.post_packet_delta_count', + type: 'long', }, - 'zeek.ssl.server.subject.locality': { - category: 'zeek', - description: 'Locality of the X.509 certificate offered by the server. ', - name: 'zeek.ssl.server.subject.locality', - type: 'keyword', + 'netflow.post_packet_total_count': { + category: 'netflow', + name: 'netflow.post_packet_total_count', + type: 'long', }, - 'zeek.ssl.server.subject.organization': { - category: 'zeek', - description: 'Organization of the X.509 certificate offered by the server. ', - name: 'zeek.ssl.server.subject.organization', + 'netflow.post_source_mac_address': { + category: 'netflow', + name: 'netflow.post_source_mac_address', type: 'keyword', }, - 'zeek.ssl.server.subject.organizational_unit': { - category: 'zeek', - description: 'Organizational unit of the X.509 certificate offered by the server. ', - name: 'zeek.ssl.server.subject.organizational_unit', - type: 'keyword', + 'netflow.post_vlan_id': { + category: 'netflow', + name: 'netflow.post_vlan_id', + type: 'integer', }, - 'zeek.ssl.server.subject.state': { - category: 'zeek', - description: 'State or province name of the X.509 certificate offered by the server. ', - name: 'zeek.ssl.server.subject.state', - type: 'keyword', + 'netflow.private_enterprise_number': { + category: 'netflow', + name: 'netflow.private_enterprise_number', + type: 'long', }, - 'zeek.ssl.client.cert_chain': { - category: 'zeek', - description: - 'Chain of certificates offered by the client to validate its complete signing chain. ', - name: 'zeek.ssl.client.cert_chain', + 'netflow.procera_apn': { + category: 'netflow', + name: 'netflow.procera_apn', type: 'keyword', }, - 'zeek.ssl.client.cert_chain_fuids': { - category: 'zeek', - description: - 'An ordered vector of certificate file identifiers for the certificates offered by the client. ', - name: 'zeek.ssl.client.cert_chain_fuids', + 'netflow.procera_base_service': { + category: 'netflow', + name: 'netflow.procera_base_service', type: 'keyword', }, - 'zeek.ssl.client.issuer.common_name': { - category: 'zeek', - description: 'Common name of the signer of the X.509 certificate offered by the client. ', - name: 'zeek.ssl.client.issuer.common_name', + 'netflow.procera_content_categories': { + category: 'netflow', + name: 'netflow.procera_content_categories', type: 'keyword', }, - 'zeek.ssl.client.issuer.country': { - category: 'zeek', - description: 'Country code of the signer of the X.509 certificate offered by the client. ', - name: 'zeek.ssl.client.issuer.country', - type: 'keyword', + 'netflow.procera_device_id': { + category: 'netflow', + name: 'netflow.procera_device_id', + type: 'long', }, - 'zeek.ssl.client.issuer.locality': { - category: 'zeek', - description: 'Locality of the signer of the X.509 certificate offered by the client. ', - name: 'zeek.ssl.client.issuer.locality', - type: 'keyword', + 'netflow.procera_external_rtt': { + category: 'netflow', + name: 'netflow.procera_external_rtt', + type: 'integer', }, - 'zeek.ssl.client.issuer.organization': { - category: 'zeek', - description: 'Organization of the signer of the X.509 certificate offered by the client. ', - name: 'zeek.ssl.client.issuer.organization', + 'netflow.procera_flow_behavior': { + category: 'netflow', + name: 'netflow.procera_flow_behavior', type: 'keyword', }, - 'zeek.ssl.client.issuer.organizational_unit': { - category: 'zeek', - description: - 'Organizational unit of the signer of the X.509 certificate offered by the client. ', - name: 'zeek.ssl.client.issuer.organizational_unit', + 'netflow.procera_ggsn': { + category: 'netflow', + name: 'netflow.procera_ggsn', type: 'keyword', }, - 'zeek.ssl.client.issuer.state': { - category: 'zeek', - description: - 'State or province name of the signer of the X.509 certificate offered by the client. ', - name: 'zeek.ssl.client.issuer.state', + 'netflow.procera_http_content_type': { + category: 'netflow', + name: 'netflow.procera_http_content_type', type: 'keyword', }, - 'zeek.ssl.client.subject.common_name': { - category: 'zeek', - description: 'Common name of the X.509 certificate offered by the client. ', - name: 'zeek.ssl.client.subject.common_name', - type: 'keyword', + 'netflow.procera_http_file_length': { + category: 'netflow', + name: 'netflow.procera_http_file_length', + type: 'long', }, - 'zeek.ssl.client.subject.country': { - category: 'zeek', - description: 'Country code of the X.509 certificate offered by the client. ', - name: 'zeek.ssl.client.subject.country', + 'netflow.procera_http_language': { + category: 'netflow', + name: 'netflow.procera_http_language', type: 'keyword', }, - 'zeek.ssl.client.subject.locality': { - category: 'zeek', - description: 'Locality of the X.509 certificate offered by the client. ', - name: 'zeek.ssl.client.subject.locality', + 'netflow.procera_http_location': { + category: 'netflow', + name: 'netflow.procera_http_location', type: 'keyword', }, - 'zeek.ssl.client.subject.organization': { - category: 'zeek', - description: 'Organization of the X.509 certificate offered by the client. ', - name: 'zeek.ssl.client.subject.organization', + 'netflow.procera_http_referer': { + category: 'netflow', + name: 'netflow.procera_http_referer', type: 'keyword', }, - 'zeek.ssl.client.subject.organizational_unit': { - category: 'zeek', - description: 'Organizational unit of the X.509 certificate offered by the client. ', - name: 'zeek.ssl.client.subject.organizational_unit', + 'netflow.procera_http_request_method': { + category: 'netflow', + name: 'netflow.procera_http_request_method', type: 'keyword', }, - 'zeek.ssl.client.subject.state': { - category: 'zeek', - description: 'State or province name of the X.509 certificate offered by the client. ', - name: 'zeek.ssl.client.subject.state', + 'netflow.procera_http_request_version': { + category: 'netflow', + name: 'netflow.procera_http_request_version', type: 'keyword', }, - 'zeek.stats.peer': { - category: 'zeek', - description: 'Peer that generated this log. Mostly for clusters. ', - name: 'zeek.stats.peer', + 'netflow.procera_http_response_status': { + category: 'netflow', + name: 'netflow.procera_http_response_status', + type: 'integer', + }, + 'netflow.procera_http_url': { + category: 'netflow', + name: 'netflow.procera_http_url', type: 'keyword', }, - 'zeek.stats.memory': { - category: 'zeek', - description: 'Amount of memory currently in use in MB. ', - name: 'zeek.stats.memory', - type: 'integer', + 'netflow.procera_http_user_agent': { + category: 'netflow', + name: 'netflow.procera_http_user_agent', + type: 'keyword', }, - 'zeek.stats.packets.processed': { - category: 'zeek', - description: 'Number of packets processed since the last stats interval. ', - name: 'zeek.stats.packets.processed', + 'netflow.procera_imsi': { + category: 'netflow', + name: 'netflow.procera_imsi', type: 'long', }, - 'zeek.stats.packets.dropped': { - category: 'zeek', - description: - 'Number of packets dropped since the last stats interval if reading live traffic. ', - name: 'zeek.stats.packets.dropped', + 'netflow.procera_incoming_octets': { + category: 'netflow', + name: 'netflow.procera_incoming_octets', type: 'long', }, - 'zeek.stats.packets.received': { - category: 'zeek', - description: - 'Number of packets seen on the link since the last stats interval if reading live traffic. ', - name: 'zeek.stats.packets.received', + 'netflow.procera_incoming_packets': { + category: 'netflow', + name: 'netflow.procera_incoming_packets', type: 'long', }, - 'zeek.stats.bytes.received': { - category: 'zeek', - description: 'Number of bytes received since the last stats interval if reading live traffic. ', - name: 'zeek.stats.bytes.received', + 'netflow.procera_incoming_shaping_drops': { + category: 'netflow', + name: 'netflow.procera_incoming_shaping_drops', type: 'long', }, - 'zeek.stats.connections.tcp.active': { - category: 'zeek', - description: 'TCP connections currently in memory. ', - name: 'zeek.stats.connections.tcp.active', - type: 'integer', - }, - 'zeek.stats.connections.tcp.count': { - category: 'zeek', - description: 'TCP connections seen since last stats interval. ', - name: 'zeek.stats.connections.tcp.count', + 'netflow.procera_incoming_shaping_latency': { + category: 'netflow', + name: 'netflow.procera_incoming_shaping_latency', type: 'integer', }, - 'zeek.stats.connections.udp.active': { - category: 'zeek', - description: 'UDP connections currently in memory. ', - name: 'zeek.stats.connections.udp.active', + 'netflow.procera_internal_rtt': { + category: 'netflow', + name: 'netflow.procera_internal_rtt', type: 'integer', }, - 'zeek.stats.connections.udp.count': { - category: 'zeek', - description: 'UDP connections seen since last stats interval. ', - name: 'zeek.stats.connections.udp.count', - type: 'integer', + 'netflow.procera_local_ipv4_host': { + category: 'netflow', + name: 'netflow.procera_local_ipv4_host', + type: 'ip', }, - 'zeek.stats.connections.icmp.active': { - category: 'zeek', - description: 'ICMP connections currently in memory. ', - name: 'zeek.stats.connections.icmp.active', - type: 'integer', + 'netflow.procera_local_ipv6_host': { + category: 'netflow', + name: 'netflow.procera_local_ipv6_host', + type: 'ip', }, - 'zeek.stats.connections.icmp.count': { - category: 'zeek', - description: 'ICMP connections seen since last stats interval. ', - name: 'zeek.stats.connections.icmp.count', - type: 'integer', + 'netflow.procera_msisdn': { + category: 'netflow', + name: 'netflow.procera_msisdn', + type: 'long', }, - 'zeek.stats.events.processed': { - category: 'zeek', - description: 'Number of events processed since the last stats interval. ', - name: 'zeek.stats.events.processed', - type: 'integer', + 'netflow.procera_outgoing_octets': { + category: 'netflow', + name: 'netflow.procera_outgoing_octets', + type: 'long', }, - 'zeek.stats.events.queued': { - category: 'zeek', - description: 'Number of events that have been queued since the last stats interval. ', - name: 'zeek.stats.events.queued', - type: 'integer', + 'netflow.procera_outgoing_packets': { + category: 'netflow', + name: 'netflow.procera_outgoing_packets', + type: 'long', }, - 'zeek.stats.timers.count': { - category: 'zeek', - description: 'Number of timers scheduled since last stats interval. ', - name: 'zeek.stats.timers.count', - type: 'integer', + 'netflow.procera_outgoing_shaping_drops': { + category: 'netflow', + name: 'netflow.procera_outgoing_shaping_drops', + type: 'long', }, - 'zeek.stats.timers.active': { - category: 'zeek', - description: 'Current number of scheduled timers. ', - name: 'zeek.stats.timers.active', + 'netflow.procera_outgoing_shaping_latency': { + category: 'netflow', + name: 'netflow.procera_outgoing_shaping_latency', type: 'integer', }, - 'zeek.stats.files.count': { - category: 'zeek', - description: 'Number of files seen since last stats interval. ', - name: 'zeek.stats.files.count', - type: 'integer', + 'netflow.procera_property': { + category: 'netflow', + name: 'netflow.procera_property', + type: 'keyword', }, - 'zeek.stats.files.active': { - category: 'zeek', - description: 'Current number of files actively being seen. ', - name: 'zeek.stats.files.active', - type: 'integer', + 'netflow.procera_qoe_incoming_external': { + category: 'netflow', + name: 'netflow.procera_qoe_incoming_external', + type: 'float', }, - 'zeek.stats.dns_requests.count': { - category: 'zeek', - description: 'Number of DNS requests seen since last stats interval. ', - name: 'zeek.stats.dns_requests.count', - type: 'integer', + 'netflow.procera_qoe_incoming_internal': { + category: 'netflow', + name: 'netflow.procera_qoe_incoming_internal', + type: 'float', }, - 'zeek.stats.dns_requests.active': { - category: 'zeek', - description: 'Current number of DNS requests awaiting a reply. ', - name: 'zeek.stats.dns_requests.active', - type: 'integer', + 'netflow.procera_qoe_outgoing_external': { + category: 'netflow', + name: 'netflow.procera_qoe_outgoing_external', + type: 'float', }, - 'zeek.stats.reassembly_size.tcp': { - category: 'zeek', - description: 'Current size of TCP data in reassembly. ', - name: 'zeek.stats.reassembly_size.tcp', - type: 'integer', + 'netflow.procera_qoe_outgoing_internal': { + category: 'netflow', + name: 'netflow.procera_qoe_outgoing_internal', + type: 'float', }, - 'zeek.stats.reassembly_size.file': { - category: 'zeek', - description: 'Current size of File data in reassembly. ', - name: 'zeek.stats.reassembly_size.file', - type: 'integer', + 'netflow.procera_rat': { + category: 'netflow', + name: 'netflow.procera_rat', + type: 'keyword', }, - 'zeek.stats.reassembly_size.frag': { - category: 'zeek', - description: 'Current size of packet fragment data in reassembly. ', - name: 'zeek.stats.reassembly_size.frag', - type: 'integer', + 'netflow.procera_remote_ipv4_host': { + category: 'netflow', + name: 'netflow.procera_remote_ipv4_host', + type: 'ip', }, - 'zeek.stats.reassembly_size.unknown': { - category: 'zeek', - description: 'Current size of unknown data in reassembly (this is only PIA buffer right now). ', - name: 'zeek.stats.reassembly_size.unknown', - type: 'integer', + 'netflow.procera_remote_ipv6_host': { + category: 'netflow', + name: 'netflow.procera_remote_ipv6_host', + type: 'ip', }, - 'zeek.stats.timestamp_lag': { - category: 'zeek', - description: 'Lag between the wall clock and packet timestamps if reading live traffic. ', - name: 'zeek.stats.timestamp_lag', + 'netflow.procera_rnc': { + category: 'netflow', + name: 'netflow.procera_rnc', type: 'integer', }, - 'zeek.syslog.facility': { - category: 'zeek', - description: 'Syslog facility for the message. ', - name: 'zeek.syslog.facility', + 'netflow.procera_server_hostname': { + category: 'netflow', + name: 'netflow.procera_server_hostname', type: 'keyword', }, - 'zeek.syslog.severity': { - category: 'zeek', - description: 'Syslog severity for the message. ', - name: 'zeek.syslog.severity', + 'netflow.procera_service': { + category: 'netflow', + name: 'netflow.procera_service', type: 'keyword', }, - 'zeek.syslog.message': { - category: 'zeek', - description: 'The plain text message. ', - name: 'zeek.syslog.message', + 'netflow.procera_sgsn': { + category: 'netflow', + name: 'netflow.procera_sgsn', type: 'keyword', }, - 'zeek.tunnel.type': { - category: 'zeek', - description: 'The type of tunnel. ', - name: 'zeek.tunnel.type', + 'netflow.procera_subscriber_identifier': { + category: 'netflow', + name: 'netflow.procera_subscriber_identifier', type: 'keyword', }, - 'zeek.tunnel.action': { - category: 'zeek', - description: 'The type of activity that occurred. ', - name: 'zeek.tunnel.action', + 'netflow.procera_template_name': { + category: 'netflow', + name: 'netflow.procera_template_name', type: 'keyword', }, - 'zeek.weird.name': { - category: 'zeek', - description: 'The name of the weird that occurred. ', - name: 'zeek.weird.name', + 'netflow.procera_user_location_information': { + category: 'netflow', + name: 'netflow.procera_user_location_information', type: 'keyword', }, - 'zeek.weird.additional_info': { - category: 'zeek', - description: 'Additional information accompanying the weird if any. ', - name: 'zeek.weird.additional_info', - type: 'keyword', + 'netflow.protocol_identifier': { + category: 'netflow', + name: 'netflow.protocol_identifier', + type: 'short', }, - 'zeek.weird.notice': { - category: 'zeek', - description: 'Indicate if this weird was also turned into a notice. ', - name: 'zeek.weird.notice', - type: 'boolean', + 'netflow.pseudo_wire_control_word': { + category: 'netflow', + name: 'netflow.pseudo_wire_control_word', + type: 'long', }, - 'zeek.weird.peer': { - category: 'zeek', - description: - 'The peer that originated this weird. This is helpful in cluster deployments if a particular cluster node is having trouble to help identify which node is having trouble. ', - name: 'zeek.weird.peer', - type: 'keyword', + 'netflow.pseudo_wire_destination_ipv4_address': { + category: 'netflow', + name: 'netflow.pseudo_wire_destination_ipv4_address', + type: 'ip', }, - 'zeek.weird.identifier': { - category: 'zeek', - description: - 'This field is to be provided when a weird is generated for the purpose of deduplicating weirds. The identifier string should be unique for a single instance of the weird. This field is used to define when a weird is conceptually a duplicate of a previous weird. ', - name: 'zeek.weird.identifier', - type: 'keyword', + 'netflow.pseudo_wire_id': { + category: 'netflow', + name: 'netflow.pseudo_wire_id', + type: 'long', }, - 'zeek.x509.id': { - category: 'zeek', - description: 'File id of this certificate. ', - name: 'zeek.x509.id', + 'netflow.pseudo_wire_type': { + category: 'netflow', + name: 'netflow.pseudo_wire_type', + type: 'integer', + }, + 'netflow.reason': { + category: 'netflow', + name: 'netflow.reason', + type: 'long', + }, + 'netflow.reason_text': { + category: 'netflow', + name: 'netflow.reason_text', type: 'keyword', }, - 'zeek.x509.certificate.version': { - category: 'zeek', - description: 'Version number. ', - name: 'zeek.x509.certificate.version', + 'netflow.relative_error': { + category: 'netflow', + name: 'netflow.relative_error', + type: 'double', + }, + 'netflow.responder_octets': { + category: 'netflow', + name: 'netflow.responder_octets', + type: 'long', + }, + 'netflow.responder_packets': { + category: 'netflow', + name: 'netflow.responder_packets', + type: 'long', + }, + 'netflow.reverse_absolute_error': { + category: 'netflow', + name: 'netflow.reverse_absolute_error', + type: 'double', + }, + 'netflow.reverse_anonymization_flags': { + category: 'netflow', + name: 'netflow.reverse_anonymization_flags', type: 'integer', }, - 'zeek.x509.certificate.serial': { - category: 'zeek', - description: 'Serial number. ', - name: 'zeek.x509.certificate.serial', - type: 'keyword', + 'netflow.reverse_anonymization_technique': { + category: 'netflow', + name: 'netflow.reverse_anonymization_technique', + type: 'integer', }, - 'zeek.x509.certificate.subject.country': { - category: 'zeek', - description: 'Country provided in the certificate subject. ', - name: 'zeek.x509.certificate.subject.country', + 'netflow.reverse_application_category_name': { + category: 'netflow', + name: 'netflow.reverse_application_category_name', type: 'keyword', }, - 'zeek.x509.certificate.subject.common_name': { - category: 'zeek', - description: 'Common name provided in the certificate subject. ', - name: 'zeek.x509.certificate.subject.common_name', + 'netflow.reverse_application_description': { + category: 'netflow', + name: 'netflow.reverse_application_description', type: 'keyword', }, - 'zeek.x509.certificate.subject.locality': { - category: 'zeek', - description: 'Locality provided in the certificate subject. ', - name: 'zeek.x509.certificate.subject.locality', + 'netflow.reverse_application_group_name': { + category: 'netflow', + name: 'netflow.reverse_application_group_name', type: 'keyword', }, - 'zeek.x509.certificate.subject.organization': { - category: 'zeek', - description: 'Organization provided in the certificate subject. ', - name: 'zeek.x509.certificate.subject.organization', + 'netflow.reverse_application_id': { + category: 'netflow', + name: 'netflow.reverse_application_id', type: 'keyword', }, - 'zeek.x509.certificate.subject.organizational_unit': { - category: 'zeek', - description: 'Organizational unit provided in the certificate subject. ', - name: 'zeek.x509.certificate.subject.organizational_unit', + 'netflow.reverse_application_name': { + category: 'netflow', + name: 'netflow.reverse_application_name', type: 'keyword', }, - 'zeek.x509.certificate.subject.state': { - category: 'zeek', - description: 'State or province provided in the certificate subject. ', - name: 'zeek.x509.certificate.subject.state', + 'netflow.reverse_application_sub_category_name': { + category: 'netflow', + name: 'netflow.reverse_application_sub_category_name', type: 'keyword', }, - 'zeek.x509.certificate.issuer.country': { - category: 'zeek', - description: 'Country provided in the certificate issuer field. ', - name: 'zeek.x509.certificate.issuer.country', - type: 'keyword', + 'netflow.reverse_average_interarrival_time': { + category: 'netflow', + name: 'netflow.reverse_average_interarrival_time', + type: 'long', }, - 'zeek.x509.certificate.issuer.common_name': { - category: 'zeek', - description: 'Common name provided in the certificate issuer field. ', - name: 'zeek.x509.certificate.issuer.common_name', - type: 'keyword', + 'netflow.reverse_bgp_destination_as_number': { + category: 'netflow', + name: 'netflow.reverse_bgp_destination_as_number', + type: 'long', }, - 'zeek.x509.certificate.issuer.locality': { - category: 'zeek', - description: 'Locality provided in the certificate issuer field. ', - name: 'zeek.x509.certificate.issuer.locality', - type: 'keyword', + 'netflow.reverse_bgp_next_adjacent_as_number': { + category: 'netflow', + name: 'netflow.reverse_bgp_next_adjacent_as_number', + type: 'long', }, - 'zeek.x509.certificate.issuer.organization': { - category: 'zeek', - description: 'Organization provided in the certificate issuer field. ', - name: 'zeek.x509.certificate.issuer.organization', - type: 'keyword', + 'netflow.reverse_bgp_next_hop_ipv4_address': { + category: 'netflow', + name: 'netflow.reverse_bgp_next_hop_ipv4_address', + type: 'ip', }, - 'zeek.x509.certificate.issuer.organizational_unit': { - category: 'zeek', - description: 'Organizational unit provided in the certificate issuer field. ', - name: 'zeek.x509.certificate.issuer.organizational_unit', - type: 'keyword', + 'netflow.reverse_bgp_next_hop_ipv6_address': { + category: 'netflow', + name: 'netflow.reverse_bgp_next_hop_ipv6_address', + type: 'ip', }, - 'zeek.x509.certificate.issuer.state': { - category: 'zeek', - description: 'State or province provided in the certificate issuer field. ', - name: 'zeek.x509.certificate.issuer.state', - type: 'keyword', + 'netflow.reverse_bgp_prev_adjacent_as_number': { + category: 'netflow', + name: 'netflow.reverse_bgp_prev_adjacent_as_number', + type: 'long', }, - 'zeek.x509.certificate.common_name': { - category: 'zeek', - description: 'Last (most specific) common name. ', - name: 'zeek.x509.certificate.common_name', - type: 'keyword', + 'netflow.reverse_bgp_source_as_number': { + category: 'netflow', + name: 'netflow.reverse_bgp_source_as_number', + type: 'long', }, - 'zeek.x509.certificate.valid.from': { - category: 'zeek', - description: 'Timestamp before when certificate is not valid. ', - name: 'zeek.x509.certificate.valid.from', - type: 'date', + 'netflow.reverse_bgp_validity_state': { + category: 'netflow', + name: 'netflow.reverse_bgp_validity_state', + type: 'short', }, - 'zeek.x509.certificate.valid.until': { - category: 'zeek', - description: 'Timestamp after when certificate is not valid. ', - name: 'zeek.x509.certificate.valid.until', - type: 'date', + 'netflow.reverse_class_id': { + category: 'netflow', + name: 'netflow.reverse_class_id', + type: 'short', }, - 'zeek.x509.certificate.key.algorithm': { - category: 'zeek', - description: 'Name of the key algorithm. ', - name: 'zeek.x509.certificate.key.algorithm', + 'netflow.reverse_class_name': { + category: 'netflow', + name: 'netflow.reverse_class_name', type: 'keyword', }, - 'zeek.x509.certificate.key.type': { - category: 'zeek', - description: 'Key type, if key parseable by openssl (either rsa, dsa or ec). ', - name: 'zeek.x509.certificate.key.type', - type: 'keyword', + 'netflow.reverse_classification_engine_id': { + category: 'netflow', + name: 'netflow.reverse_classification_engine_id', + type: 'short', }, - 'zeek.x509.certificate.key.length': { - category: 'zeek', - description: 'Key length in bits. ', - name: 'zeek.x509.certificate.key.length', - type: 'integer', + 'netflow.reverse_collection_time_milliseconds': { + category: 'netflow', + name: 'netflow.reverse_collection_time_milliseconds', + type: 'long', }, - 'zeek.x509.certificate.signature_algorithm': { - category: 'zeek', - description: 'Name of the signature algorithm. ', - name: 'zeek.x509.certificate.signature_algorithm', + 'netflow.reverse_collector_certificate': { + category: 'netflow', + name: 'netflow.reverse_collector_certificate', type: 'keyword', }, - 'zeek.x509.certificate.exponent': { - category: 'zeek', - description: 'Exponent, if RSA-certificate. ', - name: 'zeek.x509.certificate.exponent', - type: 'keyword', + 'netflow.reverse_confidence_level': { + category: 'netflow', + name: 'netflow.reverse_confidence_level', + type: 'double', }, - 'zeek.x509.certificate.curve': { - category: 'zeek', - description: 'Curve, if EC-certificate. ', - name: 'zeek.x509.certificate.curve', - type: 'keyword', + 'netflow.reverse_connection_sum_duration_seconds': { + category: 'netflow', + name: 'netflow.reverse_connection_sum_duration_seconds', + type: 'long', }, - 'zeek.x509.san.dns': { - category: 'zeek', - description: 'List of DNS entries in SAN. ', - name: 'zeek.x509.san.dns', - type: 'keyword', + 'netflow.reverse_connection_transaction_id': { + category: 'netflow', + name: 'netflow.reverse_connection_transaction_id', + type: 'long', }, - 'zeek.x509.san.uri': { - category: 'zeek', - description: 'List of URI entries in SAN. ', - name: 'zeek.x509.san.uri', - type: 'keyword', + 'netflow.reverse_data_byte_count': { + category: 'netflow', + name: 'netflow.reverse_data_byte_count', + type: 'long', }, - 'zeek.x509.san.email': { - category: 'zeek', - description: 'List of email entries in SAN. ', - name: 'zeek.x509.san.email', + 'netflow.reverse_data_link_frame_section': { + category: 'netflow', + name: 'netflow.reverse_data_link_frame_section', type: 'keyword', }, - 'zeek.x509.san.ip': { - category: 'zeek', - description: 'List of IP entries in SAN. ', - name: 'zeek.x509.san.ip', - type: 'ip', + 'netflow.reverse_data_link_frame_size': { + category: 'netflow', + name: 'netflow.reverse_data_link_frame_size', + type: 'integer', }, - 'zeek.x509.san.other_fields': { - category: 'zeek', - description: 'True if the certificate contained other, not recognized or parsed name fields. ', - name: 'zeek.x509.san.other_fields', - type: 'boolean', + 'netflow.reverse_data_link_frame_type': { + category: 'netflow', + name: 'netflow.reverse_data_link_frame_type', + type: 'integer', }, - 'zeek.x509.basic_constraints.certificate_authority': { - category: 'zeek', - description: 'CA flag set or not. ', - name: 'zeek.x509.basic_constraints.certificate_authority', - type: 'boolean', + 'netflow.reverse_data_records_reliability': { + category: 'netflow', + name: 'netflow.reverse_data_records_reliability', + type: 'short', }, - 'zeek.x509.basic_constraints.path_length': { - category: 'zeek', - description: 'Maximum path length. ', - name: 'zeek.x509.basic_constraints.path_length', - type: 'integer', + 'netflow.reverse_delta_flow_count': { + category: 'netflow', + name: 'netflow.reverse_delta_flow_count', + type: 'long', }, - 'zeek.x509.log_cert': { - category: 'zeek', - description: - 'Present if policy/protocols/ssl/log-hostcerts-only.bro is loaded Logging of certificate is suppressed if set to F. ', - name: 'zeek.x509.log_cert', - type: 'boolean', + 'netflow.reverse_destination_ipv4_address': { + category: 'netflow', + name: 'netflow.reverse_destination_ipv4_address', + type: 'ip', }, - 'awscloudwatch.log_group': { - category: 'awscloudwatch', - description: 'The name of the log group to which this event belongs.', - name: 'awscloudwatch.log_group', - type: 'keyword', + 'netflow.reverse_destination_ipv4_prefix': { + category: 'netflow', + name: 'netflow.reverse_destination_ipv4_prefix', + type: 'ip', }, - 'awscloudwatch.log_stream': { - category: 'awscloudwatch', - description: 'The name of the log stream to which this event belongs.', - name: 'awscloudwatch.log_stream', - type: 'keyword', + 'netflow.reverse_destination_ipv4_prefix_length': { + category: 'netflow', + name: 'netflow.reverse_destination_ipv4_prefix_length', + type: 'short', }, - 'awscloudwatch.ingestion_time': { - category: 'awscloudwatch', - description: 'The time the event was ingested in AWS CloudWatch.', - name: 'awscloudwatch.ingestion_time', - type: 'keyword', + 'netflow.reverse_destination_ipv6_address': { + category: 'netflow', + name: 'netflow.reverse_destination_ipv6_address', + type: 'ip', }, - 'netflow.type': { + 'netflow.reverse_destination_ipv6_prefix': { category: 'netflow', - description: 'The type of NetFlow record described by this event. ', - name: 'netflow.type', - type: 'keyword', + name: 'netflow.reverse_destination_ipv6_prefix', + type: 'ip', }, - 'netflow.exporter.address': { + 'netflow.reverse_destination_ipv6_prefix_length': { category: 'netflow', - description: "Exporter's network address in IP:port format. ", - name: 'netflow.exporter.address', + name: 'netflow.reverse_destination_ipv6_prefix_length', + type: 'short', + }, + 'netflow.reverse_destination_mac_address': { + category: 'netflow', + name: 'netflow.reverse_destination_mac_address', type: 'keyword', }, - 'netflow.exporter.source_id': { + 'netflow.reverse_destination_transport_port': { category: 'netflow', - description: 'Observation domain ID to which this record belongs. ', - name: 'netflow.exporter.source_id', + name: 'netflow.reverse_destination_transport_port', + type: 'integer', + }, + 'netflow.reverse_digest_hash_value': { + category: 'netflow', + name: 'netflow.reverse_digest_hash_value', type: 'long', }, - 'netflow.exporter.timestamp': { + 'netflow.reverse_distinct_count_of_destination_ip_address': { category: 'netflow', - description: 'Time and date of export. ', - name: 'netflow.exporter.timestamp', - type: 'date', + name: 'netflow.reverse_distinct_count_of_destination_ip_address', + type: 'long', }, - 'netflow.exporter.uptime_millis': { + 'netflow.reverse_distinct_count_of_destination_ipv4_address': { category: 'netflow', - description: 'How long the exporter process has been running, in milliseconds. ', - name: 'netflow.exporter.uptime_millis', + name: 'netflow.reverse_distinct_count_of_destination_ipv4_address', type: 'long', }, - 'netflow.exporter.version': { + 'netflow.reverse_distinct_count_of_destination_ipv6_address': { category: 'netflow', - description: 'NetFlow version used. ', - name: 'netflow.exporter.version', - type: 'integer', + name: 'netflow.reverse_distinct_count_of_destination_ipv6_address', + type: 'long', }, - 'netflow.octet_delta_count': { + 'netflow.reverse_distinct_count_of_source_ip_address': { category: 'netflow', - name: 'netflow.octet_delta_count', + name: 'netflow.reverse_distinct_count_of_source_ip_address', type: 'long', }, - 'netflow.packet_delta_count': { + 'netflow.reverse_distinct_count_of_source_ipv4_address': { category: 'netflow', - name: 'netflow.packet_delta_count', + name: 'netflow.reverse_distinct_count_of_source_ipv4_address', type: 'long', }, - 'netflow.delta_flow_count': { + 'netflow.reverse_distinct_count_of_source_ipv6_address': { category: 'netflow', - name: 'netflow.delta_flow_count', + name: 'netflow.reverse_distinct_count_of_source_ipv6_address', type: 'long', }, - 'netflow.protocol_identifier': { + 'netflow.reverse_dot1q_customer_dei': { category: 'netflow', - name: 'netflow.protocol_identifier', + name: 'netflow.reverse_dot1q_customer_dei', type: 'short', }, - 'netflow.ip_class_of_service': { + 'netflow.reverse_dot1q_customer_destination_mac_address': { category: 'netflow', - name: 'netflow.ip_class_of_service', + name: 'netflow.reverse_dot1q_customer_destination_mac_address', + type: 'keyword', + }, + 'netflow.reverse_dot1q_customer_priority': { + category: 'netflow', + name: 'netflow.reverse_dot1q_customer_priority', type: 'short', }, - 'netflow.tcp_control_bits': { + 'netflow.reverse_dot1q_customer_source_mac_address': { category: 'netflow', - name: 'netflow.tcp_control_bits', - type: 'integer', + name: 'netflow.reverse_dot1q_customer_source_mac_address', + type: 'keyword', }, - 'netflow.source_transport_port': { + 'netflow.reverse_dot1q_customer_vlan_id': { category: 'netflow', - name: 'netflow.source_transport_port', + name: 'netflow.reverse_dot1q_customer_vlan_id', type: 'integer', }, - 'netflow.source_ipv4_address': { + 'netflow.reverse_dot1q_dei': { category: 'netflow', - name: 'netflow.source_ipv4_address', - type: 'ip', + name: 'netflow.reverse_dot1q_dei', + type: 'short', }, - 'netflow.source_ipv4_prefix_length': { + 'netflow.reverse_dot1q_priority': { category: 'netflow', - name: 'netflow.source_ipv4_prefix_length', + name: 'netflow.reverse_dot1q_priority', type: 'short', }, - 'netflow.ingress_interface': { + 'netflow.reverse_dot1q_service_instance_id': { category: 'netflow', - name: 'netflow.ingress_interface', + name: 'netflow.reverse_dot1q_service_instance_id', type: 'long', }, - 'netflow.destination_transport_port': { + 'netflow.reverse_dot1q_service_instance_priority': { category: 'netflow', - name: 'netflow.destination_transport_port', - type: 'integer', + name: 'netflow.reverse_dot1q_service_instance_priority', + type: 'short', }, - 'netflow.destination_ipv4_address': { + 'netflow.reverse_dot1q_service_instance_tag': { category: 'netflow', - name: 'netflow.destination_ipv4_address', - type: 'ip', + name: 'netflow.reverse_dot1q_service_instance_tag', + type: 'keyword', }, - 'netflow.destination_ipv4_prefix_length': { + 'netflow.reverse_dot1q_vlan_id': { category: 'netflow', - name: 'netflow.destination_ipv4_prefix_length', - type: 'short', + name: 'netflow.reverse_dot1q_vlan_id', + type: 'integer', }, - 'netflow.egress_interface': { + 'netflow.reverse_dropped_layer2_octet_delta_count': { category: 'netflow', - name: 'netflow.egress_interface', + name: 'netflow.reverse_dropped_layer2_octet_delta_count', type: 'long', }, - 'netflow.ip_next_hop_ipv4_address': { + 'netflow.reverse_dropped_layer2_octet_total_count': { category: 'netflow', - name: 'netflow.ip_next_hop_ipv4_address', - type: 'ip', + name: 'netflow.reverse_dropped_layer2_octet_total_count', + type: 'long', }, - 'netflow.bgp_source_as_number': { + 'netflow.reverse_dropped_octet_delta_count': { category: 'netflow', - name: 'netflow.bgp_source_as_number', + name: 'netflow.reverse_dropped_octet_delta_count', type: 'long', }, - 'netflow.bgp_destination_as_number': { + 'netflow.reverse_dropped_octet_total_count': { category: 'netflow', - name: 'netflow.bgp_destination_as_number', + name: 'netflow.reverse_dropped_octet_total_count', type: 'long', }, - 'netflow.bgp_next_hop_ipv4_address': { + 'netflow.reverse_dropped_packet_delta_count': { category: 'netflow', - name: 'netflow.bgp_next_hop_ipv4_address', - type: 'ip', + name: 'netflow.reverse_dropped_packet_delta_count', + type: 'long', }, - 'netflow.post_mcast_packet_delta_count': { + 'netflow.reverse_dropped_packet_total_count': { category: 'netflow', - name: 'netflow.post_mcast_packet_delta_count', + name: 'netflow.reverse_dropped_packet_total_count', type: 'long', }, - 'netflow.post_mcast_octet_delta_count': { + 'netflow.reverse_dst_traffic_index': { category: 'netflow', - name: 'netflow.post_mcast_octet_delta_count', + name: 'netflow.reverse_dst_traffic_index', type: 'long', }, - 'netflow.flow_end_sys_up_time': { + 'netflow.reverse_egress_broadcast_packet_total_count': { category: 'netflow', - name: 'netflow.flow_end_sys_up_time', + name: 'netflow.reverse_egress_broadcast_packet_total_count', type: 'long', }, - 'netflow.flow_start_sys_up_time': { + 'netflow.reverse_egress_interface': { category: 'netflow', - name: 'netflow.flow_start_sys_up_time', + name: 'netflow.reverse_egress_interface', type: 'long', }, - 'netflow.post_octet_delta_count': { + 'netflow.reverse_egress_interface_type': { category: 'netflow', - name: 'netflow.post_octet_delta_count', + name: 'netflow.reverse_egress_interface_type', type: 'long', }, - 'netflow.post_packet_delta_count': { + 'netflow.reverse_egress_physical_interface': { category: 'netflow', - name: 'netflow.post_packet_delta_count', + name: 'netflow.reverse_egress_physical_interface', type: 'long', }, - 'netflow.minimum_ip_total_length': { + 'netflow.reverse_egress_unicast_packet_total_count': { category: 'netflow', - name: 'netflow.minimum_ip_total_length', + name: 'netflow.reverse_egress_unicast_packet_total_count', type: 'long', }, - 'netflow.maximum_ip_total_length': { + 'netflow.reverse_egress_vrfid': { category: 'netflow', - name: 'netflow.maximum_ip_total_length', + name: 'netflow.reverse_egress_vrfid', type: 'long', }, - 'netflow.source_ipv6_address': { + 'netflow.reverse_encrypted_technology': { category: 'netflow', - name: 'netflow.source_ipv6_address', - type: 'ip', + name: 'netflow.reverse_encrypted_technology', + type: 'keyword', }, - 'netflow.destination_ipv6_address': { + 'netflow.reverse_engine_id': { category: 'netflow', - name: 'netflow.destination_ipv6_address', - type: 'ip', + name: 'netflow.reverse_engine_id', + type: 'short', }, - 'netflow.source_ipv6_prefix_length': { + 'netflow.reverse_engine_type': { category: 'netflow', - name: 'netflow.source_ipv6_prefix_length', + name: 'netflow.reverse_engine_type', type: 'short', }, - 'netflow.destination_ipv6_prefix_length': { + 'netflow.reverse_ethernet_header_length': { category: 'netflow', - name: 'netflow.destination_ipv6_prefix_length', + name: 'netflow.reverse_ethernet_header_length', type: 'short', }, - 'netflow.flow_label_ipv6': { + 'netflow.reverse_ethernet_payload_length': { category: 'netflow', - name: 'netflow.flow_label_ipv6', - type: 'long', + name: 'netflow.reverse_ethernet_payload_length', + type: 'integer', }, - 'netflow.icmp_type_code_ipv4': { + 'netflow.reverse_ethernet_total_length': { category: 'netflow', - name: 'netflow.icmp_type_code_ipv4', + name: 'netflow.reverse_ethernet_total_length', type: 'integer', }, - 'netflow.igmp_type': { + 'netflow.reverse_ethernet_type': { category: 'netflow', - name: 'netflow.igmp_type', - type: 'short', + name: 'netflow.reverse_ethernet_type', + type: 'integer', }, - 'netflow.sampling_interval': { + 'netflow.reverse_export_sctp_stream_id': { category: 'netflow', - name: 'netflow.sampling_interval', + name: 'netflow.reverse_export_sctp_stream_id', + type: 'integer', + }, + 'netflow.reverse_exporter_certificate': { + category: 'netflow', + name: 'netflow.reverse_exporter_certificate', + type: 'keyword', + }, + 'netflow.reverse_exporting_process_id': { + category: 'netflow', + name: 'netflow.reverse_exporting_process_id', type: 'long', }, - 'netflow.sampling_algorithm': { + 'netflow.reverse_firewall_event': { category: 'netflow', - name: 'netflow.sampling_algorithm', + name: 'netflow.reverse_firewall_event', type: 'short', }, - 'netflow.flow_active_timeout': { + 'netflow.reverse_first_non_empty_packet_size': { category: 'netflow', - name: 'netflow.flow_active_timeout', + name: 'netflow.reverse_first_non_empty_packet_size', type: 'integer', }, - 'netflow.flow_idle_timeout': { + 'netflow.reverse_first_packet_banner': { category: 'netflow', - name: 'netflow.flow_idle_timeout', + name: 'netflow.reverse_first_packet_banner', + type: 'keyword', + }, + 'netflow.reverse_flags_and_sampler_id': { + category: 'netflow', + name: 'netflow.reverse_flags_and_sampler_id', + type: 'long', + }, + 'netflow.reverse_flow_active_timeout': { + category: 'netflow', + name: 'netflow.reverse_flow_active_timeout', type: 'integer', }, - 'netflow.engine_type': { + 'netflow.reverse_flow_attributes': { + category: 'netflow', + name: 'netflow.reverse_flow_attributes', + type: 'integer', + }, + 'netflow.reverse_flow_delta_milliseconds': { + category: 'netflow', + name: 'netflow.reverse_flow_delta_milliseconds', + type: 'long', + }, + 'netflow.reverse_flow_direction': { + category: 'netflow', + name: 'netflow.reverse_flow_direction', + type: 'short', + }, + 'netflow.reverse_flow_duration_microseconds': { + category: 'netflow', + name: 'netflow.reverse_flow_duration_microseconds', + type: 'long', + }, + 'netflow.reverse_flow_duration_milliseconds': { + category: 'netflow', + name: 'netflow.reverse_flow_duration_milliseconds', + type: 'long', + }, + 'netflow.reverse_flow_end_delta_microseconds': { + category: 'netflow', + name: 'netflow.reverse_flow_end_delta_microseconds', + type: 'long', + }, + 'netflow.reverse_flow_end_microseconds': { + category: 'netflow', + name: 'netflow.reverse_flow_end_microseconds', + type: 'long', + }, + 'netflow.reverse_flow_end_milliseconds': { + category: 'netflow', + name: 'netflow.reverse_flow_end_milliseconds', + type: 'long', + }, + 'netflow.reverse_flow_end_nanoseconds': { + category: 'netflow', + name: 'netflow.reverse_flow_end_nanoseconds', + type: 'long', + }, + 'netflow.reverse_flow_end_reason': { + category: 'netflow', + name: 'netflow.reverse_flow_end_reason', + type: 'short', + }, + 'netflow.reverse_flow_end_seconds': { + category: 'netflow', + name: 'netflow.reverse_flow_end_seconds', + type: 'long', + }, + 'netflow.reverse_flow_end_sys_up_time': { + category: 'netflow', + name: 'netflow.reverse_flow_end_sys_up_time', + type: 'long', + }, + 'netflow.reverse_flow_idle_timeout': { category: 'netflow', - name: 'netflow.engine_type', - type: 'short', + name: 'netflow.reverse_flow_idle_timeout', + type: 'integer', }, - 'netflow.engine_id': { + 'netflow.reverse_flow_label_ipv6': { category: 'netflow', - name: 'netflow.engine_id', - type: 'short', + name: 'netflow.reverse_flow_label_ipv6', + type: 'long', }, - 'netflow.exported_octet_total_count': { + 'netflow.reverse_flow_sampling_time_interval': { category: 'netflow', - name: 'netflow.exported_octet_total_count', + name: 'netflow.reverse_flow_sampling_time_interval', type: 'long', }, - 'netflow.exported_message_total_count': { + 'netflow.reverse_flow_sampling_time_spacing': { category: 'netflow', - name: 'netflow.exported_message_total_count', + name: 'netflow.reverse_flow_sampling_time_spacing', type: 'long', }, - 'netflow.exported_flow_record_total_count': { + 'netflow.reverse_flow_selected_flow_delta_count': { category: 'netflow', - name: 'netflow.exported_flow_record_total_count', + name: 'netflow.reverse_flow_selected_flow_delta_count', type: 'long', }, - 'netflow.ipv4_router_sc': { + 'netflow.reverse_flow_selected_octet_delta_count': { category: 'netflow', - name: 'netflow.ipv4_router_sc', - type: 'ip', + name: 'netflow.reverse_flow_selected_octet_delta_count', + type: 'long', }, - 'netflow.source_ipv4_prefix': { + 'netflow.reverse_flow_selected_packet_delta_count': { category: 'netflow', - name: 'netflow.source_ipv4_prefix', - type: 'ip', + name: 'netflow.reverse_flow_selected_packet_delta_count', + type: 'long', }, - 'netflow.destination_ipv4_prefix': { + 'netflow.reverse_flow_selector_algorithm': { category: 'netflow', - name: 'netflow.destination_ipv4_prefix', - type: 'ip', + name: 'netflow.reverse_flow_selector_algorithm', + type: 'integer', }, - 'netflow.mpls_top_label_type': { + 'netflow.reverse_flow_start_delta_microseconds': { category: 'netflow', - name: 'netflow.mpls_top_label_type', - type: 'short', + name: 'netflow.reverse_flow_start_delta_microseconds', + type: 'long', }, - 'netflow.mpls_top_label_ipv4_address': { + 'netflow.reverse_flow_start_microseconds': { category: 'netflow', - name: 'netflow.mpls_top_label_ipv4_address', - type: 'ip', + name: 'netflow.reverse_flow_start_microseconds', + type: 'long', }, - 'netflow.sampler_id': { + 'netflow.reverse_flow_start_milliseconds': { category: 'netflow', - name: 'netflow.sampler_id', - type: 'short', + name: 'netflow.reverse_flow_start_milliseconds', + type: 'long', }, - 'netflow.sampler_mode': { + 'netflow.reverse_flow_start_nanoseconds': { category: 'netflow', - name: 'netflow.sampler_mode', - type: 'short', + name: 'netflow.reverse_flow_start_nanoseconds', + type: 'long', }, - 'netflow.sampler_random_interval': { + 'netflow.reverse_flow_start_seconds': { category: 'netflow', - name: 'netflow.sampler_random_interval', + name: 'netflow.reverse_flow_start_seconds', type: 'long', }, - 'netflow.class_id': { + 'netflow.reverse_flow_start_sys_up_time': { category: 'netflow', - name: 'netflow.class_id', + name: 'netflow.reverse_flow_start_sys_up_time', type: 'long', }, - 'netflow.minimum_ttl': { + 'netflow.reverse_forwarding_status': { category: 'netflow', - name: 'netflow.minimum_ttl', - type: 'short', + name: 'netflow.reverse_forwarding_status', + type: 'long', }, - 'netflow.maximum_ttl': { + 'netflow.reverse_fragment_flags': { category: 'netflow', - name: 'netflow.maximum_ttl', + name: 'netflow.reverse_fragment_flags', type: 'short', }, - 'netflow.fragment_identification': { + 'netflow.reverse_fragment_identification': { category: 'netflow', - name: 'netflow.fragment_identification', + name: 'netflow.reverse_fragment_identification', type: 'long', }, - 'netflow.post_ip_class_of_service': { + 'netflow.reverse_fragment_offset': { category: 'netflow', - name: 'netflow.post_ip_class_of_service', - type: 'short', + name: 'netflow.reverse_fragment_offset', + type: 'integer', }, - 'netflow.source_mac_address': { + 'netflow.reverse_gre_key': { category: 'netflow', - name: 'netflow.source_mac_address', - type: 'keyword', + name: 'netflow.reverse_gre_key', + type: 'long', }, - 'netflow.post_destination_mac_address': { + 'netflow.reverse_hash_digest_output': { category: 'netflow', - name: 'netflow.post_destination_mac_address', - type: 'keyword', + name: 'netflow.reverse_hash_digest_output', + type: 'short', }, - 'netflow.vlan_id': { + 'netflow.reverse_hash_flow_domain': { category: 'netflow', - name: 'netflow.vlan_id', + name: 'netflow.reverse_hash_flow_domain', type: 'integer', }, - 'netflow.post_vlan_id': { + 'netflow.reverse_hash_initialiser_value': { category: 'netflow', - name: 'netflow.post_vlan_id', - type: 'integer', + name: 'netflow.reverse_hash_initialiser_value', + type: 'long', }, - 'netflow.ip_version': { + 'netflow.reverse_hash_ip_payload_offset': { category: 'netflow', - name: 'netflow.ip_version', - type: 'short', + name: 'netflow.reverse_hash_ip_payload_offset', + type: 'long', }, - 'netflow.flow_direction': { + 'netflow.reverse_hash_ip_payload_size': { category: 'netflow', - name: 'netflow.flow_direction', - type: 'short', + name: 'netflow.reverse_hash_ip_payload_size', + type: 'long', }, - 'netflow.ip_next_hop_ipv6_address': { + 'netflow.reverse_hash_output_range_max': { category: 'netflow', - name: 'netflow.ip_next_hop_ipv6_address', - type: 'ip', + name: 'netflow.reverse_hash_output_range_max', + type: 'long', }, - 'netflow.bgp_next_hop_ipv6_address': { + 'netflow.reverse_hash_output_range_min': { category: 'netflow', - name: 'netflow.bgp_next_hop_ipv6_address', - type: 'ip', + name: 'netflow.reverse_hash_output_range_min', + type: 'long', }, - 'netflow.ipv6_extension_headers': { + 'netflow.reverse_hash_selected_range_max': { category: 'netflow', - name: 'netflow.ipv6_extension_headers', + name: 'netflow.reverse_hash_selected_range_max', type: 'long', }, - 'netflow.mpls_top_label_stack_section': { + 'netflow.reverse_hash_selected_range_min': { category: 'netflow', - name: 'netflow.mpls_top_label_stack_section', - type: 'short', + name: 'netflow.reverse_hash_selected_range_min', + type: 'long', }, - 'netflow.mpls_label_stack_section2': { + 'netflow.reverse_icmp_code_ipv4': { category: 'netflow', - name: 'netflow.mpls_label_stack_section2', + name: 'netflow.reverse_icmp_code_ipv4', type: 'short', }, - 'netflow.mpls_label_stack_section3': { + 'netflow.reverse_icmp_code_ipv6': { category: 'netflow', - name: 'netflow.mpls_label_stack_section3', + name: 'netflow.reverse_icmp_code_ipv6', type: 'short', }, - 'netflow.mpls_label_stack_section4': { + 'netflow.reverse_icmp_type_code_ipv4': { category: 'netflow', - name: 'netflow.mpls_label_stack_section4', - type: 'short', + name: 'netflow.reverse_icmp_type_code_ipv4', + type: 'integer', }, - 'netflow.mpls_label_stack_section5': { + 'netflow.reverse_icmp_type_code_ipv6': { category: 'netflow', - name: 'netflow.mpls_label_stack_section5', - type: 'short', + name: 'netflow.reverse_icmp_type_code_ipv6', + type: 'integer', }, - 'netflow.mpls_label_stack_section6': { + 'netflow.reverse_icmp_type_ipv4': { category: 'netflow', - name: 'netflow.mpls_label_stack_section6', + name: 'netflow.reverse_icmp_type_ipv4', type: 'short', }, - 'netflow.mpls_label_stack_section7': { + 'netflow.reverse_icmp_type_ipv6': { category: 'netflow', - name: 'netflow.mpls_label_stack_section7', + name: 'netflow.reverse_icmp_type_ipv6', type: 'short', }, - 'netflow.mpls_label_stack_section8': { + 'netflow.reverse_igmp_type': { category: 'netflow', - name: 'netflow.mpls_label_stack_section8', + name: 'netflow.reverse_igmp_type', type: 'short', }, - 'netflow.mpls_label_stack_section9': { + 'netflow.reverse_ignored_data_record_total_count': { category: 'netflow', - name: 'netflow.mpls_label_stack_section9', - type: 'short', + name: 'netflow.reverse_ignored_data_record_total_count', + type: 'long', }, - 'netflow.mpls_label_stack_section10': { + 'netflow.reverse_ignored_layer2_frame_total_count': { category: 'netflow', - name: 'netflow.mpls_label_stack_section10', - type: 'short', + name: 'netflow.reverse_ignored_layer2_frame_total_count', + type: 'long', }, - 'netflow.destination_mac_address': { + 'netflow.reverse_ignored_layer2_octet_total_count': { category: 'netflow', - name: 'netflow.destination_mac_address', - type: 'keyword', + name: 'netflow.reverse_ignored_layer2_octet_total_count', + type: 'long', }, - 'netflow.post_source_mac_address': { + 'netflow.reverse_information_element_data_type': { category: 'netflow', - name: 'netflow.post_source_mac_address', - type: 'keyword', + name: 'netflow.reverse_information_element_data_type', + type: 'short', }, - 'netflow.interface_name': { + 'netflow.reverse_information_element_description': { category: 'netflow', - name: 'netflow.interface_name', + name: 'netflow.reverse_information_element_description', type: 'keyword', }, - 'netflow.interface_description': { + 'netflow.reverse_information_element_id': { category: 'netflow', - name: 'netflow.interface_description', - type: 'keyword', + name: 'netflow.reverse_information_element_id', + type: 'integer', }, - 'netflow.sampler_name': { + 'netflow.reverse_information_element_index': { category: 'netflow', - name: 'netflow.sampler_name', + name: 'netflow.reverse_information_element_index', + type: 'integer', + }, + 'netflow.reverse_information_element_name': { + category: 'netflow', + name: 'netflow.reverse_information_element_name', type: 'keyword', }, - 'netflow.octet_total_count': { + 'netflow.reverse_information_element_range_begin': { category: 'netflow', - name: 'netflow.octet_total_count', + name: 'netflow.reverse_information_element_range_begin', type: 'long', }, - 'netflow.packet_total_count': { + 'netflow.reverse_information_element_range_end': { category: 'netflow', - name: 'netflow.packet_total_count', + name: 'netflow.reverse_information_element_range_end', type: 'long', }, - 'netflow.flags_and_sampler_id': { + 'netflow.reverse_information_element_semantics': { category: 'netflow', - name: 'netflow.flags_and_sampler_id', - type: 'long', + name: 'netflow.reverse_information_element_semantics', + type: 'short', }, - 'netflow.fragment_offset': { + 'netflow.reverse_information_element_units': { category: 'netflow', - name: 'netflow.fragment_offset', + name: 'netflow.reverse_information_element_units', type: 'integer', }, - 'netflow.forwarding_status': { + 'netflow.reverse_ingress_broadcast_packet_total_count': { category: 'netflow', - name: 'netflow.forwarding_status', - type: 'short', + name: 'netflow.reverse_ingress_broadcast_packet_total_count', + type: 'long', }, - 'netflow.mpls_vpn_route_distinguisher': { + 'netflow.reverse_ingress_interface': { category: 'netflow', - name: 'netflow.mpls_vpn_route_distinguisher', - type: 'short', + name: 'netflow.reverse_ingress_interface', + type: 'long', }, - 'netflow.mpls_top_label_prefix_length': { + 'netflow.reverse_ingress_interface_type': { category: 'netflow', - name: 'netflow.mpls_top_label_prefix_length', - type: 'short', + name: 'netflow.reverse_ingress_interface_type', + type: 'long', }, - 'netflow.src_traffic_index': { + 'netflow.reverse_ingress_multicast_packet_total_count': { category: 'netflow', - name: 'netflow.src_traffic_index', + name: 'netflow.reverse_ingress_multicast_packet_total_count', type: 'long', }, - 'netflow.dst_traffic_index': { + 'netflow.reverse_ingress_physical_interface': { category: 'netflow', - name: 'netflow.dst_traffic_index', + name: 'netflow.reverse_ingress_physical_interface', type: 'long', }, - 'netflow.application_description': { + 'netflow.reverse_ingress_unicast_packet_total_count': { category: 'netflow', - name: 'netflow.application_description', - type: 'keyword', + name: 'netflow.reverse_ingress_unicast_packet_total_count', + type: 'long', }, - 'netflow.application_id': { + 'netflow.reverse_ingress_vrfid': { category: 'netflow', - name: 'netflow.application_id', - type: 'short', + name: 'netflow.reverse_ingress_vrfid', + type: 'long', }, - 'netflow.application_name': { + 'netflow.reverse_initial_tcp_flags': { category: 'netflow', - name: 'netflow.application_name', - type: 'keyword', + name: 'netflow.reverse_initial_tcp_flags', + type: 'short', }, - 'netflow.post_ip_diff_serv_code_point': { + 'netflow.reverse_initiator_octets': { category: 'netflow', - name: 'netflow.post_ip_diff_serv_code_point', - type: 'short', + name: 'netflow.reverse_initiator_octets', + type: 'long', }, - 'netflow.multicast_replication_factor': { + 'netflow.reverse_initiator_packets': { category: 'netflow', - name: 'netflow.multicast_replication_factor', + name: 'netflow.reverse_initiator_packets', type: 'long', }, - 'netflow.class_name': { + 'netflow.reverse_interface_description': { category: 'netflow', - name: 'netflow.class_name', + name: 'netflow.reverse_interface_description', type: 'keyword', }, - 'netflow.classification_engine_id': { + 'netflow.reverse_interface_name': { category: 'netflow', - name: 'netflow.classification_engine_id', - type: 'short', + name: 'netflow.reverse_interface_name', + type: 'keyword', }, - 'netflow.layer2packet_section_offset': { + 'netflow.reverse_intermediate_process_id': { category: 'netflow', - name: 'netflow.layer2packet_section_offset', - type: 'integer', + name: 'netflow.reverse_intermediate_process_id', + type: 'long', }, - 'netflow.layer2packet_section_size': { + 'netflow.reverse_ip_class_of_service': { category: 'netflow', - name: 'netflow.layer2packet_section_size', - type: 'integer', + name: 'netflow.reverse_ip_class_of_service', + type: 'short', }, - 'netflow.layer2packet_section_data': { + 'netflow.reverse_ip_diff_serv_code_point': { category: 'netflow', - name: 'netflow.layer2packet_section_data', + name: 'netflow.reverse_ip_diff_serv_code_point', type: 'short', }, - 'netflow.bgp_next_adjacent_as_number': { + 'netflow.reverse_ip_header_length': { category: 'netflow', - name: 'netflow.bgp_next_adjacent_as_number', - type: 'long', + name: 'netflow.reverse_ip_header_length', + type: 'short', }, - 'netflow.bgp_prev_adjacent_as_number': { + 'netflow.reverse_ip_header_packet_section': { category: 'netflow', - name: 'netflow.bgp_prev_adjacent_as_number', - type: 'long', + name: 'netflow.reverse_ip_header_packet_section', + type: 'keyword', }, - 'netflow.exporter_ipv4_address': { + 'netflow.reverse_ip_next_hop_ipv4_address': { category: 'netflow', - name: 'netflow.exporter_ipv4_address', + name: 'netflow.reverse_ip_next_hop_ipv4_address', type: 'ip', }, - 'netflow.exporter_ipv6_address': { + 'netflow.reverse_ip_next_hop_ipv6_address': { category: 'netflow', - name: 'netflow.exporter_ipv6_address', + name: 'netflow.reverse_ip_next_hop_ipv6_address', type: 'ip', }, - 'netflow.dropped_octet_delta_count': { + 'netflow.reverse_ip_payload_length': { category: 'netflow', - name: 'netflow.dropped_octet_delta_count', + name: 'netflow.reverse_ip_payload_length', type: 'long', }, - 'netflow.dropped_packet_delta_count': { + 'netflow.reverse_ip_payload_packet_section': { category: 'netflow', - name: 'netflow.dropped_packet_delta_count', - type: 'long', + name: 'netflow.reverse_ip_payload_packet_section', + type: 'keyword', }, - 'netflow.dropped_octet_total_count': { + 'netflow.reverse_ip_precedence': { category: 'netflow', - name: 'netflow.dropped_octet_total_count', + name: 'netflow.reverse_ip_precedence', + type: 'short', + }, + 'netflow.reverse_ip_sec_spi': { + category: 'netflow', + name: 'netflow.reverse_ip_sec_spi', type: 'long', }, - 'netflow.dropped_packet_total_count': { + 'netflow.reverse_ip_total_length': { category: 'netflow', - name: 'netflow.dropped_packet_total_count', + name: 'netflow.reverse_ip_total_length', type: 'long', }, - 'netflow.flow_end_reason': { + 'netflow.reverse_ip_ttl': { category: 'netflow', - name: 'netflow.flow_end_reason', + name: 'netflow.reverse_ip_ttl', type: 'short', }, - 'netflow.common_properties_id': { + 'netflow.reverse_ip_version': { category: 'netflow', - name: 'netflow.common_properties_id', - type: 'long', + name: 'netflow.reverse_ip_version', + type: 'short', }, - 'netflow.observation_point_id': { + 'netflow.reverse_ipv4_ihl': { category: 'netflow', - name: 'netflow.observation_point_id', - type: 'long', + name: 'netflow.reverse_ipv4_ihl', + type: 'short', }, - 'netflow.icmp_type_code_ipv6': { + 'netflow.reverse_ipv4_options': { category: 'netflow', - name: 'netflow.icmp_type_code_ipv6', - type: 'integer', + name: 'netflow.reverse_ipv4_options', + type: 'long', }, - 'netflow.mpls_top_label_ipv6_address': { + 'netflow.reverse_ipv4_router_sc': { category: 'netflow', - name: 'netflow.mpls_top_label_ipv6_address', + name: 'netflow.reverse_ipv4_router_sc', type: 'ip', }, - 'netflow.line_card_id': { + 'netflow.reverse_ipv6_extension_headers': { category: 'netflow', - name: 'netflow.line_card_id', + name: 'netflow.reverse_ipv6_extension_headers', type: 'long', }, - 'netflow.port_id': { + 'netflow.reverse_is_multicast': { category: 'netflow', - name: 'netflow.port_id', - type: 'long', + name: 'netflow.reverse_is_multicast', + type: 'short', }, - 'netflow.metering_process_id': { + 'netflow.reverse_large_packet_count': { category: 'netflow', - name: 'netflow.metering_process_id', + name: 'netflow.reverse_large_packet_count', type: 'long', }, - 'netflow.exporting_process_id': { + 'netflow.reverse_layer2_frame_delta_count': { category: 'netflow', - name: 'netflow.exporting_process_id', + name: 'netflow.reverse_layer2_frame_delta_count', type: 'long', }, - 'netflow.template_id': { - category: 'netflow', - name: 'netflow.template_id', - type: 'integer', - }, - 'netflow.wlan_channel_id': { + 'netflow.reverse_layer2_frame_total_count': { category: 'netflow', - name: 'netflow.wlan_channel_id', - type: 'short', + name: 'netflow.reverse_layer2_frame_total_count', + type: 'long', }, - 'netflow.wlan_ssid': { + 'netflow.reverse_layer2_octet_delta_count': { category: 'netflow', - name: 'netflow.wlan_ssid', - type: 'keyword', + name: 'netflow.reverse_layer2_octet_delta_count', + type: 'long', }, - 'netflow.flow_id': { + 'netflow.reverse_layer2_octet_delta_sum_of_squares': { category: 'netflow', - name: 'netflow.flow_id', + name: 'netflow.reverse_layer2_octet_delta_sum_of_squares', type: 'long', }, - 'netflow.observation_domain_id': { + 'netflow.reverse_layer2_octet_total_count': { category: 'netflow', - name: 'netflow.observation_domain_id', + name: 'netflow.reverse_layer2_octet_total_count', type: 'long', }, - 'netflow.flow_start_seconds': { + 'netflow.reverse_layer2_octet_total_sum_of_squares': { category: 'netflow', - name: 'netflow.flow_start_seconds', - type: 'date', + name: 'netflow.reverse_layer2_octet_total_sum_of_squares', + type: 'long', }, - 'netflow.flow_end_seconds': { + 'netflow.reverse_layer2_segment_id': { category: 'netflow', - name: 'netflow.flow_end_seconds', - type: 'date', + name: 'netflow.reverse_layer2_segment_id', + type: 'long', }, - 'netflow.flow_start_milliseconds': { + 'netflow.reverse_layer2packet_section_data': { category: 'netflow', - name: 'netflow.flow_start_milliseconds', - type: 'date', + name: 'netflow.reverse_layer2packet_section_data', + type: 'keyword', }, - 'netflow.flow_end_milliseconds': { + 'netflow.reverse_layer2packet_section_offset': { category: 'netflow', - name: 'netflow.flow_end_milliseconds', - type: 'date', + name: 'netflow.reverse_layer2packet_section_offset', + type: 'integer', }, - 'netflow.flow_start_microseconds': { + 'netflow.reverse_layer2packet_section_size': { category: 'netflow', - name: 'netflow.flow_start_microseconds', - type: 'date', + name: 'netflow.reverse_layer2packet_section_size', + type: 'integer', }, - 'netflow.flow_end_microseconds': { + 'netflow.reverse_line_card_id': { category: 'netflow', - name: 'netflow.flow_end_microseconds', - type: 'date', + name: 'netflow.reverse_line_card_id', + type: 'long', }, - 'netflow.flow_start_nanoseconds': { + 'netflow.reverse_lower_ci_limit': { category: 'netflow', - name: 'netflow.flow_start_nanoseconds', - type: 'date', + name: 'netflow.reverse_lower_ci_limit', + type: 'double', }, - 'netflow.flow_end_nanoseconds': { + 'netflow.reverse_max_export_seconds': { category: 'netflow', - name: 'netflow.flow_end_nanoseconds', - type: 'date', + name: 'netflow.reverse_max_export_seconds', + type: 'long', }, - 'netflow.flow_start_delta_microseconds': { + 'netflow.reverse_max_flow_end_microseconds': { category: 'netflow', - name: 'netflow.flow_start_delta_microseconds', + name: 'netflow.reverse_max_flow_end_microseconds', type: 'long', }, - 'netflow.flow_end_delta_microseconds': { + 'netflow.reverse_max_flow_end_milliseconds': { category: 'netflow', - name: 'netflow.flow_end_delta_microseconds', + name: 'netflow.reverse_max_flow_end_milliseconds', type: 'long', }, - 'netflow.system_init_time_milliseconds': { + 'netflow.reverse_max_flow_end_nanoseconds': { category: 'netflow', - name: 'netflow.system_init_time_milliseconds', - type: 'date', + name: 'netflow.reverse_max_flow_end_nanoseconds', + type: 'long', }, - 'netflow.flow_duration_milliseconds': { + 'netflow.reverse_max_flow_end_seconds': { category: 'netflow', - name: 'netflow.flow_duration_milliseconds', + name: 'netflow.reverse_max_flow_end_seconds', type: 'long', }, - 'netflow.flow_duration_microseconds': { + 'netflow.reverse_max_packet_size': { category: 'netflow', - name: 'netflow.flow_duration_microseconds', - type: 'long', + name: 'netflow.reverse_max_packet_size', + type: 'integer', }, - 'netflow.observed_flow_total_count': { + 'netflow.reverse_maximum_ip_total_length': { category: 'netflow', - name: 'netflow.observed_flow_total_count', + name: 'netflow.reverse_maximum_ip_total_length', type: 'long', }, - 'netflow.ignored_packet_total_count': { + 'netflow.reverse_maximum_layer2_total_length': { category: 'netflow', - name: 'netflow.ignored_packet_total_count', + name: 'netflow.reverse_maximum_layer2_total_length', type: 'long', }, - 'netflow.ignored_octet_total_count': { + 'netflow.reverse_maximum_ttl': { category: 'netflow', - name: 'netflow.ignored_octet_total_count', - type: 'long', + name: 'netflow.reverse_maximum_ttl', + type: 'short', }, - 'netflow.not_sent_flow_total_count': { + 'netflow.reverse_message_md5_checksum': { category: 'netflow', - name: 'netflow.not_sent_flow_total_count', - type: 'long', + name: 'netflow.reverse_message_md5_checksum', + type: 'keyword', }, - 'netflow.not_sent_packet_total_count': { + 'netflow.reverse_message_scope': { category: 'netflow', - name: 'netflow.not_sent_packet_total_count', - type: 'long', + name: 'netflow.reverse_message_scope', + type: 'short', }, - 'netflow.not_sent_octet_total_count': { + 'netflow.reverse_metering_process_id': { category: 'netflow', - name: 'netflow.not_sent_octet_total_count', + name: 'netflow.reverse_metering_process_id', type: 'long', }, - 'netflow.destination_ipv6_prefix': { + 'netflow.reverse_metro_evc_id': { category: 'netflow', - name: 'netflow.destination_ipv6_prefix', - type: 'ip', + name: 'netflow.reverse_metro_evc_id', + type: 'keyword', }, - 'netflow.source_ipv6_prefix': { + 'netflow.reverse_metro_evc_type': { category: 'netflow', - name: 'netflow.source_ipv6_prefix', - type: 'ip', + name: 'netflow.reverse_metro_evc_type', + type: 'short', }, - 'netflow.post_octet_total_count': { + 'netflow.reverse_min_export_seconds': { category: 'netflow', - name: 'netflow.post_octet_total_count', + name: 'netflow.reverse_min_export_seconds', type: 'long', }, - 'netflow.post_packet_total_count': { + 'netflow.reverse_min_flow_start_microseconds': { category: 'netflow', - name: 'netflow.post_packet_total_count', + name: 'netflow.reverse_min_flow_start_microseconds', type: 'long', }, - 'netflow.flow_key_indicator': { + 'netflow.reverse_min_flow_start_milliseconds': { category: 'netflow', - name: 'netflow.flow_key_indicator', + name: 'netflow.reverse_min_flow_start_milliseconds', type: 'long', }, - 'netflow.post_mcast_packet_total_count': { + 'netflow.reverse_min_flow_start_nanoseconds': { category: 'netflow', - name: 'netflow.post_mcast_packet_total_count', + name: 'netflow.reverse_min_flow_start_nanoseconds', type: 'long', }, - 'netflow.post_mcast_octet_total_count': { + 'netflow.reverse_min_flow_start_seconds': { category: 'netflow', - name: 'netflow.post_mcast_octet_total_count', + name: 'netflow.reverse_min_flow_start_seconds', type: 'long', }, - 'netflow.icmp_type_ipv4': { - category: 'netflow', - name: 'netflow.icmp_type_ipv4', - type: 'short', - }, - 'netflow.icmp_code_ipv4': { + 'netflow.reverse_minimum_ip_total_length': { category: 'netflow', - name: 'netflow.icmp_code_ipv4', - type: 'short', + name: 'netflow.reverse_minimum_ip_total_length', + type: 'long', }, - 'netflow.icmp_type_ipv6': { + 'netflow.reverse_minimum_layer2_total_length': { category: 'netflow', - name: 'netflow.icmp_type_ipv6', - type: 'short', + name: 'netflow.reverse_minimum_layer2_total_length', + type: 'long', }, - 'netflow.icmp_code_ipv6': { + 'netflow.reverse_minimum_ttl': { category: 'netflow', - name: 'netflow.icmp_code_ipv6', + name: 'netflow.reverse_minimum_ttl', type: 'short', }, - 'netflow.udp_source_port': { - category: 'netflow', - name: 'netflow.udp_source_port', - type: 'integer', - }, - 'netflow.udp_destination_port': { + 'netflow.reverse_monitoring_interval_end_milli_seconds': { category: 'netflow', - name: 'netflow.udp_destination_port', - type: 'integer', + name: 'netflow.reverse_monitoring_interval_end_milli_seconds', + type: 'long', }, - 'netflow.tcp_source_port': { + 'netflow.reverse_monitoring_interval_start_milli_seconds': { category: 'netflow', - name: 'netflow.tcp_source_port', - type: 'integer', + name: 'netflow.reverse_monitoring_interval_start_milli_seconds', + type: 'long', }, - 'netflow.tcp_destination_port': { + 'netflow.reverse_mpls_label_stack_depth': { category: 'netflow', - name: 'netflow.tcp_destination_port', - type: 'integer', + name: 'netflow.reverse_mpls_label_stack_depth', + type: 'long', }, - 'netflow.tcp_sequence_number': { + 'netflow.reverse_mpls_label_stack_length': { category: 'netflow', - name: 'netflow.tcp_sequence_number', + name: 'netflow.reverse_mpls_label_stack_length', type: 'long', }, - 'netflow.tcp_acknowledgement_number': { + 'netflow.reverse_mpls_label_stack_section': { category: 'netflow', - name: 'netflow.tcp_acknowledgement_number', - type: 'long', + name: 'netflow.reverse_mpls_label_stack_section', + type: 'keyword', }, - 'netflow.tcp_window_size': { + 'netflow.reverse_mpls_label_stack_section10': { category: 'netflow', - name: 'netflow.tcp_window_size', - type: 'integer', + name: 'netflow.reverse_mpls_label_stack_section10', + type: 'keyword', }, - 'netflow.tcp_urgent_pointer': { + 'netflow.reverse_mpls_label_stack_section2': { category: 'netflow', - name: 'netflow.tcp_urgent_pointer', - type: 'integer', + name: 'netflow.reverse_mpls_label_stack_section2', + type: 'keyword', }, - 'netflow.tcp_header_length': { + 'netflow.reverse_mpls_label_stack_section3': { category: 'netflow', - name: 'netflow.tcp_header_length', - type: 'short', + name: 'netflow.reverse_mpls_label_stack_section3', + type: 'keyword', }, - 'netflow.ip_header_length': { + 'netflow.reverse_mpls_label_stack_section4': { category: 'netflow', - name: 'netflow.ip_header_length', - type: 'short', + name: 'netflow.reverse_mpls_label_stack_section4', + type: 'keyword', }, - 'netflow.total_length_ipv4': { + 'netflow.reverse_mpls_label_stack_section5': { category: 'netflow', - name: 'netflow.total_length_ipv4', - type: 'integer', + name: 'netflow.reverse_mpls_label_stack_section5', + type: 'keyword', }, - 'netflow.payload_length_ipv6': { + 'netflow.reverse_mpls_label_stack_section6': { category: 'netflow', - name: 'netflow.payload_length_ipv6', - type: 'integer', + name: 'netflow.reverse_mpls_label_stack_section6', + type: 'keyword', }, - 'netflow.ip_ttl': { + 'netflow.reverse_mpls_label_stack_section7': { category: 'netflow', - name: 'netflow.ip_ttl', - type: 'short', + name: 'netflow.reverse_mpls_label_stack_section7', + type: 'keyword', }, - 'netflow.next_header_ipv6': { + 'netflow.reverse_mpls_label_stack_section8': { category: 'netflow', - name: 'netflow.next_header_ipv6', - type: 'short', + name: 'netflow.reverse_mpls_label_stack_section8', + type: 'keyword', }, - 'netflow.mpls_payload_length': { + 'netflow.reverse_mpls_label_stack_section9': { category: 'netflow', - name: 'netflow.mpls_payload_length', - type: 'long', + name: 'netflow.reverse_mpls_label_stack_section9', + type: 'keyword', }, - 'netflow.ip_diff_serv_code_point': { + 'netflow.reverse_mpls_payload_length': { category: 'netflow', - name: 'netflow.ip_diff_serv_code_point', - type: 'short', + name: 'netflow.reverse_mpls_payload_length', + type: 'long', }, - 'netflow.ip_precedence': { + 'netflow.reverse_mpls_payload_packet_section': { category: 'netflow', - name: 'netflow.ip_precedence', - type: 'short', + name: 'netflow.reverse_mpls_payload_packet_section', + type: 'keyword', }, - 'netflow.fragment_flags': { + 'netflow.reverse_mpls_top_label_exp': { category: 'netflow', - name: 'netflow.fragment_flags', + name: 'netflow.reverse_mpls_top_label_exp', type: 'short', }, - 'netflow.octet_delta_sum_of_squares': { + 'netflow.reverse_mpls_top_label_ipv4_address': { category: 'netflow', - name: 'netflow.octet_delta_sum_of_squares', - type: 'long', + name: 'netflow.reverse_mpls_top_label_ipv4_address', + type: 'ip', }, - 'netflow.octet_total_sum_of_squares': { + 'netflow.reverse_mpls_top_label_ipv6_address': { category: 'netflow', - name: 'netflow.octet_total_sum_of_squares', - type: 'long', + name: 'netflow.reverse_mpls_top_label_ipv6_address', + type: 'ip', }, - 'netflow.mpls_top_label_ttl': { + 'netflow.reverse_mpls_top_label_prefix_length': { category: 'netflow', - name: 'netflow.mpls_top_label_ttl', + name: 'netflow.reverse_mpls_top_label_prefix_length', type: 'short', }, - 'netflow.mpls_label_stack_length': { + 'netflow.reverse_mpls_top_label_stack_section': { category: 'netflow', - name: 'netflow.mpls_label_stack_length', - type: 'long', + name: 'netflow.reverse_mpls_top_label_stack_section', + type: 'keyword', }, - 'netflow.mpls_label_stack_depth': { + 'netflow.reverse_mpls_top_label_ttl': { category: 'netflow', - name: 'netflow.mpls_label_stack_depth', - type: 'long', + name: 'netflow.reverse_mpls_top_label_ttl', + type: 'short', }, - 'netflow.mpls_top_label_exp': { + 'netflow.reverse_mpls_top_label_type': { category: 'netflow', - name: 'netflow.mpls_top_label_exp', + name: 'netflow.reverse_mpls_top_label_type', type: 'short', }, - 'netflow.ip_payload_length': { + 'netflow.reverse_mpls_vpn_route_distinguisher': { category: 'netflow', - name: 'netflow.ip_payload_length', - type: 'long', + name: 'netflow.reverse_mpls_vpn_route_distinguisher', + type: 'keyword', }, - 'netflow.udp_message_length': { + 'netflow.reverse_multicast_replication_factor': { category: 'netflow', - name: 'netflow.udp_message_length', - type: 'integer', + name: 'netflow.reverse_multicast_replication_factor', + type: 'long', }, - 'netflow.is_multicast': { + 'netflow.reverse_nat_event': { category: 'netflow', - name: 'netflow.is_multicast', + name: 'netflow.reverse_nat_event', type: 'short', }, - 'netflow.ipv4_ihl': { + 'netflow.reverse_nat_originating_address_realm': { category: 'netflow', - name: 'netflow.ipv4_ihl', + name: 'netflow.reverse_nat_originating_address_realm', type: 'short', }, - 'netflow.ipv4_options': { + 'netflow.reverse_nat_pool_id': { category: 'netflow', - name: 'netflow.ipv4_options', + name: 'netflow.reverse_nat_pool_id', type: 'long', }, - 'netflow.tcp_options': { + 'netflow.reverse_nat_pool_name': { category: 'netflow', - name: 'netflow.tcp_options', - type: 'long', + name: 'netflow.reverse_nat_pool_name', + type: 'keyword', }, - 'netflow.padding_octets': { + 'netflow.reverse_nat_type': { category: 'netflow', - name: 'netflow.padding_octets', + name: 'netflow.reverse_nat_type', type: 'short', }, - 'netflow.collector_ipv4_address': { + 'netflow.reverse_new_connection_delta_count': { category: 'netflow', - name: 'netflow.collector_ipv4_address', - type: 'ip', + name: 'netflow.reverse_new_connection_delta_count', + type: 'long', }, - 'netflow.collector_ipv6_address': { + 'netflow.reverse_next_header_ipv6': { category: 'netflow', - name: 'netflow.collector_ipv6_address', - type: 'ip', + name: 'netflow.reverse_next_header_ipv6', + type: 'short', }, - 'netflow.export_interface': { + 'netflow.reverse_non_empty_packet_count': { category: 'netflow', - name: 'netflow.export_interface', + name: 'netflow.reverse_non_empty_packet_count', type: 'long', }, - 'netflow.export_protocol_version': { + 'netflow.reverse_not_sent_layer2_octet_total_count': { category: 'netflow', - name: 'netflow.export_protocol_version', - type: 'short', + name: 'netflow.reverse_not_sent_layer2_octet_total_count', + type: 'long', }, - 'netflow.export_transport_protocol': { + 'netflow.reverse_observation_domain_name': { category: 'netflow', - name: 'netflow.export_transport_protocol', - type: 'short', + name: 'netflow.reverse_observation_domain_name', + type: 'keyword', }, - 'netflow.collector_transport_port': { + 'netflow.reverse_observation_point_id': { category: 'netflow', - name: 'netflow.collector_transport_port', - type: 'integer', + name: 'netflow.reverse_observation_point_id', + type: 'long', }, - 'netflow.exporter_transport_port': { + 'netflow.reverse_observation_point_type': { category: 'netflow', - name: 'netflow.exporter_transport_port', - type: 'integer', + name: 'netflow.reverse_observation_point_type', + type: 'short', }, - 'netflow.tcp_syn_total_count': { + 'netflow.reverse_observation_time_microseconds': { category: 'netflow', - name: 'netflow.tcp_syn_total_count', + name: 'netflow.reverse_observation_time_microseconds', type: 'long', }, - 'netflow.tcp_fin_total_count': { + 'netflow.reverse_observation_time_milliseconds': { category: 'netflow', - name: 'netflow.tcp_fin_total_count', + name: 'netflow.reverse_observation_time_milliseconds', type: 'long', }, - 'netflow.tcp_rst_total_count': { + 'netflow.reverse_observation_time_nanoseconds': { category: 'netflow', - name: 'netflow.tcp_rst_total_count', + name: 'netflow.reverse_observation_time_nanoseconds', type: 'long', }, - 'netflow.tcp_psh_total_count': { + 'netflow.reverse_observation_time_seconds': { category: 'netflow', - name: 'netflow.tcp_psh_total_count', + name: 'netflow.reverse_observation_time_seconds', type: 'long', }, - 'netflow.tcp_ack_total_count': { + 'netflow.reverse_octet_delta_count': { category: 'netflow', - name: 'netflow.tcp_ack_total_count', + name: 'netflow.reverse_octet_delta_count', + type: 'long', + }, + 'netflow.reverse_octet_delta_sum_of_squares': { + category: 'netflow', + name: 'netflow.reverse_octet_delta_sum_of_squares', type: 'long', }, - 'netflow.tcp_urg_total_count': { + 'netflow.reverse_octet_total_count': { category: 'netflow', - name: 'netflow.tcp_urg_total_count', + name: 'netflow.reverse_octet_total_count', type: 'long', }, - 'netflow.ip_total_length': { + 'netflow.reverse_octet_total_sum_of_squares': { category: 'netflow', - name: 'netflow.ip_total_length', + name: 'netflow.reverse_octet_total_sum_of_squares', type: 'long', }, - 'netflow.post_nat_source_ipv4_address': { + 'netflow.reverse_opaque_octets': { category: 'netflow', - name: 'netflow.post_nat_source_ipv4_address', - type: 'ip', + name: 'netflow.reverse_opaque_octets', + type: 'keyword', }, - 'netflow.post_nat_destination_ipv4_address': { + 'netflow.reverse_original_exporter_ipv4_address': { category: 'netflow', - name: 'netflow.post_nat_destination_ipv4_address', + name: 'netflow.reverse_original_exporter_ipv4_address', type: 'ip', }, - 'netflow.post_napt_source_transport_port': { + 'netflow.reverse_original_exporter_ipv6_address': { category: 'netflow', - name: 'netflow.post_napt_source_transport_port', - type: 'integer', + name: 'netflow.reverse_original_exporter_ipv6_address', + type: 'ip', }, - 'netflow.post_napt_destination_transport_port': { + 'netflow.reverse_original_flows_completed': { category: 'netflow', - name: 'netflow.post_napt_destination_transport_port', - type: 'integer', + name: 'netflow.reverse_original_flows_completed', + type: 'long', }, - 'netflow.nat_originating_address_realm': { + 'netflow.reverse_original_flows_initiated': { category: 'netflow', - name: 'netflow.nat_originating_address_realm', - type: 'short', + name: 'netflow.reverse_original_flows_initiated', + type: 'long', }, - 'netflow.nat_event': { + 'netflow.reverse_original_flows_present': { category: 'netflow', - name: 'netflow.nat_event', - type: 'short', + name: 'netflow.reverse_original_flows_present', + type: 'long', }, - 'netflow.initiator_octets': { + 'netflow.reverse_original_observation_domain_id': { category: 'netflow', - name: 'netflow.initiator_octets', + name: 'netflow.reverse_original_observation_domain_id', type: 'long', }, - 'netflow.responder_octets': { + 'netflow.reverse_os_finger_print': { category: 'netflow', - name: 'netflow.responder_octets', - type: 'long', + name: 'netflow.reverse_os_finger_print', + type: 'keyword', }, - 'netflow.firewall_event': { + 'netflow.reverse_os_name': { category: 'netflow', - name: 'netflow.firewall_event', - type: 'short', + name: 'netflow.reverse_os_name', + type: 'keyword', }, - 'netflow.ingress_vrfid': { + 'netflow.reverse_os_version': { category: 'netflow', - name: 'netflow.ingress_vrfid', + name: 'netflow.reverse_os_version', + type: 'keyword', + }, + 'netflow.reverse_p2p_technology': { + category: 'netflow', + name: 'netflow.reverse_p2p_technology', + type: 'keyword', + }, + 'netflow.reverse_packet_delta_count': { + category: 'netflow', + name: 'netflow.reverse_packet_delta_count', type: 'long', }, - 'netflow.egress_vrfid': { + 'netflow.reverse_packet_total_count': { category: 'netflow', - name: 'netflow.egress_vrfid', + name: 'netflow.reverse_packet_total_count', type: 'long', }, - 'netflow.vr_fname': { + 'netflow.reverse_payload': { category: 'netflow', - name: 'netflow.vr_fname', + name: 'netflow.reverse_payload', type: 'keyword', }, - 'netflow.post_mpls_top_label_exp': { + 'netflow.reverse_payload_entropy': { category: 'netflow', - name: 'netflow.post_mpls_top_label_exp', + name: 'netflow.reverse_payload_entropy', type: 'short', }, - 'netflow.tcp_window_scale': { + 'netflow.reverse_payload_length_ipv6': { category: 'netflow', - name: 'netflow.tcp_window_scale', + name: 'netflow.reverse_payload_length_ipv6', type: 'integer', }, - 'netflow.biflow_direction': { + 'netflow.reverse_port_id': { category: 'netflow', - name: 'netflow.biflow_direction', - type: 'short', + name: 'netflow.reverse_port_id', + type: 'long', }, - 'netflow.ethernet_header_length': { + 'netflow.reverse_port_range_end': { category: 'netflow', - name: 'netflow.ethernet_header_length', - type: 'short', + name: 'netflow.reverse_port_range_end', + type: 'integer', }, - 'netflow.ethernet_payload_length': { + 'netflow.reverse_port_range_num_ports': { category: 'netflow', - name: 'netflow.ethernet_payload_length', + name: 'netflow.reverse_port_range_num_ports', type: 'integer', }, - 'netflow.ethernet_total_length': { + 'netflow.reverse_port_range_start': { category: 'netflow', - name: 'netflow.ethernet_total_length', + name: 'netflow.reverse_port_range_start', type: 'integer', }, - 'netflow.dot1q_vlan_id': { + 'netflow.reverse_port_range_step_size': { category: 'netflow', - name: 'netflow.dot1q_vlan_id', + name: 'netflow.reverse_port_range_step_size', type: 'integer', }, - 'netflow.dot1q_priority': { + 'netflow.reverse_post_destination_mac_address': { category: 'netflow', - name: 'netflow.dot1q_priority', - type: 'short', + name: 'netflow.reverse_post_destination_mac_address', + type: 'keyword', }, - 'netflow.dot1q_customer_vlan_id': { + 'netflow.reverse_post_dot1q_customer_vlan_id': { category: 'netflow', - name: 'netflow.dot1q_customer_vlan_id', + name: 'netflow.reverse_post_dot1q_customer_vlan_id', type: 'integer', }, - 'netflow.dot1q_customer_priority': { + 'netflow.reverse_post_dot1q_vlan_id': { category: 'netflow', - name: 'netflow.dot1q_customer_priority', + name: 'netflow.reverse_post_dot1q_vlan_id', + type: 'integer', + }, + 'netflow.reverse_post_ip_class_of_service': { + category: 'netflow', + name: 'netflow.reverse_post_ip_class_of_service', type: 'short', }, - 'netflow.metro_evc_id': { + 'netflow.reverse_post_ip_diff_serv_code_point': { category: 'netflow', - name: 'netflow.metro_evc_id', - type: 'keyword', + name: 'netflow.reverse_post_ip_diff_serv_code_point', + type: 'short', }, - 'netflow.metro_evc_type': { + 'netflow.reverse_post_ip_precedence': { category: 'netflow', - name: 'netflow.metro_evc_type', + name: 'netflow.reverse_post_ip_precedence', type: 'short', }, - 'netflow.pseudo_wire_id': { + 'netflow.reverse_post_layer2_octet_delta_count': { category: 'netflow', - name: 'netflow.pseudo_wire_id', + name: 'netflow.reverse_post_layer2_octet_delta_count', type: 'long', }, - 'netflow.pseudo_wire_type': { + 'netflow.reverse_post_layer2_octet_total_count': { category: 'netflow', - name: 'netflow.pseudo_wire_type', - type: 'integer', + name: 'netflow.reverse_post_layer2_octet_total_count', + type: 'long', }, - 'netflow.pseudo_wire_control_word': { + 'netflow.reverse_post_mcast_layer2_octet_delta_count': { category: 'netflow', - name: 'netflow.pseudo_wire_control_word', + name: 'netflow.reverse_post_mcast_layer2_octet_delta_count', type: 'long', }, - 'netflow.ingress_physical_interface': { + 'netflow.reverse_post_mcast_layer2_octet_total_count': { category: 'netflow', - name: 'netflow.ingress_physical_interface', + name: 'netflow.reverse_post_mcast_layer2_octet_total_count', type: 'long', }, - 'netflow.egress_physical_interface': { + 'netflow.reverse_post_mcast_octet_delta_count': { category: 'netflow', - name: 'netflow.egress_physical_interface', + name: 'netflow.reverse_post_mcast_octet_delta_count', type: 'long', }, - 'netflow.post_dot1q_vlan_id': { + 'netflow.reverse_post_mcast_octet_total_count': { category: 'netflow', - name: 'netflow.post_dot1q_vlan_id', - type: 'integer', + name: 'netflow.reverse_post_mcast_octet_total_count', + type: 'long', }, - 'netflow.post_dot1q_customer_vlan_id': { + 'netflow.reverse_post_mcast_packet_delta_count': { category: 'netflow', - name: 'netflow.post_dot1q_customer_vlan_id', - type: 'integer', + name: 'netflow.reverse_post_mcast_packet_delta_count', + type: 'long', }, - 'netflow.ethernet_type': { + 'netflow.reverse_post_mcast_packet_total_count': { category: 'netflow', - name: 'netflow.ethernet_type', - type: 'integer', + name: 'netflow.reverse_post_mcast_packet_total_count', + type: 'long', }, - 'netflow.post_ip_precedence': { + 'netflow.reverse_post_mpls_top_label_exp': { category: 'netflow', - name: 'netflow.post_ip_precedence', + name: 'netflow.reverse_post_mpls_top_label_exp', type: 'short', }, - 'netflow.collection_time_milliseconds': { - category: 'netflow', - name: 'netflow.collection_time_milliseconds', - type: 'date', - }, - 'netflow.export_sctp_stream_id': { + 'netflow.reverse_post_napt_destination_transport_port': { category: 'netflow', - name: 'netflow.export_sctp_stream_id', + name: 'netflow.reverse_post_napt_destination_transport_port', type: 'integer', }, - 'netflow.max_export_seconds': { + 'netflow.reverse_post_napt_source_transport_port': { category: 'netflow', - name: 'netflow.max_export_seconds', - type: 'date', + name: 'netflow.reverse_post_napt_source_transport_port', + type: 'integer', }, - 'netflow.max_flow_end_seconds': { + 'netflow.reverse_post_nat_destination_ipv4_address': { category: 'netflow', - name: 'netflow.max_flow_end_seconds', - type: 'date', + name: 'netflow.reverse_post_nat_destination_ipv4_address', + type: 'ip', }, - 'netflow.message_md5_checksum': { + 'netflow.reverse_post_nat_destination_ipv6_address': { category: 'netflow', - name: 'netflow.message_md5_checksum', - type: 'short', + name: 'netflow.reverse_post_nat_destination_ipv6_address', + type: 'ip', }, - 'netflow.message_scope': { + 'netflow.reverse_post_nat_source_ipv4_address': { category: 'netflow', - name: 'netflow.message_scope', - type: 'short', + name: 'netflow.reverse_post_nat_source_ipv4_address', + type: 'ip', }, - 'netflow.min_export_seconds': { + 'netflow.reverse_post_nat_source_ipv6_address': { category: 'netflow', - name: 'netflow.min_export_seconds', - type: 'date', + name: 'netflow.reverse_post_nat_source_ipv6_address', + type: 'ip', }, - 'netflow.min_flow_start_seconds': { + 'netflow.reverse_post_octet_delta_count': { category: 'netflow', - name: 'netflow.min_flow_start_seconds', - type: 'date', + name: 'netflow.reverse_post_octet_delta_count', + type: 'long', }, - 'netflow.opaque_octets': { + 'netflow.reverse_post_octet_total_count': { category: 'netflow', - name: 'netflow.opaque_octets', - type: 'short', + name: 'netflow.reverse_post_octet_total_count', + type: 'long', }, - 'netflow.session_scope': { + 'netflow.reverse_post_packet_delta_count': { category: 'netflow', - name: 'netflow.session_scope', - type: 'short', + name: 'netflow.reverse_post_packet_delta_count', + type: 'long', }, - 'netflow.max_flow_end_microseconds': { + 'netflow.reverse_post_packet_total_count': { category: 'netflow', - name: 'netflow.max_flow_end_microseconds', - type: 'date', + name: 'netflow.reverse_post_packet_total_count', + type: 'long', }, - 'netflow.max_flow_end_milliseconds': { + 'netflow.reverse_post_source_mac_address': { category: 'netflow', - name: 'netflow.max_flow_end_milliseconds', - type: 'date', + name: 'netflow.reverse_post_source_mac_address', + type: 'keyword', }, - 'netflow.max_flow_end_nanoseconds': { + 'netflow.reverse_post_vlan_id': { category: 'netflow', - name: 'netflow.max_flow_end_nanoseconds', - type: 'date', + name: 'netflow.reverse_post_vlan_id', + type: 'integer', }, - 'netflow.min_flow_start_microseconds': { + 'netflow.reverse_private_enterprise_number': { category: 'netflow', - name: 'netflow.min_flow_start_microseconds', - type: 'date', + name: 'netflow.reverse_private_enterprise_number', + type: 'long', }, - 'netflow.min_flow_start_milliseconds': { + 'netflow.reverse_protocol_identifier': { category: 'netflow', - name: 'netflow.min_flow_start_milliseconds', - type: 'date', + name: 'netflow.reverse_protocol_identifier', + type: 'short', }, - 'netflow.min_flow_start_nanoseconds': { + 'netflow.reverse_pseudo_wire_control_word': { category: 'netflow', - name: 'netflow.min_flow_start_nanoseconds', - type: 'date', + name: 'netflow.reverse_pseudo_wire_control_word', + type: 'long', }, - 'netflow.collector_certificate': { + 'netflow.reverse_pseudo_wire_destination_ipv4_address': { category: 'netflow', - name: 'netflow.collector_certificate', - type: 'short', + name: 'netflow.reverse_pseudo_wire_destination_ipv4_address', + type: 'ip', }, - 'netflow.exporter_certificate': { + 'netflow.reverse_pseudo_wire_id': { category: 'netflow', - name: 'netflow.exporter_certificate', - type: 'short', + name: 'netflow.reverse_pseudo_wire_id', + type: 'long', }, - 'netflow.data_records_reliability': { + 'netflow.reverse_pseudo_wire_type': { category: 'netflow', - name: 'netflow.data_records_reliability', - type: 'boolean', + name: 'netflow.reverse_pseudo_wire_type', + type: 'integer', }, - 'netflow.observation_point_type': { + 'netflow.reverse_relative_error': { category: 'netflow', - name: 'netflow.observation_point_type', - type: 'short', + name: 'netflow.reverse_relative_error', + type: 'double', }, - 'netflow.new_connection_delta_count': { + 'netflow.reverse_responder_octets': { category: 'netflow', - name: 'netflow.new_connection_delta_count', + name: 'netflow.reverse_responder_octets', type: 'long', }, - 'netflow.connection_sum_duration_seconds': { + 'netflow.reverse_responder_packets': { category: 'netflow', - name: 'netflow.connection_sum_duration_seconds', + name: 'netflow.reverse_responder_packets', type: 'long', }, - 'netflow.connection_transaction_id': { + 'netflow.reverse_rfc3550_jitter_microseconds': { category: 'netflow', - name: 'netflow.connection_transaction_id', + name: 'netflow.reverse_rfc3550_jitter_microseconds', type: 'long', }, - 'netflow.post_nat_source_ipv6_address': { - category: 'netflow', - name: 'netflow.post_nat_source_ipv6_address', - type: 'ip', - }, - 'netflow.post_nat_destination_ipv6_address': { + 'netflow.reverse_rfc3550_jitter_milliseconds': { category: 'netflow', - name: 'netflow.post_nat_destination_ipv6_address', - type: 'ip', + name: 'netflow.reverse_rfc3550_jitter_milliseconds', + type: 'long', }, - 'netflow.nat_pool_id': { + 'netflow.reverse_rfc3550_jitter_nanoseconds': { category: 'netflow', - name: 'netflow.nat_pool_id', + name: 'netflow.reverse_rfc3550_jitter_nanoseconds', type: 'long', }, - 'netflow.nat_pool_name': { + 'netflow.reverse_rtp_payload_type': { category: 'netflow', - name: 'netflow.nat_pool_name', - type: 'keyword', + name: 'netflow.reverse_rtp_payload_type', + type: 'short', }, - 'netflow.anonymization_flags': { + 'netflow.reverse_rtp_sequence_number': { category: 'netflow', - name: 'netflow.anonymization_flags', + name: 'netflow.reverse_rtp_sequence_number', type: 'integer', }, - 'netflow.anonymization_technique': { + 'netflow.reverse_sampler_id': { category: 'netflow', - name: 'netflow.anonymization_technique', - type: 'integer', + name: 'netflow.reverse_sampler_id', + type: 'short', }, - 'netflow.information_element_index': { + 'netflow.reverse_sampler_mode': { category: 'netflow', - name: 'netflow.information_element_index', - type: 'integer', + name: 'netflow.reverse_sampler_mode', + type: 'short', }, - 'netflow.p2p_technology': { + 'netflow.reverse_sampler_name': { category: 'netflow', - name: 'netflow.p2p_technology', + name: 'netflow.reverse_sampler_name', type: 'keyword', }, - 'netflow.tunnel_technology': { + 'netflow.reverse_sampler_random_interval': { category: 'netflow', - name: 'netflow.tunnel_technology', - type: 'keyword', + name: 'netflow.reverse_sampler_random_interval', + type: 'long', }, - 'netflow.encrypted_technology': { + 'netflow.reverse_sampling_algorithm': { category: 'netflow', - name: 'netflow.encrypted_technology', - type: 'keyword', + name: 'netflow.reverse_sampling_algorithm', + type: 'short', }, - 'netflow.bgp_validity_state': { + 'netflow.reverse_sampling_flow_interval': { category: 'netflow', - name: 'netflow.bgp_validity_state', - type: 'short', + name: 'netflow.reverse_sampling_flow_interval', + type: 'long', }, - 'netflow.ip_sec_spi': { + 'netflow.reverse_sampling_flow_spacing': { category: 'netflow', - name: 'netflow.ip_sec_spi', + name: 'netflow.reverse_sampling_flow_spacing', type: 'long', }, - 'netflow.gre_key': { + 'netflow.reverse_sampling_interval': { category: 'netflow', - name: 'netflow.gre_key', + name: 'netflow.reverse_sampling_interval', type: 'long', }, - 'netflow.nat_type': { + 'netflow.reverse_sampling_packet_interval': { category: 'netflow', - name: 'netflow.nat_type', - type: 'short', + name: 'netflow.reverse_sampling_packet_interval', + type: 'long', }, - 'netflow.initiator_packets': { + 'netflow.reverse_sampling_packet_space': { category: 'netflow', - name: 'netflow.initiator_packets', + name: 'netflow.reverse_sampling_packet_space', type: 'long', }, - 'netflow.responder_packets': { + 'netflow.reverse_sampling_population': { category: 'netflow', - name: 'netflow.responder_packets', + name: 'netflow.reverse_sampling_population', type: 'long', }, - 'netflow.observation_domain_name': { + 'netflow.reverse_sampling_probability': { category: 'netflow', - name: 'netflow.observation_domain_name', - type: 'keyword', + name: 'netflow.reverse_sampling_probability', + type: 'double', }, - 'netflow.selection_sequence_id': { + 'netflow.reverse_sampling_size': { category: 'netflow', - name: 'netflow.selection_sequence_id', + name: 'netflow.reverse_sampling_size', type: 'long', }, - 'netflow.selector_id': { + 'netflow.reverse_sampling_time_interval': { category: 'netflow', - name: 'netflow.selector_id', + name: 'netflow.reverse_sampling_time_interval', type: 'long', }, - 'netflow.information_element_id': { + 'netflow.reverse_sampling_time_space': { category: 'netflow', - name: 'netflow.information_element_id', + name: 'netflow.reverse_sampling_time_space', + type: 'long', + }, + 'netflow.reverse_second_packet_banner': { + category: 'netflow', + name: 'netflow.reverse_second_packet_banner', + type: 'keyword', + }, + 'netflow.reverse_section_exported_octets': { + category: 'netflow', + name: 'netflow.reverse_section_exported_octets', type: 'integer', }, - 'netflow.selector_algorithm': { + 'netflow.reverse_section_offset': { category: 'netflow', - name: 'netflow.selector_algorithm', + name: 'netflow.reverse_section_offset', type: 'integer', }, - 'netflow.sampling_packet_interval': { + 'netflow.reverse_selection_sequence_id': { category: 'netflow', - name: 'netflow.sampling_packet_interval', + name: 'netflow.reverse_selection_sequence_id', type: 'long', }, - 'netflow.sampling_packet_space': { + 'netflow.reverse_selector_algorithm': { category: 'netflow', - name: 'netflow.sampling_packet_space', - type: 'long', + name: 'netflow.reverse_selector_algorithm', + type: 'integer', }, - 'netflow.sampling_time_interval': { + 'netflow.reverse_selector_id': { category: 'netflow', - name: 'netflow.sampling_time_interval', + name: 'netflow.reverse_selector_id', type: 'long', }, - 'netflow.sampling_time_space': { + 'netflow.reverse_selector_id_total_flows_observed': { category: 'netflow', - name: 'netflow.sampling_time_space', + name: 'netflow.reverse_selector_id_total_flows_observed', type: 'long', }, - 'netflow.sampling_size': { + 'netflow.reverse_selector_id_total_flows_selected': { category: 'netflow', - name: 'netflow.sampling_size', + name: 'netflow.reverse_selector_id_total_flows_selected', type: 'long', }, - 'netflow.sampling_population': { + 'netflow.reverse_selector_id_total_pkts_observed': { category: 'netflow', - name: 'netflow.sampling_population', + name: 'netflow.reverse_selector_id_total_pkts_observed', type: 'long', }, - 'netflow.sampling_probability': { + 'netflow.reverse_selector_id_total_pkts_selected': { category: 'netflow', - name: 'netflow.sampling_probability', - type: 'double', + name: 'netflow.reverse_selector_id_total_pkts_selected', + type: 'long', }, - 'netflow.data_link_frame_size': { + 'netflow.reverse_selector_name': { category: 'netflow', - name: 'netflow.data_link_frame_size', - type: 'integer', + name: 'netflow.reverse_selector_name', + type: 'keyword', }, - 'netflow.ip_header_packet_section': { + 'netflow.reverse_session_scope': { category: 'netflow', - name: 'netflow.ip_header_packet_section', + name: 'netflow.reverse_session_scope', type: 'short', }, - 'netflow.ip_payload_packet_section': { + 'netflow.reverse_small_packet_count': { category: 'netflow', - name: 'netflow.ip_payload_packet_section', - type: 'short', + name: 'netflow.reverse_small_packet_count', + type: 'long', }, - 'netflow.data_link_frame_section': { + 'netflow.reverse_source_ipv4_address': { category: 'netflow', - name: 'netflow.data_link_frame_section', - type: 'short', + name: 'netflow.reverse_source_ipv4_address', + type: 'ip', }, - 'netflow.mpls_label_stack_section': { + 'netflow.reverse_source_ipv4_prefix': { category: 'netflow', - name: 'netflow.mpls_label_stack_section', - type: 'short', + name: 'netflow.reverse_source_ipv4_prefix', + type: 'ip', }, - 'netflow.mpls_payload_packet_section': { + 'netflow.reverse_source_ipv4_prefix_length': { category: 'netflow', - name: 'netflow.mpls_payload_packet_section', + name: 'netflow.reverse_source_ipv4_prefix_length', type: 'short', }, - 'netflow.selector_id_total_pkts_observed': { - category: 'netflow', - name: 'netflow.selector_id_total_pkts_observed', - type: 'long', - }, - 'netflow.selector_id_total_pkts_selected': { + 'netflow.reverse_source_ipv6_address': { category: 'netflow', - name: 'netflow.selector_id_total_pkts_selected', - type: 'long', + name: 'netflow.reverse_source_ipv6_address', + type: 'ip', }, - 'netflow.absolute_error': { + 'netflow.reverse_source_ipv6_prefix': { category: 'netflow', - name: 'netflow.absolute_error', - type: 'double', + name: 'netflow.reverse_source_ipv6_prefix', + type: 'ip', }, - 'netflow.relative_error': { + 'netflow.reverse_source_ipv6_prefix_length': { category: 'netflow', - name: 'netflow.relative_error', - type: 'double', + name: 'netflow.reverse_source_ipv6_prefix_length', + type: 'short', }, - 'netflow.observation_time_seconds': { + 'netflow.reverse_source_mac_address': { category: 'netflow', - name: 'netflow.observation_time_seconds', - type: 'date', + name: 'netflow.reverse_source_mac_address', + type: 'keyword', }, - 'netflow.observation_time_milliseconds': { + 'netflow.reverse_source_transport_port': { category: 'netflow', - name: 'netflow.observation_time_milliseconds', - type: 'date', + name: 'netflow.reverse_source_transport_port', + type: 'integer', }, - 'netflow.observation_time_microseconds': { + 'netflow.reverse_src_traffic_index': { category: 'netflow', - name: 'netflow.observation_time_microseconds', - type: 'date', + name: 'netflow.reverse_src_traffic_index', + type: 'long', }, - 'netflow.observation_time_nanoseconds': { + 'netflow.reverse_sta_ipv4_address': { category: 'netflow', - name: 'netflow.observation_time_nanoseconds', - type: 'date', + name: 'netflow.reverse_sta_ipv4_address', + type: 'ip', }, - 'netflow.digest_hash_value': { + 'netflow.reverse_sta_mac_address': { category: 'netflow', - name: 'netflow.digest_hash_value', - type: 'long', + name: 'netflow.reverse_sta_mac_address', + type: 'keyword', }, - 'netflow.hash_ip_payload_offset': { + 'netflow.reverse_standard_deviation_interarrival_time': { category: 'netflow', - name: 'netflow.hash_ip_payload_offset', + name: 'netflow.reverse_standard_deviation_interarrival_time', type: 'long', }, - 'netflow.hash_ip_payload_size': { + 'netflow.reverse_standard_deviation_payload_length': { category: 'netflow', - name: 'netflow.hash_ip_payload_size', - type: 'long', + name: 'netflow.reverse_standard_deviation_payload_length', + type: 'integer', }, - 'netflow.hash_output_range_min': { + 'netflow.reverse_system_init_time_milliseconds': { category: 'netflow', - name: 'netflow.hash_output_range_min', + name: 'netflow.reverse_system_init_time_milliseconds', type: 'long', }, - 'netflow.hash_output_range_max': { + 'netflow.reverse_tcp_ack_total_count': { category: 'netflow', - name: 'netflow.hash_output_range_max', + name: 'netflow.reverse_tcp_ack_total_count', type: 'long', }, - 'netflow.hash_selected_range_min': { + 'netflow.reverse_tcp_acknowledgement_number': { category: 'netflow', - name: 'netflow.hash_selected_range_min', + name: 'netflow.reverse_tcp_acknowledgement_number', type: 'long', }, - 'netflow.hash_selected_range_max': { + 'netflow.reverse_tcp_control_bits': { category: 'netflow', - name: 'netflow.hash_selected_range_max', - type: 'long', + name: 'netflow.reverse_tcp_control_bits', + type: 'integer', }, - 'netflow.hash_digest_output': { + 'netflow.reverse_tcp_destination_port': { category: 'netflow', - name: 'netflow.hash_digest_output', - type: 'boolean', + name: 'netflow.reverse_tcp_destination_port', + type: 'integer', }, - 'netflow.hash_initialiser_value': { + 'netflow.reverse_tcp_fin_total_count': { category: 'netflow', - name: 'netflow.hash_initialiser_value', + name: 'netflow.reverse_tcp_fin_total_count', type: 'long', }, - 'netflow.selector_name': { - category: 'netflow', - name: 'netflow.selector_name', - type: 'keyword', - }, - 'netflow.upper_ci_limit': { + 'netflow.reverse_tcp_header_length': { category: 'netflow', - name: 'netflow.upper_ci_limit', - type: 'double', + name: 'netflow.reverse_tcp_header_length', + type: 'short', }, - 'netflow.lower_ci_limit': { + 'netflow.reverse_tcp_options': { category: 'netflow', - name: 'netflow.lower_ci_limit', - type: 'double', + name: 'netflow.reverse_tcp_options', + type: 'long', }, - 'netflow.confidence_level': { + 'netflow.reverse_tcp_psh_total_count': { category: 'netflow', - name: 'netflow.confidence_level', - type: 'double', + name: 'netflow.reverse_tcp_psh_total_count', + type: 'long', }, - 'netflow.information_element_data_type': { + 'netflow.reverse_tcp_rst_total_count': { category: 'netflow', - name: 'netflow.information_element_data_type', - type: 'short', + name: 'netflow.reverse_tcp_rst_total_count', + type: 'long', }, - 'netflow.information_element_description': { + 'netflow.reverse_tcp_sequence_number': { category: 'netflow', - name: 'netflow.information_element_description', - type: 'keyword', + name: 'netflow.reverse_tcp_sequence_number', + type: 'long', }, - 'netflow.information_element_name': { + 'netflow.reverse_tcp_source_port': { category: 'netflow', - name: 'netflow.information_element_name', - type: 'keyword', + name: 'netflow.reverse_tcp_source_port', + type: 'integer', }, - 'netflow.information_element_range_begin': { + 'netflow.reverse_tcp_syn_total_count': { category: 'netflow', - name: 'netflow.information_element_range_begin', + name: 'netflow.reverse_tcp_syn_total_count', type: 'long', }, - 'netflow.information_element_range_end': { + 'netflow.reverse_tcp_urg_total_count': { category: 'netflow', - name: 'netflow.information_element_range_end', + name: 'netflow.reverse_tcp_urg_total_count', type: 'long', }, - 'netflow.information_element_semantics': { + 'netflow.reverse_tcp_urgent_pointer': { category: 'netflow', - name: 'netflow.information_element_semantics', - type: 'short', + name: 'netflow.reverse_tcp_urgent_pointer', + type: 'integer', }, - 'netflow.information_element_units': { + 'netflow.reverse_tcp_window_scale': { category: 'netflow', - name: 'netflow.information_element_units', + name: 'netflow.reverse_tcp_window_scale', type: 'integer', }, - 'netflow.private_enterprise_number': { + 'netflow.reverse_tcp_window_size': { category: 'netflow', - name: 'netflow.private_enterprise_number', - type: 'long', + name: 'netflow.reverse_tcp_window_size', + type: 'integer', }, - 'netflow.virtual_station_interface_id': { + 'netflow.reverse_total_length_ipv4': { category: 'netflow', - name: 'netflow.virtual_station_interface_id', - type: 'short', + name: 'netflow.reverse_total_length_ipv4', + type: 'integer', }, - 'netflow.virtual_station_interface_name': { + 'netflow.reverse_transport_octet_delta_count': { category: 'netflow', - name: 'netflow.virtual_station_interface_name', - type: 'keyword', + name: 'netflow.reverse_transport_octet_delta_count', + type: 'long', }, - 'netflow.virtual_station_uuid': { + 'netflow.reverse_transport_packet_delta_count': { category: 'netflow', - name: 'netflow.virtual_station_uuid', - type: 'short', + name: 'netflow.reverse_transport_packet_delta_count', + type: 'long', }, - 'netflow.virtual_station_name': { + 'netflow.reverse_tunnel_technology': { category: 'netflow', - name: 'netflow.virtual_station_name', + name: 'netflow.reverse_tunnel_technology', type: 'keyword', }, - 'netflow.layer2_segment_id': { + 'netflow.reverse_udp_destination_port': { category: 'netflow', - name: 'netflow.layer2_segment_id', - type: 'long', + name: 'netflow.reverse_udp_destination_port', + type: 'integer', }, - 'netflow.layer2_octet_delta_count': { + 'netflow.reverse_udp_message_length': { category: 'netflow', - name: 'netflow.layer2_octet_delta_count', - type: 'long', + name: 'netflow.reverse_udp_message_length', + type: 'integer', }, - 'netflow.layer2_octet_total_count': { + 'netflow.reverse_udp_source_port': { category: 'netflow', - name: 'netflow.layer2_octet_total_count', - type: 'long', + name: 'netflow.reverse_udp_source_port', + type: 'integer', }, - 'netflow.ingress_unicast_packet_total_count': { + 'netflow.reverse_union_tcp_flags': { category: 'netflow', - name: 'netflow.ingress_unicast_packet_total_count', - type: 'long', + name: 'netflow.reverse_union_tcp_flags', + type: 'short', }, - 'netflow.ingress_multicast_packet_total_count': { + 'netflow.reverse_upper_ci_limit': { category: 'netflow', - name: 'netflow.ingress_multicast_packet_total_count', - type: 'long', + name: 'netflow.reverse_upper_ci_limit', + type: 'double', }, - 'netflow.ingress_broadcast_packet_total_count': { + 'netflow.reverse_user_name': { category: 'netflow', - name: 'netflow.ingress_broadcast_packet_total_count', - type: 'long', + name: 'netflow.reverse_user_name', + type: 'keyword', }, - 'netflow.egress_unicast_packet_total_count': { + 'netflow.reverse_value_distribution_method': { category: 'netflow', - name: 'netflow.egress_unicast_packet_total_count', - type: 'long', + name: 'netflow.reverse_value_distribution_method', + type: 'short', }, - 'netflow.egress_broadcast_packet_total_count': { + 'netflow.reverse_virtual_station_interface_id': { category: 'netflow', - name: 'netflow.egress_broadcast_packet_total_count', - type: 'long', + name: 'netflow.reverse_virtual_station_interface_id', + type: 'keyword', }, - 'netflow.monitoring_interval_start_milli_seconds': { + 'netflow.reverse_virtual_station_interface_name': { category: 'netflow', - name: 'netflow.monitoring_interval_start_milli_seconds', - type: 'date', + name: 'netflow.reverse_virtual_station_interface_name', + type: 'keyword', }, - 'netflow.monitoring_interval_end_milli_seconds': { + 'netflow.reverse_virtual_station_name': { category: 'netflow', - name: 'netflow.monitoring_interval_end_milli_seconds', - type: 'date', + name: 'netflow.reverse_virtual_station_name', + type: 'keyword', }, - 'netflow.port_range_start': { + 'netflow.reverse_virtual_station_uuid': { category: 'netflow', - name: 'netflow.port_range_start', - type: 'integer', + name: 'netflow.reverse_virtual_station_uuid', + type: 'keyword', }, - 'netflow.port_range_end': { + 'netflow.reverse_vlan_id': { category: 'netflow', - name: 'netflow.port_range_end', + name: 'netflow.reverse_vlan_id', type: 'integer', }, - 'netflow.port_range_step_size': { + 'netflow.reverse_vr_fname': { category: 'netflow', - name: 'netflow.port_range_step_size', - type: 'integer', + name: 'netflow.reverse_vr_fname', + type: 'keyword', }, - 'netflow.port_range_num_ports': { + 'netflow.reverse_wlan_channel_id': { category: 'netflow', - name: 'netflow.port_range_num_ports', - type: 'integer', + name: 'netflow.reverse_wlan_channel_id', + type: 'short', }, - 'netflow.sta_mac_address': { + 'netflow.reverse_wlan_ssid': { category: 'netflow', - name: 'netflow.sta_mac_address', + name: 'netflow.reverse_wlan_ssid', type: 'keyword', }, - 'netflow.sta_ipv4_address': { - category: 'netflow', - name: 'netflow.sta_ipv4_address', - type: 'ip', - }, - 'netflow.wtp_mac_address': { + 'netflow.reverse_wtp_mac_address': { category: 'netflow', - name: 'netflow.wtp_mac_address', + name: 'netflow.reverse_wtp_mac_address', type: 'keyword', }, - 'netflow.ingress_interface_type': { + 'netflow.rfc3550_jitter_microseconds': { category: 'netflow', - name: 'netflow.ingress_interface_type', + name: 'netflow.rfc3550_jitter_microseconds', type: 'long', }, - 'netflow.egress_interface_type': { + 'netflow.rfc3550_jitter_milliseconds': { category: 'netflow', - name: 'netflow.egress_interface_type', + name: 'netflow.rfc3550_jitter_milliseconds', type: 'long', }, - 'netflow.rtp_sequence_number': { + 'netflow.rfc3550_jitter_nanoseconds': { category: 'netflow', - name: 'netflow.rtp_sequence_number', - type: 'integer', + name: 'netflow.rfc3550_jitter_nanoseconds', + type: 'long', }, - 'netflow.user_name': { + 'netflow.rtp_payload_type': { category: 'netflow', - name: 'netflow.user_name', - type: 'keyword', + name: 'netflow.rtp_payload_type', + type: 'short', }, - 'netflow.application_category_name': { + 'netflow.rtp_sequence_number': { category: 'netflow', - name: 'netflow.application_category_name', - type: 'keyword', + name: 'netflow.rtp_sequence_number', + type: 'integer', }, - 'netflow.application_sub_category_name': { + 'netflow.sampler_id': { category: 'netflow', - name: 'netflow.application_sub_category_name', - type: 'keyword', + name: 'netflow.sampler_id', + type: 'short', }, - 'netflow.application_group_name': { + 'netflow.sampler_mode': { category: 'netflow', - name: 'netflow.application_group_name', - type: 'keyword', + name: 'netflow.sampler_mode', + type: 'short', }, - 'netflow.original_flows_present': { + 'netflow.sampler_name': { category: 'netflow', - name: 'netflow.original_flows_present', - type: 'long', + name: 'netflow.sampler_name', + type: 'keyword', }, - 'netflow.original_flows_initiated': { + 'netflow.sampler_random_interval': { category: 'netflow', - name: 'netflow.original_flows_initiated', + name: 'netflow.sampler_random_interval', type: 'long', }, - 'netflow.original_flows_completed': { + 'netflow.sampling_algorithm': { category: 'netflow', - name: 'netflow.original_flows_completed', - type: 'long', + name: 'netflow.sampling_algorithm', + type: 'short', }, - 'netflow.distinct_count_of_source_ip_address': { + 'netflow.sampling_flow_interval': { category: 'netflow', - name: 'netflow.distinct_count_of_source_ip_address', + name: 'netflow.sampling_flow_interval', type: 'long', }, - 'netflow.distinct_count_of_destination_ip_address': { + 'netflow.sampling_flow_spacing': { category: 'netflow', - name: 'netflow.distinct_count_of_destination_ip_address', + name: 'netflow.sampling_flow_spacing', type: 'long', }, - 'netflow.distinct_count_of_source_ipv4_address': { + 'netflow.sampling_interval': { category: 'netflow', - name: 'netflow.distinct_count_of_source_ipv4_address', + name: 'netflow.sampling_interval', type: 'long', }, - 'netflow.distinct_count_of_destination_ipv4_address': { + 'netflow.sampling_packet_interval': { category: 'netflow', - name: 'netflow.distinct_count_of_destination_ipv4_address', + name: 'netflow.sampling_packet_interval', type: 'long', }, - 'netflow.distinct_count_of_source_ipv6_address': { + 'netflow.sampling_packet_space': { category: 'netflow', - name: 'netflow.distinct_count_of_source_ipv6_address', + name: 'netflow.sampling_packet_space', type: 'long', }, - 'netflow.distinct_count_of_destination_ipv6_address': { + 'netflow.sampling_population': { category: 'netflow', - name: 'netflow.distinct_count_of_destination_ipv6_address', + name: 'netflow.sampling_population', type: 'long', }, - 'netflow.value_distribution_method': { + 'netflow.sampling_probability': { category: 'netflow', - name: 'netflow.value_distribution_method', - type: 'short', + name: 'netflow.sampling_probability', + type: 'double', }, - 'netflow.rfc3550_jitter_milliseconds': { + 'netflow.sampling_size': { category: 'netflow', - name: 'netflow.rfc3550_jitter_milliseconds', + name: 'netflow.sampling_size', type: 'long', }, - 'netflow.rfc3550_jitter_microseconds': { + 'netflow.sampling_time_interval': { category: 'netflow', - name: 'netflow.rfc3550_jitter_microseconds', + name: 'netflow.sampling_time_interval', type: 'long', }, - 'netflow.rfc3550_jitter_nanoseconds': { + 'netflow.sampling_time_space': { category: 'netflow', - name: 'netflow.rfc3550_jitter_nanoseconds', + name: 'netflow.sampling_time_space', type: 'long', }, - 'netflow.dot1q_dei': { + 'netflow.second_packet_banner': { category: 'netflow', - name: 'netflow.dot1q_dei', - type: 'boolean', + name: 'netflow.second_packet_banner', + type: 'keyword', }, - 'netflow.dot1q_customer_dei': { + 'netflow.section_exported_octets': { category: 'netflow', - name: 'netflow.dot1q_customer_dei', - type: 'boolean', + name: 'netflow.section_exported_octets', + type: 'integer', }, - 'netflow.flow_selector_algorithm': { + 'netflow.section_offset': { category: 'netflow', - name: 'netflow.flow_selector_algorithm', + name: 'netflow.section_offset', type: 'integer', }, - 'netflow.flow_selected_octet_delta_count': { + 'netflow.selection_sequence_id': { category: 'netflow', - name: 'netflow.flow_selected_octet_delta_count', + name: 'netflow.selection_sequence_id', type: 'long', }, - 'netflow.flow_selected_packet_delta_count': { + 'netflow.selector_algorithm': { category: 'netflow', - name: 'netflow.flow_selected_packet_delta_count', - type: 'long', + name: 'netflow.selector_algorithm', + type: 'integer', }, - 'netflow.flow_selected_flow_delta_count': { + 'netflow.selector_id': { category: 'netflow', - name: 'netflow.flow_selected_flow_delta_count', + name: 'netflow.selector_id', type: 'long', }, 'netflow.selector_id_total_flows_observed': { @@ -30519,433 +44204,491 @@ export const fieldsBeat: BeatFields = { name: 'netflow.selector_id_total_flows_selected', type: 'long', }, - 'netflow.sampling_flow_interval': { + 'netflow.selector_id_total_pkts_observed': { category: 'netflow', - name: 'netflow.sampling_flow_interval', + name: 'netflow.selector_id_total_pkts_observed', type: 'long', }, - 'netflow.sampling_flow_spacing': { + 'netflow.selector_id_total_pkts_selected': { category: 'netflow', - name: 'netflow.sampling_flow_spacing', + name: 'netflow.selector_id_total_pkts_selected', type: 'long', }, - 'netflow.flow_sampling_time_interval': { + 'netflow.selector_name': { category: 'netflow', - name: 'netflow.flow_sampling_time_interval', - type: 'long', + name: 'netflow.selector_name', + type: 'keyword', }, - 'netflow.flow_sampling_time_spacing': { + 'netflow.service_name': { category: 'netflow', - name: 'netflow.flow_sampling_time_spacing', - type: 'long', + name: 'netflow.service_name', + type: 'keyword', }, - 'netflow.hash_flow_domain': { + 'netflow.session_scope': { category: 'netflow', - name: 'netflow.hash_flow_domain', + name: 'netflow.session_scope', + type: 'short', + }, + 'netflow.silk_app_label': { + category: 'netflow', + name: 'netflow.silk_app_label', type: 'integer', }, - 'netflow.transport_octet_delta_count': { + 'netflow.small_packet_count': { category: 'netflow', - name: 'netflow.transport_octet_delta_count', + name: 'netflow.small_packet_count', type: 'long', }, - 'netflow.transport_packet_delta_count': { + 'netflow.source_ipv4_address': { category: 'netflow', - name: 'netflow.transport_packet_delta_count', - type: 'long', + name: 'netflow.source_ipv4_address', + type: 'ip', }, - 'netflow.original_exporter_ipv4_address': { + 'netflow.source_ipv4_prefix': { category: 'netflow', - name: 'netflow.original_exporter_ipv4_address', + name: 'netflow.source_ipv4_prefix', type: 'ip', }, - 'netflow.original_exporter_ipv6_address': { + 'netflow.source_ipv4_prefix_length': { category: 'netflow', - name: 'netflow.original_exporter_ipv6_address', + name: 'netflow.source_ipv4_prefix_length', + type: 'short', + }, + 'netflow.source_ipv6_address': { + category: 'netflow', + name: 'netflow.source_ipv6_address', type: 'ip', }, - 'netflow.original_observation_domain_id': { + 'netflow.source_ipv6_prefix': { category: 'netflow', - name: 'netflow.original_observation_domain_id', - type: 'long', + name: 'netflow.source_ipv6_prefix', + type: 'ip', }, - 'netflow.intermediate_process_id': { + 'netflow.source_ipv6_prefix_length': { category: 'netflow', - name: 'netflow.intermediate_process_id', - type: 'long', + name: 'netflow.source_ipv6_prefix_length', + type: 'short', }, - 'netflow.ignored_data_record_total_count': { + 'netflow.source_mac_address': { category: 'netflow', - name: 'netflow.ignored_data_record_total_count', - type: 'long', + name: 'netflow.source_mac_address', + type: 'keyword', }, - 'netflow.data_link_frame_type': { + 'netflow.source_transport_port': { category: 'netflow', - name: 'netflow.data_link_frame_type', + name: 'netflow.source_transport_port', type: 'integer', }, - 'netflow.section_offset': { + 'netflow.source_transport_ports_limit': { category: 'netflow', - name: 'netflow.section_offset', + name: 'netflow.source_transport_ports_limit', type: 'integer', }, - 'netflow.section_exported_octets': { + 'netflow.src_traffic_index': { category: 'netflow', - name: 'netflow.section_exported_octets', - type: 'integer', + name: 'netflow.src_traffic_index', + type: 'long', }, - 'netflow.dot1q_service_instance_tag': { + 'netflow.ssl_cert_serial_number': { category: 'netflow', - name: 'netflow.dot1q_service_instance_tag', - type: 'short', + name: 'netflow.ssl_cert_serial_number', + type: 'keyword', }, - 'netflow.dot1q_service_instance_id': { + 'netflow.ssl_cert_signature': { category: 'netflow', - name: 'netflow.dot1q_service_instance_id', - type: 'long', + name: 'netflow.ssl_cert_signature', + type: 'keyword', }, - 'netflow.dot1q_service_instance_priority': { + 'netflow.ssl_cert_validity_not_after': { category: 'netflow', - name: 'netflow.dot1q_service_instance_priority', - type: 'short', + name: 'netflow.ssl_cert_validity_not_after', + type: 'keyword', }, - 'netflow.dot1q_customer_source_mac_address': { + 'netflow.ssl_cert_validity_not_before': { category: 'netflow', - name: 'netflow.dot1q_customer_source_mac_address', + name: 'netflow.ssl_cert_validity_not_before', type: 'keyword', }, - 'netflow.dot1q_customer_destination_mac_address': { + 'netflow.ssl_cert_version': { category: 'netflow', - name: 'netflow.dot1q_customer_destination_mac_address', + name: 'netflow.ssl_cert_version', + type: 'short', + }, + 'netflow.ssl_certificate_hash': { + category: 'netflow', + name: 'netflow.ssl_certificate_hash', type: 'keyword', }, - 'netflow.post_layer2_octet_delta_count': { + 'netflow.ssl_cipher': { category: 'netflow', - name: 'netflow.post_layer2_octet_delta_count', - type: 'long', + name: 'netflow.ssl_cipher', + type: 'keyword', }, - 'netflow.post_mcast_layer2_octet_delta_count': { + 'netflow.ssl_client_version': { category: 'netflow', - name: 'netflow.post_mcast_layer2_octet_delta_count', - type: 'long', + name: 'netflow.ssl_client_version', + type: 'short', }, - 'netflow.post_layer2_octet_total_count': { + 'netflow.ssl_compression_method': { category: 'netflow', - name: 'netflow.post_layer2_octet_total_count', - type: 'long', + name: 'netflow.ssl_compression_method', + type: 'short', }, - 'netflow.post_mcast_layer2_octet_total_count': { + 'netflow.ssl_object_type': { category: 'netflow', - name: 'netflow.post_mcast_layer2_octet_total_count', - type: 'long', + name: 'netflow.ssl_object_type', + type: 'keyword', }, - 'netflow.minimum_layer2_total_length': { + 'netflow.ssl_object_value': { category: 'netflow', - name: 'netflow.minimum_layer2_total_length', - type: 'long', + name: 'netflow.ssl_object_value', + type: 'keyword', }, - 'netflow.maximum_layer2_total_length': { + 'netflow.ssl_public_key_algorithm': { category: 'netflow', - name: 'netflow.maximum_layer2_total_length', - type: 'long', + name: 'netflow.ssl_public_key_algorithm', + type: 'keyword', }, - 'netflow.dropped_layer2_octet_delta_count': { + 'netflow.ssl_public_key_length': { category: 'netflow', - name: 'netflow.dropped_layer2_octet_delta_count', - type: 'long', + name: 'netflow.ssl_public_key_length', + type: 'keyword', }, - 'netflow.dropped_layer2_octet_total_count': { + 'netflow.ssl_server_cipher': { category: 'netflow', - name: 'netflow.dropped_layer2_octet_total_count', + name: 'netflow.ssl_server_cipher', type: 'long', }, - 'netflow.ignored_layer2_octet_total_count': { + 'netflow.ssl_server_name': { category: 'netflow', - name: 'netflow.ignored_layer2_octet_total_count', - type: 'long', + name: 'netflow.ssl_server_name', + type: 'keyword', }, - 'netflow.not_sent_layer2_octet_total_count': { + 'netflow.sta_ipv4_address': { category: 'netflow', - name: 'netflow.not_sent_layer2_octet_total_count', - type: 'long', + name: 'netflow.sta_ipv4_address', + type: 'ip', }, - 'netflow.layer2_octet_delta_sum_of_squares': { + 'netflow.sta_mac_address': { category: 'netflow', - name: 'netflow.layer2_octet_delta_sum_of_squares', - type: 'long', + name: 'netflow.sta_mac_address', + type: 'keyword', }, - 'netflow.layer2_octet_total_sum_of_squares': { + 'netflow.standard_deviation_interarrival_time': { category: 'netflow', - name: 'netflow.layer2_octet_total_sum_of_squares', + name: 'netflow.standard_deviation_interarrival_time', type: 'long', }, - 'netflow.layer2_frame_delta_count': { + 'netflow.standard_deviation_payload_length': { category: 'netflow', - name: 'netflow.layer2_frame_delta_count', - type: 'long', + name: 'netflow.standard_deviation_payload_length', + type: 'short', }, - 'netflow.layer2_frame_total_count': { + 'netflow.system_init_time_milliseconds': { category: 'netflow', - name: 'netflow.layer2_frame_total_count', - type: 'long', + name: 'netflow.system_init_time_milliseconds', + type: 'date', }, - 'netflow.pseudo_wire_destination_ipv4_address': { + 'netflow.tcp_ack_total_count': { category: 'netflow', - name: 'netflow.pseudo_wire_destination_ipv4_address', - type: 'ip', + name: 'netflow.tcp_ack_total_count', + type: 'long', }, - 'netflow.ignored_layer2_frame_total_count': { + 'netflow.tcp_acknowledgement_number': { category: 'netflow', - name: 'netflow.ignored_layer2_frame_total_count', + name: 'netflow.tcp_acknowledgement_number', type: 'long', }, - 'netflow.mib_object_value_integer': { + 'netflow.tcp_control_bits': { category: 'netflow', - name: 'netflow.mib_object_value_integer', + name: 'netflow.tcp_control_bits', type: 'integer', }, - 'netflow.mib_object_value_octet_string': { + 'netflow.tcp_destination_port': { category: 'netflow', - name: 'netflow.mib_object_value_octet_string', - type: 'short', + name: 'netflow.tcp_destination_port', + type: 'integer', }, - 'netflow.mib_object_value_oid': { + 'netflow.tcp_fin_total_count': { category: 'netflow', - name: 'netflow.mib_object_value_oid', - type: 'short', + name: 'netflow.tcp_fin_total_count', + type: 'long', }, - 'netflow.mib_object_value_bits': { + 'netflow.tcp_header_length': { category: 'netflow', - name: 'netflow.mib_object_value_bits', + name: 'netflow.tcp_header_length', type: 'short', }, - 'netflow.mib_object_value_ip_address': { - category: 'netflow', - name: 'netflow.mib_object_value_ip_address', - type: 'ip', - }, - 'netflow.mib_object_value_counter': { + 'netflow.tcp_options': { category: 'netflow', - name: 'netflow.mib_object_value_counter', + name: 'netflow.tcp_options', type: 'long', }, - 'netflow.mib_object_value_gauge': { + 'netflow.tcp_psh_total_count': { category: 'netflow', - name: 'netflow.mib_object_value_gauge', + name: 'netflow.tcp_psh_total_count', type: 'long', }, - 'netflow.mib_object_value_time_ticks': { + 'netflow.tcp_rst_total_count': { category: 'netflow', - name: 'netflow.mib_object_value_time_ticks', + name: 'netflow.tcp_rst_total_count', type: 'long', }, - 'netflow.mib_object_value_unsigned': { + 'netflow.tcp_sequence_number': { category: 'netflow', - name: 'netflow.mib_object_value_unsigned', + name: 'netflow.tcp_sequence_number', type: 'long', }, - 'netflow.mib_object_identifier': { + 'netflow.tcp_source_port': { category: 'netflow', - name: 'netflow.mib_object_identifier', - type: 'short', + name: 'netflow.tcp_source_port', + type: 'integer', }, - 'netflow.mib_sub_identifier': { + 'netflow.tcp_syn_total_count': { category: 'netflow', - name: 'netflow.mib_sub_identifier', + name: 'netflow.tcp_syn_total_count', type: 'long', }, - 'netflow.mib_index_indicator': { + 'netflow.tcp_urg_total_count': { category: 'netflow', - name: 'netflow.mib_index_indicator', + name: 'netflow.tcp_urg_total_count', type: 'long', }, - 'netflow.mib_capture_time_semantics': { + 'netflow.tcp_urgent_pointer': { category: 'netflow', - name: 'netflow.mib_capture_time_semantics', - type: 'short', + name: 'netflow.tcp_urgent_pointer', + type: 'integer', }, - 'netflow.mib_context_engine_id': { + 'netflow.tcp_window_scale': { category: 'netflow', - name: 'netflow.mib_context_engine_id', - type: 'short', + name: 'netflow.tcp_window_scale', + type: 'integer', }, - 'netflow.mib_context_name': { + 'netflow.tcp_window_size': { category: 'netflow', - name: 'netflow.mib_context_name', - type: 'keyword', + name: 'netflow.tcp_window_size', + type: 'integer', }, - 'netflow.mib_object_name': { + 'netflow.template_id': { category: 'netflow', - name: 'netflow.mib_object_name', - type: 'keyword', + name: 'netflow.template_id', + type: 'integer', }, - 'netflow.mib_object_description': { + 'netflow.tftp_filename': { category: 'netflow', - name: 'netflow.mib_object_description', + name: 'netflow.tftp_filename', type: 'keyword', }, - 'netflow.mib_object_syntax': { + 'netflow.tftp_mode': { category: 'netflow', - name: 'netflow.mib_object_syntax', + name: 'netflow.tftp_mode', type: 'keyword', }, - 'netflow.mib_module_name': { + 'netflow.timestamp': { category: 'netflow', - name: 'netflow.mib_module_name', - type: 'keyword', + name: 'netflow.timestamp', + type: 'long', }, - 'netflow.mobile_imsi': { + 'netflow.timestamp_absolute_monitoring-interval': { category: 'netflow', - name: 'netflow.mobile_imsi', - type: 'keyword', + name: 'netflow.timestamp_absolute_monitoring-interval', + type: 'long', }, - 'netflow.mobile_msisdn': { + 'netflow.total_length_ipv4': { category: 'netflow', - name: 'netflow.mobile_msisdn', - type: 'keyword', + name: 'netflow.total_length_ipv4', + type: 'integer', }, - 'netflow.http_status_code': { + 'netflow.traffic_type': { category: 'netflow', - name: 'netflow.http_status_code', - type: 'integer', + name: 'netflow.traffic_type', + type: 'short', }, - 'netflow.source_transport_ports_limit': { + 'netflow.transport_octet_delta_count': { category: 'netflow', - name: 'netflow.source_transport_ports_limit', - type: 'integer', + name: 'netflow.transport_octet_delta_count', + type: 'long', }, - 'netflow.http_request_method': { + 'netflow.transport_packet_delta_count': { category: 'netflow', - name: 'netflow.http_request_method', - type: 'keyword', + name: 'netflow.transport_packet_delta_count', + type: 'long', }, - 'netflow.http_request_host': { + 'netflow.tunnel_technology': { category: 'netflow', - name: 'netflow.http_request_host', + name: 'netflow.tunnel_technology', type: 'keyword', }, - 'netflow.http_request_target': { + 'netflow.udp_destination_port': { category: 'netflow', - name: 'netflow.http_request_target', - type: 'keyword', + name: 'netflow.udp_destination_port', + type: 'integer', }, - 'netflow.http_message_version': { + 'netflow.udp_message_length': { category: 'netflow', - name: 'netflow.http_message_version', - type: 'keyword', + name: 'netflow.udp_message_length', + type: 'integer', }, - 'netflow.nat_instance_id': { + 'netflow.udp_source_port': { category: 'netflow', - name: 'netflow.nat_instance_id', - type: 'long', + name: 'netflow.udp_source_port', + type: 'integer', }, - 'netflow.internal_address_realm': { + 'netflow.union_tcp_flags': { category: 'netflow', - name: 'netflow.internal_address_realm', + name: 'netflow.union_tcp_flags', type: 'short', }, - 'netflow.external_address_realm': { + 'netflow.upper_ci_limit': { category: 'netflow', - name: 'netflow.external_address_realm', + name: 'netflow.upper_ci_limit', + type: 'double', + }, + 'netflow.user_name': { + category: 'netflow', + name: 'netflow.user_name', + type: 'keyword', + }, + 'netflow.username': { + category: 'netflow', + name: 'netflow.username', + type: 'keyword', + }, + 'netflow.value_distribution_method': { + category: 'netflow', + name: 'netflow.value_distribution_method', type: 'short', }, - 'netflow.nat_quota_exceeded_event': { + 'netflow.viptela_vpn_id': { category: 'netflow', - name: 'netflow.nat_quota_exceeded_event', + name: 'netflow.viptela_vpn_id', type: 'long', }, - 'netflow.nat_threshold_event': { + 'netflow.virtual_station_interface_id': { category: 'netflow', - name: 'netflow.nat_threshold_event', - type: 'long', + name: 'netflow.virtual_station_interface_id', + type: 'short', }, - 'netflow.http_user_agent': { + 'netflow.virtual_station_interface_name': { category: 'netflow', - name: 'netflow.http_user_agent', + name: 'netflow.virtual_station_interface_name', type: 'keyword', }, - 'netflow.http_content_type': { + 'netflow.virtual_station_name': { category: 'netflow', - name: 'netflow.http_content_type', + name: 'netflow.virtual_station_name', type: 'keyword', }, - 'netflow.http_reason_phrase': { + 'netflow.virtual_station_uuid': { category: 'netflow', - name: 'netflow.http_reason_phrase', - type: 'keyword', + name: 'netflow.virtual_station_uuid', + type: 'short', }, - 'netflow.max_session_entries': { + 'netflow.vlan_id': { category: 'netflow', - name: 'netflow.max_session_entries', - type: 'long', + name: 'netflow.vlan_id', + type: 'integer', }, - 'netflow.max_bib_entries': { + 'netflow.vmware_egress_interface_attr': { category: 'netflow', - name: 'netflow.max_bib_entries', - type: 'long', + name: 'netflow.vmware_egress_interface_attr', + type: 'integer', }, - 'netflow.max_entries_per_user': { + 'netflow.vmware_ingress_interface_attr': { category: 'netflow', - name: 'netflow.max_entries_per_user', - type: 'long', + name: 'netflow.vmware_ingress_interface_attr', + type: 'integer', }, - 'netflow.max_subscribers': { + 'netflow.vmware_tenant_dest_ipv4': { category: 'netflow', - name: 'netflow.max_subscribers', - type: 'long', + name: 'netflow.vmware_tenant_dest_ipv4', + type: 'ip', }, - 'netflow.max_fragments_pending_reassembly': { + 'netflow.vmware_tenant_dest_ipv6': { category: 'netflow', - name: 'netflow.max_fragments_pending_reassembly', - type: 'long', + name: 'netflow.vmware_tenant_dest_ipv6', + type: 'ip', }, - 'netflow.address_pool_high_threshold': { + 'netflow.vmware_tenant_dest_port': { category: 'netflow', - name: 'netflow.address_pool_high_threshold', - type: 'long', + name: 'netflow.vmware_tenant_dest_port', + type: 'integer', }, - 'netflow.address_pool_low_threshold': { + 'netflow.vmware_tenant_protocol': { category: 'netflow', - name: 'netflow.address_pool_low_threshold', - type: 'long', + name: 'netflow.vmware_tenant_protocol', + type: 'short', }, - 'netflow.address_port_mapping_high_threshold': { + 'netflow.vmware_tenant_source_ipv4': { category: 'netflow', - name: 'netflow.address_port_mapping_high_threshold', - type: 'long', + name: 'netflow.vmware_tenant_source_ipv4', + type: 'ip', }, - 'netflow.address_port_mapping_low_threshold': { + 'netflow.vmware_tenant_source_ipv6': { category: 'netflow', - name: 'netflow.address_port_mapping_low_threshold', - type: 'long', + name: 'netflow.vmware_tenant_source_ipv6', + type: 'ip', }, - 'netflow.address_port_mapping_per_user_high_threshold': { + 'netflow.vmware_tenant_source_port': { category: 'netflow', - name: 'netflow.address_port_mapping_per_user_high_threshold', - type: 'long', + name: 'netflow.vmware_tenant_source_port', + type: 'integer', }, - 'netflow.global_address_mapping_high_threshold': { + 'netflow.vmware_vxlan_export_role': { category: 'netflow', - name: 'netflow.global_address_mapping_high_threshold', - type: 'long', + name: 'netflow.vmware_vxlan_export_role', + type: 'short', }, 'netflow.vpn_identifier': { category: 'netflow', name: 'netflow.vpn_identifier', type: 'short', }, - bucket_name: { - category: 'base', - description: 'Name of the S3 bucket that this log retrieved from. ', - name: 'bucket_name', + 'netflow.vr_fname': { + category: 'netflow', + name: 'netflow.vr_fname', type: 'keyword', }, - object_key: { - category: 'base', - description: 'Name of the S3 object that this log retrieved from. ', - name: 'object_key', + 'netflow.waasoptimization_segment': { + category: 'netflow', + name: 'netflow.waasoptimization_segment', + type: 'short', + }, + 'netflow.wlan_channel_id': { + category: 'netflow', + name: 'netflow.wlan_channel_id', + type: 'short', + }, + 'netflow.wlan_ssid': { + category: 'netflow', + name: 'netflow.wlan_ssid', + type: 'keyword', + }, + 'netflow.wtp_mac_address': { + category: 'netflow', + name: 'netflow.wtp_mac_address', type: 'keyword', }, + 'netflow.xlate_destination_address_ip_v4': { + category: 'netflow', + name: 'netflow.xlate_destination_address_ip_v4', + type: 'ip', + }, + 'netflow.xlate_destination_port': { + category: 'netflow', + name: 'netflow.xlate_destination_port', + type: 'integer', + }, + 'netflow.xlate_source_address_ip_v4': { + category: 'netflow', + name: 'netflow.xlate_source_address_ip_v4', + type: 'ip', + }, + 'netflow.xlate_source_port': { + category: 'netflow', + name: 'netflow.xlate_source_port', + type: 'integer', + }, 'cef.version': { category: 'cef', description: 'Version of the CEF specification used by the message. ', @@ -33954,377 +47697,451 @@ export const fieldsBeat: BeatFields = { 'If the Redis command has resulted in an error, this field contains the error message returned by the Redis server. ', name: 'redis.error', }, - 'thrift.params': { - category: 'thrift', - description: - 'The RPC method call parameters in a human readable format. If the IDL files are available, the parameters use names whenever possible. Otherwise, the IDs from the message are used. ', - name: 'thrift.params', + 'sip.code': { + category: 'sip', + description: 'Response status code.', + name: 'sip.code', + type: 'keyword', }, - 'thrift.service': { - category: 'thrift', - description: 'The name of the Thrift-RPC service as defined in the IDL files. ', - name: 'thrift.service', + 'sip.method': { + category: 'sip', + description: 'Request method.', + name: 'sip.method', + type: 'keyword', }, - 'thrift.return_value': { - category: 'thrift', - description: - 'The value returned by the Thrift-RPC call. This is encoded in a human readable format. ', - name: 'thrift.return_value', + 'sip.status': { + category: 'sip', + description: 'Response status phrase.', + name: 'sip.status', + type: 'keyword', }, - 'thrift.exceptions': { - category: 'thrift', - description: - 'If the call resulted in exceptions, this field contains the exceptions in a human readable format. ', - name: 'thrift.exceptions', + 'sip.type': { + category: 'sip', + description: 'Either request or response.', + name: 'sip.type', + type: 'keyword', }, - 'tls.client.x509.version': { - category: 'tls', - description: 'Version of x509 format.', - example: 3, - name: 'tls.client.x509.version', + 'sip.version': { + category: 'sip', + description: 'SIP protocol version.', + name: 'sip.version', type: 'keyword', }, - 'tls.client.x509.version_number': { - category: 'tls', - description: 'Version of x509 format.', - example: 3, - name: 'tls.client.x509.version_number', + 'sip.uri.original': { + category: 'sip', + description: 'The original URI.', + name: 'sip.uri.original', type: 'keyword', }, - 'tls.client.x509.serial_number': { - category: 'tls', - description: - 'Unique serial number issued by the certificate authority. For consistency, if this value is alphanumeric, it should be formatted without colons and uppercase characters. ', - example: '55FBB9C7DEBF09809D12CCAA', - name: 'tls.client.x509.serial_number', + 'sip.uri.scheme': { + category: 'sip', + description: 'The URI scheme.', + name: 'sip.uri.scheme', type: 'keyword', }, - 'tls.client.x509.issuer.distinguished_name': { - category: 'tls', - description: 'Distinguished name (DN) of issuing certificate authority.', - example: 'C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert SHA2 High Assurance Server CA', - name: 'tls.client.x509.issuer.distinguished_name', + 'sip.uri.username': { + category: 'sip', + description: 'The URI user name.', + name: 'sip.uri.username', type: 'keyword', }, - 'tls.client.x509.issuer.common_name': { - category: 'tls', - description: 'List of common name (CN) of issuing certificate authority.', - example: 'DigiCert SHA2 High Assurance Server CA', - name: 'tls.client.x509.issuer.common_name', + 'sip.uri.host': { + category: 'sip', + description: 'The URI host.', + name: 'sip.uri.host', type: 'keyword', }, - 'tls.client.x509.issuer.organizational_unit': { - category: 'tls', - description: 'List of organizational units (OU) of issuing certificate authority.', - example: 'www.digicert.com', - name: 'tls.client.x509.issuer.organizational_unit', + 'sip.uri.port': { + category: 'sip', + description: 'The URI port.', + name: 'sip.uri.port', type: 'keyword', }, - 'tls.client.x509.issuer.organization': { - category: 'tls', - description: 'List of organizations (O) of issuing certificate authority.', - example: 'DigiCert Inc', - name: 'tls.client.x509.issuer.organization', + 'sip.accept': { + category: 'sip', + description: 'Accept header value.', + name: 'sip.accept', type: 'keyword', }, - 'tls.client.x509.issuer.locality': { - category: 'tls', - description: 'List of locality names (L)', - example: 'Mountain View', - name: 'tls.client.x509.issuer.locality', + 'sip.allow': { + category: 'sip', + description: 'Allowed methods.', + name: 'sip.allow', type: 'keyword', }, - 'tls.client.x509.issuer.province': { - category: 'tls', - description: 'Province or region within country.', - name: 'tls.client.x509.issuer.province', + 'sip.call_id': { + category: 'sip', + description: 'Call ID.', + name: 'sip.call_id', type: 'keyword', }, - 'tls.client.x509.issuer.state_or_province': { - category: 'tls', - description: 'List of state or province names (ST, S, or P)', - example: 'California', - name: 'tls.client.x509.issuer.state_or_province', + 'sip.content_length': { + category: 'sip', + name: 'sip.content_length', + type: 'long', + }, + 'sip.content_type': { + category: 'sip', + name: 'sip.content_type', type: 'keyword', }, - 'tls.client.x509.issuer.country': { - category: 'tls', - description: 'List of country (C) codes', - example: 'US', - name: 'tls.client.x509.issuer.country', + 'sip.max_forwards': { + category: 'sip', + name: 'sip.max_forwards', + type: 'long', + }, + 'sip.supported': { + category: 'sip', + description: 'Supported methods.', + name: 'sip.supported', type: 'keyword', }, - 'tls.client.x509.signature_algorithm': { - category: 'tls', - description: - 'Identifier for certificate signature algorithm. Recommend using names found in Go Lang Crypto library (See https://github.com/golang/go/blob/go1.14/src/crypto/x509/x509.go#L337-L353).', - example: 'SHA256-RSA', - name: 'tls.client.x509.signature_algorithm', + 'sip.user_agent.original': { + category: 'sip', + name: 'sip.user_agent.original', type: 'keyword', }, - 'tls.client.x509.not_before': { - category: 'tls', - description: 'Time at which the certificate is first considered valid.', - example: '"2019-08-16T01:40:25.000Z"', - name: 'tls.client.x509.not_before', - type: 'date', + 'sip.private.uri.original': { + category: 'sip', + description: 'Private original URI.', + name: 'sip.private.uri.original', + type: 'keyword', }, - 'tls.client.x509.not_after': { - category: 'tls', - description: 'Time at which the certificate is no longer considered valid.', - example: '"2020-07-16T03:15:39.000Z"', - name: 'tls.client.x509.not_after', - type: 'date', + 'sip.private.uri.scheme': { + category: 'sip', + description: 'Private URI scheme.', + name: 'sip.private.uri.scheme', + type: 'keyword', }, - 'tls.client.x509.subject.distinguished_name': { - category: 'tls', - description: 'Distinguished name (DN) of the certificate subject entity.', - example: 'C=US, ST=California, L=San Francisco, O=Fastly, Inc., CN=r2.shared.global.fastly.net', - name: 'tls.client.x509.subject.distinguished_name', + 'sip.private.uri.username': { + category: 'sip', + description: 'Private URI user name.', + name: 'sip.private.uri.username', type: 'keyword', }, - 'tls.client.x509.subject.common_name': { - category: 'tls', - description: 'List of common names (CN) of subject.', - example: 'r2.shared.global.fastly.net', - name: 'tls.client.x509.subject.common_name', + 'sip.private.uri.host': { + category: 'sip', + description: 'Private URI host.', + name: 'sip.private.uri.host', type: 'keyword', }, - 'tls.client.x509.subject.organizational_unit': { - category: 'tls', - description: 'List of organizational units (OU) of subject.', - name: 'tls.client.x509.subject.organizational_unit', + 'sip.private.uri.port': { + category: 'sip', + description: 'Private URI port.', + name: 'sip.private.uri.port', type: 'keyword', }, - 'tls.client.x509.subject.organization': { - category: 'tls', - description: 'List of organizations (O) of subject.', - example: 'Fastly, Inc.', - name: 'tls.client.x509.subject.organization', + 'sip.cseq.code': { + category: 'sip', + description: 'Sequence code.', + name: 'sip.cseq.code', type: 'keyword', }, - 'tls.client.x509.subject.locality': { - category: 'tls', - description: 'List of locality names (L)', - example: 'San Francisco', - name: 'tls.client.x509.subject.locality', + 'sip.cseq.method': { + category: 'sip', + description: 'Sequence method.', + name: 'sip.cseq.method', type: 'keyword', }, - 'tls.client.x509.subject.province': { - category: 'tls', - description: 'Province or region within country.', - name: 'tls.client.x509.subject.province', + 'sip.via.original': { + category: 'sip', + description: 'The original Via value.', + name: 'sip.via.original', type: 'keyword', }, - 'tls.client.x509.subject.state_or_province': { - category: 'tls', - description: 'List of state or province names (ST, S, or P)', - example: 'California', - name: 'tls.client.x509.subject.state_or_province', + 'sip.to.display_info': { + category: 'sip', + description: 'To display info', + name: 'sip.to.display_info', type: 'keyword', }, - 'tls.client.x509.subject.country': { - category: 'tls', - description: 'List of country (C) code', - example: 'US', - name: 'tls.client.x509.subject.country', + 'sip.to.uri.original': { + category: 'sip', + description: 'To original URI', + name: 'sip.to.uri.original', type: 'keyword', }, - 'tls.client.x509.public_key_algorithm': { - category: 'tls', - description: 'Algorithm used to generate the public key.', - example: 'RSA', - name: 'tls.client.x509.public_key_algorithm', + 'sip.to.uri.scheme': { + category: 'sip', + description: 'To URI scheme', + name: 'sip.to.uri.scheme', type: 'keyword', }, - 'tls.client.x509.public_key_size': { - category: 'tls', - description: 'The size of the public key space in bits.', - example: 2048, - name: 'tls.client.x509.public_key_size', - type: 'long', + 'sip.to.uri.username': { + category: 'sip', + description: 'To URI user name', + name: 'sip.to.uri.username', + type: 'keyword', }, - 'tls.client.x509.alternative_names': { - category: 'tls', - description: - 'List of subject alternative names (SAN). Name types vary by certificate authority and certificate type but commonly contain IP addresses, DNS names (and wildcards), and email addresses.', - example: '*.elastic.co', - name: 'tls.client.x509.alternative_names', + 'sip.to.uri.host': { + category: 'sip', + description: 'To URI host', + name: 'sip.to.uri.host', type: 'keyword', }, - 'tls.server.x509.version': { - category: 'tls', - description: 'Version of x509 format.', - example: 3, - name: 'tls.server.x509.version', + 'sip.to.uri.port': { + category: 'sip', + description: 'To URI port', + name: 'sip.to.uri.port', type: 'keyword', }, - 'tls.server.x509.version_number': { - category: 'tls', - description: 'Version of x509 format.', - example: 3, - name: 'tls.server.x509.version_number', + 'sip.to.tag': { + category: 'sip', + description: 'To tag', + name: 'sip.to.tag', type: 'keyword', }, - 'tls.server.x509.serial_number': { - category: 'tls', - description: - 'Unique serial number issued by the certificate authority. For consistency, if this value is alphanumeric, it should be formatted without colons and uppercase characters. ', - example: '55FBB9C7DEBF09809D12CCAA', - name: 'tls.server.x509.serial_number', + 'sip.from.display_info': { + category: 'sip', + description: 'From display info', + name: 'sip.from.display_info', type: 'keyword', }, - 'tls.server.x509.issuer.distinguished_name': { - category: 'tls', - description: 'Distinguished name (DN) of issuing certificate authority.', - example: 'C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert SHA2 High Assurance Server CA', - name: 'tls.server.x509.issuer.distinguished_name', + 'sip.from.uri.original': { + category: 'sip', + description: 'From original URI', + name: 'sip.from.uri.original', type: 'keyword', }, - 'tls.server.x509.issuer.common_name': { - category: 'tls', - description: 'List of common name (CN) of issuing certificate authority.', - example: 'DigiCert SHA2 High Assurance Server CA', - name: 'tls.server.x509.issuer.common_name', + 'sip.from.uri.scheme': { + category: 'sip', + description: 'From URI scheme', + name: 'sip.from.uri.scheme', type: 'keyword', }, - 'tls.server.x509.issuer.organizational_unit': { - category: 'tls', - description: 'List of organizational units (OU) of issuing certificate authority.', - example: 'www.digicert.com', - name: 'tls.server.x509.issuer.organizational_unit', + 'sip.from.uri.username': { + category: 'sip', + description: 'From URI user name', + name: 'sip.from.uri.username', type: 'keyword', }, - 'tls.server.x509.issuer.organization': { - category: 'tls', - description: 'List of organizations (O) of issuing certificate authority.', - example: 'DigiCert Inc', - name: 'tls.server.x509.issuer.organization', + 'sip.from.uri.host': { + category: 'sip', + description: 'From URI host', + name: 'sip.from.uri.host', type: 'keyword', }, - 'tls.server.x509.issuer.locality': { - category: 'tls', - description: 'List of locality names (L)', - example: 'Mountain View', - name: 'tls.server.x509.issuer.locality', + 'sip.from.uri.port': { + category: 'sip', + description: 'From URI port', + name: 'sip.from.uri.port', type: 'keyword', }, - 'tls.server.x509.issuer.province': { - category: 'tls', - description: 'Province or region within country.', - name: 'tls.server.x509.issuer.province', + 'sip.from.tag': { + category: 'sip', + description: 'From tag', + name: 'sip.from.tag', type: 'keyword', }, - 'tls.server.x509.issuer.state_or_province': { - category: 'tls', - description: 'List of state or province names (ST, S, or P)', - example: 'California', - name: 'tls.server.x509.issuer.state_or_province', + 'sip.contact.display_info': { + category: 'sip', + description: 'Contact display info', + name: 'sip.contact.display_info', type: 'keyword', }, - 'tls.server.x509.issuer.country': { - category: 'tls', - description: 'List of country (C) codes', - example: 'US', - name: 'tls.server.x509.issuer.country', + 'sip.contact.uri.original': { + category: 'sip', + description: 'Contact original URI', + name: 'sip.contact.uri.original', type: 'keyword', }, - 'tls.server.x509.signature_algorithm': { - category: 'tls', - description: - 'Identifier for certificate signature algorithm. Recommend using names found in Go Lang Crypto library (See https://github.com/golang/go/blob/go1.14/src/crypto/x509/x509.go#L337-L353).', - example: 'SHA256-RSA', - name: 'tls.server.x509.signature_algorithm', + 'sip.contact.uri.scheme': { + category: 'sip', + description: 'Contat URI scheme', + name: 'sip.contact.uri.scheme', type: 'keyword', }, - 'tls.server.x509.not_before': { - category: 'tls', - description: 'Time at which the certificate is first considered valid.', - example: '"2019-08-16T01:40:25.000Z"', - name: 'tls.server.x509.not_before', - type: 'date', + 'sip.contact.uri.username': { + category: 'sip', + description: 'Contact URI user name', + name: 'sip.contact.uri.username', + type: 'keyword', }, - 'tls.server.x509.not_after': { - category: 'tls', - description: 'Time at which the certificate is no longer considered valid.', - example: '"2020-07-16T03:15:39.000Z"', - name: 'tls.server.x509.not_after', - type: 'date', + 'sip.contact.uri.host': { + category: 'sip', + description: 'Contact URI host', + name: 'sip.contact.uri.host', + type: 'keyword', }, - 'tls.server.x509.subject.distinguished_name': { - category: 'tls', - description: 'Distinguished name (DN) of the certificate subject entity.', - example: 'C=US, ST=California, L=San Francisco, O=Fastly, Inc., CN=r2.shared.global.fastly.net', - name: 'tls.server.x509.subject.distinguished_name', + 'sip.contact.uri.port': { + category: 'sip', + description: 'Contact URI port', + name: 'sip.contact.uri.port', type: 'keyword', }, - 'tls.server.x509.subject.common_name': { - category: 'tls', - description: 'List of common names (CN) of subject.', - example: 'r2.shared.global.fastly.net', - name: 'tls.server.x509.subject.common_name', + 'sip.contact.transport': { + category: 'sip', + description: 'Contact transport', + name: 'sip.contact.transport', type: 'keyword', }, - 'tls.server.x509.subject.organizational_unit': { - category: 'tls', - description: 'List of organizational units (OU) of subject.', - name: 'tls.server.x509.subject.organizational_unit', + 'sip.contact.line': { + category: 'sip', + description: 'Contact line', + name: 'sip.contact.line', type: 'keyword', }, - 'tls.server.x509.subject.organization': { - category: 'tls', - description: 'List of organizations (O) of subject.', - example: 'Fastly, Inc.', - name: 'tls.server.x509.subject.organization', + 'sip.contact.expires': { + category: 'sip', + description: 'Contact expires', + name: 'sip.contact.expires', type: 'keyword', }, - 'tls.server.x509.subject.locality': { - category: 'tls', - description: 'List of locality names (L)', - example: 'San Francisco', - name: 'tls.server.x509.subject.locality', + 'sip.contact.q': { + category: 'sip', + description: 'Contact Q', + name: 'sip.contact.q', type: 'keyword', }, - 'tls.server.x509.subject.province': { + 'sip.auth.scheme': { + category: 'sip', + description: 'Auth scheme', + name: 'sip.auth.scheme', + type: 'keyword', + }, + 'sip.auth.realm': { + category: 'sip', + description: 'Auth realm', + name: 'sip.auth.realm', + type: 'keyword', + }, + 'sip.auth.uri.original': { + category: 'sip', + description: 'Auth original URI', + name: 'sip.auth.uri.original', + type: 'keyword', + }, + 'sip.auth.uri.scheme': { + category: 'sip', + description: 'Auth URI scheme', + name: 'sip.auth.uri.scheme', + type: 'keyword', + }, + 'sip.auth.uri.host': { + category: 'sip', + description: 'Auth URI host', + name: 'sip.auth.uri.host', + type: 'keyword', + }, + 'sip.auth.uri.port': { + category: 'sip', + description: 'Auth URI port', + name: 'sip.auth.uri.port', + type: 'keyword', + }, + 'sip.sdp.version': { + category: 'sip', + description: 'SDP version', + name: 'sip.sdp.version', + type: 'keyword', + }, + 'sip.sdp.owner.username': { + category: 'sip', + description: 'SDP owner user name', + name: 'sip.sdp.owner.username', + type: 'keyword', + }, + 'sip.sdp.owner.session_id': { + category: 'sip', + description: 'SDP owner session ID', + name: 'sip.sdp.owner.session_id', + type: 'keyword', + }, + 'sip.sdp.owner.version': { + category: 'sip', + description: 'SDP owner version', + name: 'sip.sdp.owner.version', + type: 'keyword', + }, + 'sip.sdp.owner.ip': { + category: 'sip', + description: 'SDP owner IP', + name: 'sip.sdp.owner.ip', + type: 'ip', + }, + 'sip.sdp.session.name': { + category: 'sip', + description: 'SDP session name', + name: 'sip.sdp.session.name', + type: 'keyword', + }, + 'sip.sdp.connection.info': { + category: 'sip', + description: 'SDP connection info', + name: 'sip.sdp.connection.info', + type: 'keyword', + }, + 'sip.sdp.connection.address': { + category: 'sip', + description: 'SDP connection address', + name: 'sip.sdp.connection.address', + type: 'keyword', + }, + 'sip.sdp.body.original': { + category: 'sip', + description: 'SDP original body', + name: 'sip.sdp.body.original', + type: 'keyword', + }, + 'thrift.params': { + category: 'thrift', + description: + 'The RPC method call parameters in a human readable format. If the IDL files are available, the parameters use names whenever possible. Otherwise, the IDs from the message are used. ', + name: 'thrift.params', + }, + 'thrift.service': { + category: 'thrift', + description: 'The name of the Thrift-RPC service as defined in the IDL files. ', + name: 'thrift.service', + }, + 'thrift.return_value': { + category: 'thrift', + description: + 'The value returned by the Thrift-RPC call. This is encoded in a human readable format. ', + name: 'thrift.return_value', + }, + 'thrift.exceptions': { + category: 'thrift', + description: + 'If the call resulted in exceptions, this field contains the exceptions in a human readable format. ', + name: 'thrift.exceptions', + }, + 'tls.client.x509.version': { category: 'tls', - description: 'Province or region within country.', - name: 'tls.server.x509.subject.province', + description: 'Version of x509 format.', + example: 3, + name: 'tls.client.x509.version', type: 'keyword', }, - 'tls.server.x509.subject.state_or_province': { + 'tls.client.x509.issuer.province': { category: 'tls', - description: 'List of state or province names (ST, S, or P)', - example: 'California', - name: 'tls.server.x509.subject.state_or_province', + description: 'Province or region within country.', + name: 'tls.client.x509.issuer.province', type: 'keyword', }, - 'tls.server.x509.subject.country': { + 'tls.client.x509.subject.province': { category: 'tls', - description: 'List of country (C) code', - example: 'US', - name: 'tls.server.x509.subject.country', + description: 'Province or region within country.', + name: 'tls.client.x509.subject.province', type: 'keyword', }, - 'tls.server.x509.public_key_algorithm': { + 'tls.server.x509.version': { category: 'tls', - description: 'Algorithm used to generate the public key.', - example: 'RSA', - name: 'tls.server.x509.public_key_algorithm', + description: 'Version of x509 format.', + example: 3, + name: 'tls.server.x509.version', type: 'keyword', }, - 'tls.server.x509.public_key_size': { + 'tls.server.x509.issuer.province': { category: 'tls', - description: 'The size of the public key space in bits.', - example: 2048, - name: 'tls.server.x509.public_key_size', - type: 'long', + description: 'Province or region within country.', + name: 'tls.server.x509.issuer.province', + type: 'keyword', }, - 'tls.server.x509.alternative_names': { + 'tls.server.x509.subject.province': { category: 'tls', - description: - 'List of subject alternative names (SAN). Name types vary by certificate authority and certificate type but commonly contain IP addresses, DNS names (and wildcards), and email addresses.', - example: '*.elastic.co', - name: 'tls.server.x509.alternative_names', + description: 'Province or region within country.', + name: 'tls.server.x509.subject.province', type: 'keyword', }, 'tls.detailed.version': { @@ -34472,300 +48289,6 @@ export const fieldsBeat: BeatFields = { name: 'tls.detailed.server_hello.extensions._unparsed_', type: 'keyword', }, - 'tls.detailed.client_certificate.version': { - category: 'tls', - description: 'X509 format version.', - name: 'tls.detailed.client_certificate.version', - type: 'long', - }, - 'tls.detailed.client_certificate.version_number': { - category: 'tls', - description: 'Version of x509 format.', - example: 3, - name: 'tls.detailed.client_certificate.version_number', - type: 'keyword', - }, - 'tls.detailed.client_certificate.serial_number': { - category: 'tls', - description: "The certificate's serial number.", - name: 'tls.detailed.client_certificate.serial_number', - type: 'keyword', - }, - 'tls.detailed.client_certificate.not_before': { - category: 'tls', - description: 'Date before which the certificate is not valid.', - name: 'tls.detailed.client_certificate.not_before', - type: 'date', - }, - 'tls.detailed.client_certificate.not_after': { - category: 'tls', - description: 'Date after which the certificate expires.', - name: 'tls.detailed.client_certificate.not_after', - type: 'date', - }, - 'tls.detailed.client_certificate.public_key_algorithm': { - category: 'tls', - description: "The algorithm used for this certificate's public key. One of RSA, DSA or ECDSA. ", - name: 'tls.detailed.client_certificate.public_key_algorithm', - type: 'keyword', - }, - 'tls.detailed.client_certificate.public_key_size': { - category: 'tls', - description: 'Size of the public key.', - name: 'tls.detailed.client_certificate.public_key_size', - type: 'long', - }, - 'tls.detailed.client_certificate.signature_algorithm': { - category: 'tls', - description: "The algorithm used for the certificate's signature. ", - name: 'tls.detailed.client_certificate.signature_algorithm', - type: 'keyword', - }, - 'tls.detailed.client_certificate.alternative_names': { - category: 'tls', - description: 'Subject Alternative Names for this certificate.', - name: 'tls.detailed.client_certificate.alternative_names', - type: 'keyword', - }, - 'tls.detailed.client_certificate.subject.country': { - category: 'tls', - description: 'Country code.', - name: 'tls.detailed.client_certificate.subject.country', - type: 'keyword', - }, - 'tls.detailed.client_certificate.subject.organization': { - category: 'tls', - description: 'Organization name.', - name: 'tls.detailed.client_certificate.subject.organization', - type: 'keyword', - }, - 'tls.detailed.client_certificate.subject.organizational_unit': { - category: 'tls', - description: 'Unit within organization.', - name: 'tls.detailed.client_certificate.subject.organizational_unit', - type: 'keyword', - }, - 'tls.detailed.client_certificate.subject.province': { - category: 'tls', - description: 'Province or region within country.', - name: 'tls.detailed.client_certificate.subject.province', - type: 'keyword', - }, - 'tls.detailed.client_certificate.subject.common_name': { - category: 'tls', - description: 'Name or host name identified by the certificate.', - name: 'tls.detailed.client_certificate.subject.common_name', - type: 'keyword', - }, - 'tls.detailed.client_certificate.subject.locality': { - category: 'tls', - description: 'Locality.', - name: 'tls.detailed.client_certificate.subject.locality', - type: 'keyword', - }, - 'tls.detailed.client_certificate.subject.distinguished_name': { - category: 'tls', - description: 'Distinguished name (DN) of the certificate subject entity.', - example: 'C=US, ST=California, L=San Francisco, O=Fastly, Inc., CN=r2.shared.global.fastly.net', - name: 'tls.detailed.client_certificate.subject.distinguished_name', - type: 'keyword', - }, - 'tls.detailed.client_certificate.issuer.country': { - category: 'tls', - description: 'Country code.', - name: 'tls.detailed.client_certificate.issuer.country', - type: 'keyword', - }, - 'tls.detailed.client_certificate.issuer.organization': { - category: 'tls', - description: 'Organization name.', - name: 'tls.detailed.client_certificate.issuer.organization', - type: 'keyword', - }, - 'tls.detailed.client_certificate.issuer.organizational_unit': { - category: 'tls', - description: 'Unit within organization.', - name: 'tls.detailed.client_certificate.issuer.organizational_unit', - type: 'keyword', - }, - 'tls.detailed.client_certificate.issuer.province': { - category: 'tls', - description: 'Province or region within country.', - name: 'tls.detailed.client_certificate.issuer.province', - type: 'keyword', - }, - 'tls.detailed.client_certificate.issuer.common_name': { - category: 'tls', - description: 'Name or host name identified by the certificate.', - name: 'tls.detailed.client_certificate.issuer.common_name', - type: 'keyword', - }, - 'tls.detailed.client_certificate.issuer.locality': { - category: 'tls', - description: 'Locality.', - name: 'tls.detailed.client_certificate.issuer.locality', - type: 'keyword', - }, - 'tls.detailed.client_certificate.issuer.distinguished_name': { - category: 'tls', - description: 'Distinguished name (DN) of the certificate issuer entity.', - example: 'C=US, ST=California, L=San Francisco, O=Fastly, Inc., CN=r2.shared.global.fastly.net', - name: 'tls.detailed.client_certificate.issuer.distinguished_name', - type: 'keyword', - }, - 'tls.detailed.server_certificate.version': { - category: 'tls', - description: 'X509 format version.', - name: 'tls.detailed.server_certificate.version', - type: 'long', - }, - 'tls.detailed.server_certificate.version_number': { - category: 'tls', - description: 'Version of x509 format.', - example: 3, - name: 'tls.detailed.server_certificate.version_number', - type: 'keyword', - }, - 'tls.detailed.server_certificate.serial_number': { - category: 'tls', - description: "The certificate's serial number.", - name: 'tls.detailed.server_certificate.serial_number', - type: 'keyword', - }, - 'tls.detailed.server_certificate.not_before': { - category: 'tls', - description: 'Date before which the certificate is not valid.', - name: 'tls.detailed.server_certificate.not_before', - type: 'date', - }, - 'tls.detailed.server_certificate.not_after': { - category: 'tls', - description: 'Date after which the certificate expires.', - name: 'tls.detailed.server_certificate.not_after', - type: 'date', - }, - 'tls.detailed.server_certificate.public_key_algorithm': { - category: 'tls', - description: "The algorithm used for this certificate's public key. One of RSA, DSA or ECDSA. ", - name: 'tls.detailed.server_certificate.public_key_algorithm', - type: 'keyword', - }, - 'tls.detailed.server_certificate.public_key_size': { - category: 'tls', - description: 'Size of the public key.', - name: 'tls.detailed.server_certificate.public_key_size', - type: 'long', - }, - 'tls.detailed.server_certificate.signature_algorithm': { - category: 'tls', - description: "The algorithm used for the certificate's signature. ", - name: 'tls.detailed.server_certificate.signature_algorithm', - type: 'keyword', - }, - 'tls.detailed.server_certificate.alternative_names': { - category: 'tls', - description: 'Subject Alternative Names for this certificate.', - name: 'tls.detailed.server_certificate.alternative_names', - type: 'keyword', - }, - 'tls.detailed.server_certificate.subject.country': { - category: 'tls', - description: 'Country code.', - name: 'tls.detailed.server_certificate.subject.country', - type: 'keyword', - }, - 'tls.detailed.server_certificate.subject.organization': { - category: 'tls', - description: 'Organization name.', - name: 'tls.detailed.server_certificate.subject.organization', - type: 'keyword', - }, - 'tls.detailed.server_certificate.subject.organizational_unit': { - category: 'tls', - description: 'Unit within organization.', - name: 'tls.detailed.server_certificate.subject.organizational_unit', - type: 'keyword', - }, - 'tls.detailed.server_certificate.subject.province': { - category: 'tls', - description: 'Province or region within country.', - name: 'tls.detailed.server_certificate.subject.province', - type: 'keyword', - }, - 'tls.detailed.server_certificate.subject.state_or_province': { - category: 'tls', - description: 'Province or region within country.', - name: 'tls.detailed.server_certificate.subject.state_or_province', - type: 'keyword', - }, - 'tls.detailed.server_certificate.subject.common_name': { - category: 'tls', - description: 'Name or host name identified by the certificate.', - name: 'tls.detailed.server_certificate.subject.common_name', - type: 'keyword', - }, - 'tls.detailed.server_certificate.subject.locality': { - category: 'tls', - description: 'Locality.', - name: 'tls.detailed.server_certificate.subject.locality', - type: 'keyword', - }, - 'tls.detailed.server_certificate.subject.distinguished_name': { - category: 'tls', - description: 'Distinguished name (DN) of the certificate subject entity.', - example: 'C=US, ST=California, L=San Francisco, O=Fastly, Inc., CN=r2.shared.global.fastly.net', - name: 'tls.detailed.server_certificate.subject.distinguished_name', - type: 'keyword', - }, - 'tls.detailed.server_certificate.issuer.country': { - category: 'tls', - description: 'Country code.', - name: 'tls.detailed.server_certificate.issuer.country', - type: 'keyword', - }, - 'tls.detailed.server_certificate.issuer.organization': { - category: 'tls', - description: 'Organization name.', - name: 'tls.detailed.server_certificate.issuer.organization', - type: 'keyword', - }, - 'tls.detailed.server_certificate.issuer.organizational_unit': { - category: 'tls', - description: 'Unit within organization.', - name: 'tls.detailed.server_certificate.issuer.organizational_unit', - type: 'keyword', - }, - 'tls.detailed.server_certificate.issuer.province': { - category: 'tls', - description: 'Province or region within country.', - name: 'tls.detailed.server_certificate.issuer.province', - type: 'keyword', - }, - 'tls.detailed.server_certificate.issuer.state_or_province': { - category: 'tls', - description: 'Province or region within country.', - name: 'tls.detailed.server_certificate.issuer.state_or_province', - type: 'keyword', - }, - 'tls.detailed.server_certificate.issuer.common_name': { - category: 'tls', - description: 'Name or host name identified by the certificate.', - name: 'tls.detailed.server_certificate.issuer.common_name', - type: 'keyword', - }, - 'tls.detailed.server_certificate.issuer.locality': { - category: 'tls', - description: 'Locality.', - name: 'tls.detailed.server_certificate.issuer.locality', - type: 'keyword', - }, - 'tls.detailed.server_certificate.issuer.distinguished_name': { - category: 'tls', - description: 'Distinguished name (DN) of the certificate issuer entity.', - example: 'C=US, ST=California, L=San Francisco, O=Fastly, Inc., CN=r2.shared.global.fastly.net', - name: 'tls.detailed.server_certificate.issuer.distinguished_name', - type: 'keyword', - }, 'tls.detailed.server_certificate_chain': { category: 'tls', description: 'Chain of trust for the server certificate.', @@ -34784,340 +48307,10 @@ export const fieldsBeat: BeatFields = { name: 'tls.detailed.alert_types', type: 'keyword', }, - 'tls.handshake_completed': { - category: 'tls', - name: 'tls.handshake_completed', - type: 'alias', - }, - 'tls.client_hello.supported_ciphers': { - category: 'tls', - name: 'tls.client_hello.supported_ciphers', - type: 'alias', - }, - 'tls.server_hello.selected_cipher': { - category: 'tls', - name: 'tls.server_hello.selected_cipher', - type: 'alias', - }, - 'tls.fingerprints.ja3': { - category: 'tls', - name: 'tls.fingerprints.ja3', - type: 'alias', - }, - 'tls.resumption_method': { - category: 'tls', - name: 'tls.resumption_method', - type: 'alias', - }, - 'tls.client_certificate_requested': { - category: 'tls', - name: 'tls.client_certificate_requested', - type: 'alias', - }, - 'tls.client_hello.version': { - category: 'tls', - name: 'tls.client_hello.version', - type: 'alias', - }, - 'tls.client_hello.session_id': { - category: 'tls', - name: 'tls.client_hello.session_id', - type: 'alias', - }, - 'tls.client_hello.supported_compression_methods': { - category: 'tls', - name: 'tls.client_hello.supported_compression_methods', - type: 'alias', - }, - 'tls.client_hello.extensions.server_name_indication': { - category: 'tls', - name: 'tls.client_hello.extensions.server_name_indication', - type: 'alias', - }, - 'tls.client_hello.extensions.application_layer_protocol_negotiation': { - category: 'tls', - name: 'tls.client_hello.extensions.application_layer_protocol_negotiation', - type: 'alias', - }, - 'tls.client_hello.extensions.session_ticket': { - category: 'tls', - name: 'tls.client_hello.extensions.session_ticket', - type: 'alias', - }, - 'tls.client_hello.extensions.supported_versions': { - category: 'tls', - name: 'tls.client_hello.extensions.supported_versions', - type: 'alias', - }, - 'tls.client_hello.extensions.supported_groups': { - category: 'tls', - name: 'tls.client_hello.extensions.supported_groups', - type: 'alias', - }, - 'tls.client_hello.extensions.signature_algorithms': { - category: 'tls', - name: 'tls.client_hello.extensions.signature_algorithms', - type: 'alias', - }, - 'tls.client_hello.extensions.ec_points_formats': { - category: 'tls', - name: 'tls.client_hello.extensions.ec_points_formats', - type: 'alias', - }, - 'tls.client_hello.extensions._unparsed_': { - category: 'tls', - name: 'tls.client_hello.extensions._unparsed_', - type: 'alias', - }, - 'tls.server_hello.version': { - category: 'tls', - name: 'tls.server_hello.version', - type: 'alias', - }, - 'tls.server_hello.selected_compression_method': { - category: 'tls', - name: 'tls.server_hello.selected_compression_method', - type: 'alias', - }, - 'tls.server_hello.session_id': { - category: 'tls', - name: 'tls.server_hello.session_id', - type: 'alias', - }, - 'tls.server_hello.extensions.application_layer_protocol_negotiation': { - category: 'tls', - name: 'tls.server_hello.extensions.application_layer_protocol_negotiation', - type: 'alias', - }, - 'tls.server_hello.extensions.session_ticket': { - category: 'tls', - name: 'tls.server_hello.extensions.session_ticket', - type: 'alias', - }, - 'tls.server_hello.extensions.supported_versions': { - category: 'tls', - name: 'tls.server_hello.extensions.supported_versions', - type: 'alias', - }, - 'tls.server_hello.extensions.ec_points_formats': { - category: 'tls', - name: 'tls.server_hello.extensions.ec_points_formats', - type: 'alias', - }, - 'tls.server_hello.extensions._unparsed_': { - category: 'tls', - name: 'tls.server_hello.extensions._unparsed_', - type: 'alias', - }, - 'tls.client_certificate.version': { - category: 'tls', - name: 'tls.client_certificate.version', - type: 'alias', - }, - 'tls.client_certificate.serial_number': { - category: 'tls', - name: 'tls.client_certificate.serial_number', - type: 'alias', - }, - 'tls.client_certificate.not_before': { - category: 'tls', - name: 'tls.client_certificate.not_before', - type: 'alias', - }, - 'tls.client_certificate.not_after': { - category: 'tls', - name: 'tls.client_certificate.not_after', - type: 'alias', - }, - 'tls.client_certificate.public_key_algorithm': { - category: 'tls', - name: 'tls.client_certificate.public_key_algorithm', - type: 'alias', - }, - 'tls.client_certificate.public_key_size': { - category: 'tls', - name: 'tls.client_certificate.public_key_size', - type: 'alias', - }, - 'tls.client_certificate.signature_algorithm': { - category: 'tls', - name: 'tls.client_certificate.signature_algorithm', - type: 'alias', - }, - 'tls.client_certificate.alternative_names': { - category: 'tls', - name: 'tls.client_certificate.alternative_names', - type: 'alias', - }, - 'tls.client_certificate.subject.country': { - category: 'tls', - name: 'tls.client_certificate.subject.country', - type: 'alias', - }, - 'tls.client_certificate.subject.organization': { - category: 'tls', - name: 'tls.client_certificate.subject.organization', - type: 'alias', - }, - 'tls.client_certificate.subject.organizational_unit': { - category: 'tls', - name: 'tls.client_certificate.subject.organizational_unit', - type: 'alias', - }, - 'tls.client_certificate.subject.province': { - category: 'tls', - name: 'tls.client_certificate.subject.province', - type: 'alias', - }, - 'tls.client_certificate.subject.common_name': { - category: 'tls', - name: 'tls.client_certificate.subject.common_name', - type: 'alias', - }, - 'tls.client_certificate.subject.locality': { - category: 'tls', - name: 'tls.client_certificate.subject.locality', - type: 'alias', - }, - 'tls.client_certificate.issuer.country': { - category: 'tls', - name: 'tls.client_certificate.issuer.country', - type: 'alias', - }, - 'tls.client_certificate.issuer.organization': { - category: 'tls', - name: 'tls.client_certificate.issuer.organization', - type: 'alias', - }, - 'tls.client_certificate.issuer.organizational_unit': { - category: 'tls', - name: 'tls.client_certificate.issuer.organizational_unit', - type: 'alias', - }, - 'tls.client_certificate.issuer.province': { - category: 'tls', - name: 'tls.client_certificate.issuer.province', - type: 'alias', - }, - 'tls.client_certificate.issuer.common_name': { - category: 'tls', - name: 'tls.client_certificate.issuer.common_name', - type: 'alias', - }, - 'tls.client_certificate.issuer.locality': { - category: 'tls', - name: 'tls.client_certificate.issuer.locality', - type: 'alias', - }, - 'tls.server_certificate.version': { - category: 'tls', - name: 'tls.server_certificate.version', - type: 'alias', - }, - 'tls.server_certificate.serial_number': { - category: 'tls', - name: 'tls.server_certificate.serial_number', - type: 'alias', - }, - 'tls.server_certificate.not_before': { - category: 'tls', - name: 'tls.server_certificate.not_before', - type: 'alias', - }, - 'tls.server_certificate.not_after': { - category: 'tls', - name: 'tls.server_certificate.not_after', - type: 'alias', - }, - 'tls.server_certificate.public_key_algorithm': { - category: 'tls', - name: 'tls.server_certificate.public_key_algorithm', - type: 'alias', - }, - 'tls.server_certificate.public_key_size': { - category: 'tls', - name: 'tls.server_certificate.public_key_size', - type: 'alias', - }, - 'tls.server_certificate.signature_algorithm': { - category: 'tls', - name: 'tls.server_certificate.signature_algorithm', - type: 'alias', - }, - 'tls.server_certificate.alternative_names': { - category: 'tls', - name: 'tls.server_certificate.alternative_names', - type: 'alias', - }, - 'tls.server_certificate.subject.country': { - category: 'tls', - name: 'tls.server_certificate.subject.country', - type: 'alias', - }, - 'tls.server_certificate.subject.organization': { - category: 'tls', - name: 'tls.server_certificate.subject.organization', - type: 'alias', - }, - 'tls.server_certificate.subject.organizational_unit': { - category: 'tls', - name: 'tls.server_certificate.subject.organizational_unit', - type: 'alias', - }, - 'tls.server_certificate.subject.province': { - category: 'tls', - name: 'tls.server_certificate.subject.province', - type: 'alias', - }, - 'tls.server_certificate.subject.common_name': { - category: 'tls', - name: 'tls.server_certificate.subject.common_name', - type: 'alias', - }, - 'tls.server_certificate.subject.locality': { - category: 'tls', - name: 'tls.server_certificate.subject.locality', - type: 'alias', - }, - 'tls.server_certificate.issuer.country': { - category: 'tls', - name: 'tls.server_certificate.issuer.country', - type: 'alias', - }, - 'tls.server_certificate.issuer.organization': { - category: 'tls', - name: 'tls.server_certificate.issuer.organization', - type: 'alias', - }, - 'tls.server_certificate.issuer.organizational_unit': { - category: 'tls', - name: 'tls.server_certificate.issuer.organizational_unit', - type: 'alias', - }, - 'tls.server_certificate.issuer.province': { - category: 'tls', - name: 'tls.server_certificate.issuer.province', - type: 'alias', - }, - 'tls.server_certificate.issuer.common_name': { - category: 'tls', - name: 'tls.server_certificate.issuer.common_name', - type: 'alias', - }, - 'tls.server_certificate.issuer.locality': { - category: 'tls', - name: 'tls.server_certificate.issuer.locality', - type: 'alias', - }, - 'tls.alert_types': { - category: 'tls', - name: 'tls.alert_types', - type: 'alias', - }, 'winlog.api': { category: 'winlog', description: - 'The event log API type used to read the record. The possible values are "wineventlog" for the Windows Event Log API or "eventlogging" for the Event Logging API. The Event Logging API was designed for Windows Server 2003 or Windows 2000 operating systems. In Windows Vista, the event logging infrastructure was redesigned. On Windows Vista or later operating systems, the Windows Event Log API is used. Winlogbeat automatically detects which API to use for reading event logs. ', + 'The event log API type used to read the record. The possible values are "wineventlog" for the Windows Event Log API or "wineventlog-experimental" for its experimental implementation. ', name: 'winlog.api', }, 'winlog.activity_id': { @@ -35763,6 +48956,12 @@ export const fieldsBeat: BeatFields = { name: 'winlog.task', type: 'keyword', }, + 'winlog.time_created': { + category: 'winlog', + description: 'The event creation time. ', + name: 'winlog.time_created', + type: 'date', + }, 'winlog.process.thread.id': { category: 'winlog', name: 'winlog.process.thread.id', From fc64d172e723d6073a66631c638d4de33f314147 Mon Sep 17 00:00:00 2001 From: Yara Tercero Date: Tue, 18 Jan 2022 12:49:57 -0800 Subject: [PATCH 024/108] [Security Solution][Exceptions] - Update exceptions tab privileges checks (#122902) ### Summary Addresses #122227. --- .../routes/read_privileges_route.mock.ts | 8 +-- .../detection_alerts/attach_to_case.spec.ts | 6 +- .../exception_item/exception_entries.test.tsx | 29 +++++----- .../exception_item/exception_entries.tsx | 56 +++++++++---------- .../viewer/exception_item/index.stories.tsx | 30 ++++++++++ .../viewer/exception_item/index.test.tsx | 34 ++++++++++- .../viewer/exception_item/index.tsx | 6 +- .../viewer/exceptions_viewer_header.test.tsx | 16 ++++++ .../viewer/exceptions_viewer_header.tsx | 2 +- .../viewer/exceptions_viewer_items.test.tsx | 7 +++ .../viewer/exceptions_viewer_items.tsx | 3 + .../components/exceptions/viewer/index.tsx | 17 +++++- .../use_add_exception_actions.tsx | 39 +++++++------ .../take_action_dropdown/index.test.tsx | 3 + .../timeline/body/actions/index.test.tsx | 4 ++ .../security_and_spaces/tests/delete_lists.ts | 15 +++-- .../tests/read_list_privileges.ts | 3 +- 17 files changed, 196 insertions(+), 82 deletions(-) diff --git a/x-pack/plugins/lists/server/routes/read_privileges_route.mock.ts b/x-pack/plugins/lists/server/routes/read_privileges_route.mock.ts index 1e027e50f50701..caf7e6d8da62b3 100644 --- a/x-pack/plugins/lists/server/routes/read_privileges_route.mock.ts +++ b/x-pack/plugins/lists/server/routes/read_privileges_route.mock.ts @@ -88,7 +88,7 @@ export const getReadPrivilegeMock = ( manage_index_templates: booleanValues, manage_ingest_pipelines: booleanValues, manage_ml: booleanValues, - manage_own_api_key: false, + manage_own_api_key: booleanValues, manage_pipeline: booleanValues, manage_rollup: booleanValues, manage_saml: booleanValues, @@ -105,7 +105,7 @@ export const getReadPrivilegeMock = ( read_ilm: booleanValues, transport_client: booleanValues, }, - has_all_requested: false, + has_all_requested: booleanValues, index: { [listItemsIndex]: { all: booleanValues, @@ -141,7 +141,7 @@ export const getReadPrivilegeMock = ( manage_index_templates: booleanValues, manage_ingest_pipelines: booleanValues, manage_ml: booleanValues, - manage_own_api_key: false, + manage_own_api_key: booleanValues, manage_pipeline: booleanValues, manage_rollup: booleanValues, manage_saml: booleanValues, @@ -158,7 +158,7 @@ export const getReadPrivilegeMock = ( read_ilm: booleanValues, transport_client: booleanValues, }, - has_all_requested: false, + has_all_requested: booleanValues, index: { [listIndex]: { all: booleanValues, diff --git a/x-pack/plugins/security_solution/cypress/integration/detection_alerts/attach_to_case.spec.ts b/x-pack/plugins/security_solution/cypress/integration/detection_alerts/attach_to_case.spec.ts index d7a5ce6799230c..e5c9832c52fd7b 100644 --- a/x-pack/plugins/security_solution/cypress/integration/detection_alerts/attach_to_case.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/detection_alerts/attach_to_case.spec.ts @@ -20,7 +20,7 @@ import { login, loginAndWaitForPage, waitForPageWithoutDateRange } from '../../t import { refreshPage } from '../../tasks/security_header'; import { ALERTS_URL } from '../../urls/navigation'; -import { ATTACH_ALERT_TO_CASE_BUTTON } from '../../screens/alerts'; +import { ATTACH_ALERT_TO_CASE_BUTTON, TIMELINE_CONTEXT_MENU_BTN } from '../../screens/alerts'; const loadDetectionsPage = (role: ROLES) => { waitForPageWithoutDateRange(ALERTS_URL, role); @@ -48,8 +48,8 @@ describe('Alerts timeline', () => { }); it('should not allow user with read only privileges to attach alerts to cases', () => { - expandFirstAlertActions(); - cy.get(ATTACH_ALERT_TO_CASE_BUTTON).should('not.exist'); + // Disabled actions for read only users are hidden, so actions button should not show + cy.get(TIMELINE_CONTEXT_MENU_BTN).should('not.exist'); }); }); diff --git a/x-pack/plugins/security_solution/public/common/components/exceptions/viewer/exception_item/exception_entries.test.tsx b/x-pack/plugins/security_solution/public/common/components/exceptions/viewer/exception_item/exception_entries.test.tsx index 228de32fee7d29..6070924523f63c 100644 --- a/x-pack/plugins/security_solution/public/common/components/exceptions/viewer/exception_item/exception_entries.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/exceptions/viewer/exception_item/exception_entries.test.tsx @@ -23,7 +23,7 @@ describe('ExceptionEntries', () => { const wrapper = mount( { const wrapper = mount( { const wrapper = mount( { const wrapper = mount( { expect(mockOnDelete).toHaveBeenCalledTimes(1); }); - test('it renders edit button disabled if "disableDelete" is "true"', () => { + test('it does not render edit button if "disableActions" is "true"', () => { const wrapper = mount( ); - const editBtn = wrapper.find('[data-test-subj="exceptionsViewerEditBtn"] button').at(0); + const editBtns = wrapper.find('[data-test-subj="exceptionsViewerEditBtn"] button'); - expect(editBtn.prop('disabled')).toBeTruthy(); + expect(editBtns).toHaveLength(0); }); - test('it renders delete button in loading state if "disableDelete" is "true"', () => { + test('it does not render delete button if "disableActions" is "true"', () => { const wrapper = mount( ); - const deleteBtn = wrapper.find('[data-test-subj="exceptionsViewerDeleteBtn"] button').at(0); + const deleteBtns = wrapper.find('[data-test-subj="exceptionsViewerDeleteBtn"] button').at(0); - expect(deleteBtn.prop('disabled')).toBeTruthy(); - expect(deleteBtn.find('.euiLoadingSpinner')).toBeTruthy(); + expect(deleteBtns).toHaveLength(0); }); test('it renders nested entry', () => { @@ -126,7 +125,7 @@ describe('ExceptionEntries', () => { const wrapper = mount( { const wrapper = mount( void; onEdit: () => void; } const ExceptionEntriesComponent = ({ entries, - disableDelete, + disableActions, onDelete, onEdit, }: ExceptionEntriesComponentProps): JSX.Element => { @@ -181,32 +181,32 @@ const ExceptionEntriesComponent = ({ - - - - - {i18n.EDIT} - - - - - {i18n.REMOVE} - - - - + {!disableActions && ( + + + + + {i18n.EDIT} + + + + + {i18n.REMOVE} + + + + + )} ); diff --git a/x-pack/plugins/security_solution/public/common/components/exceptions/viewer/exception_item/index.stories.tsx b/x-pack/plugins/security_solution/public/common/components/exceptions/viewer/exception_item/index.stories.tsx index f8697b2f3db797..898a9e3ab03886 100644 --- a/x-pack/plugins/security_solution/public/common/components/exceptions/viewer/exception_item/index.stories.tsx +++ b/x-pack/plugins/security_solution/public/common/components/exceptions/viewer/exception_item/index.stories.tsx @@ -35,6 +35,7 @@ storiesOf('Components/ExceptionItem', module) return ( ); + }) + .add('with actions disabled', () => { + const payload = getExceptionListItemSchemaMock(); + payload.description = ''; + payload.comments = getCommentsArrayMock(); + payload.entries = [ + { + field: 'actingProcess.file.signer', + type: 'match', + operator: 'included', + value: 'Elastic, N.V.', + }, + ]; + + return ( + + ); }); diff --git a/x-pack/plugins/security_solution/public/common/components/exceptions/viewer/exception_item/index.test.tsx b/x-pack/plugins/security_solution/public/common/components/exceptions/viewer/exception_item/index.test.tsx index 7c55c0de68c641..983d837267795a 100644 --- a/x-pack/plugins/security_solution/public/common/components/exceptions/viewer/exception_item/index.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/exceptions/viewer/exception_item/index.test.tsx @@ -32,6 +32,7 @@ describe('ExceptionItem', () => { const wrapper = mount( { const wrapper = mount( { ); }); + it('it does not render edit or delete action buttons when "disableActions" is "true"', () => { + const mockOnEditException = jest.fn(); + const exceptionItem = getExceptionListItemSchemaMock(); + + const wrapper = mount( + + + + ); + + const editBtn = wrapper.find('[data-test-subj="exceptionsViewerEditBtn"] button'); + const deleteBtn = wrapper.find('[data-test-subj="exceptionsViewerDeleteBtn"] button'); + + expect(editBtn).toHaveLength(0); + expect(deleteBtn).toHaveLength(0); + }); + it('it invokes "onEditException" when edit button clicked', () => { const mockOnEditException = jest.fn(); const exceptionItem = getExceptionListItemSchemaMock(); @@ -77,6 +103,7 @@ describe('ExceptionItem', () => { const wrapper = mount( { const wrapper = mount( { ); - const editBtn = wrapper.find('[data-test-subj="exceptionsViewerDeleteBtn"] button').at(0); - editBtn.simulate('click'); + const deleteBtn = wrapper.find('[data-test-subj="exceptionsViewerDeleteBtn"] button').at(0); + deleteBtn.simulate('click'); expect(mockOnDeleteException).toHaveBeenCalledWith({ id: '1', @@ -124,6 +152,7 @@ describe('ExceptionItem', () => { const wrapper = mount( { const wrapper = mount( void; showName?: boolean; showModified?: boolean; + disableActions: boolean; 'data-test-subj'?: string; } const ExceptionItemComponent = ({ + disableActions, loadingItemIds, exceptionItem, commentsAccordionId, @@ -78,7 +80,7 @@ const ExceptionItemComponent = ({ return getFormattedComments(exceptionItem.comments); }, [exceptionItem.comments]); - const disableDelete = useMemo((): boolean => { + const disableItemActions = useMemo((): boolean => { const foundItems = loadingItemIds.filter(({ id }) => id === exceptionItem.id); return foundItems.length > 0; }, [loadingItemIds, exceptionItem.id]); @@ -96,7 +98,7 @@ const ExceptionItemComponent = ({ showName={showName} /> { ).toBeTruthy(); }); + // This occurs if user does not have sufficient privileges + it('it does not display add exception button if no list types available', () => { + const wrapper = mount( + + ); + + expect(wrapper.find('[data-test-subj="exceptionsHeaderAddExceptionBtn"]').exists()).toBeFalsy(); + }); + it('it displays toggles and add exception popover when more than one list type available', () => { const wrapper = mount( - {supportedListTypes.length < 2 && ( + {supportedListTypes.length === 1 && ( { showEmpty showNoResults={false} isInitLoading={false} + disableActions={false} exceptions={[]} loadingItemIds={[]} commentsAccordionId="comments-accordion-id" @@ -54,6 +55,7 @@ describe('ExceptionsViewerItems', () => { showEmpty={false} showNoResults isInitLoading={false} + disableActions={false} exceptions={[]} loadingItemIds={[]} commentsAccordionId="comments-accordion-id" @@ -78,6 +80,7 @@ describe('ExceptionsViewerItems', () => { showEmpty={false} showNoResults={false} isInitLoading={false} + disableActions={false} exceptions={[getExceptionListItemSchemaMock()]} loadingItemIds={[]} commentsAccordionId="comments-accordion-id" @@ -98,6 +101,7 @@ describe('ExceptionsViewerItems', () => { showEmpty={false} showNoResults={false} isInitLoading={true} + disableActions={false} exceptions={[]} loadingItemIds={[]} commentsAccordionId="comments-accordion-id" @@ -122,6 +126,7 @@ describe('ExceptionsViewerItems', () => { showEmpty={false} showNoResults={false} isInitLoading={false} + disableActions={false} exceptions={[exception1, exception2]} loadingItemIds={[]} commentsAccordionId="comments-accordion-id" @@ -147,6 +152,7 @@ describe('ExceptionsViewerItems', () => { showEmpty={false} showNoResults={false} isInitLoading={false} + disableActions={false} exceptions={[exception1, exception2]} loadingItemIds={[]} commentsAccordionId="comments-accordion-id" @@ -172,6 +178,7 @@ describe('ExceptionsViewerItems', () => { showEmpty={false} showNoResults={false} isInitLoading={false} + disableActions={false} exceptions={[getExceptionListItemSchemaMock()]} loadingItemIds={[]} commentsAccordionId="comments-accordion-id" diff --git a/x-pack/plugins/security_solution/public/common/components/exceptions/viewer/exceptions_viewer_items.tsx b/x-pack/plugins/security_solution/public/common/components/exceptions/viewer/exceptions_viewer_items.tsx index 64fb032b0425cb..5331b2376fd9f1 100644 --- a/x-pack/plugins/security_solution/public/common/components/exceptions/viewer/exceptions_viewer_items.tsx +++ b/x-pack/plugins/security_solution/public/common/components/exceptions/viewer/exceptions_viewer_items.tsx @@ -36,6 +36,7 @@ interface ExceptionsViewerItemsProps { showEmpty: boolean; showNoResults: boolean; isInitLoading: boolean; + disableActions: boolean; exceptions: ExceptionListItemSchema[]; loadingItemIds: ExceptionListItemIdentifiers[]; commentsAccordionId: string; @@ -52,6 +53,7 @@ const ExceptionsViewerItemsComponent: React.FC = ({ commentsAccordionId, onDeleteException, onEditExceptionItem, + disableActions, }): JSX.Element => ( {showEmpty || showNoResults || isInitLoading ? ( @@ -93,6 +95,7 @@ const ExceptionsViewerItemsComponent: React.FC = ({ )} ([]); + + const [{ canUserCRUD, hasIndexWrite }] = useUserData(); + + useEffect((): void => { + if (!canUserCRUD || !hasIndexWrite) { + setSupportedListTypes([]); + } else { + setSupportedListTypes(availableListTypes); + } + }, [availableListTypes, canUserCRUD, hasIndexWrite]); const setExceptions = useCallback( ({ @@ -356,7 +368,7 @@ const ExceptionsViewerComponent = ({ [ - - {ACTION_ADD_ENDPOINT_EXCEPTION} - , + () => + disabledAddException + ? [] + : [ + + {ACTION_ADD_ENDPOINT_EXCEPTION} + , - - {ACTION_ADD_EXCEPTION} - , - ], + + {ACTION_ADD_EXCEPTION} + , + ], [ disabledAddEndpointException, disabledAddException, diff --git a/x-pack/plugins/security_solution/public/detections/components/take_action_dropdown/index.test.tsx b/x-pack/plugins/security_solution/public/detections/components/take_action_dropdown/index.test.tsx index bf990cb292cd79..e12f01458da4c4 100644 --- a/x-pack/plugins/security_solution/public/detections/components/take_action_dropdown/index.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/take_action_dropdown/index.test.tsx @@ -18,6 +18,9 @@ import { mockTimelines } from '../../../common/mock/mock_timelines_plugin'; import { createStartServicesMock } from '../../../common/lib/kibana/kibana_react.mock'; import { useKibana } from '../../../common/lib/kibana'; +jest.mock('../user_info', () => ({ + useUserData: jest.fn().mockReturnValue([{ canUserCRUD: true, hasIndexWrite: true }]), +})); jest.mock('../../../common/hooks/endpoint/use_isolate_privileges', () => ({ useIsolationPrivileges: jest.fn().mockReturnValue({ isAllowed: true }), })); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/actions/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/actions/index.test.tsx index 06835e78b03e13..b6e6aa40876ccf 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/actions/index.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/actions/index.test.tsx @@ -12,6 +12,10 @@ import { TestProviders, mockTimelineModel, mockTimelineData } from '../../../../ import { Actions } from '.'; import { mockTimelines } from '../../../../../common/mock/mock_timelines_plugin'; import { useIsExperimentalFeatureEnabled } from '../../../../../common/hooks/use_experimental_features'; + +jest.mock('../../../../../detections/components/user_info', () => ({ + useUserData: jest.fn().mockReturnValue([{ canUserCRUD: true, hasIndexWrite: true }]), +})); jest.mock('../../../../../common/hooks/use_experimental_features', () => ({ useIsExperimentalFeatureEnabled: jest.fn().mockReturnValue(false), })); diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/delete_lists.ts b/x-pack/test/lists_api_integration/security_and_spaces/tests/delete_lists.ts index 939291d1e4a5dd..cecb4510be9c3b 100644 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/delete_lists.ts +++ b/x-pack/test/lists_api_integration/security_and_spaces/tests/delete_lists.ts @@ -166,8 +166,7 @@ export default ({ getService }: FtrProviderContext) => { .expect(200); }); - // Tests in development - it.skip('should delete a single list referenced within an exception list item if ignoreReferences=true', async () => { + it('should delete a single list referenced within an exception list item if ignoreReferences=true', async () => { // create a list const { body: valueListBody } = await supertest .post(LIST_URL) @@ -207,8 +206,7 @@ export default ({ getService }: FtrProviderContext) => { .expect(409); }); - // Tests in development - it.skip('should delete a single list referenced within an exception list item and referenced exception list items if deleteReferences=true', async () => { + it('should delete a single list referenced within an exception list item and referenced exception list items if deleteReferences=true', async () => { // create a list const { body: valueListBody } = await supertest .post(LIST_URL) @@ -241,6 +239,13 @@ export default ({ getService }: FtrProviderContext) => { }) .expect(200); + // sanity check + await supertest + .get(`${LIST_ITEM_URL}/_find?list_id=${LIST_ID}`) + .set('kbn-xsrf', 'true') + .send() + .expect(200); + // delete that list by its auto-generated id and delete referenced list items const deleteListBody = await supertest .delete(`${LIST_URL}?id=${valueListBody.id}&ignoreReferences=true`) @@ -253,7 +258,7 @@ export default ({ getService }: FtrProviderContext) => { .get(`${LIST_ITEM_URL}/_find?list_id=${LIST_ID}`) .set('kbn-xsrf', 'true') .send() - .expect(200); + .expect(404); }); }); }); diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/read_list_privileges.ts b/x-pack/test/lists_api_integration/security_and_spaces/tests/read_list_privileges.ts index b90a3f86a290d1..e2633eea08e12c 100644 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/read_list_privileges.ts +++ b/x-pack/test/lists_api_integration/security_and_spaces/tests/read_list_privileges.ts @@ -18,8 +18,7 @@ export default ({ getService }: FtrProviderContext) => { const spacesService = getService('spaces'); const supertestWithoutAuth = getService('supertestWithoutAuth'); - // FAILING ES PROMOTION: https://github.com/elastic/kibana/issues/88302 - describe.skip('read_list_privileges', () => { + describe('read_list_privileges', () => { const space1Id = 'space_1'; const user1 = { From 57895460670f973945e1392500e79accdaed86db Mon Sep 17 00:00:00 2001 From: Dominique Clarke Date: Tue, 18 Jan 2022 15:53:10 -0500 Subject: [PATCH 025/108] [Uptime] UI Monitor Management/Synthetics Service e2e tests - add environment variables for service (#122552) * add environment variables for service * add SYNTHETICS_SERVICE_MANIFEST and basic tests * Update x-pack/plugins/uptime/e2e/playwright_run.ts Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .buildkite/scripts/lifecycle/pre_command.sh | 9 + x-pack/plugins/uptime/e2e/config.ts | 5 + x-pack/plugins/uptime/e2e/journeys/index.ts | 1 + .../journeys/monitor_management.journey.ts | 136 +++++++++++++ .../plugins/uptime/e2e/page_objects/login.tsx | 28 +++ .../e2e/page_objects/monitor_management.tsx | 183 ++++++++++++++++++ .../plugins/uptime/e2e/page_objects/utils.tsx | 47 +++++ .../monitor_config/monitor_name_location.tsx | 1 + .../monitor_list/actions.tsx | 5 +- 9 files changed, 413 insertions(+), 2 deletions(-) create mode 100644 x-pack/plugins/uptime/e2e/journeys/monitor_management.journey.ts create mode 100644 x-pack/plugins/uptime/e2e/page_objects/login.tsx create mode 100644 x-pack/plugins/uptime/e2e/page_objects/monitor_management.tsx create mode 100644 x-pack/plugins/uptime/e2e/page_objects/utils.tsx diff --git a/.buildkite/scripts/lifecycle/pre_command.sh b/.buildkite/scripts/lifecycle/pre_command.sh index 46235b63161cd7..ec2b55ecb2a7d2 100755 --- a/.buildkite/scripts/lifecycle/pre_command.sh +++ b/.buildkite/scripts/lifecycle/pre_command.sh @@ -92,6 +92,15 @@ export KIBANA_DOCKER_USERNAME KIBANA_DOCKER_PASSWORD="$(retry 5 5 vault read -field=password secret/kibana-issues/dev/container-registry)" export KIBANA_DOCKER_PASSWORD +SYNTHETICS_SERVICE_USERNAME="$(retry 5 5 vault read -field=username secret/kibana-issues/dev/kibana-ci-synthetics-credentials)" +export SYNTHETICS_SERVICE_USERNAME + +SYNTHETICS_SERVICE_PASSWORD="$(retry 5 5 vault read -field=password secret/kibana-issues/dev/kibana-ci-synthetics-credentials)" +export SYNTHETICS_SERVICE_PASSWORD + +SYNTHETICS_SERVICE_MANIFEST="$(retry 5 5 vault read -field=manifest secret/kibana-issues/dev/kibana-ci-synthetics-credentials)" +export SYNTHETICS_SERVICE_MANIFEST + # Setup Failed Test Reporter Elasticsearch credentials { TEST_FAILURES_ES_CLOUD_ID=$(retry 5 5 vault read -field=cloud_id secret/kibana-issues/dev/failed_tests_reporter_es) diff --git a/x-pack/plugins/uptime/e2e/config.ts b/x-pack/plugins/uptime/e2e/config.ts index d2c7a691e0a49f..42e23c540cd489 100644 --- a/x-pack/plugins/uptime/e2e/config.ts +++ b/x-pack/plugins/uptime/e2e/config.ts @@ -44,6 +44,11 @@ async function config({ readConfigFile }: FtrConfigProviderContext) { `--elasticsearch.username=kibana_system`, `--elasticsearch.password=changeme`, '--xpack.reporting.enabled=false', + `--xpack.uptime.unsafe.service.manifestUrl=${process.env.SYNTHETICS_SERVICE_MANIFEST}`, + `--xpack.uptime.unsafe.service.username=${process.env.SYNTHETICS_SERVICE_USERNAME}`, + `--xpack.uptime.unsafe.service.password=${process.env.SYNTHETICS_SERVICE_PASSWORD}`, + '--xpack.uptime.unsafe.service.enabled=true', + '--xpack.uptime.ui.unsafe.monitorManagement.enabled=true', ], }, }; diff --git a/x-pack/plugins/uptime/e2e/journeys/index.ts b/x-pack/plugins/uptime/e2e/journeys/index.ts index e090a2dcd9c3bb..941adf378ab29f 100644 --- a/x-pack/plugins/uptime/e2e/journeys/index.ts +++ b/x-pack/plugins/uptime/e2e/journeys/index.ts @@ -7,5 +7,6 @@ export * from './data_view_permissions'; export * from './uptime.journey'; +export * from './monitor_management.journey'; export * from './step_duration.journey'; export * from './alerts'; diff --git a/x-pack/plugins/uptime/e2e/journeys/monitor_management.journey.ts b/x-pack/plugins/uptime/e2e/journeys/monitor_management.journey.ts new file mode 100644 index 00000000000000..efc47c44765c8c --- /dev/null +++ b/x-pack/plugins/uptime/e2e/journeys/monitor_management.journey.ts @@ -0,0 +1,136 @@ +/* + * 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 { journey, step, expect, before, Page } from '@elastic/synthetics'; +import { monitorManagementPageProvider } from '../page_objects/monitor_management'; + +journey('Monitor Management', async ({ page, params }: { page: Page; params: any }) => { + const uptime = monitorManagementPageProvider({ page, kibanaUrl: params.kibanaUrl }); + const basicMonitorDetails = { + name: 'Sample monitor', + location: 'US Central', + schedule: '@every 3m', + apmServiceName: 'service', + }; + + const deleteMonitor = async () => { + const isSuccessful = await uptime.deleteMonitor(); + expect(isSuccessful).toBeTruthy(); + }; + + before(async () => { + await uptime.waitForLoadingToFinish(); + }); + + step('Go to monitor-management', async () => { + await uptime.navigateToMonitorManagement(); + }); + + step('login to Kibana', async () => { + await uptime.loginToKibana(); + }); + + step('create monitor http monitor', async () => { + const monitorDetails = { + ...basicMonitorDetails, + url: 'https://elastic.co', + locations: [basicMonitorDetails.location], + }; + await uptime.clickAddMonitor(); + await uptime.createBasicHTTPMonitorDetails(monitorDetails); + const isSuccessful = await uptime.confirmAndSave(); + expect(isSuccessful).toBeTruthy(); + }); + + step('view HTTP details in monitor management UI', async () => { + const monitorDetails = { + ...basicMonitorDetails, + url: 'https://elastic.co', + }; + await uptime.clickAddMonitor(); + await uptime.findMonitorConfiguration(monitorDetails); + }); + + step('delete http monitor', async () => { + await deleteMonitor(); + }); + + step('create monitor tcp monitor', async () => { + const monitorDetails = { + ...basicMonitorDetails, + host: 'smtp.gmail.com:587', + locations: [basicMonitorDetails.location], + }; + await uptime.clickAddMonitor(); + await uptime.createBasicTCPMonitorDetails(monitorDetails); + const isSuccessful = await uptime.confirmAndSave(); + expect(isSuccessful).toBeTruthy(); + }); + + step('view TCP details in monitor management UI', async () => { + const monitorDetails = { + ...basicMonitorDetails, + host: 'smtp.gmail.com:587', + }; + await uptime.clickAddMonitor(); + await uptime.findMonitorConfiguration(monitorDetails); + }); + + step('delete tcp monitor', async () => { + await deleteMonitor(); + }); + + step('create basic ICMP monitor', async () => { + const monitorDetails = { + ...basicMonitorDetails, + host: '1.1.1.1', + locations: [basicMonitorDetails.location], + }; + await uptime.clickAddMonitor(); + await uptime.createBasicICMPMonitorDetails(monitorDetails); + const isSuccessful = await uptime.confirmAndSave(); + expect(isSuccessful).toBeTruthy(); + }); + + step('view ICMP details in monitor management UI', async () => { + const monitorDetails = { + ...basicMonitorDetails, + host: '1.1.1.1', + }; + await uptime.clickAddMonitor(); + await uptime.findMonitorConfiguration(monitorDetails); + }); + + step('delete ICMP monitor', async () => { + await deleteMonitor(); + }); + + step('create basic Browser monitor', async () => { + const monitorDetails = { + ...basicMonitorDetails, + inlineScript: 'step("test step", () => {})', + locations: [basicMonitorDetails.location], + }; + await uptime.clickAddMonitor(); + await uptime.createBasicBrowserMonitorDetails(monitorDetails, true); + const isSuccessful = await uptime.confirmAndSave(); + expect(isSuccessful).toBeTruthy(); + }); + + step('view ICMP details in monitor management UI', async () => { + const monitorDetails = { + ...basicMonitorDetails, + host: '1.1.1.1', + }; + await uptime.clickAddMonitor(); + await uptime.findMonitorConfiguration(monitorDetails); + }); + + step('delete ICMP monitor', async () => { + await deleteMonitor(); + }); +}); diff --git a/x-pack/plugins/uptime/e2e/page_objects/login.tsx b/x-pack/plugins/uptime/e2e/page_objects/login.tsx new file mode 100644 index 00000000000000..82062a0a710e7f --- /dev/null +++ b/x-pack/plugins/uptime/e2e/page_objects/login.tsx @@ -0,0 +1,28 @@ +/* + * 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 { Page } from '@elastic/synthetics'; + +export function loginPageProvider({ page }: { page: Page; kibanaUrl: string }) { + return { + async waitForLoadingToFinish() { + while (true) { + if ((await page.$('[data-test-subj=kbnLoadingMessage]')) === null) break; + await page.waitForTimeout(5 * 1000); + } + }, + async loginToKibana() { + await page.fill('[data-test-subj=loginUsername]', 'elastic', { + timeout: 60 * 1000, + }); + await page.fill('[data-test-subj=loginPassword]', 'changeme'); + + await page.click('[data-test-subj=loginSubmit]'); + + await this.waitForLoadingToFinish(); + }, + }; +} diff --git a/x-pack/plugins/uptime/e2e/page_objects/monitor_management.tsx b/x-pack/plugins/uptime/e2e/page_objects/monitor_management.tsx new file mode 100644 index 00000000000000..51f476a7a17429 --- /dev/null +++ b/x-pack/plugins/uptime/e2e/page_objects/monitor_management.tsx @@ -0,0 +1,183 @@ +/* + * 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 { Page } from '@elastic/synthetics'; +import { loginPageProvider } from './login'; +import { utilsPageProvider } from './utils'; + +export function monitorManagementPageProvider({ + page, + kibanaUrl, +}: { + page: Page; + kibanaUrl: string; +}) { + const monitorManagement = `${kibanaUrl}/app/uptime/manage-monitors`; + const addMonitor = `${kibanaUrl}/app/uptime/add-monitor`; + + return { + ...loginPageProvider({ page, kibanaUrl }), + ...utilsPageProvider({ page }), + + async navigateToMonitorManagement() { + await page.goto(monitorManagement, { + waitUntil: 'networkidle', + }); + }, + + async navigateToAddMonitor() { + await page.goto(addMonitor, { + waitUntil: 'networkidle', + }); + }, + + async clickAddMonitor() { + await page.click('text=Add monitor'); + }, + + async deleteMonitor() { + await this.clickByTestSubj('monitorManagementDeleteMonitor'); + return await this.findByTestSubj('uptimeDeleteMonitorSuccess'); + }, + + async findMonitorConfiguration(monitorConfig: Record) { + const values = Object.values(monitorConfig); + + for (let i = 0; i < values.length; i++) { + await this.findByText(values[i]); + } + }, + + async selectMonitorType(monitorType: string) { + await this.selectByTestSubj('syntheticsMonitorTypeField', monitorType); + }, + + async ensureIsOnMonitorConfigPage() { + await page.isVisible('[data-test-subj=monitorSettingsSection]'); + }, + + async confirmAndSave(isEditPage?: boolean) { + await this.ensureIsOnMonitorConfigPage(); + if (isEditPage) { + await page.click('text=Update monitor'); + } else { + await page.click('text=Save monitor'); + } + return await this.findByTestSubj('uptimeAddMonitorSuccess'); + }, + + async fillCodeEditor(value: string) { + await page.fill('[data-test-subj=codeEditorContainer] textarea', value); + }, + + async selectLocations({ locations }: { locations: string[] }) { + await this.clickByTestSubj('syntheticsServiceLocationsComboBox'); + for (let i = 0; i < locations.length; i++) { + await page.click(`text=${locations[i]}`); + } + }, + + async createBasicMonitorDetails({ + name, + apmServiceName, + locations, + }: { + name: string; + apmServiceName: string; + locations: string[]; + }) { + await this.fillByTestSubj('monitorManagementMonitorName', name); + await this.fillByTestSubj('syntheticsAPMServiceName', apmServiceName); + await this.selectLocations({ locations }); + }, + + async createBasicHTTPMonitorDetails({ + name, + url, + apmServiceName, + locations, + }: { + name: string; + url: string; + apmServiceName: string; + locations: string[]; + }) { + await this.createBasicMonitorDetails({ name, apmServiceName, locations }); + await this.fillByTestSubj('syntheticsUrlField', url); + }, + + async createBasicTCPMonitorDetails({ + name, + host, + apmServiceName, + locations, + }: { + name: string; + host: string; + apmServiceName: string; + locations: string[]; + }) { + await this.selectMonitorType('tcp'); + await this.createBasicMonitorDetails({ name, apmServiceName, locations }); + await this.fillByTestSubj('syntheticsTCPHostField', host); + }, + + async createBasicICMPMonitorDetails({ + name, + host, + apmServiceName, + locations, + }: { + name: string; + host: string; + apmServiceName: string; + locations: string[]; + }) { + await this.selectMonitorType('icmp'); + await this.createBasicMonitorDetails({ name, apmServiceName, locations }); + await this.fillByTestSubj('syntheticsICMPHostField', host); + }, + + async createBasicBrowserMonitorDetails( + { + name, + inlineScript, + zipUrl, + folder, + params, + username, + password, + apmServiceName, + locations, + }: { + name: string; + inlineScript?: string; + zipUrl?: string; + folder?: string; + params?: string; + username?: string; + password?: string; + apmServiceName: string; + locations: string[]; + }, + isInline: boolean = false + ) { + await this.selectMonitorType('browser'); + await this.createBasicMonitorDetails({ name, apmServiceName, locations }); + if (isInline && inlineScript) { + await this.clickByTestSubj('syntheticsSourceTab__inline'); + await this.fillCodeEditor(inlineScript); + return; + } + await this.fillByTestSubj('syntheticsBrowserZipUrl', zipUrl || ''); + await this.fillByTestSubj('syntheticsBrowserZipUrlFolder', folder || ''); + await this.fillByTestSubj('syntheticsBrowserZipUrlUsername', username || ''); + await this.fillByTestSubj('syntheticsBrowserZipUrlPassword', password || ''); + await this.fillCodeEditor(params || ''); + }, + }; +} diff --git a/x-pack/plugins/uptime/e2e/page_objects/utils.tsx b/x-pack/plugins/uptime/e2e/page_objects/utils.tsx new file mode 100644 index 00000000000000..d6b54bd7dd737c --- /dev/null +++ b/x-pack/plugins/uptime/e2e/page_objects/utils.tsx @@ -0,0 +1,47 @@ +/* + * 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, Page } from '@elastic/synthetics'; + +export function utilsPageProvider({ page }: { page: Page }) { + return { + byTestId(testId: string) { + return `[data-test-subj=${testId}]`; + }, + + async waitForLoadingToFinish() { + while (true) { + if ((await page.$(this.byTestId('kbnLoadingMessage'))) === null) break; + await page.waitForTimeout(5 * 1000); + } + }, + + async assertText({ text }: { text: string }) { + await page.waitForSelector(`text=${text}`); + expect(await page.$(`text=${text}`)).toBeTruthy(); + }, + + async fillByTestSubj(dataTestSubj: string, value: string) { + await page.fill(`[data-test-subj=${dataTestSubj}]`, value); + }, + + async selectByTestSubj(dataTestSubj: string, value: string) { + await page.selectOption(`[data-test-subj=${dataTestSubj}]`, value); + }, + + async clickByTestSubj(dataTestSubj: string) { + await page.click(`[data-test-subj=${dataTestSubj}]`); + }, + + async findByTestSubj(dataTestSubj: string) { + return await page.locator(`[data-test-subj=${dataTestSubj}]`); + }, + + async findByText(text: string) { + return await page.locator(`text=${text}`); + }, + }; +} diff --git a/x-pack/plugins/uptime/public/components/monitor_management/monitor_config/monitor_name_location.tsx b/x-pack/plugins/uptime/public/components/monitor_management/monitor_config/monitor_name_location.tsx index f3e04a0040418e..11c7862b32cc5a 100644 --- a/x-pack/plugins/uptime/public/components/monitor_management/monitor_config/monitor_name_location.tsx +++ b/x-pack/plugins/uptime/public/components/monitor_management/monitor_config/monitor_name_location.tsx @@ -50,6 +50,7 @@ export const MonitorNameAndLocation = ({ validate }: Props) => { fullWidth={true} name="name" onChange={(event) => setName(event.target.value)} + data-test-subj="monitorManagementMonitorName" /> { } if (status === FETCH_STATUS.FAILURE) { notifications.toasts.danger({ - title:

{MONITOR_DELETE_FAILURE_LABEL}

, + title:

{MONITOR_DELETE_FAILURE_LABEL}

, toastLifeTimeMs: 3000, }); } else if (status === FETCH_STATUS.SUCCESS) { setRefresh(true); notifications.toasts.success({ - title:

{MONITOR_DELETE_SUCCESS_LABEL}

, + title:

{MONITOR_DELETE_SUCCESS_LABEL}

, toastLifeTimeMs: 3000, }); } @@ -71,6 +71,7 @@ export const Actions = ({ id, setRefresh }: Props) => { iconType="trash" onClick={handleDelete} aria-label={DELETE_MONITOR_LABEL} + data-test-subj="monitorManagementDeleteMonitor" /> )}
From 8e6ec25a51d4121cabb33363e391bda1dce1aeea Mon Sep 17 00:00:00 2001 From: Chris Cowan Date: Tue, 18 Jan 2022 14:36:03 -0700 Subject: [PATCH 026/108] [Metrics UI] Increase composite size to 10K for Metric Threshold Rule and optimize processing (#121904) * [Metrics UI] Increase composite size for Metric Threshold Rule to 10K * Adding performance optimizations * Fixing metrics_alerting integration test * fixing tests * Fixing integration test and config mock * Removing the setTimeout code to simplify to a for/of * Adding new setting to docs * Adding metric_threshold identifier to the config setting --- .../general-infra-logs-ui-settings.asciidoc | 5 +- .../metric_threshold/lib/evaluate_rule.ts | 61 +++++++++---------- .../metric_threshold/lib/metric_query.test.ts | 3 +- .../metric_threshold/lib/metric_query.ts | 5 +- .../metric_threshold_executor.test.ts | 5 ++ .../metric_threshold_executor.ts | 5 +- .../plugins/infra/server/lib/infra_types.ts | 2 +- .../infra/server/lib/sources/sources.test.ts | 5 ++ x-pack/plugins/infra/server/plugin.ts | 13 ++-- x-pack/plugins/infra/server/types.ts | 18 ++++++ .../apis/metrics_ui/metric_threshold_alert.ts | 59 +++++++++++++++--- .../apis/metrics_ui/metrics_alerting.ts | 5 +- 12 files changed, 133 insertions(+), 53 deletions(-) diff --git a/docs/settings/general-infra-logs-ui-settings.asciidoc b/docs/settings/general-infra-logs-ui-settings.asciidoc index d56c38f120170a..5fb20d6622b43c 100644 --- a/docs/settings/general-infra-logs-ui-settings.asciidoc +++ b/docs/settings/general-infra-logs-ui-settings.asciidoc @@ -21,4 +21,7 @@ Field used to identify hosts. Defaults to `host.name`. Field used to identify Docker containers. Defaults to `container.id`. `xpack.infra.sources.default.fields.pod`:: -Field used to identify Kubernetes pods. Defaults to `kubernetes.pod.uid`. \ No newline at end of file +Field used to identify Kubernetes pods. Defaults to `kubernetes.pod.uid`. + +`xpack.infra.alerting.metric_threshold.group_by_page_size`:: +Controls the size of the composite aggregations used by the Metric Threshold group by feature. Defaults to `10000`. \ No newline at end of file diff --git a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/lib/evaluate_rule.ts b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/lib/evaluate_rule.ts index d1d4f4e9560b52..01c8f252fc71b2 100644 --- a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/lib/evaluate_rule.ts +++ b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/lib/evaluate_rule.ts @@ -7,7 +7,7 @@ import moment from 'moment'; import { ElasticsearchClient } from 'kibana/server'; -import { mapValues, first, last, isNaN, isNumber, isObject, has } from 'lodash'; +import { difference, mapValues, first, last, isNaN, isNumber, isObject, has } from 'lodash'; import { isTooManyBucketsPreviewException, TOO_MANY_BUCKETS_PREVIEW_EXCEPTION, @@ -66,6 +66,7 @@ export const evaluateRule = { const { criteria, groupBy, filterQuery, shouldDropPartialBuckets } = params; @@ -78,6 +79,7 @@ export const evaluateRule = !currentGroups.includes(g)); + const missingGroups = difference(prevGroups, currentGroups); + if (currentGroups.length === 0 && missingGroups.length === 0) { missingGroups.push(UNGROUPED_FACTORY_KEY); } const backfillTimestamp = last(last(Object.values(currentValues)))?.key ?? new Date().toISOString(); - const backfilledPrevGroups: Record< - string, - Array<{ key: string; value: number }> - > = missingGroups.reduce( - (result, group) => ({ - ...result, - [group]: [ - { - key: backfillTimestamp, - value: criterion.aggType === Aggregators.COUNT ? 0 : null, - }, - ], - }), - {} - ); + const backfilledPrevGroups: Record> = {}; + for (const group of missingGroups) { + backfilledPrevGroups[group] = [ + { + key: backfillTimestamp, + value: criterion.aggType === Aggregators.COUNT ? 0 : null, + }, + ]; + } const currentValuesWithBackfilledPrevGroups = { ...currentValues, ...backfilledPrevGroups, @@ -150,6 +147,7 @@ const getMetric: ( index: string, groupBy: string | undefined | string[], filterQuery: string | undefined, + compositeSize: number, timeframe?: { start?: number; end: number }, shouldDropPartialBuckets?: boolean ) => Promise>> = async function ( @@ -158,6 +156,7 @@ const getMetric: ( index, groupBy, filterQuery, + compositeSize, timeframe, shouldDropPartialBuckets ) { @@ -172,6 +171,7 @@ const getMetric: ( const searchBody = getElasticsearchMetricQuery( params, calculatedTimerange, + compositeSize, hasGroupBy ? groupBy : undefined, filterQuery ); @@ -202,21 +202,18 @@ const getMetric: ( bucketSelector, afterKeyHandler )) as Array; doc_count: number }>; - const groupedResults = compositeBuckets.reduce( - (result, bucket) => ({ - ...result, - [Object.values(bucket.key) - .map((value) => value) - .join(', ')]: getValuesFromAggregations( - bucket, - aggType, - dropPartialBucketsOptions, - calculatedTimerange, - bucket.doc_count - ), - }), - {} - ); + const groupedResults: Record = {}; + for (const bucket of compositeBuckets) { + const key = Object.values(bucket.key).join(', '); + const value = getValuesFromAggregations( + bucket, + aggType, + dropPartialBucketsOptions, + calculatedTimerange, + bucket.doc_count + ); + groupedResults[key] = value; + } return groupedResults; } const { body: result } = await esClient.search({ diff --git a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/lib/metric_query.test.ts b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/lib/metric_query.test.ts index 463365b6449d0f..3c6bca67de413d 100644 --- a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/lib/metric_query.test.ts +++ b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/lib/metric_query.test.ts @@ -24,7 +24,7 @@ describe("The Metric Threshold Alert's getElasticsearchMetricQuery", () => { }; describe('when passed no filterQuery', () => { - const searchBody = getElasticsearchMetricQuery(expressionParams, timeframe, groupBy); + const searchBody = getElasticsearchMetricQuery(expressionParams, timeframe, 100, groupBy); test('includes a range filter', () => { expect( searchBody.query.bool.filter.find((filter) => filter.hasOwnProperty('range')) @@ -47,6 +47,7 @@ describe("The Metric Threshold Alert's getElasticsearchMetricQuery", () => { const searchBody = getElasticsearchMetricQuery( expressionParams, timeframe, + 100, groupBy, filterQuery ); diff --git a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/lib/metric_query.ts b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/lib/metric_query.ts index 588b77250e6a64..e0abd8465e306e 100644 --- a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/lib/metric_query.ts +++ b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/lib/metric_query.ts @@ -11,8 +11,6 @@ import { MetricExpressionParams, Aggregators } from '../types'; import { createPercentileAggregation } from './create_percentile_aggregation'; import { calculateDateHistogramOffset } from '../../../metrics/lib/calculate_date_histogram_offset'; -const COMPOSITE_RESULTS_PER_PAGE = 100; - const getParsedFilterQuery: (filterQuery: string | undefined) => Record | null = ( filterQuery ) => { @@ -23,6 +21,7 @@ const getParsedFilterQuery: (filterQuery: string | undefined) => Record { @@ -73,7 +72,7 @@ export const getElasticsearchMetricQuery = ( ? { groupings: { composite: { - size: COMPOSITE_RESULTS_PER_PAGE, + size: compositeSize, sources: Array.isArray(groupBy) ? groupBy.map((field, index) => ({ [`groupBy${index}`]: { diff --git a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.test.ts b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.test.ts index 5a75b18e47590c..4bbbb355d573e1 100644 --- a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.test.ts +++ b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.test.ts @@ -747,6 +747,11 @@ describe('The metric threshold alert type', () => { }); const createMockStaticConfiguration = (sources: any) => ({ + alerting: { + metric_threshold: { + group_by_page_size: 100, + }, + }, inventory: { compositeSize: 2000, }, diff --git a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.ts b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.ts index 810055fc1771a6..1b85df04c428bd 100644 --- a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.ts +++ b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.ts @@ -118,6 +118,7 @@ export const createMetricThresholdExecutor = (libs: InfraBackendLibs) => sourceId || 'default' ); const config = source.configuration; + const compositeSize = libs.configuration.alerting.metric_threshold.group_by_page_size; const previousGroupBy = state.groupBy; const previousFilterQuery = state.filterQuery; @@ -135,7 +136,8 @@ export const createMetricThresholdExecutor = (libs: InfraBackendLibs) => services.scopedClusterClient.asCurrentUser, params as EvaluatedRuleParams, config, - prevGroups + prevGroups, + compositeSize ); // Because each alert result has the same group definitions, just grab the groups from the first one. @@ -248,7 +250,6 @@ export const createMetricThresholdExecutor = (libs: InfraBackendLibs) => }); } } - return { groups, groupBy: params.groupBy, filterQuery: params.filterQuery }; }); diff --git a/x-pack/plugins/infra/server/lib/infra_types.ts b/x-pack/plugins/infra/server/lib/infra_types.ts index 332a2e499977bb..bfac01d3138f4a 100644 --- a/x-pack/plugins/infra/server/lib/infra_types.ts +++ b/x-pack/plugins/infra/server/lib/infra_types.ts @@ -6,7 +6,7 @@ */ import { handleEsError } from '../../../../../src/plugins/es_ui_shared/server'; -import { InfraConfig } from '../plugin'; +import { InfraConfig } from '../types'; import { GetLogQueryFields } from '../services/log_queries/get_log_query_fields'; import { RulesServiceSetup } from '../services/rules'; import { KibanaFramework } from './adapters/framework/kibana_framework_adapter'; diff --git a/x-pack/plugins/infra/server/lib/sources/sources.test.ts b/x-pack/plugins/infra/server/lib/sources/sources.test.ts index 396d2c22a100f0..adcec1bf055ea8 100644 --- a/x-pack/plugins/infra/server/lib/sources/sources.test.ts +++ b/x-pack/plugins/infra/server/lib/sources/sources.test.ts @@ -109,6 +109,11 @@ describe('the InfraSources lib', () => { }); const createMockStaticConfiguration = (sources: any) => ({ + alerting: { + metric_threshold: { + group_by_page_size: 10000, + }, + }, enabled: true, inventory: { compositeSize: 2000, diff --git a/x-pack/plugins/infra/server/plugin.ts b/x-pack/plugins/infra/server/plugin.ts index 79998ae6d56909..32562e319e1e59 100644 --- a/x-pack/plugins/infra/server/plugin.ts +++ b/x-pack/plugins/infra/server/plugin.ts @@ -6,7 +6,7 @@ */ import { Server } from '@hapi/hapi'; -import { schema, TypeOf } from '@kbn/config-schema'; +import { schema } from '@kbn/config-schema'; import { i18n } from '@kbn/i18n'; import { Logger } from '@kbn/logging'; import { @@ -35,15 +35,20 @@ import { InfraBackendLibs, InfraDomainLibs } from './lib/infra_types'; import { infraSourceConfigurationSavedObjectType, InfraSources } from './lib/sources'; import { InfraSourceStatus } from './lib/source_status'; import { LogEntriesService } from './services/log_entries'; -import { InfraPluginRequestHandlerContext } from './types'; +import { InfraPluginRequestHandlerContext, InfraConfig } from './types'; import { UsageCollector } from './usage/usage_collector'; import { createGetLogQueryFields } from './services/log_queries/get_log_query_fields'; import { handleEsError } from '../../../../src/plugins/es_ui_shared/server'; import { RulesService } from './services/rules'; import { configDeprecations, getInfraDeprecationsFactory } from './deprecations'; -export const config: PluginConfigDescriptor = { +export const config: PluginConfigDescriptor = { schema: schema.object({ + alerting: schema.object({ + metric_threshold: schema.object({ + group_by_page_size: schema.number({ defaultValue: 10000 }), + }), + }), inventory: schema.object({ compositeSize: schema.number({ defaultValue: 2000 }), }), @@ -64,7 +69,7 @@ export const config: PluginConfigDescriptor = { deprecations: configDeprecations, }; -export type InfraConfig = TypeOf; +export type { InfraConfig }; export interface KbnServer extends Server { usage: any; diff --git a/x-pack/plugins/infra/server/types.ts b/x-pack/plugins/infra/server/types.ts index 5cae0158619460..9bfdc4784d26c2 100644 --- a/x-pack/plugins/infra/server/types.ts +++ b/x-pack/plugins/infra/server/types.ts @@ -31,3 +31,21 @@ export interface InfraPluginRequestHandlerContext extends RequestHandlerContext infra: InfraRequestHandlerContext; search: SearchRequestHandlerContext; } + +export interface InfraConfig { + alerting: { + metric_threshold: { + group_by_page_size: number; + }; + }; + inventory: { + compositeSize: number; + }; + sources?: { + default?: { + fields?: { + message?: string[]; + }; + }; + }; +} diff --git a/x-pack/test/api_integration/apis/metrics_ui/metric_threshold_alert.ts b/x-pack/test/api_integration/apis/metrics_ui/metric_threshold_alert.ts index ecefef2fe930c4..d0fac5a7bd170f 100644 --- a/x-pack/test/api_integration/apis/metrics_ui/metric_threshold_alert.ts +++ b/x-pack/test/api_integration/apis/metrics_ui/metric_threshold_alert.ts @@ -100,7 +100,7 @@ export default function ({ getService }: FtrProviderContext) { }; const timeFrame = { end: DATES.ten_thousand_plus.max }; const kbnClient = convertToKibanaClient(esClient); - const results = await evaluateRule(kbnClient, params, config, [], timeFrame); + const results = await evaluateRule(kbnClient, params, config, [], 10000, timeFrame); expect(results).to.eql([ { '*': { @@ -142,7 +142,7 @@ export default function ({ getService }: FtrProviderContext) { }; const timeFrame = { end: DATES.ten_thousand_plus.max }; const kbnClient = convertToKibanaClient(esClient); - const results = await evaluateRule(kbnClient, params, config, [], timeFrame); + const results = await evaluateRule(kbnClient, params, config, [], 10000, timeFrame); expect(results).to.eql([ { web: { @@ -184,7 +184,14 @@ export default function ({ getService }: FtrProviderContext) { }; const timeFrame = { end: gauge.max }; const kbnClient = convertToKibanaClient(esClient); - const results = await evaluateRule(kbnClient, params, configuration, [], timeFrame); + const results = await evaluateRule( + kbnClient, + params, + configuration, + [], + 10000, + timeFrame + ); expect(results).to.eql([ { '*': { @@ -208,7 +215,14 @@ export default function ({ getService }: FtrProviderContext) { const params = { ...baseParams }; const timeFrame = { end: gauge.max }; const kbnClient = convertToKibanaClient(esClient); - const results = await evaluateRule(kbnClient, params, configuration, [], timeFrame); + const results = await evaluateRule( + kbnClient, + params, + configuration, + [], + 10000, + timeFrame + ); expect(results).to.eql([ { '*': { @@ -246,7 +260,14 @@ export default function ({ getService }: FtrProviderContext) { }; const timeFrame = { end: gauge.max }; const kbnClient = convertToKibanaClient(esClient); - const results = await evaluateRule(kbnClient, params, configuration, [], timeFrame); + const results = await evaluateRule( + kbnClient, + params, + configuration, + [], + 10000, + timeFrame + ); expect(results).to.eql([ { dev: { @@ -287,7 +308,14 @@ export default function ({ getService }: FtrProviderContext) { }; const timeFrame = { end: gauge.max }; const kbnClient = convertToKibanaClient(esClient); - const results = await evaluateRule(kbnClient, params, configuration, [], timeFrame); + const results = await evaluateRule( + kbnClient, + params, + configuration, + [], + 10000, + timeFrame + ); expect(results).to.eql([ { dev: { @@ -334,6 +362,7 @@ export default function ({ getService }: FtrProviderContext) { params, configuration, ['dev', 'prod'], + 10000, timeFrame ); expect(results).to.eql([ @@ -392,7 +421,14 @@ export default function ({ getService }: FtrProviderContext) { }; const timeFrame = { end: rate.max }; const kbnClient = convertToKibanaClient(esClient); - const results = await evaluateRule(kbnClient, params, configuration, [], timeFrame); + const results = await evaluateRule( + kbnClient, + params, + configuration, + [], + 10000, + timeFrame + ); expect(results).to.eql([ { '*': { @@ -433,7 +469,14 @@ export default function ({ getService }: FtrProviderContext) { }; const timeFrame = { end: rate.max }; const kbnClient = convertToKibanaClient(esClient); - const results = await evaluateRule(kbnClient, params, configuration, [], timeFrame); + const results = await evaluateRule( + kbnClient, + params, + configuration, + [], + 10000, + timeFrame + ); expect(results).to.eql([ { dev: { diff --git a/x-pack/test/api_integration/apis/metrics_ui/metrics_alerting.ts b/x-pack/test/api_integration/apis/metrics_ui/metrics_alerting.ts index eb8888a613dc3c..fd9767e13d9ef3 100644 --- a/x-pack/test/api_integration/apis/metrics_ui/metrics_alerting.ts +++ b/x-pack/test/api_integration/apis/metrics_ui/metrics_alerting.ts @@ -37,7 +37,7 @@ export default function ({ getService }: FtrProviderContext) { start: moment().subtract(25, 'minutes').valueOf(), end: moment().valueOf(), }; - const searchBody = getElasticsearchMetricQuery(getSearchParams(aggType), timeframe); + const searchBody = getElasticsearchMetricQuery(getSearchParams(aggType), timeframe, 100); const result = await client.search({ index, // @ts-expect-error @elastic/elasticsearch AggregationsBucketsPath is not valid @@ -58,6 +58,7 @@ export default function ({ getService }: FtrProviderContext) { const searchBody = getElasticsearchMetricQuery( getSearchParams('avg'), timeframe, + 100, undefined, '{"bool":{"should":[{"match_phrase":{"agent.hostname":"foo"}}],"minimum_should_match":1}}' ); @@ -81,6 +82,7 @@ export default function ({ getService }: FtrProviderContext) { const searchBody = getElasticsearchMetricQuery( getSearchParams(aggType), timeframe, + 100, 'agent.id' ); const result = await client.search({ @@ -101,6 +103,7 @@ export default function ({ getService }: FtrProviderContext) { const searchBody = getElasticsearchMetricQuery( getSearchParams('avg'), timeframe, + 100, 'agent.id', '{"bool":{"should":[{"match_phrase":{"agent.hostname":"foo"}}],"minimum_should_match":1}}' ); From 4d98af824f0fe0bb52de1c4ef7170bb7004d15de Mon Sep 17 00:00:00 2001 From: Pete Hampton Date: Tue, 18 Jan 2022 22:04:51 +0000 Subject: [PATCH 027/108] Fix issue with parsing out endpoint package policy. (#123287) * Fix issue with parsing out endpoint package policy. * revert schedule. --- .../server/lib/telemetry/helpers.test.ts | 38 +++++++++++++++++++ .../server/lib/telemetry/helpers.ts | 15 ++++++-- .../server/lib/telemetry/tasks/endpoint.ts | 8 ++-- 3 files changed, 55 insertions(+), 6 deletions(-) diff --git a/x-pack/plugins/security_solution/server/lib/telemetry/helpers.test.ts b/x-pack/plugins/security_solution/server/lib/telemetry/helpers.test.ts index cacb34dc8fa70a..6f865aa19b7814 100644 --- a/x-pack/plugins/security_solution/server/lib/telemetry/helpers.test.ts +++ b/x-pack/plugins/security_solution/server/lib/telemetry/helpers.test.ts @@ -14,6 +14,7 @@ import { LIST_TRUSTED_APPLICATION, } from './constants'; import { + extractEndpointPolicyConfig, getPreviousDiagTaskTimestamp, getPreviousDailyTaskTimestamp, batchTelemetryRecords, @@ -21,6 +22,7 @@ import { templateExceptionList, } from './helpers'; import type { ESClusterInfo, ESLicense, ExceptionListItem } from './types'; +import { PolicyData } from '../../../common/endpoint/types'; describe('test diagnostic telemetry scheduled task timing helper', () => { test('test -5 mins is returned when there is no previous task run', async () => { @@ -266,3 +268,39 @@ describe('list telemetry schema', () => { expect(templatedItems[0]?.trusted_application).toBeUndefined(); }); }); + +describe('test endpoint policy data config extraction', () => { + const stubPolicyData = { + id: '872de8c5-85cf-4e1b-a504-9fd39b38570c', + version: 'WzU4MjkwLDFd', + name: 'Test Policy Data', + namespace: 'default', + description: '', + package: { + name: 'endpoint', + title: 'Endpoint Security', + version: '1.4.1', + }, + enabled: true, + policy_id: '499b5aa7-d214-5b5d-838b-3cd76469844e', + output_id: '', + inputs: [ + { + type: 'endpoint', + enabled: true, + streams: [], + config: null, + }, + ], + revision: 1, + created_at: '2022-01-18T14:52:17.385Z', + created_by: 'elastic', + updated_at: '2022-01-18T14:52:17.385Z', + updated_by: 'elastic', + } as unknown as PolicyData; + + test('can succeed when policy config is null or empty', async () => { + const endpointPolicyConfig = extractEndpointPolicyConfig(stubPolicyData); + expect(endpointPolicyConfig).toBeNull(); + }); +}); diff --git a/x-pack/plugins/security_solution/server/lib/telemetry/helpers.ts b/x-pack/plugins/security_solution/server/lib/telemetry/helpers.ts index 92ea33a7b07eda..d2dce77866d06d 100644 --- a/x-pack/plugins/security_solution/server/lib/telemetry/helpers.ts +++ b/x-pack/plugins/security_solution/server/lib/telemetry/helpers.ts @@ -9,6 +9,7 @@ import moment from 'moment'; import type { ExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; import { PackagePolicy } from '../../../../fleet/common/types/models/package_policy'; import { copyAllowlistedFields, exceptionListEventFields } from './filters'; +import { PolicyData } from '../../../common/endpoint/types'; import type { ExceptionListItem, ESClusterInfo, @@ -216,6 +217,14 @@ export const templateExceptionList = ( * @param label_list the list of labels to create standardized UsageCounter from * @returns a string label for usage in the UsageCounter */ -export function createUsageCounterLabel(labelList: string[]): string { - return labelList.join('-'); -} +export const createUsageCounterLabel = (labelList: string[]): string => labelList.join('-'); + +/** + * Resiliantly handles an edge case where the endpoint config details are not present + * + * @returns the endpoint policy configuration + */ +export const extractEndpointPolicyConfig = (policyData: PolicyData | null) => { + const epPolicyConfig = policyData?.inputs[0]?.config?.policy; + return epPolicyConfig ? epPolicyConfig : null; +}; diff --git a/x-pack/plugins/security_solution/server/lib/telemetry/tasks/endpoint.ts b/x-pack/plugins/security_solution/server/lib/telemetry/tasks/endpoint.ts index 78f2889ac1d589..000182a3d7a9a9 100644 --- a/x-pack/plugins/security_solution/server/lib/telemetry/tasks/endpoint.ts +++ b/x-pack/plugins/security_solution/server/lib/telemetry/tasks/endpoint.ts @@ -18,6 +18,7 @@ import { TelemetryReceiver } from '../receiver'; import { TaskExecutionPeriod } from '../task'; import { batchTelemetryRecords, + extractEndpointPolicyConfig, getPreviousDailyTaskTimestamp, isPackagePolicyList, } from '../helpers'; @@ -145,11 +146,11 @@ export function createTelemetryEndpointTaskConfig(maxTelemetryBatch: number) { packagePolicies .map((pPolicy) => pPolicy as PolicyData) .forEach((pPolicy) => { - if (pPolicy.inputs[0].config !== undefined) { + if (pPolicy.inputs[0]?.config !== undefined && pPolicy.inputs[0]?.config !== null) { pPolicy.inputs.forEach((input) => { if ( input.type === FLEET_ENDPOINT_PACKAGE && - input.config !== undefined && + input?.config !== undefined && policyInfo !== undefined ) { endpointPolicyCache.set(policyInfo, pPolicy); @@ -212,6 +213,7 @@ export function createTelemetryEndpointTaskConfig(maxTelemetryBatch: number) { } const { cpu, memory, uptime } = endpoint.endpoint_metrics.Endpoint.metrics; + const endpointPolicyDetail = extractEndpointPolicyConfig(policyConfig); return { '@timestamp': taskExecutionPeriod.current, @@ -229,7 +231,7 @@ export function createTelemetryEndpointTaskConfig(maxTelemetryBatch: number) { endpoint_meta: { os: endpoint.endpoint_metrics.host.os, }, - policy_config: policyConfig !== null ? policyConfig?.inputs[0].config.policy : {}, + policy_config: endpointPolicyDetail !== null ? endpointPolicyDetail : {}, policy_response: failedPolicy !== null && failedPolicy !== undefined ? { From 886ad6fdafd90efadf05d7a3ad20c5a3eeeb3e72 Mon Sep 17 00:00:00 2001 From: Marshall Main <55718608+marshallmain@users.noreply.github.com> Date: Tue, 18 Jan 2022 14:31:14 -0800 Subject: [PATCH 028/108] [Security Solution] Add aliases, fix types, remove extra fields (#122880) * Add aliases, fix types, remove extra fields * Update aliases version and update tests * Update aliases version test * Remove dangling references to fields * Update test Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../common/field_maps/alerts.ts | 2 +- .../common/field_maps/rules.ts | 96 +----------- .../components/drag_and_drop/helpers.ts | 11 -- .../event_details/__mocks__/index.ts | 101 ------------- .../common/components/top_n/helpers.test.tsx | 13 +- .../public/common/components/top_n/helpers.ts | 1 - .../alerts_table/default_config.tsx | 4 - .../side_panel/event_details/footer.tsx | 3 +- .../get_signals_template.test.ts.snap | 137 ++++-------------- .../routes/index/get_signals_template.ts | 2 +- .../routes/index/signal_aad_mapping.json | 16 +- .../routes/index/signal_extra_fields.json | 3 + .../public/components/t_grid/body/helpers.tsx | 11 -- .../timeline/factory/helpers/constants.ts | 7 - .../helpers/format_timeline_data.test.ts | 135 ----------------- .../security_and_spaces/tests/create_index.ts | 4 +- 16 files changed, 50 insertions(+), 496 deletions(-) diff --git a/x-pack/plugins/security_solution/common/field_maps/alerts.ts b/x-pack/plugins/security_solution/common/field_maps/alerts.ts index 08ce8f098f6fd8..330f85a8a83439 100644 --- a/x-pack/plugins/security_solution/common/field_maps/alerts.ts +++ b/x-pack/plugins/security_solution/common/field_maps/alerts.ts @@ -54,7 +54,7 @@ export const alertsFieldMap: FieldMap = { required: false, }, 'kibana.alert.group.index': { - type: 'keyword', + type: 'integer', array: false, required: false, }, diff --git a/x-pack/plugins/security_solution/common/field_maps/rules.ts b/x-pack/plugins/security_solution/common/field_maps/rules.ts index 5277a594bc31ea..062e4ee5c52475 100644 --- a/x-pack/plugins/security_solution/common/field_maps/rules.ts +++ b/x-pack/plugins/security_solution/common/field_maps/rules.ts @@ -26,31 +26,11 @@ export const rulesFieldMap = { array: true, required: false, }, - 'kibana.alert.rule.index': { - type: 'keyword', - array: true, - required: true, - }, - 'kibana.alert.rule.language': { - type: 'keyword', - array: true, - required: true, - }, 'kibana.alert.rule.max_signals': { type: 'long', array: true, required: true, }, - 'kibana.alert.rule.query': { - type: 'keyword', - array: true, - required: true, - }, - 'kibana.alert.rule.saved_id': { - type: 'keyword', - array: true, - required: true, - }, 'kibana.alert.rule.threat.framework': { type: 'keyword', array: false, @@ -101,91 +81,21 @@ export const rulesFieldMap = { array: false, required: true, }, - 'kibana.alert.rule.threat_filters': { - type: 'keyword', - array: true, - required: false, - }, - 'kibana.alert.rule.threat_index': { - type: 'keyword', - array: true, - required: false, - }, - 'kibana.alert.rule.threat_indicator_path': { - type: 'keyword', - array: true, - required: false, - }, - 'kibana.alert.rule.threat_language': { - type: 'keyword', - array: true, - required: false, - }, - 'kibana.alert.rule.threat_mapping': { - type: 'object', - array: true, - required: false, - }, - 'kibana.alert.rule.threat_mapping.entries.field': { - type: 'keyword', - array: true, - required: false, - }, - 'kibana.alert.rule.threat_mapping.entries.value': { + 'kibana.alert.rule.timeline_id': { type: 'keyword', array: true, required: false, }, - 'kibana.alert.rule.threat_mapping.entries.type': { + 'kibana.alert.rule.timeline_title': { type: 'keyword', array: true, required: false, }, - 'kibana.alert.rule.threat_query': { + 'kibana.alert.rule.timestamp_override': { type: 'keyword', - array: true, - required: false, - }, - 'kibana.alert.rule.threshold': { - type: 'object', - array: true, - required: false, - }, - 'kibana.alert.rule.threshold.field': { - type: 'keyword', - array: false, - required: false, - }, - 'kibana.alert.rule.threshold.value': { - type: 'float', array: false, required: false, }, - 'kibana.alert.rule.threshold.cardinality': { - type: 'object', - array: true, - required: false, - }, - 'kibana.alert.rule.threshold.cardinality.field': { - type: 'keyword', - array: false, - required: false, - }, - 'kibana.alert.rule.threshold.cardinality.value': { - type: 'long', - array: false, - required: false, - }, - 'kibana.alert.rule.timeline_id': { - type: 'keyword', - array: true, - required: false, - }, - 'kibana.alert.rule.timeline_title': { - type: 'keyword', - array: true, - required: false, - }, } as const; export type RulesFieldMap = typeof rulesFieldMap; diff --git a/x-pack/plugins/security_solution/public/common/components/drag_and_drop/helpers.ts b/x-pack/plugins/security_solution/public/common/components/drag_and_drop/helpers.ts index 1334ab6acd467e..a43ae947a5f124 100644 --- a/x-pack/plugins/security_solution/public/common/components/drag_and_drop/helpers.ts +++ b/x-pack/plugins/security_solution/public/common/components/drag_and_drop/helpers.ts @@ -139,31 +139,20 @@ export const allowTopN = ({ 'kibana.alert.original_event.timezone', 'kibana.alert.original_event.type', 'kibana.alert.original_time', - 'kibana.alert.parent.depth', - 'kibana.alert.parent.id', - 'kibana.alert.parent.index', - 'kibana.alert.parent.rule', - 'kibana.alert.parent.type', 'kibana.alert.rule.created_by', 'kibana.alert.rule.description', 'kibana.alert.rule.enabled', 'kibana.alert.rule.false_positives', - 'kibana.alert.rule.filters', 'kibana.alert.rule.from', 'kibana.alert.rule.uuid', 'kibana.alert.rule.immutable', - 'kibana.alert.rule.index', 'kibana.alert.rule.interval', - 'kibana.alert.rule.language', 'kibana.alert.rule.max_signals', 'kibana.alert.rule.name', 'kibana.alert.rule.note', - 'kibana.alert.rule.output_index', - 'kibana.alert.rule.query', 'kibana.alert.rule.references', 'kibana.alert.risk_score', 'kibana.alert.rule.rule_id', - 'kibana.alert.rule.saved_id', 'kibana.alert.severity', 'kibana.alert.rule.size', 'kibana.alert.rule.tags', diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/__mocks__/index.ts b/x-pack/plugins/security_solution/public/common/components/event_details/__mocks__/index.ts index e06cd379e51311..98075f3db187c3 100644 --- a/x-pack/plugins/security_solution/public/common/components/event_details/__mocks__/index.ts +++ b/x-pack/plugins/security_solution/public/common/components/event_details/__mocks__/index.ts @@ -332,22 +332,6 @@ export const mockAlertDetailsData = [ originalValue: 'administrator', }, { category: 'user', field: 'user.id', values: ['S-1-0-0'], originalValue: 'S-1-0-0' }, - // TODO: The `parents` field no longer exists... use `ancestors` and `depth` - { - category: 'kibana', - field: 'kibana.alert.parents', - values: [ - '{"id":"688MAHYB7WTwW_Glsi_d","type":"event","index":"winlogbeat-7.10.0-2020.11.12-000001","depth":0}', - ], - originalValue: [ - { - id: '688MAHYB7WTwW_Glsi_d', - type: 'event', - index: 'winlogbeat-7.10.0-2020.11.12-000001', - depth: 0, - }, - ], - }, { category: 'kibana', field: 'kibana.alert.ancestors', @@ -399,12 +383,6 @@ export const mockAlertDetailsData = [ values: [], originalValue: [], }, - { - category: 'kibana', - field: 'kibana.alert.rule.output_index', - values: ['.siem-signals-angelachuang-default'], - originalValue: '.siem-signals-angelachuang-default', - }, { category: 'kibana', field: 'kibana.alert.rule.description', @@ -417,45 +395,9 @@ export const mockAlertDetailsData = [ values: ['now-360s'], originalValue: 'now-360s', }, - { - category: 'kibana', - field: 'kibana.alert.rule.index', - values: [ - 'apm-*-transaction*', - 'traces-apm*', - 'auditbeat-*', - 'endgame-*', - 'filebeat-*', - 'logs-*', - 'packetbeat-*', - 'winlogbeat-*', - ], - originalValue: [ - 'apm-*-transaction*', - 'traces-apm*', - 'auditbeat-*', - 'endgame-*', - 'filebeat-*', - 'logs-*', - 'packetbeat-*', - 'winlogbeat-*', - ], - }, { category: 'kibana', field: 'kibana.alert.rule.interval', values: ['5m'], originalValue: '5m' }, - { - category: 'kibana', - field: 'kibana.alert.rule.language', - values: ['kuery'], - originalValue: 'kuery', - }, { category: 'kibana', field: 'kibana.alert.rule.license', values: [''], originalValue: '' }, { category: 'kibana', field: 'kibana.alert.rule.name', values: ['xxx'], originalValue: 'xxx' }, - { - category: 'kibana', - field: 'kibana.alert.rule.query', - values: ['@timestamp : * '], - originalValue: '@timestamp : * ', - }, { category: 'kibana', field: 'kibana.alert.rule.references', values: [], originalValue: [] }, { category: 'kibana', @@ -477,27 +419,6 @@ export const mockAlertDetailsData = [ originalValue: 'query', }, { category: 'kibana', field: 'kibana.alert.rule.to', values: ['now'], originalValue: 'now' }, - { - category: 'kibana', - field: 'kibana.alert.rule.filters', - values: [ - '{"meta":{"alias":null,"negate":false,"disabled":false,"type":"exists","key":"message","value":"exists"},"exists":{"field":"message"},"$state":{"store":"appState"}}', - ], - originalValue: [ - { - meta: { - alias: null, - negate: false, - disabled: false, - type: 'exists', - key: 'message', - value: 'exists', - }, - exists: { field: 'message' }, - $state: { store: 'appState' }, - }, - ], - }, { category: 'kibana', field: 'kibana.alert.rule.created_by', @@ -526,28 +447,6 @@ export const mockAlertDetailsData = [ }, { category: 'kibana', field: 'kibana.alert.rule.exceptions_list', values: [], originalValue: [] }, { category: 'kibana', field: 'kibana.alert.depth', values: [1], originalValue: 1 }, - // TODO: The `parent` no longer exists. Use `ancestors` and `depth` - { - category: 'kibana', - field: 'kibana.alert.parent.id', - values: ['688MAHYB7WTwW_Glsi_d'], - originalValue: '688MAHYB7WTwW_Glsi_d', - }, - // TODO: The `parent` no longer exists. Use `ancestors` and `depth` - { - category: 'kibana', - field: 'kibana.alert.parent.type', - values: ['event'], - originalValue: 'event', - }, - // TODO: The `parent` no longer exists. Use `ancestors` and `depth` - { - category: 'kibana', - field: 'kibana.alert.parent.index', - values: ['winlogbeat-7.10.0-2020.11.12-000001'], - originalValue: 'winlogbeat-7.10.0-2020.11.12-000001', - }, - { category: 'kibana', field: 'kibana.alert.parent.depth', values: [0], originalValue: 0 }, { category: 'kibana', field: 'kibana.alert.original_time', diff --git a/x-pack/plugins/security_solution/public/common/components/top_n/helpers.test.tsx b/x-pack/plugins/security_solution/public/common/components/top_n/helpers.test.tsx index ffc49a0cfe36cf..68e1e6614e5f1b 100644 --- a/x-pack/plugins/security_solution/public/common/components/top_n/helpers.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/top_n/helpers.test.tsx @@ -115,17 +115,12 @@ const ruleNameFilter: Filter = { const threatMappingFilter: Filter = { meta: { alias: null, - negate: true, disabled: false, - type: 'exists', - key: 'kibana.alert.rule.threat_mapping', - value: 'exists', - }, - query: { - exists: { - field: 'kibana.alert.rule.threat_mapping', - }, + negate: false, + key: 'kibana.alert.rule.type', + type: 'term', }, + query: { term: { 'kibana.alert.rule.type': 'threat_match' } }, }; const workflowStatusFilter: Filter = { diff --git a/x-pack/plugins/security_solution/public/common/components/top_n/helpers.ts b/x-pack/plugins/security_solution/public/common/components/top_n/helpers.ts index 20ac48789a32fb..78a380bafe82c3 100644 --- a/x-pack/plugins/security_solution/public/common/components/top_n/helpers.ts +++ b/x-pack/plugins/security_solution/public/common/components/top_n/helpers.ts @@ -158,7 +158,6 @@ export const IGNORED_ALERT_FILTERS = [ ALERT_RULE_RULE_ID, // filters alerts to a single rule on the Security > Rules > details pages ALERT_RULE_RULE_NAME_OVERRIDE, ALERT_RULE_TAGS, - 'kibana.alert.rule.threat_mapping', // an "Additional filters" option on the alerts table ALERT_RULE_TO, ALERT_RULE_TYPE, ALERT_RULE_TYPE_ID, diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/default_config.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_table/default_config.tsx index 911ab7fed59f57..dc8c5bf4de65e1 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_table/default_config.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/default_config.tsx @@ -162,14 +162,10 @@ export const requiredFieldsForActions = [ 'kibana.alert.group.id', 'kibana.alert.original_time', 'kibana.alert.building_block_type', - 'kibana.alert.rule.filters', 'kibana.alert.rule.from', - 'kibana.alert.rule.language', - 'kibana.alert.rule.query', 'kibana.alert.rule.name', 'kibana.alert.rule.to', 'kibana.alert.rule.uuid', - 'kibana.alert.rule.index', 'kibana.alert.rule.type', 'kibana.alert.original_event.kind', 'kibana.alert.original_event.module', diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/footer.tsx b/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/footer.tsx index 9b988f054d1303..e43bbbadba7823 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/footer.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/footer.tsx @@ -60,7 +60,8 @@ export const EventDetailsFooterComponent = React.memo( const ruleIndex = useMemo( () => find({ category: 'signal', field: 'signal.rule.index' }, detailsData)?.values ?? - find({ category: 'kibana', field: 'kibana.alert.rule.index' }, detailsData)?.values, + find({ category: 'kibana', field: 'kibana.alert.rule.parameters.index' }, detailsData) + ?.values, [detailsData] ); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/index/__snapshots__/get_signals_template.test.ts.snap b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/index/__snapshots__/get_signals_template.test.ts.snap index 6e0712332157d2..e03e438650df91 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/index/__snapshots__/get_signals_template.test.ts.snap +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/index/__snapshots__/get_signals_template.test.ts.snap @@ -3,7 +3,7 @@ exports[`get_signals_template backwards compatibility mappings for version 45 should match snapshot 1`] = ` Object { "_meta": Object { - "aliases_version": 1, + "aliases_version": 2, "version": 45, }, "properties": Object { @@ -31,6 +31,14 @@ Object { "path": "signal.depth", "type": "alias", }, + "kibana.alert.group.id": Object { + "path": "signal.group.id", + "type": "alias", + }, + "kibana.alert.group.index": Object { + "path": "signal.group.index", + "type": "alias", + }, "kibana.alert.original_event.action": Object { "path": "signal.original_event.action", "type": "alias", @@ -159,18 +167,10 @@ Object { "path": "signal.rule.immutable", "type": "alias", }, - "kibana.alert.rule.index": Object { - "path": "signal.rule.index", - "type": "alias", - }, "kibana.alert.rule.interval": Object { "path": "signal.rule.interval", "type": "alias", }, - "kibana.alert.rule.language": Object { - "path": "signal.rule.language", - "type": "alias", - }, "kibana.alert.rule.license": Object { "path": "signal.rule.license", "type": "alias", @@ -187,10 +187,6 @@ Object { "path": "signal.rule.note", "type": "alias", }, - "kibana.alert.rule.query": Object { - "path": "signal.rule.query", - "type": "alias", - }, "kibana.alert.rule.references": Object { "path": "signal.rule.references", "type": "alias", @@ -203,10 +199,6 @@ Object { "path": "signal.rule.rule_name_override", "type": "alias", }, - "kibana.alert.rule.saved_id": Object { - "path": "signal.rule.saved_id", - "type": "alias", - }, "kibana.alert.rule.tags": Object { "path": "signal.rule.tags", "type": "alias", @@ -251,42 +243,6 @@ Object { "path": "signal.rule.threat.technique.subtechnique.reference", "type": "alias", }, - "kibana.alert.rule.threat_index": Object { - "path": "signal.rule.threat_index", - "type": "alias", - }, - "kibana.alert.rule.threat_indicator_path": Object { - "path": "signal.rule.threat_indicator_path", - "type": "alias", - }, - "kibana.alert.rule.threat_language": Object { - "path": "signal.rule.threat_language", - "type": "alias", - }, - "kibana.alert.rule.threat_mapping.entries.field": Object { - "path": "signal.rule.threat_mapping.entries.field", - "type": "alias", - }, - "kibana.alert.rule.threat_mapping.entries.type": Object { - "path": "signal.rule.threat_mapping.entries.type", - "type": "alias", - }, - "kibana.alert.rule.threat_mapping.entries.value": Object { - "path": "signal.rule.threat_mapping.entries.value", - "type": "alias", - }, - "kibana.alert.rule.threat_query": Object { - "path": "signal.rule.threat_query", - "type": "alias", - }, - "kibana.alert.rule.threshold.field": Object { - "path": "signal.rule.threshold.field", - "type": "alias", - }, - "kibana.alert.rule.threshold.value": Object { - "path": "signal.rule.threshold.value", - "type": "alias", - }, "kibana.alert.rule.timeline_id": Object { "path": "signal.rule.timeline_id", "type": "alias", @@ -295,6 +251,10 @@ Object { "path": "signal.rule.timeline_title", "type": "alias", }, + "kibana.alert.rule.timestamp_override": Object { + "path": "signal.rule.timestamp_override", + "type": "alias", + }, "kibana.alert.rule.to": Object { "path": "signal.rule.to", "type": "alias", @@ -519,6 +479,9 @@ Object { }, "type": "object", }, + "timestamp_override": Object { + "type": "keyword", + }, }, "type": "object", }, @@ -570,7 +533,7 @@ Object { exports[`get_signals_template backwards compatibility mappings for version 57 should match snapshot 1`] = ` Object { "_meta": Object { - "aliases_version": 1, + "aliases_version": 2, "version": 57, }, } @@ -589,7 +552,7 @@ Object { }, "mappings": Object { "_meta": Object { - "aliases_version": 1, + "aliases_version": 2, "version": 67, }, "dynamic": false, @@ -2291,6 +2254,14 @@ Object { "path": "signal.depth", "type": "alias", }, + "kibana.alert.group.id": Object { + "path": "signal.group.id", + "type": "alias", + }, + "kibana.alert.group.index": Object { + "path": "signal.group.index", + "type": "alias", + }, "kibana.alert.original_event.action": Object { "path": "signal.original_event.action", "type": "alias", @@ -2419,18 +2390,10 @@ Object { "path": "signal.rule.immutable", "type": "alias", }, - "kibana.alert.rule.index": Object { - "path": "signal.rule.index", - "type": "alias", - }, "kibana.alert.rule.interval": Object { "path": "signal.rule.interval", "type": "alias", }, - "kibana.alert.rule.language": Object { - "path": "signal.rule.language", - "type": "alias", - }, "kibana.alert.rule.license": Object { "path": "signal.rule.license", "type": "alias", @@ -2447,10 +2410,6 @@ Object { "path": "signal.rule.note", "type": "alias", }, - "kibana.alert.rule.query": Object { - "path": "signal.rule.query", - "type": "alias", - }, "kibana.alert.rule.references": Object { "path": "signal.rule.references", "type": "alias", @@ -2463,10 +2422,6 @@ Object { "path": "signal.rule.rule_name_override", "type": "alias", }, - "kibana.alert.rule.saved_id": Object { - "path": "signal.rule.saved_id", - "type": "alias", - }, "kibana.alert.rule.tags": Object { "path": "signal.rule.tags", "type": "alias", @@ -2511,42 +2466,6 @@ Object { "path": "signal.rule.threat.technique.subtechnique.reference", "type": "alias", }, - "kibana.alert.rule.threat_index": Object { - "path": "signal.rule.threat_index", - "type": "alias", - }, - "kibana.alert.rule.threat_indicator_path": Object { - "path": "signal.rule.threat_indicator_path", - "type": "alias", - }, - "kibana.alert.rule.threat_language": Object { - "path": "signal.rule.threat_language", - "type": "alias", - }, - "kibana.alert.rule.threat_mapping.entries.field": Object { - "path": "signal.rule.threat_mapping.entries.field", - "type": "alias", - }, - "kibana.alert.rule.threat_mapping.entries.type": Object { - "path": "signal.rule.threat_mapping.entries.type", - "type": "alias", - }, - "kibana.alert.rule.threat_mapping.entries.value": Object { - "path": "signal.rule.threat_mapping.entries.value", - "type": "alias", - }, - "kibana.alert.rule.threat_query": Object { - "path": "signal.rule.threat_query", - "type": "alias", - }, - "kibana.alert.rule.threshold.field": Object { - "path": "signal.rule.threshold.field", - "type": "alias", - }, - "kibana.alert.rule.threshold.value": Object { - "path": "signal.rule.threshold.value", - "type": "alias", - }, "kibana.alert.rule.timeline_id": Object { "path": "signal.rule.timeline_id", "type": "alias", @@ -2555,6 +2474,10 @@ Object { "path": "signal.rule.timeline_title", "type": "alias", }, + "kibana.alert.rule.timestamp_override": Object { + "path": "signal.rule.timestamp_override", + "type": "alias", + }, "kibana.alert.rule.to": Object { "path": "signal.rule.to", "type": "alias", diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/index/get_signals_template.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/index/get_signals_template.ts index d80b9123d0edd8..1f02fcde671844 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/index/get_signals_template.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/index/get_signals_template.ts @@ -47,7 +47,7 @@ export const SIGNALS_TEMPLATE_VERSION = 67; UI will call create_index_route and and go through the index update process. Increment this number if making changes to the field aliases we use to make signals forwards-compatible. */ -export const SIGNALS_FIELD_ALIASES_VERSION = 1; +export const SIGNALS_FIELD_ALIASES_VERSION = 2; /** @constant diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/index/signal_aad_mapping.json b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/index/signal_aad_mapping.json index 66768c86f05e47..f6b88a1968a5b0 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/index/signal_aad_mapping.json +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/index/signal_aad_mapping.json @@ -4,6 +4,8 @@ "signal.ancestors.index": "kibana.alert.ancestors.index", "signal.ancestors.type": "kibana.alert.ancestors.type", "signal.depth": "kibana.alert.depth", + "signal.group.id": "kibana.alert.group.id", + "signal.group.index": "kibana.alert.group.index", "signal.original_event.action": "kibana.alert.original_event.action", "signal.original_event.category": "kibana.alert.original_event.category", "signal.original_event.code": "kibana.alert.original_event.code", @@ -37,19 +39,15 @@ "signal.rule.from": "kibana.alert.rule.from", "signal.rule.id": "kibana.alert.rule.uuid", "signal.rule.immutable": "kibana.alert.rule.immutable", - "signal.rule.index": "kibana.alert.rule.index", "signal.rule.interval": "kibana.alert.rule.interval", - "signal.rule.language": "kibana.alert.rule.language", "signal.rule.license": "kibana.alert.rule.license", "signal.rule.max_signals": "kibana.alert.rule.max_signals", "signal.rule.name": "kibana.alert.rule.name", "signal.rule.note": "kibana.alert.rule.note", - "signal.rule.query": "kibana.alert.rule.query", "signal.rule.references": "kibana.alert.rule.references", "signal.rule.risk_score": "kibana.alert.risk_score", "signal.rule.rule_id": "kibana.alert.rule.rule_id", "signal.rule.rule_name_override": "kibana.alert.rule.rule_name_override", - "signal.rule.saved_id": "kibana.alert.rule.saved_id", "signal.rule.severity": "kibana.alert.severity", "signal.rule.tags": "kibana.alert.rule.tags", "signal.rule.threat.framework": "kibana.alert.rule.threat.framework", @@ -62,17 +60,9 @@ "signal.rule.threat.technique.subtechnique.id": "kibana.alert.rule.threat.technique.subtechnique.id", "signal.rule.threat.technique.subtechnique.name": "kibana.alert.rule.threat.technique.subtechnique.name", "signal.rule.threat.technique.subtechnique.reference": "kibana.alert.rule.threat.technique.subtechnique.reference", - "signal.rule.threat_index": "kibana.alert.rule.threat_index", - "signal.rule.threat_indicator_path": "kibana.alert.rule.threat_indicator_path", - "signal.rule.threat_language": "kibana.alert.rule.threat_language", - "signal.rule.threat_mapping.entries.field": "kibana.alert.rule.threat_mapping.entries.field", - "signal.rule.threat_mapping.entries.value": "kibana.alert.rule.threat_mapping.entries.value", - "signal.rule.threat_mapping.entries.type": "kibana.alert.rule.threat_mapping.entries.type", - "signal.rule.threat_query": "kibana.alert.rule.threat_query", - "signal.rule.threshold.field": "kibana.alert.rule.threshold.field", - "signal.rule.threshold.value": "kibana.alert.rule.threshold.value", "signal.rule.timeline_id": "kibana.alert.rule.timeline_id", "signal.rule.timeline_title": "kibana.alert.rule.timeline_title", + "signal.rule.timestamp_override": "kibana.alert.rule.timestamp_override", "signal.rule.to": "kibana.alert.rule.to", "signal.rule.type": "kibana.alert.rule.type", "signal.rule.updated_at": "kibana.alert.rule.updated_at", diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/index/signal_extra_fields.json b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/index/signal_extra_fields.json index 32c084f927d7b0..02dcc9ec84926e 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/index/signal_extra_fields.json +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/index/signal_extra_fields.json @@ -168,6 +168,9 @@ "type": "float" } } + }, + "timestamp_override": { + "type": "keyword" } } }, diff --git a/x-pack/plugins/timelines/public/components/t_grid/body/helpers.tsx b/x-pack/plugins/timelines/public/components/t_grid/body/helpers.tsx index 017ddfd62cc2f5..afe7c5954cdada 100644 --- a/x-pack/plugins/timelines/public/components/t_grid/body/helpers.tsx +++ b/x-pack/plugins/timelines/public/components/t_grid/body/helpers.tsx @@ -165,32 +165,21 @@ export const allowSorting = ({ 'kibana.alert.original_event.timezone', 'kibana.alert.original_event.type', 'kibana.alert.original_time', - 'kibana.alert.parent.depth', - 'kibana.alert.parent.id', - 'kibana.alert.parent.index', - 'kibana.alert.parent.rule', - 'kibana.alert.parent.type', 'kibana.alert.reason', 'kibana.alert.rule.created_by', 'kibana.alert.rule.description', 'kibana.alert.rule.enabled', 'kibana.alert.rule.false_positives', - 'kibana.alert.rule.filters', 'kibana.alert.rule.from', 'kibana.alert.rule.uuid', 'kibana.alert.rule.immutable', - 'kibana.alert.rule.index', 'kibana.alert.rule.interval', - 'kibana.alert.rule.language', 'kibana.alert.rule.max_signals', 'kibana.alert.rule.name', 'kibana.alert.rule.note', - 'kibana.alert.rule.output_index', - 'kibana.alert.rule.query', 'kibana.alert.rule.references', 'kibana.alert.risk_score', 'kibana.alert.rule.rule_id', - 'kibana.alert.rule.saved_id', 'kibana.alert.severity', 'kibana.alert.rule.size', 'kibana.alert.rule.tags', diff --git a/x-pack/plugins/timelines/server/search_strategy/timeline/factory/helpers/constants.ts b/x-pack/plugins/timelines/server/search_strategy/timeline/factory/helpers/constants.ts index 43c638b2bb4535..e764e32243c183 100644 --- a/x-pack/plugins/timelines/server/search_strategy/timeline/factory/helpers/constants.ts +++ b/x-pack/plugins/timelines/server/search_strategy/timeline/factory/helpers/constants.ts @@ -49,14 +49,10 @@ export const TIMELINE_EVENTS_FIELDS = [ 'kibana.alert.group.id', 'kibana.alert.original_time', 'kibana.alert.reason', - 'kibana.alert.rule.filters', 'kibana.alert.rule.from', - 'kibana.alert.rule.language', - 'kibana.alert.rule.query', 'kibana.alert.rule.name', 'kibana.alert.rule.to', 'kibana.alert.rule.uuid', - 'kibana.alert.rule.index', 'kibana.alert.rule.type', 'kibana.alert.original_event.kind', 'kibana.alert.original_event.module', @@ -175,12 +171,9 @@ export const TIMELINE_EVENTS_FIELDS = [ 'endgame.target_domain_name', 'endgame.target_logon_id', 'endgame.target_user_name', - 'kibana.alert.rule.saved_id', 'kibana.alert.rule.timeline_id', 'kibana.alert.rule.timeline_title', - 'kibana.alert.rule.output_index', 'kibana.alert.rule.note', - 'kibana.alert.rule.threshold', 'kibana.alert.rule.exceptions_list', 'kibana.alert.rule.building_block_type', 'suricata.eve.proto', diff --git a/x-pack/plugins/timelines/server/search_strategy/timeline/factory/helpers/format_timeline_data.test.ts b/x-pack/plugins/timelines/server/search_strategy/timeline/factory/helpers/format_timeline_data.test.ts index 17a3dbcbd56275..4c850665a903b2 100644 --- a/x-pack/plugins/timelines/server/search_strategy/timeline/factory/helpers/format_timeline_data.test.ts +++ b/x-pack/plugins/timelines/server/search_strategy/timeline/factory/helpers/format_timeline_data.test.ts @@ -139,13 +139,6 @@ describe('formatTimelineData', () => { count: 10000, value: '2a990c11-f61b-4c8e-b210-da2574e9f9db', }, - parent: { - depth: 0, - index: - 'apm-*-transaction*,traces-apm*,auditbeat-*,endgame-*,filebeat-*,logs-*,packetbeat-*,winlogbeat-*', - id: '0268af90-d8da-576a-9747-2a191519416a', - type: 'event', - }, depth: 1, _meta: { version: 14, @@ -158,13 +151,7 @@ describe('formatTimelineData', () => { references: [], description: 'asdasd', created_at: '2021-01-09T11:25:45.046Z', - language: 'kuery', - threshold: { - field: '', - value: 200, - }, building_block_type: null, - output_index: '.siem-signals-patrykkopycinski-default', type: 'threshold', rule_name_override: null, enabled: true, @@ -176,54 +163,8 @@ describe('formatTimelineData', () => { timeline_id: null, max_signals: 100, author: [], - query: '_id :*', - index: [ - 'apm-*-transaction*', - 'traces-apm*', - 'auditbeat-*', - 'endgame-*', - 'filebeat-*', - 'logs-*', - 'packetbeat-*', - 'winlogbeat-*', - ], - filters: [ - { - $state: { - store: 'appState', - }, - meta: { - negate: false, - alias: null, - disabled: false, - type: 'exists', - value: 'exists', - key: '_index', - }, - exists: { - field: '_index', - }, - }, - { - $state: { - store: 'appState', - }, - meta: { - negate: false, - alias: 'id_exists', - disabled: false, - type: 'exists', - value: 'exists', - key: '_id', - }, - exists: { - field: '_id', - }, - }, - ], created_by: 'patryk_test_user', version: 1, - saved_id: null, tags: [], rule_id: '2a990c11-f61b-4c8e-b210-da2574e9f9db', license: '', @@ -251,25 +192,13 @@ describe('formatTimelineData', () => { type: 'event', }, ], - parents: [ - { - depth: 0, - index: - 'apm-*-transaction*,traces-apm*,auditbeat-*,endgame-*,filebeat-*,logs-*,packetbeat-*,winlogbeat-*', - id: '0268af90-d8da-576a-9747-2a191519416a', - type: 'event', - }, - ], workflow_status: 'open', }, }, }, fields: { - 'kibana.alert.rule.output_index': ['.siem-signals-patrykkopycinski-default'], 'kibana.alert.rule.from': ['now-360s'], - 'kibana.alert.rule.language': ['kuery'], '@timestamp': ['2021-01-09T13:41:40.517Z'], - 'kibana.alert.rule.query': ['_id :*'], 'kibana.alert.rule.type': ['threshold'], 'kibana.alert.rule.uuid': ['696c24e0-526d-11eb-836c-e1620268b945'], 'kibana.alert.risk_score': [21], @@ -278,16 +207,6 @@ describe('formatTimelineData', () => { 'kibana.alert.original_time': ['2021-01-09T13:39:32.595Z'], 'kibana.alert.severity': ['low'], 'kibana.alert.rule.version': ['1'], - 'kibana.alert.rule.index': [ - 'apm-*-transaction*', - 'traces-apm*', - 'auditbeat-*', - 'endgame-*', - 'filebeat-*', - 'logs-*', - 'packetbeat-*', - 'winlogbeat-*', - ], 'kibana.alert.rule.name': ['Threshold test'], 'kibana.alert.rule.to': ['now'], }, @@ -334,67 +253,13 @@ describe('formatTimelineData', () => { exceptions_list: [], from: ['now-360s'], uuid: ['696c24e0-526d-11eb-836c-e1620268b945'], - index: [ - 'apm-*-transaction*', - 'traces-apm*', - 'auditbeat-*', - 'endgame-*', - 'filebeat-*', - 'logs-*', - 'packetbeat-*', - 'winlogbeat-*', - ], - language: ['kuery'], name: ['Threshold test'], - output_index: ['.siem-signals-patrykkopycinski-default'], - query: ['_id :*'], to: ['now'], type: ['threshold'], version: ['1'], timeline_id: [], timeline_title: [], - saved_id: [], note: [], - threshold: [ - JSON.stringify({ - field: '', - value: 200, - }), - ], - filters: [ - JSON.stringify({ - $state: { - store: 'appState', - }, - meta: { - negate: false, - alias: null, - disabled: false, - type: 'exists', - value: 'exists', - key: '_index', - }, - exists: { - field: '_index', - }, - }), - JSON.stringify({ - $state: { - store: 'appState', - }, - meta: { - negate: false, - alias: 'id_exists', - disabled: false, - type: 'exists', - value: 'exists', - key: '_id', - }, - exists: { - field: '_id', - }, - }), - ], }, }, }, diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/create_index.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/create_index.ts index fabc964692c7d7..17d6b3957637ae 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/create_index.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/create_index.ts @@ -11,6 +11,8 @@ import { DETECTION_ENGINE_INDEX_URL, } from '../../../../plugins/security_solution/common/constants'; +import { SIGNALS_FIELD_ALIASES_VERSION } from '../../../../plugins/security_solution/server/lib/detection_engine/routes/index/get_signals_template'; + import { FtrProviderContext } from '../../common/ftr_provider_context'; import { deleteSignalsIndex } from '../../utils'; @@ -81,7 +83,7 @@ export default ({ getService }: FtrProviderContext) => { }); // Make sure that aliases_version has been updated on the existing index expect(mappings['.siem-signals-default-000001'].mappings?._meta?.aliases_version).to.eql( - 1 + SIGNALS_FIELD_ALIASES_VERSION ); }); }); From 91a35c20cef0c396a3f81b37c7335e713b79a490 Mon Sep 17 00:00:00 2001 From: Kristof C Date: Tue, 18 Jan 2022 16:49:59 -0600 Subject: [PATCH 029/108] =?UTF-8?q?Fix=20success=20message=20to=20show=20c?= =?UTF-8?q?orrect=20language=20based=20on=20timelin=E2=80=A6=20(#123258)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix success message to show correct language based on timeline type * Fix translation problems Co-authored-by: Kristof-Pierre Cummings --- .../components/flyout/header/index.tsx | 4 +- .../components/flyout/header/translations.ts | 13 ++++--- .../actions/add_to_timeline.test.tsx | 39 +++++++++++++++++++ .../hover_actions/actions/add_to_timeline.tsx | 24 ++++++++++-- .../hover_actions/actions/translations.tsx | 6 +-- .../timelines/public/mock/global_state.ts | 1 + .../public/mock/mock_timeline_data.ts | 1 + .../timelines/public/store/t_grid/model.ts | 1 + .../translations/translations/ja-JP.json | 2 - .../translations/translations/zh-CN.json | 2 - 10 files changed, 75 insertions(+), 18 deletions(-) diff --git a/x-pack/plugins/security_solution/public/timelines/components/flyout/header/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/flyout/header/index.tsx index 9c5b2887d2a8e2..fba78be83fa369 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/flyout/header/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/flyout/header/index.tsx @@ -180,9 +180,9 @@ const FlyoutHeaderPanelComponent: React.FC = ({ timeline )} - + + i18n.translate('xpack.securitySolution.timeline.flyout.header.closeTimelineButtonLabel', { + defaultMessage: 'Close {isTimeline, select, true {timeline} false {template}}', + values: { + isTimeline, + }, + }); export const UNSAVED = i18n.translate('xpack.securitySolution.timeline.properties.unsavedLabel', { defaultMessage: 'Unsaved', diff --git a/x-pack/plugins/timelines/public/components/hover_actions/actions/add_to_timeline.test.tsx b/x-pack/plugins/timelines/public/components/hover_actions/actions/add_to_timeline.test.tsx index 4c43bdde50df0b..26300400dbcfd4 100644 --- a/x-pack/plugins/timelines/public/components/hover_actions/actions/add_to_timeline.test.tsx +++ b/x-pack/plugins/timelines/public/components/hover_actions/actions/add_to_timeline.test.tsx @@ -11,9 +11,19 @@ import React from 'react'; import AddToTimelineButton, { ADD_TO_TIMELINE_KEYBOARD_SHORTCUT } from './add_to_timeline'; import { DataProvider, IS_OPERATOR } from '../../../../common/types'; +import { useDeepEqualSelector } from '../../../hooks/use_selector'; import { TestProviders } from '../../../mock'; import * as i18n from './translations'; +const mockAddSuccess = jest.fn(); +jest.mock('../../../hooks/use_app_toasts', () => ({ + useAppToasts: () => ({ + addSuccess: mockAddSuccess, + }), +})); + +jest.mock('../../../hooks/use_selector'); + const mockDispatch = jest.fn(); jest.mock('react-redux', () => { const originalModule = jest.requireActual('react-redux'); @@ -72,6 +82,7 @@ const providerB: DataProvider = { describe('add to timeline', () => { beforeEach(() => { jest.resetAllMocks(); + (useDeepEqualSelector as jest.Mock).mockReturnValue({ timelineType: 'default' }); }); const field = 'user.name'; @@ -369,4 +380,32 @@ describe('add to timeline', () => { }); }); }); + + describe('it shows the appropriate text based on timeline type', () => { + test('Add success is called with "timeline" if timeline type is timeline', () => { + render( + + + + ); + + fireEvent.click(screen.getByRole('button')); + + expect(mockAddSuccess).toBeCalledWith('Added a to timeline'); + }); + + test('Add success is called with "template" if timeline type is template', () => { + (useDeepEqualSelector as jest.Mock).mockReturnValue({ timelineType: 'template' }); + + render( + + + + ); + + fireEvent.click(screen.getByRole('button')); + + expect(mockAddSuccess).toBeCalledWith('Added a to template'); + }); + }); }); diff --git a/x-pack/plugins/timelines/public/components/hover_actions/actions/add_to_timeline.tsx b/x-pack/plugins/timelines/public/components/hover_actions/actions/add_to_timeline.tsx index 0ab5cb09565516..6cbfee6bec99f8 100644 --- a/x-pack/plugins/timelines/public/components/hover_actions/actions/add_to_timeline.tsx +++ b/x-pack/plugins/timelines/public/components/hover_actions/actions/add_to_timeline.tsx @@ -9,10 +9,12 @@ import React, { useCallback, useEffect, useMemo } from 'react'; import { EuiContextMenuItem, EuiButtonEmpty, EuiButtonIcon, EuiToolTip } from '@elastic/eui'; import { DraggableId } from 'react-beautiful-dnd'; import { useDispatch } from 'react-redux'; - import { isEmpty } from 'lodash'; + import { stopPropagationAndPreventDefault } from '../../../../common/utils/accessibility'; import { DataProvider, TimelineId } from '../../../../common/types'; +import { useDeepEqualSelector } from '../../../hooks/use_selector'; +import { tGridSelectors } from '../../../types'; import { TooltipWithKeyboardShortcut } from '../../tooltip_with_keyboard_shortcut'; import { getAdditionalScreenReaderOnlyContext } from '../utils'; import { useAddToTimeline } from '../../../hooks/use_add_to_timeline'; @@ -67,6 +69,12 @@ const AddToTimelineButton: React.FC = React.memo( const dispatch = useDispatch(); const { addSuccess } = useAppToasts(); const startDragToTimeline = useGetHandleStartDragToTimeline({ draggableId, field }); + const getTGrid = tGridSelectors.getTGridByIdSelector(); + + const { timelineType } = useDeepEqualSelector((state) => { + return getTGrid(state, TimelineId.active); + }); + const handleStartDragToTimeline = useCallback(() => { if (draggableId != null) { startDragToTimeline(); @@ -80,7 +88,9 @@ const AddToTimelineButton: React.FC = React.memo( dataProvider: provider, }) ); - addSuccess(i18n.ADDED_TO_TIMELINE_MESSAGE(provider.name)); + addSuccess( + i18n.ADDED_TO_TIMELINE_OR_TEMPLATE_MESSAGE(provider.name, timelineType === 'default') + ); } }); } @@ -88,7 +98,15 @@ const AddToTimelineButton: React.FC = React.memo( if (onClick != null) { onClick(); } - }, [addSuccess, onClick, dataProvider, dispatch, draggableId, startDragToTimeline]); + }, [ + addSuccess, + dataProvider, + dispatch, + draggableId, + onClick, + startDragToTimeline, + timelineType, + ]); useEffect(() => { if (!ownFocus) { diff --git a/x-pack/plugins/timelines/public/components/hover_actions/actions/translations.tsx b/x-pack/plugins/timelines/public/components/hover_actions/actions/translations.tsx index 2f8587ddfab497..10b20377f6c1c5 100644 --- a/x-pack/plugins/timelines/public/components/hover_actions/actions/translations.tsx +++ b/x-pack/plugins/timelines/public/components/hover_actions/actions/translations.tsx @@ -11,8 +11,8 @@ export const ADD_TO_TIMELINE = i18n.translate('xpack.timelines.hoverActions.addT defaultMessage: 'Add to timeline investigation', }); -export const ADDED_TO_TIMELINE_MESSAGE = (fieldOrValue: string) => +export const ADDED_TO_TIMELINE_OR_TEMPLATE_MESSAGE = (fieldOrValue: string, isTimeline: boolean) => i18n.translate('xpack.timelines.hoverActions.addToTimeline.addedFieldMessage', { - values: { fieldOrValue }, - defaultMessage: `Added {fieldOrValue} to timeline`, + values: { fieldOrValue, isTimeline }, + defaultMessage: `Added {fieldOrValue} to {isTimeline, select, true {timeline} false {template}}`, }); diff --git a/x-pack/plugins/timelines/public/mock/global_state.ts b/x-pack/plugins/timelines/public/mock/global_state.ts index f02abfd50ae7e5..fea8aa57b88dd3 100644 --- a/x-pack/plugins/timelines/public/mock/global_state.ts +++ b/x-pack/plugins/timelines/public/mock/global_state.ts @@ -53,6 +53,7 @@ export const mockGlobalState: TimelineState = { queryFields: [], selectAll: false, title: 'Events', + timelineType: 'default', }, }, }; diff --git a/x-pack/plugins/timelines/public/mock/mock_timeline_data.ts b/x-pack/plugins/timelines/public/mock/mock_timeline_data.ts index 3f59ae3a15b681..363a67a30b978e 100644 --- a/x-pack/plugins/timelines/public/mock/mock_timeline_data.ts +++ b/x-pack/plugins/timelines/public/mock/mock_timeline_data.ts @@ -1588,4 +1588,5 @@ export const mockTgridModel: TGridModel = { ], title: 'Test rule', version: '1', + timelineType: 'default', }; diff --git a/x-pack/plugins/timelines/public/store/t_grid/model.ts b/x-pack/plugins/timelines/public/store/t_grid/model.ts index 29e8b08d0e0e5d..0640cfb845d9c9 100644 --- a/x-pack/plugins/timelines/public/store/t_grid/model.ts +++ b/x-pack/plugins/timelines/public/store/t_grid/model.ts @@ -84,6 +84,7 @@ export interface TGridModel extends TGridModelSettings { /** Events selected on this timeline -- eventId to TimelineNonEcsData[] mapping of data required for bulk actions **/ selectedEventIds: Record; savedObjectId: string | null; + timelineType: 'default' | 'template'; version: string | null; initialized?: boolean; } diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index c796ff340eb0a3..f03b4d07d336be 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -23643,7 +23643,6 @@ "xpack.securitySolution.timeline.failSearchDescription": "検索を実行できませんでした", "xpack.securitySolution.timeline.fieldTooltip": "フィールド", "xpack.securitySolution.timeline.file.fromOriginalPathDescription": "元のパスから", - "xpack.securitySolution.timeline.flyout.header.closeTimelineButtonLabel": "タイムラインを閉じる", "xpack.securitySolution.timeline.flyout.pane.removeColumnButtonLabel": "列を削除", "xpack.securitySolution.timeline.flyout.pane.timelinePropertiesAriaLabel": "タイムラインのプロパティ", "xpack.securitySolution.timeline.flyoutTimelineTemplateLabel": "タイムラインテンプレート", @@ -25025,7 +25024,6 @@ "xpack.timelines.footer.rowsPerPageLabel": "ページごとの行:{rowsPerPage}", "xpack.timelines.footer.totalCountOfEvents": "イベント", "xpack.timelines.hoverActions.addToTimeline": "タイムライン調査に追加", - "xpack.timelines.hoverActions.addToTimeline.addedFieldMessage": "{fieldOrValue}をタイムラインに追加しました", "xpack.timelines.hoverActions.columnToggleLabel": "表の{field}列を切り替える", "xpack.timelines.hoverActions.fieldLabel": "フィールド", "xpack.timelines.hoverActions.filterIn": "フィルタリング", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 3388937227960f..440de7312f4375 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -24038,7 +24038,6 @@ "xpack.securitySolution.timeline.failSearchDescription": "无法运行搜索", "xpack.securitySolution.timeline.fieldTooltip": "字段", "xpack.securitySolution.timeline.file.fromOriginalPathDescription": "从其原始路径", - "xpack.securitySolution.timeline.flyout.header.closeTimelineButtonLabel": "关闭时间线", "xpack.securitySolution.timeline.flyout.pane.removeColumnButtonLabel": "移除列", "xpack.securitySolution.timeline.flyout.pane.timelinePropertiesAriaLabel": "时间线属性", "xpack.securitySolution.timeline.flyoutTimelineTemplateLabel": "时间线模板", @@ -25456,7 +25455,6 @@ "xpack.timelines.footer.rowsPerPageLabel": "每页行数:{rowsPerPage}", "xpack.timelines.footer.totalCountOfEvents": "事件", "xpack.timelines.hoverActions.addToTimeline": "添加到时间线调查", - "xpack.timelines.hoverActions.addToTimeline.addedFieldMessage": "已将 {fieldOrValue} 添加到时间线", "xpack.timelines.hoverActions.columnToggleLabel": "在表中切换 {field} 列", "xpack.timelines.hoverActions.fieldLabel": "字段", "xpack.timelines.hoverActions.filterIn": "筛选", From 5e71b39a1d9a3f052849ad1a15e95c48676e5c3b Mon Sep 17 00:00:00 2001 From: Dominique Clarke Date: Tue, 18 Jan 2022 18:05:38 -0500 Subject: [PATCH 030/108] uptime - update synthetics tests kibana config (#123311) --- x-pack/plugins/uptime/e2e/config.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/x-pack/plugins/uptime/e2e/config.ts b/x-pack/plugins/uptime/e2e/config.ts index 42e23c540cd489..4e265d948ffef3 100644 --- a/x-pack/plugins/uptime/e2e/config.ts +++ b/x-pack/plugins/uptime/e2e/config.ts @@ -44,11 +44,11 @@ async function config({ readConfigFile }: FtrConfigProviderContext) { `--elasticsearch.username=kibana_system`, `--elasticsearch.password=changeme`, '--xpack.reporting.enabled=false', - `--xpack.uptime.unsafe.service.manifestUrl=${process.env.SYNTHETICS_SERVICE_MANIFEST}`, - `--xpack.uptime.unsafe.service.username=${process.env.SYNTHETICS_SERVICE_USERNAME}`, - `--xpack.uptime.unsafe.service.password=${process.env.SYNTHETICS_SERVICE_PASSWORD}`, - '--xpack.uptime.unsafe.service.enabled=true', - '--xpack.uptime.ui.unsafe.monitorManagement.enabled=true', + `--xpack.uptime.service.manifestUrl=${process.env.SYNTHETICS_SERVICE_MANIFEST}`, + `--xpack.uptime.service.username=${process.env.SYNTHETICS_SERVICE_USERNAME}`, + `--xpack.uptime.service.password=${process.env.SYNTHETICS_SERVICE_PASSWORD}`, + '--xpack.uptime.service.enabled=true', + '--xpack.uptime.ui.monitorManagement.enabled=true', ], }, }; From b2c9f10691837d6411b665715f24ed75db3cc85d Mon Sep 17 00:00:00 2001 From: Yara Tercero Date: Tue, 18 Jan 2022 15:18:31 -0800 Subject: [PATCH 031/108] [Security Solution][Exceptions] Fix export toast text (#123307) ### Summary Fix bug on rule export where toaster reports export total as being rule objects + exceptions objects, but should just be rule objects total. Adds cypress test. --- .../detection_rules/export_rule.spec.ts | 5 ++++- .../detection_rules/import_rules.spec.ts | 14 ++++++++---- .../cypress/tasks/alerts_detection_rules.ts | 2 +- .../detection_engine/rules/all/helpers.ts | 22 +++++++++++++++---- 4 files changed, 33 insertions(+), 10 deletions(-) diff --git a/x-pack/plugins/security_solution/cypress/integration/detection_rules/export_rule.spec.ts b/x-pack/plugins/security_solution/cypress/integration/detection_rules/export_rule.spec.ts index 18b7b122f0967b..1923343f65e61d 100644 --- a/x-pack/plugins/security_solution/cypress/integration/detection_rules/export_rule.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/detection_rules/export_rule.spec.ts @@ -11,7 +11,7 @@ import { waitForAlertsIndexToBeCreated, waitForAlertsPanelToBeLoaded, } from '../../tasks/alerts'; -import { exportFirstRule } from '../../tasks/alerts_detection_rules'; +import { exportFirstRule, getRulesImportExportToast } from '../../tasks/alerts_detection_rules'; import { createCustomRule } from '../../tasks/api_calls/rules'; import { cleanKibana } from '../../tasks/common'; import { loginAndWaitForPageWithoutDateRange } from '../../tasks/login'; @@ -36,6 +36,9 @@ describe('Export rules', () => { exportFirstRule(); cy.wait('@export').then(({ response }) => { cy.wrap(response?.body).should('eql', expectedExportedRule(this.ruleResponse)); + getRulesImportExportToast([ + 'Successfully exported 1 of 1 rule. Prebuilt rules were excluded from the resulting file.', + ]); }); }); }); diff --git a/x-pack/plugins/security_solution/cypress/integration/detection_rules/import_rules.spec.ts b/x-pack/plugins/security_solution/cypress/integration/detection_rules/import_rules.spec.ts index f12df0bf7f026d..f6aeafaa97e7ac 100644 --- a/x-pack/plugins/security_solution/cypress/integration/detection_rules/import_rules.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/detection_rules/import_rules.spec.ts @@ -11,7 +11,7 @@ import { waitForAlertsPanelToBeLoaded, } from '../../tasks/alerts'; import { - getRulesImportToast, + getRulesImportExportToast, importRules, importRulesWithOverwriteAll, } from '../../tasks/alerts_detection_rules'; @@ -35,7 +35,10 @@ describe('Import rules', () => { cy.wait('@import').then(({ response }) => { cy.wrap(response?.statusCode).should('eql', 200); - getRulesImportToast(['Successfully imported 1 rule', 'Successfully imported 2 exceptions.']); + getRulesImportExportToast([ + 'Successfully imported 1 rule', + 'Successfully imported 2 exceptions.', + ]); }); }); @@ -51,7 +54,7 @@ describe('Import rules', () => { cy.wait('@import').then(({ response }) => { cy.wrap(response?.statusCode).should('eql', 200); - getRulesImportToast(['Failed to import 1 rule', 'Failed to import 2 exceptions']); + getRulesImportExportToast(['Failed to import 1 rule', 'Failed to import 2 exceptions']); }); }); @@ -67,7 +70,10 @@ describe('Import rules', () => { cy.wait('@import').then(({ response }) => { cy.wrap(response?.statusCode).should('eql', 200); - getRulesImportToast(['Successfully imported 1 rule', 'Successfully imported 2 exceptions.']); + getRulesImportExportToast([ + 'Successfully imported 1 rule', + 'Successfully imported 2 exceptions.', + ]); }); }); }); diff --git a/x-pack/plugins/security_solution/cypress/tasks/alerts_detection_rules.ts b/x-pack/plugins/security_solution/cypress/tasks/alerts_detection_rules.ts index e2c3882d10b8c7..a000607d0a8036 100644 --- a/x-pack/plugins/security_solution/cypress/tasks/alerts_detection_rules.ts +++ b/x-pack/plugins/security_solution/cypress/tasks/alerts_detection_rules.ts @@ -275,7 +275,7 @@ export const importRules = (rulesFile: string) => { cy.get(INPUT_FILE).should('not.exist'); }; -export const getRulesImportToast = (headers: string[]) => { +export const getRulesImportExportToast = (headers: string[]) => { cy.get(TOASTER) .should('exist') .then(($els) => { diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/helpers.ts b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/helpers.ts index b03c5ebc84688c..99fc72b9d0c2b9 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/helpers.ts +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/helpers.ts @@ -6,6 +6,7 @@ */ import { Query } from '@elastic/eui'; +import { ExportRulesDetails } from '../../../../../../common/detection_engine/schemas/response/export_rules_details_schema'; import { BulkRuleResponse, RuleResponseBuckets, @@ -71,16 +72,29 @@ export const getSearchFilters = ({ /** * This function helps to parse NDJSON with exported rules - * and retrieve the number of successfully exported rules. + * and retrieve the metadata of exported rules. * * @param blob a Blob received from an _export endpoint - * @returns Number of exported rules + * @returns Export details */ -export const getExportedRulesCount = async (blob: Blob): Promise => { +export const getExportedRulesDetails = async (blob: Blob): Promise => { const blobContent = await blob.text(); // The Blob content is an NDJSON file, the last line of which contains export details. const exportDetailsJson = blobContent.split('\n').filter(Boolean).slice(-1)[0]; const exportDetails = JSON.parse(exportDetailsJson); - return exportDetails.exported_count; + return exportDetails; +}; + +/** + * This function helps to parse NDJSON with exported rules + * and retrieve the number of successfully exported rules. + * + * @param blob a Blob received from an _export endpoint + * @returns Number of exported rules + */ +export const getExportedRulesCount = async (blob: Blob): Promise => { + const details = await getExportedRulesDetails(blob); + + return details.exported_rules_count; }; From 467d1115662f69a574011f9ec0c7b4e6b5c21b64 Mon Sep 17 00:00:00 2001 From: "Devin W. Hurley" Date: Tue, 18 Jan 2022 18:19:43 -0500 Subject: [PATCH 032/108] [Security Solution] [Platform] Return additional errors during import rule + action migration process (#123088) * exposes additional errors when ES failures occur during the swap of old, pre-8.0 action ids with the new migrated action SO ids. Ref: https://github.com/elastic/kibana/pull/120975#discussion_r778449187 for more information * fix test error Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../routes/rules/utils.test.ts | 77 ++++++++++++++++--- .../detection_engine/routes/rules/utils.ts | 43 +++++------ 2 files changed, 88 insertions(+), 32 deletions(-) diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils.test.ts index 8b4a9cf2502266..db04d8eded8692 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils.test.ts @@ -26,7 +26,7 @@ import { import { getAlertMock } from '../__mocks__/request_responses'; import { INTERNAL_IDENTIFIER } from '../../../../../common/constants'; import { PartialFilter } from '../../types'; -import { BulkError } from '../utils'; +import { BulkError, createBulkErrorObject } from '../utils'; import { getOutputRuleAlertForRest } from '../__mocks__/utils'; import { PartialAlert } from '../../../../../../alerting/server'; import { createRulesAndExceptionsStreamFromNdJson } from '../../rules/create_rules_stream_from_ndjson'; @@ -46,9 +46,24 @@ import { LegacyRulesActionsSavedObject } from '../../rule_actions/legacy_get_rul // eslint-disable-next-line no-restricted-imports import { LegacyRuleAlertAction } from '../../rule_actions/legacy_types'; import { RuleExceptionsPromiseFromStreams } from './utils/import_rules_utils'; +import { partition } from 'lodash/fp'; type PromiseFromStreams = ImportRulesSchemaDecoded | Error; +const createMockImportRule = async (rule: ReturnType) => { + const ndJsonStream = new Readable({ + read() { + this.push(`${JSON.stringify(rule)}\n`); + this.push(null); + }, + }); + const [{ rules }] = await createPromiseFromStreams([ + ndJsonStream, + ...createRulesAndExceptionsStreamFromNdJson(1000), + ]); + return rules; +}; + describe.each([ ['Legacy', false], ['RAC', true], @@ -667,12 +682,10 @@ describe.each([ soClient.find.mockClear(); }); - test('returns original action if Elasticsearch query fails', async () => { - clients.core.savedObjects - .getClient() - .find.mockRejectedValueOnce(new Error('failed to query')); + test('returns error if Elasticsearch query fails', async () => { + soClient.find.mockRejectedValue(new Error('failed to query')); const result = await swapActionIds(mockAction, soClient); - expect(result).toEqual(mockAction); + expect((result as Error).message).toEqual('failed to query'); }); test('returns original action if Elasticsearch query returns no hits', async () => { @@ -781,9 +794,50 @@ describe.each([ ]); }); + test('returns import rules schemas + one migrated action + one error', async () => { + const rule: ReturnType = { + ...getCreateRulesSchemaMock('rule-1'), + actions: [mockAction, { ...mockAction, id: 'different-id' }], + }; + const rules = await createMockImportRule(rule); + soClient.find.mockImplementationOnce(async () => ({ + total: 0, + per_page: 0, + page: 1, + saved_objects: [ + { score: 0, id: 'new-post-8.0-id', type: 'action', attributes: {}, references: [] }, + ], + })); + + soClient.find.mockRejectedValueOnce(new Error('failed to query')); + + const res = await migrateLegacyActionsIds(rules, soClient); + expect(soClient.find.mock.calls).toHaveLength(2); + const [error, ruleRes] = partition( + (item): item is Error => item instanceof Error + )(res); + + expect(ruleRes[0]).toEqual({ + ...rules[0], + actions: [{ ...mockAction, id: 'new-post-8.0-id' }], + }); + expect(error[0]).toEqual( + new Error( + JSON.stringify( + createBulkErrorObject({ + ruleId: rule.rule_id, + statusCode: 409, + message: `${[new Error('failed to query')].map((e: Error) => e.message).join(',')}`, + }) + ) + ) + ); + }); + test('returns import rules schemas + migrated action resulting in error', async () => { const rule: ReturnType = { ...getCreateRulesSchemaMock('rule-1'), + // only passing in one action here actions: [mockAction], }; soClient.find.mockImplementationOnce(async () => ({ @@ -791,6 +845,7 @@ describe.each([ per_page: 0, page: 1, saved_objects: [ + // two actions are being returned, thus resulting in a conflict { score: 0, id: 'new-post-8.0-id', type: 'action', attributes: {}, references: [] }, { score: 0, id: 'new-post-8.0-id-2', type: 'action', attributes: {}, references: [] }, ], @@ -801,13 +856,14 @@ describe.each([ [rule], soClient ); - expect(res[0] instanceof Error).toBeTruthy(); - expect((res[0] as unknown as Error).message).toEqual( + expect(res[1] instanceof Error).toBeTruthy(); + expect((res[1] as unknown as Error).message).toEqual( JSON.stringify({ rule_id: 'rule-1', error: { status_code: 409, message: + // error message for when two or more action connectors are found for a single id 'Found two action connectors with originId or _id: some-7.x-id The upload cannot be completed unless the _id or the originId of the action connector is changed. See https://www.elastic.co/guide/en/kibana/current/sharing-saved-objects.html for more details', }, }) @@ -843,8 +899,9 @@ describe.each([ soClient ); expect(res[0]).toEqual({ ...rule, actions: [{ ...mockAction, id: 'new-post-8.0-id' }] }); - expect(res[1] instanceof Error).toBeTruthy(); - expect((res[1] as unknown as Error).message).toEqual( + expect(res[1]).toEqual({ ...rule, actions: [] }); + expect(res[2] instanceof Error).toBeTruthy(); + expect((res[2] as unknown as Error).message).toEqual( JSON.stringify({ rule_id: 'rule-1', error: { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils.ts index a52a2804d3c7e2..8819b068fd5d78 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { countBy } from 'lodash/fp'; +import { countBy, partition } from 'lodash/fp'; import uuid from 'uuid'; import { Action } from '@kbn/securitysolution-io-ts-alerting-types'; import { SavedObjectsClientContract } from 'kibana/server'; @@ -229,10 +229,10 @@ export const swapActionIds = async ( `Found two action connectors with originId or _id: ${action.id} The upload cannot be completed unless the _id or the originId of the action connector is changed. See https://www.elastic.co/guide/en/kibana/current/sharing-saved-objects.html for more details` ); } - } catch (exc) { return action; + } catch (exc) { + return exc; } - return action; }; /** @@ -271,7 +271,7 @@ export const migrateLegacyActionsIds = async ( ): Promise => { const isImportRule = (r: unknown): r is ImportRulesSchemaDecoded => !(r instanceof Error); - return pMap( + const toReturn = await pMap( rules, async (rule) => { if (isImportRule(rule)) { @@ -284,33 +284,32 @@ export const migrateLegacyActionsIds = async ( ); // were there any errors discovered while trying to migrate and swap the action connector ids? - const actionMigrationErrors = newActions.filter( - (action): action is Error => action instanceof Error - ); - - const newlyMigratedActions: Action[] = newActions.filter( - (action): action is Action => !(action instanceof Error) - ); + const [actionMigrationErrors, newlyMigratedActions] = partition( + (item): item is Error => item instanceof Error + )(newActions); if (actionMigrationErrors == null || actionMigrationErrors.length === 0) { return { ...rule, actions: newlyMigratedActions }; } - // return an Error object with the rule_id and the error messages - // for the actions associated with that rule. - return new Error( - JSON.stringify( - createBulkErrorObject({ - ruleId: rule.rule_id, - statusCode: 409, - message: `${actionMigrationErrors.map((error: Error) => error.message).join(',')}`, - }) - ) - ); + + return [ + { ...rule, actions: newlyMigratedActions }, + new Error( + JSON.stringify( + createBulkErrorObject({ + ruleId: rule.rule_id, + statusCode: 409, + message: `${actionMigrationErrors.map((error: Error) => error.message).join(',')}`, + }) + ) + ), + ]; } return rule; }, { concurrency: MAX_CONCURRENT_SEARCHES } ); + return toReturn.flat(); }; /** From 3b28f55ddbd5fe0fcb751180335ab757bb40e213 Mon Sep 17 00:00:00 2001 From: Steph Milovic Date: Tue, 18 Jan 2022 17:11:36 -0700 Subject: [PATCH 033/108] [Security Solution] Newsfeed Url bugfix (#123283) --- .../components/news_feed/helpers.test.ts | 35 ++++++++----------- .../common/components/news_feed/helpers.ts | 12 +++---- 2 files changed, 20 insertions(+), 27 deletions(-) diff --git a/x-pack/plugins/security_solution/public/common/components/news_feed/helpers.test.ts b/x-pack/plugins/security_solution/public/common/components/news_feed/helpers.test.ts index 5ccf9ba505b557..a5f04fe32f0a46 100644 --- a/x-pack/plugins/security_solution/public/common/components/news_feed/helpers.test.ts +++ b/x-pack/plugins/security_solution/public/common/components/news_feed/helpers.test.ts @@ -15,7 +15,7 @@ import { getLocale, getNewsFeedUrl, getNewsItemsFromApiResponse, - removeSnapshotFromVersion, + removeSuffixFromVersion, showNewsItem, } from './helpers'; import { NewsItem, RawNewsApiResponse } from './types'; @@ -23,53 +23,46 @@ import { NewsItem, RawNewsApiResponse } from './types'; jest.mock('../../lib/kibana'); describe('helpers', () => { - describe('removeSnapshotFromVersion', () => { + describe('removeSuffixFromVersion', () => { + test('removes entire suffix after version number', () => { + const version = '8.0.0-SNAPSHOT-rc1'; + + expect(removeSuffixFromVersion(version)).toEqual('8.0.0'); + }); test('it should remove an all-caps `-SNAPSHOT`', () => { const version = '8.0.0-SNAPSHOT'; - expect(removeSnapshotFromVersion(version)).toEqual('8.0.0'); + expect(removeSuffixFromVersion(version)).toEqual('8.0.0'); }); test('it should remove a mixed-case `-SnApShoT`', () => { const version = '8.0.0-SnApShoT'; - expect(removeSnapshotFromVersion(version)).toEqual('8.0.0'); - }); - - test('it should remove all occurrences of `-SNAPSHOT`, regardless of where they appear in the version', () => { - const version = '-SNAPSHOT8.0.0-SNAPSHOT'; - - expect(removeSnapshotFromVersion(version)).toEqual('8.0.0'); + expect(removeSuffixFromVersion(version)).toEqual('8.0.0'); }); test('it should NOT transform a version when it does not contain a `-SNAPSHOT`', () => { const version = '8.0.0'; - expect(removeSnapshotFromVersion(version)).toEqual('8.0.0'); + expect(removeSuffixFromVersion(version)).toEqual('8.0.0'); }); - test('it should NOT transform a version if it omits the dash in `SNAPSHOT`', () => { + test('it should transform a version if it omits the dash in `SNAPSHOT`', () => { const version = '8.0.0SNAPSHOT'; - expect(removeSnapshotFromVersion(version)).toEqual('8.0.0SNAPSHOT'); - }); - - test('it should NOT transform a version if has only a partial `-SNAPSHOT`', () => { - const version = '8.0.0-SNAP'; - - expect(removeSnapshotFromVersion(version)).toEqual('8.0.0-SNAP'); + expect(removeSuffixFromVersion(version)).toEqual('8.0.0'); }); test('it should NOT transform an undefined version', () => { const version = undefined; - expect(removeSnapshotFromVersion(version)).toBeUndefined(); + expect(removeSuffixFromVersion(version)).toBeUndefined(); }); test('it should NOT transform an empty version', () => { const version = ''; - expect(removeSnapshotFromVersion(version)).toEqual(''); + expect(removeSuffixFromVersion(version)).toEqual(''); }); }); diff --git a/x-pack/plugins/security_solution/public/common/components/news_feed/helpers.ts b/x-pack/plugins/security_solution/public/common/components/news_feed/helpers.ts index a6e551b378c5d8..0b6411f8362139 100644 --- a/x-pack/plugins/security_solution/public/common/components/news_feed/helpers.ts +++ b/x-pack/plugins/security_solution/public/common/components/news_feed/helpers.ts @@ -8,17 +8,17 @@ import { get } from 'lodash/fp'; import moment from 'moment'; import uuid from 'uuid'; - +import semverCoerce from 'semver/functions/coerce'; import { NewsItem, RawNewsApiItem, RawNewsApiResponse } from './types'; import { KibanaServices } from '../../lib/kibana'; /** - * Removes the `-SNAPSHOT` that is sometimes appended to the Kibana version, - * (e.g. `8.0.0-SNAPSHOT`), which is typically only seen in non-production + * Removes the suffix that is sometimes appended to the Kibana version, + * (e.g. `8.0.0-SNAPSHOT-rc1`), which is typically only seen in non-production * environments */ -export const removeSnapshotFromVersion = (kibanaVersion?: string) => - kibanaVersion?.replace(/-SNAPSHOT/gi, '') ?? kibanaVersion; +export const removeSuffixFromVersion = (kibanaVersion?: string) => + semverCoerce(kibanaVersion)?.version ?? kibanaVersion; /** * Combines the URL specified in the `newsFeedUrlSetting`, e.g. @@ -36,7 +36,7 @@ export const getNewsFeedUrl = ({ }) => [ newsFeedUrlSetting?.trim().replace(/\/$/, ''), - `v${removeSnapshotFromVersion(getKibanaVersion())}.json`, + `v${removeSuffixFromVersion(getKibanaVersion())}.json`, ].join('/'); /** Fall back to this language when extracting i18n news items from the feed */ From 8737691bce68eec3f780c07c260fd1e2c9bfa9fe Mon Sep 17 00:00:00 2001 From: Ryland Herrick Date: Tue, 18 Jan 2022 19:47:44 -0600 Subject: [PATCH 034/108] [RAC][Rule Registry] Generate ECS fieldmap from ECS 8.0 (#123012) * Generate ECS fieldmap from ECS 8.0 This is the result of running the generate_ecs_fieldmap script against ECS' 8.0 branch. * Account for scaling_factor property from ECS This is a required field for e.g. scaled_float fields, so we need to reflect its value in our field map. * Remove unused, unset property from FieldMap It does not appear that this value was ever being set, nor does this value appear in ECS' flat output, so I'm removing it for now to keep our types as accurate as possible. * Add path back to FieldMap definition This is a required field for type: alias fields. * Try upping the fields limit on our ECS component template This now exceeds the default of 1000. * Bump our field limit a bit more Apparently 1300 wasn't enough, either. * Fix type error Makes this field optional, since the technical component template doesn't currently use it. * Bump the field limit of our composed template Including the newest ECS fields, this index now exceeds 1600 fields. This value should probably be derived from the composed template's limits, but for now this allows the template to be created. Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../ecs_component_template.ts | 1 + .../common/assets/field_maps/ecs_field_map.ts | 3221 ++++++++++++++--- .../rule_registry/common/field_map/types.ts | 1 + x-pack/plugins/rule_registry/common/types.ts | 1 + .../scripts/generate_ecs_fieldmap/index.js | 8 +- .../resource_installer.ts | 2 +- 6 files changed, 2747 insertions(+), 487 deletions(-) diff --git a/x-pack/plugins/rule_registry/common/assets/component_templates/ecs_component_template.ts b/x-pack/plugins/rule_registry/common/assets/component_templates/ecs_component_template.ts index 81a3a76fc65f64..05ff64a2b753e9 100644 --- a/x-pack/plugins/rule_registry/common/assets/component_templates/ecs_component_template.ts +++ b/x-pack/plugins/rule_registry/common/assets/component_templates/ecs_component_template.ts @@ -14,6 +14,7 @@ export const ecsComponentTemplate: ClusterPutComponentTemplateBody = { template: { settings: { number_of_shards: 1, + 'index.mapping.total_fields.limit': 1500, }, mappings: merge( {}, diff --git a/x-pack/plugins/rule_registry/common/assets/field_maps/ecs_field_map.ts b/x-pack/plugins/rule_registry/common/assets/field_maps/ecs_field_map.ts index 114d54eb7b4bb5..7c4095cca039fd 100644 --- a/x-pack/plugins/rule_registry/common/assets/field_maps/ecs_field_map.ts +++ b/x-pack/plugins/rule_registry/common/assets/field_maps/ecs_field_map.ts @@ -75,6 +75,11 @@ export const ecsFieldMap = { array: false, required: false, }, + 'client.geo.continent_code': { + type: 'keyword', + array: false, + required: false, + }, 'client.geo.continent_name': { type: 'keyword', array: false, @@ -100,6 +105,11 @@ export const ecsFieldMap = { array: false, required: false, }, + 'client.geo.postal_code': { + type: 'keyword', + array: false, + required: false, + }, 'client.geo.region_iso_code': { type: 'keyword', array: false, @@ -110,6 +120,11 @@ export const ecsFieldMap = { array: false, required: false, }, + 'client.geo.timezone': { + type: 'keyword', + array: false, + required: false, + }, 'client.ip': { type: 'ip', array: false, @@ -235,6 +250,61 @@ export const ecsFieldMap = { array: false, required: false, }, + 'cloud.origin.account.id': { + type: 'keyword', + array: false, + required: false, + }, + 'cloud.origin.account.name': { + type: 'keyword', + array: false, + required: false, + }, + 'cloud.origin.availability_zone': { + type: 'keyword', + array: false, + required: false, + }, + 'cloud.origin.instance.id': { + type: 'keyword', + array: false, + required: false, + }, + 'cloud.origin.instance.name': { + type: 'keyword', + array: false, + required: false, + }, + 'cloud.origin.machine.type': { + type: 'keyword', + array: false, + required: false, + }, + 'cloud.origin.project.id': { + type: 'keyword', + array: false, + required: false, + }, + 'cloud.origin.project.name': { + type: 'keyword', + array: false, + required: false, + }, + 'cloud.origin.provider': { + type: 'keyword', + array: false, + required: false, + }, + 'cloud.origin.region': { + type: 'keyword', + array: false, + required: false, + }, + 'cloud.origin.service.name': { + type: 'keyword', + array: false, + required: false, + }, 'cloud.project.id': { type: 'keyword', array: false, @@ -255,6 +325,66 @@ export const ecsFieldMap = { array: false, required: false, }, + 'cloud.service.name': { + type: 'keyword', + array: false, + required: false, + }, + 'cloud.target.account.id': { + type: 'keyword', + array: false, + required: false, + }, + 'cloud.target.account.name': { + type: 'keyword', + array: false, + required: false, + }, + 'cloud.target.availability_zone': { + type: 'keyword', + array: false, + required: false, + }, + 'cloud.target.instance.id': { + type: 'keyword', + array: false, + required: false, + }, + 'cloud.target.instance.name': { + type: 'keyword', + array: false, + required: false, + }, + 'cloud.target.machine.type': { + type: 'keyword', + array: false, + required: false, + }, + 'cloud.target.project.id': { + type: 'keyword', + array: false, + required: false, + }, + 'cloud.target.project.name': { + type: 'keyword', + array: false, + required: false, + }, + 'cloud.target.provider': { + type: 'keyword', + array: false, + required: false, + }, + 'cloud.target.region': { + type: 'keyword', + array: false, + required: false, + }, + 'cloud.target.service.name': { + type: 'keyword', + array: false, + required: false, + }, 'container.id': { type: 'keyword', array: false, @@ -285,6 +415,21 @@ export const ecsFieldMap = { array: false, required: false, }, + 'data_stream.dataset': { + type: 'constant_keyword', + array: false, + required: false, + }, + 'data_stream.namespace': { + type: 'constant_keyword', + array: false, + required: false, + }, + 'data_stream.type': { + type: 'constant_keyword', + array: false, + required: false, + }, 'destination.address': { type: 'keyword', array: false, @@ -315,6 +460,11 @@ export const ecsFieldMap = { array: false, required: false, }, + 'destination.geo.continent_code': { + type: 'keyword', + array: false, + required: false, + }, 'destination.geo.continent_name': { type: 'keyword', array: false, @@ -340,6 +490,11 @@ export const ecsFieldMap = { array: false, required: false, }, + 'destination.geo.postal_code': { + type: 'keyword', + array: false, + required: false, + }, 'destination.geo.region_iso_code': { type: 'keyword', array: false, @@ -350,6 +505,11 @@ export const ecsFieldMap = { array: false, required: false, }, + 'destination.geo.timezone': { + type: 'keyword', + array: false, + required: false, + }, 'destination.ip': { type: 'ip', array: false, @@ -445,11 +605,21 @@ export const ecsFieldMap = { array: true, required: false, }, + 'dll.code_signature.digest_algorithm': { + type: 'keyword', + array: false, + required: false, + }, 'dll.code_signature.exists': { type: 'boolean', array: false, required: false, }, + 'dll.code_signature.signing_id': { + type: 'keyword', + array: false, + required: false, + }, 'dll.code_signature.status': { type: 'keyword', array: false, @@ -460,6 +630,16 @@ export const ecsFieldMap = { array: false, required: false, }, + 'dll.code_signature.team_id': { + type: 'keyword', + array: false, + required: false, + }, + 'dll.code_signature.timestamp': { + type: 'date', + array: false, + required: false, + }, 'dll.code_signature.trusted': { type: 'boolean', array: false, @@ -490,6 +670,11 @@ export const ecsFieldMap = { array: false, required: false, }, + 'dll.hash.ssdeep': { + type: 'keyword', + array: false, + required: false, + }, 'dll.name': { type: 'keyword', array: false, @@ -641,12 +826,12 @@ export const ecsFieldMap = { required: false, }, 'error.message': { - type: 'text', + type: 'match_only_text', array: false, required: false, }, 'error.stack_trace': { - type: 'keyword', + type: 'wildcard', array: false, required: false, }, @@ -785,6 +970,31 @@ export const ecsFieldMap = { array: false, required: false, }, + 'faas.coldstart': { + type: 'boolean', + array: false, + required: false, + }, + 'faas.execution': { + type: 'keyword', + array: false, + required: false, + }, + 'faas.trigger': { + type: 'nested', + array: false, + required: false, + }, + 'faas.trigger.request_id': { + type: 'keyword', + array: false, + required: false, + }, + 'faas.trigger.type': { + type: 'keyword', + array: false, + required: false, + }, 'file.accessed': { type: 'date', array: false, @@ -795,11 +1005,21 @@ export const ecsFieldMap = { array: true, required: false, }, + 'file.code_signature.digest_algorithm': { + type: 'keyword', + array: false, + required: false, + }, 'file.code_signature.exists': { type: 'boolean', array: false, required: false, }, + 'file.code_signature.signing_id': { + type: 'keyword', + array: false, + required: false, + }, 'file.code_signature.status': { type: 'keyword', array: false, @@ -810,6 +1030,16 @@ export const ecsFieldMap = { array: false, required: false, }, + 'file.code_signature.team_id': { + type: 'keyword', + array: false, + required: false, + }, + 'file.code_signature.timestamp': { + type: 'date', + array: false, + required: false, + }, 'file.code_signature.trusted': { type: 'boolean', array: false, @@ -845,164 +1075,319 @@ export const ecsFieldMap = { array: false, required: false, }, - 'file.extension': { + 'file.elf.architecture': { type: 'keyword', array: false, required: false, }, - 'file.gid': { + 'file.elf.byte_order': { type: 'keyword', array: false, required: false, }, - 'file.group': { + 'file.elf.cpu_type': { type: 'keyword', array: false, required: false, }, - 'file.hash.md5': { - type: 'keyword', + 'file.elf.creation_date': { + type: 'date', array: false, required: false, }, - 'file.hash.sha1': { - type: 'keyword', - array: false, + 'file.elf.exports': { + type: 'flattened', + array: true, required: false, }, - 'file.hash.sha256': { + 'file.elf.header.abi_version': { type: 'keyword', array: false, required: false, }, - 'file.hash.sha512': { + 'file.elf.header.class': { type: 'keyword', array: false, required: false, }, - 'file.inode': { + 'file.elf.header.data': { type: 'keyword', array: false, required: false, }, - 'file.mime_type': { - type: 'keyword', + 'file.elf.header.entrypoint': { + type: 'long', array: false, required: false, }, - 'file.mode': { + 'file.elf.header.object_version': { type: 'keyword', array: false, required: false, }, - 'file.mtime': { - type: 'date', + 'file.elf.header.os_abi': { + type: 'keyword', array: false, required: false, }, - 'file.name': { + 'file.elf.header.type': { type: 'keyword', array: false, required: false, }, - 'file.owner': { + 'file.elf.header.version': { type: 'keyword', array: false, required: false, }, - 'file.path': { - type: 'keyword', - array: false, + 'file.elf.imports': { + type: 'flattened', + array: true, required: false, }, - 'file.pe.architecture': { - type: 'keyword', + 'file.elf.sections': { + type: 'nested', + array: true, + required: false, + }, + 'file.elf.sections.chi2': { + type: 'long', array: false, required: false, }, - 'file.pe.company': { - type: 'keyword', + 'file.elf.sections.entropy': { + type: 'long', array: false, required: false, }, - 'file.pe.description': { + 'file.elf.sections.flags': { type: 'keyword', array: false, required: false, }, - 'file.pe.file_version': { + 'file.elf.sections.name': { type: 'keyword', array: false, required: false, }, - 'file.pe.imphash': { + 'file.elf.sections.physical_offset': { type: 'keyword', array: false, required: false, }, - 'file.pe.original_file_name': { - type: 'keyword', + 'file.elf.sections.physical_size': { + type: 'long', array: false, required: false, }, - 'file.pe.product': { + 'file.elf.sections.type': { type: 'keyword', array: false, required: false, }, - 'file.size': { + 'file.elf.sections.virtual_address': { type: 'long', array: false, required: false, }, - 'file.target_path': { - type: 'keyword', + 'file.elf.sections.virtual_size': { + type: 'long', array: false, required: false, }, - 'file.type': { - type: 'keyword', - array: false, + 'file.elf.segments': { + type: 'nested', + array: true, required: false, }, - 'file.uid': { + 'file.elf.segments.sections': { type: 'keyword', array: false, required: false, }, - 'file.x509.alternative_names': { + 'file.elf.segments.type': { type: 'keyword', - array: true, + array: false, required: false, }, - 'file.x509.issuer.common_name': { + 'file.elf.shared_libraries': { type: 'keyword', array: true, required: false, }, - 'file.x509.issuer.country': { + 'file.elf.telfhash': { type: 'keyword', - array: true, + array: false, required: false, }, - 'file.x509.issuer.distinguished_name': { + 'file.extension': { type: 'keyword', array: false, required: false, }, - 'file.x509.issuer.locality': { + 'file.fork_name': { type: 'keyword', - array: true, + array: false, required: false, }, - 'file.x509.issuer.organization': { + 'file.gid': { type: 'keyword', - array: true, + array: false, required: false, }, - 'file.x509.issuer.organizational_unit': { + 'file.group': { type: 'keyword', - array: true, + array: false, + required: false, + }, + 'file.hash.md5': { + type: 'keyword', + array: false, + required: false, + }, + 'file.hash.sha1': { + type: 'keyword', + array: false, + required: false, + }, + 'file.hash.sha256': { + type: 'keyword', + array: false, + required: false, + }, + 'file.hash.sha512': { + type: 'keyword', + array: false, + required: false, + }, + 'file.hash.ssdeep': { + type: 'keyword', + array: false, + required: false, + }, + 'file.inode': { + type: 'keyword', + array: false, + required: false, + }, + 'file.mime_type': { + type: 'keyword', + array: false, + required: false, + }, + 'file.mode': { + type: 'keyword', + array: false, + required: false, + }, + 'file.mtime': { + type: 'date', + array: false, + required: false, + }, + 'file.name': { + type: 'keyword', + array: false, + required: false, + }, + 'file.owner': { + type: 'keyword', + array: false, + required: false, + }, + 'file.path': { + type: 'keyword', + array: false, + required: false, + }, + 'file.pe.architecture': { + type: 'keyword', + array: false, + required: false, + }, + 'file.pe.company': { + type: 'keyword', + array: false, + required: false, + }, + 'file.pe.description': { + type: 'keyword', + array: false, + required: false, + }, + 'file.pe.file_version': { + type: 'keyword', + array: false, + required: false, + }, + 'file.pe.imphash': { + type: 'keyword', + array: false, + required: false, + }, + 'file.pe.original_file_name': { + type: 'keyword', + array: false, + required: false, + }, + 'file.pe.product': { + type: 'keyword', + array: false, + required: false, + }, + 'file.size': { + type: 'long', + array: false, + required: false, + }, + 'file.target_path': { + type: 'keyword', + array: false, + required: false, + }, + 'file.type': { + type: 'keyword', + array: false, + required: false, + }, + 'file.uid': { + type: 'keyword', + array: false, + required: false, + }, + 'file.x509.alternative_names': { + type: 'keyword', + array: true, + required: false, + }, + 'file.x509.issuer.common_name': { + type: 'keyword', + array: true, + required: false, + }, + 'file.x509.issuer.country': { + type: 'keyword', + array: true, + required: false, + }, + 'file.x509.issuer.distinguished_name': { + type: 'keyword', + array: false, + required: false, + }, + 'file.x509.issuer.locality': { + type: 'keyword', + array: true, + required: false, + }, + 'file.x509.issuer.organization': { + type: 'keyword', + array: true, + required: false, + }, + 'file.x509.issuer.organizational_unit': { + type: 'keyword', + array: true, required: false, }, 'file.x509.issuer.state_or_province': { @@ -1110,6 +1495,22 @@ export const ecsFieldMap = { array: false, required: false, }, + 'host.cpu.usage': { + type: 'scaled_float', + array: false, + required: false, + scaling_factor: 1000, + }, + 'host.disk.read.bytes': { + type: 'long', + array: false, + required: false, + }, + 'host.disk.write.bytes': { + type: 'long', + array: false, + required: false, + }, 'host.domain': { type: 'keyword', array: false, @@ -1120,6 +1521,11 @@ export const ecsFieldMap = { array: false, required: false, }, + 'host.geo.continent_code': { + type: 'keyword', + array: false, + required: false, + }, 'host.geo.continent_name': { type: 'keyword', array: false, @@ -1145,6 +1551,11 @@ export const ecsFieldMap = { array: false, required: false, }, + 'host.geo.postal_code': { + type: 'keyword', + array: false, + required: false, + }, 'host.geo.region_iso_code': { type: 'keyword', array: false, @@ -1155,6 +1566,11 @@ export const ecsFieldMap = { array: false, required: false, }, + 'host.geo.timezone': { + type: 'keyword', + array: false, + required: false, + }, 'host.hostname': { type: 'keyword', array: false, @@ -1180,108 +1596,78 @@ export const ecsFieldMap = { array: false, required: false, }, - 'host.os.family': { - type: 'keyword', - array: false, - required: false, - }, - 'host.os.full': { - type: 'keyword', - array: false, - required: false, - }, - 'host.os.kernel': { - type: 'keyword', - array: false, - required: false, - }, - 'host.os.name': { - type: 'keyword', - array: false, - required: false, - }, - 'host.os.platform': { - type: 'keyword', - array: false, - required: false, - }, - 'host.os.type': { - type: 'keyword', + 'host.network.egress.bytes': { + type: 'long', array: false, required: false, }, - 'host.os.version': { - type: 'keyword', + 'host.network.egress.packets': { + type: 'long', array: false, required: false, }, - 'host.type': { - type: 'keyword', + 'host.network.ingress.bytes': { + type: 'long', array: false, required: false, }, - 'host.uptime': { + 'host.network.ingress.packets': { type: 'long', array: false, required: false, }, - 'host.user.domain': { + 'host.os.family': { type: 'keyword', array: false, required: false, }, - 'host.user.email': { + 'host.os.full': { type: 'keyword', array: false, required: false, }, - 'host.user.full_name': { + 'host.os.kernel': { type: 'keyword', array: false, required: false, }, - 'host.user.group.domain': { + 'host.os.name': { type: 'keyword', array: false, required: false, }, - 'host.user.group.id': { + 'host.os.platform': { type: 'keyword', array: false, required: false, }, - 'host.user.group.name': { + 'host.os.type': { type: 'keyword', array: false, required: false, }, - 'host.user.hash': { + 'host.os.version': { type: 'keyword', array: false, required: false, }, - 'host.user.id': { + 'host.type': { type: 'keyword', array: false, required: false, }, - 'host.user.name': { - type: 'keyword', + 'host.uptime': { + type: 'long', array: false, required: false, }, - 'host.user.roles': { - type: 'keyword', - array: true, - required: false, - }, 'http.request.body.bytes': { type: 'long', array: false, required: false, }, 'http.request.body.content': { - type: 'keyword', + type: 'wildcard', array: false, required: false, }, @@ -1290,6 +1676,11 @@ export const ecsFieldMap = { array: false, required: false, }, + 'http.request.id': { + type: 'keyword', + array: false, + required: false, + }, 'http.request.method': { type: 'keyword', array: false, @@ -1311,7 +1702,7 @@ export const ecsFieldMap = { required: false, }, 'http.response.body.content': { - type: 'keyword', + type: 'wildcard', array: false, required: false, }, @@ -1356,7 +1747,7 @@ export const ecsFieldMap = { required: false, }, 'log.origin.file.line': { - type: 'integer', + type: 'long', array: false, required: false, }, @@ -1370,11 +1761,6 @@ export const ecsFieldMap = { array: false, required: false, }, - 'log.original': { - type: 'keyword', - array: false, - required: false, - }, 'log.syslog': { type: 'object', array: false, @@ -1406,7 +1792,7 @@ export const ecsFieldMap = { required: false, }, message: { - type: 'text', + type: 'match_only_text', array: false, required: false, }, @@ -1530,6 +1916,11 @@ export const ecsFieldMap = { array: false, required: false, }, + 'observer.geo.continent_code': { + type: 'keyword', + array: false, + required: false, + }, 'observer.geo.continent_name': { type: 'keyword', array: false, @@ -1555,6 +1946,11 @@ export const ecsFieldMap = { array: false, required: false, }, + 'observer.geo.postal_code': { + type: 'keyword', + array: false, + required: false, + }, 'observer.geo.region_iso_code': { type: 'keyword', array: false, @@ -1565,6 +1961,11 @@ export const ecsFieldMap = { array: false, required: false, }, + 'observer.geo.timezone': { + type: 'keyword', + array: false, + required: false, + }, 'observer.hostname': { type: 'keyword', array: false, @@ -1680,43 +2081,88 @@ export const ecsFieldMap = { array: false, required: false, }, - 'organization.id': { + 'orchestrator.api_version': { type: 'keyword', array: false, required: false, }, - 'organization.name': { + 'orchestrator.cluster.name': { type: 'keyword', array: false, required: false, }, - 'package.architecture': { + 'orchestrator.cluster.url': { type: 'keyword', array: false, required: false, }, - 'package.build_version': { + 'orchestrator.cluster.version': { type: 'keyword', array: false, required: false, }, - 'package.checksum': { + 'orchestrator.namespace': { type: 'keyword', array: false, required: false, }, - 'package.description': { + 'orchestrator.organization': { type: 'keyword', array: false, required: false, }, - 'package.install_scope': { + 'orchestrator.resource.name': { type: 'keyword', array: false, required: false, }, - 'package.installed': { - type: 'date', + 'orchestrator.resource.type': { + type: 'keyword', + array: false, + required: false, + }, + 'orchestrator.type': { + type: 'keyword', + array: false, + required: false, + }, + 'organization.id': { + type: 'keyword', + array: false, + required: false, + }, + 'organization.name': { + type: 'keyword', + array: false, + required: false, + }, + 'package.architecture': { + type: 'keyword', + array: false, + required: false, + }, + 'package.build_version': { + type: 'keyword', + array: false, + required: false, + }, + 'package.checksum': { + type: 'keyword', + array: false, + required: false, + }, + 'package.description': { + type: 'keyword', + array: false, + required: false, + }, + 'package.install_scope': { + type: 'keyword', + array: false, + required: false, + }, + 'package.installed': { + type: 'date', array: false, required: false, }, @@ -1765,11 +2211,21 @@ export const ecsFieldMap = { array: false, required: false, }, + 'process.code_signature.digest_algorithm': { + type: 'keyword', + array: false, + required: false, + }, 'process.code_signature.exists': { type: 'boolean', array: false, required: false, }, + 'process.code_signature.signing_id': { + type: 'keyword', + array: false, + required: false, + }, 'process.code_signature.status': { type: 'keyword', array: false, @@ -1780,6 +2236,16 @@ export const ecsFieldMap = { array: false, required: false, }, + 'process.code_signature.team_id': { + type: 'keyword', + array: false, + required: false, + }, + 'process.code_signature.timestamp': { + type: 'date', + array: false, + required: false, + }, 'process.code_signature.trusted': { type: 'boolean', array: false, @@ -1791,10 +2257,160 @@ export const ecsFieldMap = { required: false, }, 'process.command_line': { + type: 'wildcard', + array: false, + required: false, + }, + 'process.elf.architecture': { + type: 'keyword', + array: false, + required: false, + }, + 'process.elf.byte_order': { + type: 'keyword', + array: false, + required: false, + }, + 'process.elf.cpu_type': { + type: 'keyword', + array: false, + required: false, + }, + 'process.elf.creation_date': { + type: 'date', + array: false, + required: false, + }, + 'process.elf.exports': { + type: 'flattened', + array: true, + required: false, + }, + 'process.elf.header.abi_version': { + type: 'keyword', + array: false, + required: false, + }, + 'process.elf.header.class': { + type: 'keyword', + array: false, + required: false, + }, + 'process.elf.header.data': { + type: 'keyword', + array: false, + required: false, + }, + 'process.elf.header.entrypoint': { + type: 'long', + array: false, + required: false, + }, + 'process.elf.header.object_version': { + type: 'keyword', + array: false, + required: false, + }, + 'process.elf.header.os_abi': { + type: 'keyword', + array: false, + required: false, + }, + 'process.elf.header.type': { + type: 'keyword', + array: false, + required: false, + }, + 'process.elf.header.version': { + type: 'keyword', + array: false, + required: false, + }, + 'process.elf.imports': { + type: 'flattened', + array: true, + required: false, + }, + 'process.elf.sections': { + type: 'nested', + array: true, + required: false, + }, + 'process.elf.sections.chi2': { + type: 'long', + array: false, + required: false, + }, + 'process.elf.sections.entropy': { + type: 'long', + array: false, + required: false, + }, + 'process.elf.sections.flags': { + type: 'keyword', + array: false, + required: false, + }, + 'process.elf.sections.name': { + type: 'keyword', + array: false, + required: false, + }, + 'process.elf.sections.physical_offset': { + type: 'keyword', + array: false, + required: false, + }, + 'process.elf.sections.physical_size': { + type: 'long', + array: false, + required: false, + }, + 'process.elf.sections.type': { + type: 'keyword', + array: false, + required: false, + }, + 'process.elf.sections.virtual_address': { + type: 'long', + array: false, + required: false, + }, + 'process.elf.sections.virtual_size': { + type: 'long', + array: false, + required: false, + }, + 'process.elf.segments': { + type: 'nested', + array: true, + required: false, + }, + 'process.elf.segments.sections': { + type: 'keyword', + array: false, + required: false, + }, + 'process.elf.segments.type': { + type: 'keyword', + array: false, + required: false, + }, + 'process.elf.shared_libraries': { + type: 'keyword', + array: true, + required: false, + }, + 'process.elf.telfhash': { type: 'keyword', array: false, required: false, }, + 'process.end': { + type: 'date', + array: false, + required: false, + }, 'process.entity_id': { type: 'keyword', array: false, @@ -1830,6 +2446,11 @@ export const ecsFieldMap = { array: false, required: false, }, + 'process.hash.ssdeep': { + type: 'keyword', + array: false, + required: false, + }, 'process.name': { type: 'keyword', array: false, @@ -1845,11 +2466,21 @@ export const ecsFieldMap = { array: false, required: false, }, + 'process.parent.code_signature.digest_algorithm': { + type: 'keyword', + array: false, + required: false, + }, 'process.parent.code_signature.exists': { type: 'boolean', array: false, required: false, }, + 'process.parent.code_signature.signing_id': { + type: 'keyword', + array: false, + required: false, + }, 'process.parent.code_signature.status': { type: 'keyword', array: false, @@ -1860,6 +2491,16 @@ export const ecsFieldMap = { array: false, required: false, }, + 'process.parent.code_signature.team_id': { + type: 'keyword', + array: false, + required: false, + }, + 'process.parent.code_signature.timestamp': { + type: 'date', + array: false, + required: false, + }, 'process.parent.code_signature.trusted': { type: 'boolean', array: false, @@ -1870,1112 +2511,2722 @@ export const ecsFieldMap = { array: false, required: false, }, - 'process.parent.command_line': { - type: 'keyword', + 'process.parent.command_line': { + type: 'wildcard', + array: false, + required: false, + }, + 'process.parent.elf.architecture': { + type: 'keyword', + array: false, + required: false, + }, + 'process.parent.elf.byte_order': { + type: 'keyword', + array: false, + required: false, + }, + 'process.parent.elf.cpu_type': { + type: 'keyword', + array: false, + required: false, + }, + 'process.parent.elf.creation_date': { + type: 'date', + array: false, + required: false, + }, + 'process.parent.elf.exports': { + type: 'flattened', + array: true, + required: false, + }, + 'process.parent.elf.header.abi_version': { + type: 'keyword', + array: false, + required: false, + }, + 'process.parent.elf.header.class': { + type: 'keyword', + array: false, + required: false, + }, + 'process.parent.elf.header.data': { + type: 'keyword', + array: false, + required: false, + }, + 'process.parent.elf.header.entrypoint': { + type: 'long', + array: false, + required: false, + }, + 'process.parent.elf.header.object_version': { + type: 'keyword', + array: false, + required: false, + }, + 'process.parent.elf.header.os_abi': { + type: 'keyword', + array: false, + required: false, + }, + 'process.parent.elf.header.type': { + type: 'keyword', + array: false, + required: false, + }, + 'process.parent.elf.header.version': { + type: 'keyword', + array: false, + required: false, + }, + 'process.parent.elf.imports': { + type: 'flattened', + array: true, + required: false, + }, + 'process.parent.elf.sections': { + type: 'nested', + array: true, + required: false, + }, + 'process.parent.elf.sections.chi2': { + type: 'long', + array: false, + required: false, + }, + 'process.parent.elf.sections.entropy': { + type: 'long', + array: false, + required: false, + }, + 'process.parent.elf.sections.flags': { + type: 'keyword', + array: false, + required: false, + }, + 'process.parent.elf.sections.name': { + type: 'keyword', + array: false, + required: false, + }, + 'process.parent.elf.sections.physical_offset': { + type: 'keyword', + array: false, + required: false, + }, + 'process.parent.elf.sections.physical_size': { + type: 'long', + array: false, + required: false, + }, + 'process.parent.elf.sections.type': { + type: 'keyword', + array: false, + required: false, + }, + 'process.parent.elf.sections.virtual_address': { + type: 'long', + array: false, + required: false, + }, + 'process.parent.elf.sections.virtual_size': { + type: 'long', + array: false, + required: false, + }, + 'process.parent.elf.segments': { + type: 'nested', + array: true, + required: false, + }, + 'process.parent.elf.segments.sections': { + type: 'keyword', + array: false, + required: false, + }, + 'process.parent.elf.segments.type': { + type: 'keyword', + array: false, + required: false, + }, + 'process.parent.elf.shared_libraries': { + type: 'keyword', + array: true, + required: false, + }, + 'process.parent.elf.telfhash': { + type: 'keyword', + array: false, + required: false, + }, + 'process.parent.end': { + type: 'date', + array: false, + required: false, + }, + 'process.parent.entity_id': { + type: 'keyword', + array: false, + required: false, + }, + 'process.parent.executable': { + type: 'keyword', + array: false, + required: false, + }, + 'process.parent.exit_code': { + type: 'long', + array: false, + required: false, + }, + 'process.parent.hash.md5': { + type: 'keyword', + array: false, + required: false, + }, + 'process.parent.hash.sha1': { + type: 'keyword', + array: false, + required: false, + }, + 'process.parent.hash.sha256': { + type: 'keyword', + array: false, + required: false, + }, + 'process.parent.hash.sha512': { + type: 'keyword', + array: false, + required: false, + }, + 'process.parent.hash.ssdeep': { + type: 'keyword', + array: false, + required: false, + }, + 'process.parent.name': { + type: 'keyword', + array: false, + required: false, + }, + 'process.parent.pe.architecture': { + type: 'keyword', + array: false, + required: false, + }, + 'process.parent.pe.company': { + type: 'keyword', + array: false, + required: false, + }, + 'process.parent.pe.description': { + type: 'keyword', + array: false, + required: false, + }, + 'process.parent.pe.file_version': { + type: 'keyword', + array: false, + required: false, + }, + 'process.parent.pe.imphash': { + type: 'keyword', + array: false, + required: false, + }, + 'process.parent.pe.original_file_name': { + type: 'keyword', + array: false, + required: false, + }, + 'process.parent.pe.product': { + type: 'keyword', + array: false, + required: false, + }, + 'process.parent.pgid': { + type: 'long', + array: false, + required: false, + }, + 'process.parent.pid': { + type: 'long', + array: false, + required: false, + }, + 'process.parent.start': { + type: 'date', + array: false, + required: false, + }, + 'process.parent.thread.id': { + type: 'long', + array: false, + required: false, + }, + 'process.parent.thread.name': { + type: 'keyword', + array: false, + required: false, + }, + 'process.parent.title': { + type: 'keyword', + array: false, + required: false, + }, + 'process.parent.uptime': { + type: 'long', + array: false, + required: false, + }, + 'process.parent.working_directory': { + type: 'keyword', + array: false, + required: false, + }, + 'process.pe.architecture': { + type: 'keyword', + array: false, + required: false, + }, + 'process.pe.company': { + type: 'keyword', + array: false, + required: false, + }, + 'process.pe.description': { + type: 'keyword', + array: false, + required: false, + }, + 'process.pe.file_version': { + type: 'keyword', + array: false, + required: false, + }, + 'process.pe.imphash': { + type: 'keyword', + array: false, + required: false, + }, + 'process.pe.original_file_name': { + type: 'keyword', + array: false, + required: false, + }, + 'process.pe.product': { + type: 'keyword', + array: false, + required: false, + }, + 'process.pgid': { + type: 'long', + array: false, + required: false, + }, + 'process.pid': { + type: 'long', + array: false, + required: false, + }, + 'process.start': { + type: 'date', + array: false, + required: false, + }, + 'process.thread.id': { + type: 'long', + array: false, + required: false, + }, + 'process.thread.name': { + type: 'keyword', + array: false, + required: false, + }, + 'process.title': { + type: 'keyword', + array: false, + required: false, + }, + 'process.uptime': { + type: 'long', + array: false, + required: false, + }, + 'process.working_directory': { + type: 'keyword', + array: false, + required: false, + }, + 'registry.data.bytes': { + type: 'keyword', + array: false, + required: false, + }, + 'registry.data.strings': { + type: 'wildcard', + array: true, + required: false, + }, + 'registry.data.type': { + type: 'keyword', + array: false, + required: false, + }, + 'registry.hive': { + type: 'keyword', + array: false, + required: false, + }, + 'registry.key': { + type: 'keyword', + array: false, + required: false, + }, + 'registry.path': { + type: 'keyword', + array: false, + required: false, + }, + 'registry.value': { + type: 'keyword', + array: false, + required: false, + }, + 'related.hash': { + type: 'keyword', + array: true, + required: false, + }, + 'related.hosts': { + type: 'keyword', + array: true, + required: false, + }, + 'related.ip': { + type: 'ip', + array: true, + required: false, + }, + 'related.user': { + type: 'keyword', + array: true, + required: false, + }, + 'rule.author': { + type: 'keyword', + array: true, + required: false, + }, + 'rule.category': { + type: 'keyword', + array: false, + required: false, + }, + 'rule.description': { + type: 'keyword', + array: false, + required: false, + }, + 'rule.id': { + type: 'keyword', + array: false, + required: false, + }, + 'rule.license': { + type: 'keyword', + array: false, + required: false, + }, + 'rule.name': { + type: 'keyword', + array: false, + required: false, + }, + 'rule.reference': { + type: 'keyword', + array: false, + required: false, + }, + 'rule.ruleset': { + type: 'keyword', + array: false, + required: false, + }, + 'rule.uuid': { + type: 'keyword', + array: false, + required: false, + }, + 'rule.version': { + type: 'keyword', + array: false, + required: false, + }, + 'server.address': { + type: 'keyword', + array: false, + required: false, + }, + 'server.as.number': { + type: 'long', + array: false, + required: false, + }, + 'server.as.organization.name': { + type: 'keyword', + array: false, + required: false, + }, + 'server.bytes': { + type: 'long', + array: false, + required: false, + }, + 'server.domain': { + type: 'keyword', + array: false, + required: false, + }, + 'server.geo.city_name': { + type: 'keyword', + array: false, + required: false, + }, + 'server.geo.continent_code': { + type: 'keyword', + array: false, + required: false, + }, + 'server.geo.continent_name': { + type: 'keyword', + array: false, + required: false, + }, + 'server.geo.country_iso_code': { + type: 'keyword', + array: false, + required: false, + }, + 'server.geo.country_name': { + type: 'keyword', + array: false, + required: false, + }, + 'server.geo.location': { + type: 'geo_point', + array: false, + required: false, + }, + 'server.geo.name': { + type: 'keyword', + array: false, + required: false, + }, + 'server.geo.postal_code': { + type: 'keyword', + array: false, + required: false, + }, + 'server.geo.region_iso_code': { + type: 'keyword', + array: false, + required: false, + }, + 'server.geo.region_name': { + type: 'keyword', + array: false, + required: false, + }, + 'server.geo.timezone': { + type: 'keyword', + array: false, + required: false, + }, + 'server.ip': { + type: 'ip', + array: false, + required: false, + }, + 'server.mac': { + type: 'keyword', + array: false, + required: false, + }, + 'server.nat.ip': { + type: 'ip', + array: false, + required: false, + }, + 'server.nat.port': { + type: 'long', + array: false, + required: false, + }, + 'server.packets': { + type: 'long', + array: false, + required: false, + }, + 'server.port': { + type: 'long', + array: false, + required: false, + }, + 'server.registered_domain': { + type: 'keyword', + array: false, + required: false, + }, + 'server.subdomain': { + type: 'keyword', + array: false, + required: false, + }, + 'server.top_level_domain': { + type: 'keyword', + array: false, + required: false, + }, + 'server.user.domain': { + type: 'keyword', + array: false, + required: false, + }, + 'server.user.email': { + type: 'keyword', + array: false, + required: false, + }, + 'server.user.full_name': { + type: 'keyword', + array: false, + required: false, + }, + 'server.user.group.domain': { + type: 'keyword', + array: false, + required: false, + }, + 'server.user.group.id': { + type: 'keyword', + array: false, + required: false, + }, + 'server.user.group.name': { + type: 'keyword', + array: false, + required: false, + }, + 'server.user.hash': { + type: 'keyword', + array: false, + required: false, + }, + 'server.user.id': { + type: 'keyword', + array: false, + required: false, + }, + 'server.user.name': { + type: 'keyword', + array: false, + required: false, + }, + 'server.user.roles': { + type: 'keyword', + array: true, + required: false, + }, + 'service.address': { + type: 'keyword', + array: false, + required: false, + }, + 'service.environment': { + type: 'keyword', + array: false, + required: false, + }, + 'service.ephemeral_id': { + type: 'keyword', + array: false, + required: false, + }, + 'service.id': { + type: 'keyword', + array: false, + required: false, + }, + 'service.name': { + type: 'keyword', + array: false, + required: false, + }, + 'service.node.name': { + type: 'keyword', + array: false, + required: false, + }, + 'service.origin.address': { + type: 'keyword', + array: false, + required: false, + }, + 'service.origin.environment': { + type: 'keyword', + array: false, + required: false, + }, + 'service.origin.ephemeral_id': { + type: 'keyword', + array: false, + required: false, + }, + 'service.origin.id': { + type: 'keyword', + array: false, + required: false, + }, + 'service.origin.name': { + type: 'keyword', + array: false, + required: false, + }, + 'service.origin.node.name': { + type: 'keyword', + array: false, + required: false, + }, + 'service.origin.state': { + type: 'keyword', + array: false, + required: false, + }, + 'service.origin.type': { + type: 'keyword', + array: false, + required: false, + }, + 'service.origin.version': { + type: 'keyword', + array: false, + required: false, + }, + 'service.state': { + type: 'keyword', + array: false, + required: false, + }, + 'service.target.address': { + type: 'keyword', + array: false, + required: false, + }, + 'service.target.environment': { + type: 'keyword', + array: false, + required: false, + }, + 'service.target.ephemeral_id': { + type: 'keyword', + array: false, + required: false, + }, + 'service.target.id': { + type: 'keyword', + array: false, + required: false, + }, + 'service.target.name': { + type: 'keyword', + array: false, + required: false, + }, + 'service.target.node.name': { + type: 'keyword', + array: false, + required: false, + }, + 'service.target.state': { + type: 'keyword', + array: false, + required: false, + }, + 'service.target.type': { + type: 'keyword', + array: false, + required: false, + }, + 'service.target.version': { + type: 'keyword', + array: false, + required: false, + }, + 'service.type': { + type: 'keyword', + array: false, + required: false, + }, + 'service.version': { + type: 'keyword', + array: false, + required: false, + }, + 'source.address': { + type: 'keyword', + array: false, + required: false, + }, + 'source.as.number': { + type: 'long', + array: false, + required: false, + }, + 'source.as.organization.name': { + type: 'keyword', + array: false, + required: false, + }, + 'source.bytes': { + type: 'long', + array: false, + required: false, + }, + 'source.domain': { + type: 'keyword', + array: false, + required: false, + }, + 'source.geo.city_name': { + type: 'keyword', + array: false, + required: false, + }, + 'source.geo.continent_code': { + type: 'keyword', + array: false, + required: false, + }, + 'source.geo.continent_name': { + type: 'keyword', + array: false, + required: false, + }, + 'source.geo.country_iso_code': { + type: 'keyword', + array: false, + required: false, + }, + 'source.geo.country_name': { + type: 'keyword', + array: false, + required: false, + }, + 'source.geo.location': { + type: 'geo_point', + array: false, + required: false, + }, + 'source.geo.name': { + type: 'keyword', + array: false, + required: false, + }, + 'source.geo.postal_code': { + type: 'keyword', + array: false, + required: false, + }, + 'source.geo.region_iso_code': { + type: 'keyword', + array: false, + required: false, + }, + 'source.geo.region_name': { + type: 'keyword', + array: false, + required: false, + }, + 'source.geo.timezone': { + type: 'keyword', + array: false, + required: false, + }, + 'source.ip': { + type: 'ip', + array: false, + required: false, + }, + 'source.mac': { + type: 'keyword', + array: false, + required: false, + }, + 'source.nat.ip': { + type: 'ip', + array: false, + required: false, + }, + 'source.nat.port': { + type: 'long', + array: false, + required: false, + }, + 'source.packets': { + type: 'long', + array: false, + required: false, + }, + 'source.port': { + type: 'long', + array: false, + required: false, + }, + 'source.registered_domain': { + type: 'keyword', + array: false, + required: false, + }, + 'source.subdomain': { + type: 'keyword', + array: false, + required: false, + }, + 'source.top_level_domain': { + type: 'keyword', + array: false, + required: false, + }, + 'source.user.domain': { + type: 'keyword', + array: false, + required: false, + }, + 'source.user.email': { + type: 'keyword', + array: false, + required: false, + }, + 'source.user.full_name': { + type: 'keyword', + array: false, + required: false, + }, + 'source.user.group.domain': { + type: 'keyword', + array: false, + required: false, + }, + 'source.user.group.id': { + type: 'keyword', + array: false, + required: false, + }, + 'source.user.group.name': { + type: 'keyword', + array: false, + required: false, + }, + 'source.user.hash': { + type: 'keyword', + array: false, + required: false, + }, + 'source.user.id': { + type: 'keyword', + array: false, + required: false, + }, + 'source.user.name': { + type: 'keyword', + array: false, + required: false, + }, + 'source.user.roles': { + type: 'keyword', + array: true, + required: false, + }, + 'span.id': { + type: 'keyword', + array: false, + required: false, + }, + tags: { + type: 'keyword', + array: true, + required: false, + }, + 'threat.enrichments': { + type: 'nested', + array: true, + required: false, + }, + 'threat.enrichments.indicator': { + type: 'object', + array: false, + required: false, + }, + 'threat.enrichments.indicator.as.number': { + type: 'long', + array: false, + required: false, + }, + 'threat.enrichments.indicator.as.organization.name': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.confidence': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.description': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.email.address': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.file.accessed': { + type: 'date', + array: false, + required: false, + }, + 'threat.enrichments.indicator.file.attributes': { + type: 'keyword', + array: true, + required: false, + }, + 'threat.enrichments.indicator.file.code_signature.digest_algorithm': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.file.code_signature.exists': { + type: 'boolean', + array: false, + required: false, + }, + 'threat.enrichments.indicator.file.code_signature.signing_id': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.file.code_signature.status': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.file.code_signature.subject_name': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.file.code_signature.team_id': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.file.code_signature.timestamp': { + type: 'date', + array: false, + required: false, + }, + 'threat.enrichments.indicator.file.code_signature.trusted': { + type: 'boolean', + array: false, + required: false, + }, + 'threat.enrichments.indicator.file.code_signature.valid': { + type: 'boolean', + array: false, + required: false, + }, + 'threat.enrichments.indicator.file.created': { + type: 'date', + array: false, + required: false, + }, + 'threat.enrichments.indicator.file.ctime': { + type: 'date', + array: false, + required: false, + }, + 'threat.enrichments.indicator.file.device': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.file.directory': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.file.drive_letter': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.file.elf.architecture': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.file.elf.byte_order': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.file.elf.cpu_type': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.file.elf.creation_date': { + type: 'date', + array: false, + required: false, + }, + 'threat.enrichments.indicator.file.elf.exports': { + type: 'flattened', + array: true, + required: false, + }, + 'threat.enrichments.indicator.file.elf.header.abi_version': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.file.elf.header.class': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.file.elf.header.data': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.file.elf.header.entrypoint': { + type: 'long', + array: false, + required: false, + }, + 'threat.enrichments.indicator.file.elf.header.object_version': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.file.elf.header.os_abi': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.file.elf.header.type': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.file.elf.header.version': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.file.elf.imports': { + type: 'flattened', + array: true, + required: false, + }, + 'threat.enrichments.indicator.file.elf.sections': { + type: 'nested', + array: true, + required: false, + }, + 'threat.enrichments.indicator.file.elf.sections.chi2': { + type: 'long', + array: false, + required: false, + }, + 'threat.enrichments.indicator.file.elf.sections.entropy': { + type: 'long', + array: false, + required: false, + }, + 'threat.enrichments.indicator.file.elf.sections.flags': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.file.elf.sections.name': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.file.elf.sections.physical_offset': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.file.elf.sections.physical_size': { + type: 'long', + array: false, + required: false, + }, + 'threat.enrichments.indicator.file.elf.sections.type': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.file.elf.sections.virtual_address': { + type: 'long', + array: false, + required: false, + }, + 'threat.enrichments.indicator.file.elf.sections.virtual_size': { + type: 'long', + array: false, + required: false, + }, + 'threat.enrichments.indicator.file.elf.segments': { + type: 'nested', + array: true, + required: false, + }, + 'threat.enrichments.indicator.file.elf.segments.sections': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.file.elf.segments.type': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.file.elf.shared_libraries': { + type: 'keyword', + array: true, + required: false, + }, + 'threat.enrichments.indicator.file.elf.telfhash': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.file.extension': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.file.fork_name': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.file.gid': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.file.group': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.file.hash.md5': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.file.hash.sha1': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.file.hash.sha256': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.file.hash.sha512': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.file.hash.ssdeep': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.file.inode': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.file.mime_type': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.file.mode': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.file.mtime': { + type: 'date', + array: false, + required: false, + }, + 'threat.enrichments.indicator.file.name': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.file.owner': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.file.path': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.file.pe.architecture': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.file.pe.company': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.file.pe.description': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.file.pe.file_version': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.file.pe.imphash': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.file.pe.original_file_name': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.file.pe.product': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.file.size': { + type: 'long', + array: false, + required: false, + }, + 'threat.enrichments.indicator.file.target_path': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.file.type': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.file.uid': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.file.x509.alternative_names': { + type: 'keyword', + array: true, + required: false, + }, + 'threat.enrichments.indicator.file.x509.issuer.common_name': { + type: 'keyword', + array: true, + required: false, + }, + 'threat.enrichments.indicator.file.x509.issuer.country': { + type: 'keyword', + array: true, + required: false, + }, + 'threat.enrichments.indicator.file.x509.issuer.distinguished_name': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.file.x509.issuer.locality': { + type: 'keyword', + array: true, + required: false, + }, + 'threat.enrichments.indicator.file.x509.issuer.organization': { + type: 'keyword', + array: true, + required: false, + }, + 'threat.enrichments.indicator.file.x509.issuer.organizational_unit': { + type: 'keyword', + array: true, + required: false, + }, + 'threat.enrichments.indicator.file.x509.issuer.state_or_province': { + type: 'keyword', + array: true, + required: false, + }, + 'threat.enrichments.indicator.file.x509.not_after': { + type: 'date', + array: false, + required: false, + }, + 'threat.enrichments.indicator.file.x509.not_before': { + type: 'date', + array: false, + required: false, + }, + 'threat.enrichments.indicator.file.x509.public_key_algorithm': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.file.x509.public_key_curve': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.file.x509.public_key_exponent': { + type: 'long', + array: false, + required: false, + }, + 'threat.enrichments.indicator.file.x509.public_key_size': { + type: 'long', + array: false, + required: false, + }, + 'threat.enrichments.indicator.file.x509.serial_number': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.file.x509.signature_algorithm': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.file.x509.subject.common_name': { + type: 'keyword', + array: true, + required: false, + }, + 'threat.enrichments.indicator.file.x509.subject.country': { + type: 'keyword', + array: true, + required: false, + }, + 'threat.enrichments.indicator.file.x509.subject.distinguished_name': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.file.x509.subject.locality': { + type: 'keyword', + array: true, + required: false, + }, + 'threat.enrichments.indicator.file.x509.subject.organization': { + type: 'keyword', + array: true, + required: false, + }, + 'threat.enrichments.indicator.file.x509.subject.organizational_unit': { + type: 'keyword', + array: true, + required: false, + }, + 'threat.enrichments.indicator.file.x509.subject.state_or_province': { + type: 'keyword', + array: true, + required: false, + }, + 'threat.enrichments.indicator.file.x509.version_number': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.first_seen': { + type: 'date', + array: false, + required: false, + }, + 'threat.enrichments.indicator.geo.city_name': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.geo.continent_code': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.geo.continent_name': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.geo.country_iso_code': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.geo.country_name': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.geo.location': { + type: 'geo_point', + array: false, + required: false, + }, + 'threat.enrichments.indicator.geo.name': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.geo.postal_code': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.geo.region_iso_code': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.geo.region_name': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.geo.timezone': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.ip': { + type: 'ip', + array: false, + required: false, + }, + 'threat.enrichments.indicator.last_seen': { + type: 'date', + array: false, + required: false, + }, + 'threat.enrichments.indicator.marking.tlp': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.modified_at': { + type: 'date', + array: false, + required: false, + }, + 'threat.enrichments.indicator.port': { + type: 'long', + array: false, + required: false, + }, + 'threat.enrichments.indicator.provider': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.reference': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.registry.data.bytes': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.registry.data.strings': { + type: 'wildcard', + array: true, + required: false, + }, + 'threat.enrichments.indicator.registry.data.type': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.registry.hive': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.registry.key': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.registry.path': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.registry.value': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.scanner_stats': { + type: 'long', + array: false, + required: false, + }, + 'threat.enrichments.indicator.sightings': { + type: 'long', + array: false, + required: false, + }, + 'threat.enrichments.indicator.type': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.url.domain': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.url.extension': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.url.fragment': { + type: 'keyword', + array: false, + required: false, + }, + 'threat.enrichments.indicator.url.full': { + type: 'wildcard', + array: false, + required: false, + }, + 'threat.enrichments.indicator.url.original': { + type: 'wildcard', array: false, required: false, }, - 'process.parent.entity_id': { + 'threat.enrichments.indicator.url.password': { type: 'keyword', array: false, required: false, }, - 'process.parent.executable': { - type: 'keyword', + 'threat.enrichments.indicator.url.path': { + type: 'wildcard', array: false, required: false, }, - 'process.parent.exit_code': { + 'threat.enrichments.indicator.url.port': { type: 'long', array: false, required: false, }, - 'process.parent.hash.md5': { + 'threat.enrichments.indicator.url.query': { type: 'keyword', array: false, required: false, }, - 'process.parent.hash.sha1': { + 'threat.enrichments.indicator.url.registered_domain': { type: 'keyword', array: false, required: false, }, - 'process.parent.hash.sha256': { + 'threat.enrichments.indicator.url.scheme': { type: 'keyword', array: false, required: false, }, - 'process.parent.hash.sha512': { + 'threat.enrichments.indicator.url.subdomain': { type: 'keyword', array: false, required: false, }, - 'process.parent.name': { + 'threat.enrichments.indicator.url.top_level_domain': { type: 'keyword', array: false, required: false, }, - 'process.parent.pe.architecture': { + 'threat.enrichments.indicator.url.username': { type: 'keyword', array: false, required: false, }, - 'process.parent.pe.company': { + 'threat.enrichments.indicator.x509.alternative_names': { type: 'keyword', - array: false, + array: true, required: false, }, - 'process.parent.pe.description': { + 'threat.enrichments.indicator.x509.issuer.common_name': { type: 'keyword', - array: false, + array: true, required: false, }, - 'process.parent.pe.file_version': { + 'threat.enrichments.indicator.x509.issuer.country': { type: 'keyword', - array: false, + array: true, required: false, }, - 'process.parent.pe.imphash': { + 'threat.enrichments.indicator.x509.issuer.distinguished_name': { type: 'keyword', array: false, required: false, }, - 'process.parent.pe.original_file_name': { + 'threat.enrichments.indicator.x509.issuer.locality': { type: 'keyword', - array: false, + array: true, required: false, }, - 'process.parent.pe.product': { + 'threat.enrichments.indicator.x509.issuer.organization': { type: 'keyword', - array: false, - required: false, - }, - 'process.parent.pgid': { - type: 'long', - array: false, + array: true, required: false, }, - 'process.parent.pid': { - type: 'long', - array: false, + 'threat.enrichments.indicator.x509.issuer.organizational_unit': { + type: 'keyword', + array: true, required: false, }, - 'process.parent.ppid': { - type: 'long', - array: false, + 'threat.enrichments.indicator.x509.issuer.state_or_province': { + type: 'keyword', + array: true, required: false, }, - 'process.parent.start': { + 'threat.enrichments.indicator.x509.not_after': { type: 'date', array: false, required: false, }, - 'process.parent.thread.id': { - type: 'long', + 'threat.enrichments.indicator.x509.not_before': { + type: 'date', array: false, required: false, }, - 'process.parent.thread.name': { + 'threat.enrichments.indicator.x509.public_key_algorithm': { type: 'keyword', array: false, required: false, }, - 'process.parent.title': { + 'threat.enrichments.indicator.x509.public_key_curve': { type: 'keyword', array: false, required: false, }, - 'process.parent.uptime': { + 'threat.enrichments.indicator.x509.public_key_exponent': { type: 'long', array: false, required: false, }, - 'process.parent.working_directory': { - type: 'keyword', + 'threat.enrichments.indicator.x509.public_key_size': { + type: 'long', array: false, required: false, }, - 'process.pe.architecture': { + 'threat.enrichments.indicator.x509.serial_number': { type: 'keyword', array: false, required: false, }, - 'process.pe.company': { + 'threat.enrichments.indicator.x509.signature_algorithm': { type: 'keyword', array: false, required: false, }, - 'process.pe.description': { + 'threat.enrichments.indicator.x509.subject.common_name': { type: 'keyword', - array: false, + array: true, required: false, }, - 'process.pe.file_version': { + 'threat.enrichments.indicator.x509.subject.country': { type: 'keyword', - array: false, + array: true, required: false, }, - 'process.pe.imphash': { + 'threat.enrichments.indicator.x509.subject.distinguished_name': { type: 'keyword', array: false, required: false, }, - 'process.pe.original_file_name': { + 'threat.enrichments.indicator.x509.subject.locality': { type: 'keyword', - array: false, + array: true, required: false, }, - 'process.pe.product': { + 'threat.enrichments.indicator.x509.subject.organization': { type: 'keyword', - array: false, - required: false, - }, - 'process.pgid': { - type: 'long', - array: false, + array: true, required: false, }, - 'process.pid': { - type: 'long', - array: false, + 'threat.enrichments.indicator.x509.subject.organizational_unit': { + type: 'keyword', + array: true, required: false, }, - 'process.ppid': { - type: 'long', - array: false, + 'threat.enrichments.indicator.x509.subject.state_or_province': { + type: 'keyword', + array: true, required: false, }, - 'process.start': { - type: 'date', + 'threat.enrichments.indicator.x509.version_number': { + type: 'keyword', array: false, required: false, }, - 'process.thread.id': { - type: 'long', + 'threat.enrichments.matched.atomic': { + type: 'keyword', array: false, required: false, }, - 'process.thread.name': { + 'threat.enrichments.matched.field': { type: 'keyword', array: false, required: false, }, - 'process.title': { + 'threat.enrichments.matched.id': { type: 'keyword', array: false, required: false, }, - 'process.uptime': { - type: 'long', + 'threat.enrichments.matched.index': { + type: 'keyword', array: false, required: false, }, - 'process.working_directory': { + 'threat.enrichments.matched.type': { type: 'keyword', array: false, required: false, }, - 'registry.data.bytes': { + 'threat.framework': { type: 'keyword', array: false, required: false, }, - 'registry.data.strings': { + 'threat.group.alias': { type: 'keyword', array: true, required: false, }, - 'registry.data.type': { + 'threat.group.id': { type: 'keyword', array: false, required: false, }, - 'registry.hive': { + 'threat.group.name': { type: 'keyword', array: false, required: false, }, - 'registry.key': { + 'threat.group.reference': { type: 'keyword', array: false, required: false, }, - 'registry.path': { - type: 'keyword', + 'threat.indicator.as.number': { + type: 'long', array: false, required: false, }, - 'registry.value': { + 'threat.indicator.as.organization.name': { type: 'keyword', array: false, required: false, }, - 'related.hash': { + 'threat.indicator.confidence': { type: 'keyword', - array: true, + array: false, required: false, }, - 'related.hosts': { + 'threat.indicator.description': { type: 'keyword', - array: true, + array: false, required: false, }, - 'related.ip': { - type: 'ip', - array: true, + 'threat.indicator.email.address': { + type: 'keyword', + array: false, required: false, }, - 'related.user': { - type: 'keyword', - array: true, + 'threat.indicator.file.accessed': { + type: 'date', + array: false, required: false, }, - 'rule.author': { + 'threat.indicator.file.attributes': { type: 'keyword', array: true, required: false, }, - 'rule.category': { + 'threat.indicator.file.code_signature.digest_algorithm': { type: 'keyword', array: false, required: false, }, - 'rule.description': { - type: 'keyword', + 'threat.indicator.file.code_signature.exists': { + type: 'boolean', array: false, required: false, }, - 'rule.id': { - type: 'keyword', - array: false, - required: true, - }, - 'rule.license': { + 'threat.indicator.file.code_signature.signing_id': { type: 'keyword', array: false, required: false, }, - 'rule.name': { + 'threat.indicator.file.code_signature.status': { type: 'keyword', array: false, required: false, }, - 'rule.reference': { + 'threat.indicator.file.code_signature.subject_name': { type: 'keyword', array: false, required: false, }, - 'rule.ruleset': { + 'threat.indicator.file.code_signature.team_id': { type: 'keyword', array: false, required: false, }, - 'rule.uuid': { - type: 'keyword', + 'threat.indicator.file.code_signature.timestamp': { + type: 'date', array: false, required: false, }, - 'rule.version': { - type: 'keyword', + 'threat.indicator.file.code_signature.trusted': { + type: 'boolean', array: false, required: false, }, - 'server.address': { - type: 'keyword', + 'threat.indicator.file.code_signature.valid': { + type: 'boolean', array: false, required: false, }, - 'server.as.number': { - type: 'long', + 'threat.indicator.file.created': { + type: 'date', array: false, required: false, }, - 'server.as.organization.name': { - type: 'keyword', + 'threat.indicator.file.ctime': { + type: 'date', array: false, required: false, }, - 'server.bytes': { - type: 'long', + 'threat.indicator.file.device': { + type: 'keyword', array: false, required: false, }, - 'server.domain': { + 'threat.indicator.file.directory': { type: 'keyword', array: false, required: false, }, - 'server.geo.city_name': { + 'threat.indicator.file.drive_letter': { type: 'keyword', array: false, required: false, }, - 'server.geo.continent_name': { + 'threat.indicator.file.elf.architecture': { type: 'keyword', array: false, required: false, }, - 'server.geo.country_iso_code': { + 'threat.indicator.file.elf.byte_order': { type: 'keyword', array: false, required: false, }, - 'server.geo.country_name': { + 'threat.indicator.file.elf.cpu_type': { type: 'keyword', array: false, required: false, }, - 'server.geo.location': { - type: 'geo_point', + 'threat.indicator.file.elf.creation_date': { + type: 'date', array: false, required: false, }, - 'server.geo.name': { - type: 'keyword', - array: false, + 'threat.indicator.file.elf.exports': { + type: 'flattened', + array: true, required: false, }, - 'server.geo.region_iso_code': { + 'threat.indicator.file.elf.header.abi_version': { type: 'keyword', array: false, required: false, }, - 'server.geo.region_name': { + 'threat.indicator.file.elf.header.class': { type: 'keyword', array: false, required: false, }, - 'server.ip': { - type: 'ip', - array: false, - required: false, - }, - 'server.mac': { + 'threat.indicator.file.elf.header.data': { type: 'keyword', array: false, required: false, }, - 'server.nat.ip': { - type: 'ip', - array: false, - required: false, - }, - 'server.nat.port': { + 'threat.indicator.file.elf.header.entrypoint': { type: 'long', array: false, required: false, }, - 'server.packets': { - type: 'long', + 'threat.indicator.file.elf.header.object_version': { + type: 'keyword', array: false, required: false, }, - 'server.port': { - type: 'long', + 'threat.indicator.file.elf.header.os_abi': { + type: 'keyword', array: false, required: false, }, - 'server.registered_domain': { + 'threat.indicator.file.elf.header.type': { type: 'keyword', array: false, required: false, }, - 'server.subdomain': { + 'threat.indicator.file.elf.header.version': { type: 'keyword', array: false, required: false, }, - 'server.top_level_domain': { - type: 'keyword', - array: false, + 'threat.indicator.file.elf.imports': { + type: 'flattened', + array: true, required: false, }, - 'server.user.domain': { - type: 'keyword', + 'threat.indicator.file.elf.sections': { + type: 'nested', + array: true, + required: false, + }, + 'threat.indicator.file.elf.sections.chi2': { + type: 'long', array: false, required: false, }, - 'server.user.email': { - type: 'keyword', + 'threat.indicator.file.elf.sections.entropy': { + type: 'long', array: false, required: false, }, - 'server.user.full_name': { + 'threat.indicator.file.elf.sections.flags': { type: 'keyword', array: false, required: false, }, - 'server.user.group.domain': { + 'threat.indicator.file.elf.sections.name': { type: 'keyword', array: false, required: false, }, - 'server.user.group.id': { + 'threat.indicator.file.elf.sections.physical_offset': { type: 'keyword', array: false, required: false, }, - 'server.user.group.name': { - type: 'keyword', + 'threat.indicator.file.elf.sections.physical_size': { + type: 'long', array: false, required: false, }, - 'server.user.hash': { + 'threat.indicator.file.elf.sections.type': { type: 'keyword', array: false, required: false, }, - 'server.user.id': { - type: 'keyword', + 'threat.indicator.file.elf.sections.virtual_address': { + type: 'long', array: false, required: false, }, - 'server.user.name': { - type: 'keyword', + 'threat.indicator.file.elf.sections.virtual_size': { + type: 'long', array: false, required: false, }, - 'server.user.roles': { - type: 'keyword', + 'threat.indicator.file.elf.segments': { + type: 'nested', array: true, required: false, }, - 'service.ephemeral_id': { + 'threat.indicator.file.elf.segments.sections': { type: 'keyword', array: false, required: false, }, - 'service.id': { + 'threat.indicator.file.elf.segments.type': { type: 'keyword', array: false, required: false, }, - 'service.name': { + 'threat.indicator.file.elf.shared_libraries': { type: 'keyword', - array: false, + array: true, required: false, }, - 'service.node.name': { + 'threat.indicator.file.elf.telfhash': { type: 'keyword', array: false, required: false, }, - 'service.state': { + 'threat.indicator.file.extension': { type: 'keyword', array: false, required: false, }, - 'service.type': { + 'threat.indicator.file.fork_name': { type: 'keyword', array: false, required: false, }, - 'service.version': { + 'threat.indicator.file.gid': { type: 'keyword', array: false, required: false, }, - 'source.address': { + 'threat.indicator.file.group': { type: 'keyword', array: false, required: false, }, - 'source.as.number': { - type: 'long', + 'threat.indicator.file.hash.md5': { + type: 'keyword', array: false, required: false, }, - 'source.as.organization.name': { + 'threat.indicator.file.hash.sha1': { type: 'keyword', array: false, required: false, }, - 'source.bytes': { - type: 'long', + 'threat.indicator.file.hash.sha256': { + type: 'keyword', array: false, required: false, }, - 'source.domain': { + 'threat.indicator.file.hash.sha512': { type: 'keyword', array: false, required: false, }, - 'source.geo.city_name': { + 'threat.indicator.file.hash.ssdeep': { type: 'keyword', array: false, required: false, }, - 'source.geo.continent_name': { + 'threat.indicator.file.inode': { type: 'keyword', array: false, required: false, }, - 'source.geo.country_iso_code': { + 'threat.indicator.file.mime_type': { type: 'keyword', array: false, required: false, }, - 'source.geo.country_name': { + 'threat.indicator.file.mode': { type: 'keyword', array: false, required: false, }, - 'source.geo.location': { - type: 'geo_point', + 'threat.indicator.file.mtime': { + type: 'date', array: false, required: false, }, - 'source.geo.name': { + 'threat.indicator.file.name': { type: 'keyword', array: false, required: false, }, - 'source.geo.region_iso_code': { + 'threat.indicator.file.owner': { type: 'keyword', array: false, required: false, }, - 'source.geo.region_name': { + 'threat.indicator.file.path': { type: 'keyword', array: false, required: false, }, - 'source.ip': { - type: 'ip', + 'threat.indicator.file.pe.architecture': { + type: 'keyword', array: false, required: false, }, - 'source.mac': { + 'threat.indicator.file.pe.company': { type: 'keyword', array: false, required: false, }, - 'source.nat.ip': { - type: 'ip', + 'threat.indicator.file.pe.description': { + type: 'keyword', array: false, required: false, }, - 'source.nat.port': { - type: 'long', + 'threat.indicator.file.pe.file_version': { + type: 'keyword', array: false, required: false, }, - 'source.packets': { - type: 'long', + 'threat.indicator.file.pe.imphash': { + type: 'keyword', array: false, required: false, }, - 'source.port': { - type: 'long', + 'threat.indicator.file.pe.original_file_name': { + type: 'keyword', array: false, required: false, }, - 'source.registered_domain': { + 'threat.indicator.file.pe.product': { type: 'keyword', array: false, required: false, }, - 'source.subdomain': { - type: 'keyword', + 'threat.indicator.file.size': { + type: 'long', array: false, required: false, }, - 'source.top_level_domain': { + 'threat.indicator.file.target_path': { type: 'keyword', array: false, required: false, }, - 'source.user.domain': { + 'threat.indicator.file.type': { type: 'keyword', array: false, required: false, }, - 'source.user.email': { + 'threat.indicator.file.uid': { type: 'keyword', array: false, required: false, }, - 'source.user.full_name': { + 'threat.indicator.file.x509.alternative_names': { type: 'keyword', - array: false, + array: true, required: false, }, - 'source.user.group.domain': { + 'threat.indicator.file.x509.issuer.common_name': { type: 'keyword', - array: false, + array: true, required: false, }, - 'source.user.group.id': { + 'threat.indicator.file.x509.issuer.country': { type: 'keyword', - array: false, + array: true, required: false, }, - 'source.user.group.name': { + 'threat.indicator.file.x509.issuer.distinguished_name': { type: 'keyword', array: false, required: false, }, - 'source.user.hash': { + 'threat.indicator.file.x509.issuer.locality': { type: 'keyword', - array: false, + array: true, required: false, }, - 'source.user.id': { + 'threat.indicator.file.x509.issuer.organization': { type: 'keyword', - array: false, + array: true, required: false, }, - 'source.user.name': { + 'threat.indicator.file.x509.issuer.organizational_unit': { type: 'keyword', - array: false, + array: true, required: false, }, - 'source.user.roles': { + 'threat.indicator.file.x509.issuer.state_or_province': { type: 'keyword', array: true, required: false, }, - 'span.id': { - type: 'keyword', + 'threat.indicator.file.x509.not_after': { + type: 'date', array: false, required: false, }, - tags: { - type: 'keyword', - array: true, + 'threat.indicator.file.x509.not_before': { + type: 'date', + array: false, required: false, }, - 'threat.framework': { + 'threat.indicator.file.x509.public_key_algorithm': { type: 'keyword', array: false, required: false, }, - 'threat.enrichments': { - type: 'nested', - array: true, + 'threat.indicator.file.x509.public_key_curve': { + type: 'keyword', + array: false, required: false, }, - 'threat.enrichments.indicator': { - type: 'object', + 'threat.indicator.file.x509.public_key_exponent': { + type: 'long', array: false, required: false, }, - 'threat.enrichments.indicator.as.number': { + 'threat.indicator.file.x509.public_key_size': { type: 'long', array: false, required: false, }, - 'threat.enrichments.indicator.as.organization.name': { + 'threat.indicator.file.x509.serial_number': { type: 'keyword', array: false, required: false, }, - 'threat.enrichments.indicator.confidence': { + 'threat.indicator.file.x509.signature_algorithm': { type: 'keyword', array: false, required: false, }, - 'threat.enrichments.indicator.description': { + 'threat.indicator.file.x509.subject.common_name': { type: 'keyword', - array: false, + array: true, required: false, }, - 'threat.enrichments.indicator.email.address': { + 'threat.indicator.file.x509.subject.country': { type: 'keyword', - array: false, + array: true, required: false, }, - 'threat.enrichments.indicator.file.accessed': { - type: 'date', + 'threat.indicator.file.x509.subject.distinguished_name': { + type: 'keyword', array: false, required: false, }, - 'threat.enrichments.indicator.file.attributes': { + 'threat.indicator.file.x509.subject.locality': { type: 'keyword', array: true, required: false, }, - 'threat.enrichments.indicator.file.code_signature.digest_algorithm': { + 'threat.indicator.file.x509.subject.organization': { type: 'keyword', - array: false, + array: true, required: false, }, - 'threat.enrichments.indicator.file.code_signature.exists': { - type: 'boolean', - array: false, + 'threat.indicator.file.x509.subject.organizational_unit': { + type: 'keyword', + array: true, required: false, }, - 'threat.enrichments.indicator.file.code_signature.signing_id': { + 'threat.indicator.file.x509.subject.state_or_province': { type: 'keyword', - array: false, + array: true, required: false, }, - 'threat.enrichments.indicator.file.code_signature.status': { + 'threat.indicator.file.x509.version_number': { type: 'keyword', array: false, required: false, }, - 'threat.enrichments.indicator.file.code_signature.subject_name': { - type: 'keyword', + 'threat.indicator.first_seen': { + type: 'date', array: false, required: false, }, - 'threat.enrichments.indicator.file.code_signature.team_id': { + 'threat.indicator.geo.city_name': { type: 'keyword', array: false, required: false, }, - 'threat.enrichments.indicator.file.code_signature.timestamp': { - type: 'date', + 'threat.indicator.geo.continent_code': { + type: 'keyword', array: false, required: false, }, - 'threat.enrichments.indicator.file.code_signature.trusted': { - type: 'boolean', + 'threat.indicator.geo.continent_name': { + type: 'keyword', array: false, required: false, }, - 'threat.enrichments.indicator.file.code_signature.valid': { - type: 'boolean', + 'threat.indicator.geo.country_iso_code': { + type: 'keyword', array: false, required: false, }, - 'threat.enrichments.indicator.file.created': { - type: 'date', + 'threat.indicator.geo.country_name': { + type: 'keyword', array: false, required: false, }, - 'threat.enrichments.indicator.file.ctime': { - type: 'date', + 'threat.indicator.geo.location': { + type: 'geo_point', array: false, required: false, }, - 'threat.enrichments.indicator.file.device': { + 'threat.indicator.geo.name': { type: 'keyword', array: false, required: false, }, - 'threat.enrichments.indicator.file.directory': { + 'threat.indicator.geo.postal_code': { type: 'keyword', array: false, required: false, }, - 'threat.enrichments.indicator.file.drive_letter': { + 'threat.indicator.geo.region_iso_code': { type: 'keyword', array: false, required: false, }, - 'threat.enrichments.indicator.file.extension': { + 'threat.indicator.geo.region_name': { type: 'keyword', array: false, required: false, }, - 'threat.enrichments.indicator.file.fork_name': { + 'threat.indicator.geo.timezone': { type: 'keyword', array: false, required: false, }, - 'threat.enrichments.indicator.file.gid': { - type: 'keyword', + 'threat.indicator.ip': { + type: 'ip', array: false, required: false, }, - 'threat.enrichments.indicator.file.group': { - type: 'keyword', + 'threat.indicator.last_seen': { + type: 'date', array: false, required: false, }, - 'threat.enrichments.indicator.file.hash.md5': { + 'threat.indicator.marking.tlp': { type: 'keyword', array: false, required: false, }, - 'threat.enrichments.indicator.file.hash.sha1': { - type: 'keyword', + 'threat.indicator.modified_at': { + type: 'date', array: false, required: false, }, - 'threat.enrichments.indicator.file.hash.sha256': { - type: 'keyword', + 'threat.indicator.port': { + type: 'long', array: false, required: false, }, - 'threat.enrichments.indicator.file.hash.sha512': { + 'threat.indicator.provider': { type: 'keyword', array: false, required: false, }, - 'threat.enrichments.indicator.file.hash.ssdeep': { + 'threat.indicator.reference': { type: 'keyword', array: false, required: false, }, - 'threat.enrichments.indicator.file.inode': { + 'threat.indicator.registry.data.bytes': { type: 'keyword', array: false, required: false, }, - 'threat.enrichments.indicator.file.mime_type': { + 'threat.indicator.registry.data.strings': { + type: 'wildcard', + array: true, + required: false, + }, + 'threat.indicator.registry.data.type': { type: 'keyword', array: false, required: false, }, - 'threat.enrichments.indicator.file.mode': { + 'threat.indicator.registry.hive': { type: 'keyword', array: false, required: false, }, - 'threat.enrichments.indicator.file.mtime': { - type: 'date', + 'threat.indicator.registry.key': { + type: 'keyword', array: false, required: false, }, - 'threat.enrichments.indicator.file.name': { + 'threat.indicator.registry.path': { type: 'keyword', array: false, required: false, }, - 'threat.enrichments.indicator.file.owner': { + 'threat.indicator.registry.value': { type: 'keyword', array: false, required: false, }, - 'threat.enrichments.indicator.file.path': { - type: 'keyword', + 'threat.indicator.scanner_stats': { + type: 'long', array: false, required: false, }, - 'threat.enrichments.indicator.file.size': { + 'threat.indicator.sightings': { type: 'long', array: false, required: false, }, - 'threat.enrichments.indicator.file.target_path': { + 'threat.indicator.type': { type: 'keyword', array: false, required: false, }, - 'threat.enrichments.indicator.file.type': { + 'threat.indicator.url.domain': { type: 'keyword', array: false, required: false, }, - 'threat.enrichments.indicator.file.uid': { + 'threat.indicator.url.extension': { type: 'keyword', array: false, required: false, }, - 'threat.enrichments.indicator.first_seen': { - type: 'date', + 'threat.indicator.url.fragment': { + type: 'keyword', array: false, required: false, }, - 'threat.enrichments.indicator.ip': { - type: 'ip', + 'threat.indicator.url.full': { + type: 'wildcard', array: false, required: false, }, - 'threat.enrichments.indicator.last_seen': { - type: 'date', + 'threat.indicator.url.original': { + type: 'wildcard', array: false, required: false, }, - 'threat.enrichments.indicator.marking.tlp': { + 'threat.indicator.url.password': { type: 'keyword', array: false, required: false, }, - 'threat.enrichments.indicator.modified_at': { - type: 'date', + 'threat.indicator.url.path': { + type: 'wildcard', array: false, required: false, }, - 'threat.enrichments.indicator.port': { + 'threat.indicator.url.port': { type: 'long', array: false, required: false, }, - 'threat.enrichments.indicator.provider': { + 'threat.indicator.url.query': { type: 'keyword', array: false, required: false, }, - 'threat.enrichments.indicator.reference': { + 'threat.indicator.url.registered_domain': { type: 'keyword', array: false, required: false, }, - 'threat.enrichments.indicator.registry.data.bytes': { + 'threat.indicator.url.scheme': { type: 'keyword', array: false, required: false, }, - 'threat.enrichments.indicator.registry.data.strings': { - type: 'wildcard', - array: true, - required: false, - }, - 'threat.enrichments.indicator.registry.data.type': { + 'threat.indicator.url.subdomain': { type: 'keyword', array: false, required: false, }, - 'threat.enrichments.indicator.registry.hive': { + 'threat.indicator.url.top_level_domain': { type: 'keyword', array: false, required: false, }, - 'threat.enrichments.indicator.registry.key': { + 'threat.indicator.url.username': { type: 'keyword', array: false, required: false, }, - 'threat.enrichments.indicator.registry.path': { + 'threat.indicator.x509.alternative_names': { type: 'keyword', - array: false, + array: true, required: false, }, - 'threat.enrichments.indicator.registry.value': { + 'threat.indicator.x509.issuer.common_name': { type: 'keyword', - array: false, + array: true, required: false, }, - 'threat.enrichments.indicator.scanner_stats': { - type: 'long', - array: false, + 'threat.indicator.x509.issuer.country': { + type: 'keyword', + array: true, required: false, }, - 'threat.enrichments.indicator.sightings': { - type: 'long', + 'threat.indicator.x509.issuer.distinguished_name': { + type: 'keyword', array: false, required: false, }, - 'threat.enrichments.indicator.type': { + 'threat.indicator.x509.issuer.locality': { type: 'keyword', - array: false, + array: true, required: false, }, - 'threat.enrichments.indicator.url.domain': { + 'threat.indicator.x509.issuer.organization': { type: 'keyword', - array: false, + array: true, required: false, }, - 'threat.enrichments.indicator.url.extension': { + 'threat.indicator.x509.issuer.organizational_unit': { type: 'keyword', - array: false, + array: true, required: false, }, - 'threat.enrichments.indicator.url.fragment': { + 'threat.indicator.x509.issuer.state_or_province': { type: 'keyword', - array: false, + array: true, required: false, }, - 'threat.enrichments.indicator.url.full': { - type: 'wildcard', + 'threat.indicator.x509.not_after': { + type: 'date', array: false, required: false, }, - 'threat.enrichments.indicator.url.original': { - type: 'wildcard', + 'threat.indicator.x509.not_before': { + type: 'date', array: false, required: false, }, - 'threat.enrichments.indicator.url.password': { + 'threat.indicator.x509.public_key_algorithm': { type: 'keyword', array: false, required: false, }, - 'threat.enrichments.indicator.url.path': { - type: 'wildcard', + 'threat.indicator.x509.public_key_curve': { + type: 'keyword', array: false, required: false, }, - 'threat.enrichments.indicator.url.port': { + 'threat.indicator.x509.public_key_exponent': { type: 'long', array: false, required: false, }, - 'threat.enrichments.indicator.url.query': { - type: 'keyword', + 'threat.indicator.x509.public_key_size': { + type: 'long', array: false, required: false, }, - 'threat.enrichments.indicator.url.registered_domain': { + 'threat.indicator.x509.serial_number': { type: 'keyword', array: false, required: false, }, - 'threat.enrichments.indicator.url.scheme': { + 'threat.indicator.x509.signature_algorithm': { type: 'keyword', array: false, required: false, }, - 'threat.enrichments.indicator.url.subdomain': { + 'threat.indicator.x509.subject.common_name': { type: 'keyword', - array: false, + array: true, required: false, }, - 'threat.enrichments.indicator.url.top_level_domain': { + 'threat.indicator.x509.subject.country': { type: 'keyword', - array: false, + array: true, required: false, }, - 'threat.enrichments.indicator.url.username': { + 'threat.indicator.x509.subject.distinguished_name': { type: 'keyword', array: false, required: false, }, - 'threat.enrichments.feed': { - type: 'object', - array: false, + 'threat.indicator.x509.subject.locality': { + type: 'keyword', + array: true, required: false, }, - 'threat.enrichments.feed.name': { + 'threat.indicator.x509.subject.organization': { type: 'keyword', - array: false, + array: true, required: false, }, - 'threat.enrichments.matched.atomic': { + 'threat.indicator.x509.subject.organizational_unit': { type: 'keyword', - array: false, + array: true, required: false, }, - 'threat.enrichments.matched.field': { + 'threat.indicator.x509.subject.state_or_province': { type: 'keyword', - array: false, + array: true, required: false, }, - 'threat.enrichments.matched.id': { + 'threat.indicator.x509.version_number': { type: 'keyword', array: false, required: false, }, - 'threat.enrichments.matched.index': { + 'threat.software.alias': { type: 'keyword', - array: false, + array: true, required: false, }, - 'threat.enrichments.matched.type': { + 'threat.software.id': { type: 'keyword', array: false, required: false, }, - 'threat.group.alias': { + 'threat.software.name': { type: 'keyword', - array: true, + array: false, required: false, }, - 'threat.group.id': { + 'threat.software.platforms': { type: 'keyword', - array: false, + array: true, required: false, }, - 'threat.group.name': { + 'threat.software.reference': { type: 'keyword', array: false, required: false, }, - 'threat.group.reference': { + 'threat.software.type': { type: 'keyword', array: false, required: false, @@ -3436,12 +5687,12 @@ export const ecsFieldMap = { required: false, }, 'url.full': { - type: 'keyword', + type: 'wildcard', array: false, required: false, }, 'url.original': { - type: 'keyword', + type: 'wildcard', array: false, required: false, }, @@ -3451,7 +5702,7 @@ export const ecsFieldMap = { required: false, }, 'url.path': { - type: 'keyword', + type: 'wildcard', array: false, required: false, }, diff --git a/x-pack/plugins/rule_registry/common/field_map/types.ts b/x-pack/plugins/rule_registry/common/field_map/types.ts index ad2f8ed1e5536d..6eeffa12400fe2 100644 --- a/x-pack/plugins/rule_registry/common/field_map/types.ts +++ b/x-pack/plugins/rule_registry/common/field_map/types.ts @@ -11,5 +11,6 @@ export interface FieldMap { required?: boolean; array?: boolean; path?: string; + scaling_factor?: number; }; } diff --git a/x-pack/plugins/rule_registry/common/types.ts b/x-pack/plugins/rule_registry/common/types.ts index 8ffbebbc631a16..4bf5fa8b23fdc1 100644 --- a/x-pack/plugins/rule_registry/common/types.ts +++ b/x-pack/plugins/rule_registry/common/types.ts @@ -275,6 +275,7 @@ export interface ClusterPutComponentTemplateBody { template: { settings: { number_of_shards: number; + 'index.mapping.total_fields.limit'?: number; }; mappings: estypes.MappingTypeMapping; }; diff --git a/x-pack/plugins/rule_registry/scripts/generate_ecs_fieldmap/index.js b/x-pack/plugins/rule_registry/scripts/generate_ecs_fieldmap/index.js index bbcf651bd6d691..5e90a3c16aa7c6 100644 --- a/x-pack/plugins/rule_registry/scripts/generate_ecs_fieldmap/index.js +++ b/x-pack/plugins/rule_registry/scripts/generate_ecs_fieldmap/index.js @@ -33,11 +33,17 @@ async function generate() { const flatYaml = await yaml.safeLoad(await readFile(ecsYamlFilename)); const fields = mapValues(flatYaml, (description) => { - return { + const field = { type: description.type, array: description.normalize.includes('array'), required: !!description.required, }; + + if (description.scaling_factor) { + field.scaling_factor = description.scaling_factor; + } + + return field; }); await Promise.all([ diff --git a/x-pack/plugins/rule_registry/server/rule_data_plugin_service/resource_installer.ts b/x-pack/plugins/rule_registry/server/rule_data_plugin_service/resource_installer.ts index 0d55335a652ea9..c49e9d1e111bfe 100644 --- a/x-pack/plugins/rule_registry/server/rule_data_plugin_service/resource_installer.ts +++ b/x-pack/plugins/rule_registry/server/rule_data_plugin_service/resource_installer.ts @@ -315,7 +315,7 @@ export class ResourceInstaller { // @ts-expect-error rollover_alias: primaryNamespacedAlias, }, - 'index.mapping.total_fields.limit': 1200, + 'index.mapping.total_fields.limit': 1700, }, mappings: { dynamic: false, From 51ac9a0c89536e9a52dc89888519b772ee873ec1 Mon Sep 17 00:00:00 2001 From: "Devin W. Hurley" Date: Tue, 18 Jan 2022 21:51:03 -0500 Subject: [PATCH 035/108] [Security Solution] [Platform] updates rule indices to include indices from the enriched alert data (#123324) * updates rule indices to include indices from the enriched alert data * quick fix for type failure * rely on functions, not types --- .../timeline_actions/alert_context_menu.tsx | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/alert_context_menu.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/alert_context_menu.tsx index d64864a699a60e..3e4090706f91eb 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/alert_context_menu.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/alert_context_menu.tsx @@ -286,13 +286,29 @@ export const AddExceptionModalWrapper: React.FC = } }, [data?.hits.hits, isLoadingAlertData]); + /** + * This should be re-visited after UEBA work is merged + */ + const useRuleIndices = useMemo(() => { + if (enrichedAlert != null && enrichedAlert['kibana.alert.rule.parameters']?.index != null) { + return Array.isArray(enrichedAlert['kibana.alert.rule.parameters'].index) + ? enrichedAlert['kibana.alert.rule.parameters'].index + : [enrichedAlert['kibana.alert.rule.parameters'].index]; + } else if (enrichedAlert != null && enrichedAlert?.signal?.rule?.index != null) { + return Array.isArray(enrichedAlert.signal.rule.index) + ? enrichedAlert.signal.rule.index + : [enrichedAlert.signal.rule.index]; + } + return ruleIndices; + }, [enrichedAlert, ruleIndices]); + const isLoading = isLoadingAlertData && isSignalIndexLoading; return ( Date: Wed, 19 Jan 2022 10:12:06 +0100 Subject: [PATCH 036/108] [ML] Standardize Add embeddable flow from the Anomaly Explorer page (#123199) * wip: remove add to dashboard, add table action, replace url generator with locator * add swim lane embeddable * get embeddable input * update functional tests * clean up DashboardService * remove unused i18n * remove console statement --- x-pack/plugins/ml/kibana.json | 3 +- x-pack/plugins/ml/public/application/app.tsx | 1 + .../contexts/kibana/kibana_context.ts | 2 + .../explorer/anomaly_context_menu.tsx | 10 +- ...d_anomaly_charts_to_dashboard_controls.tsx | 43 ++---- .../add_swimlane_to_dashboard_controls.tsx | 81 ++++------ .../add_to_dashboard_controls.tsx | 93 ++++++----- .../use_add_to_dashboard_actions.tsx | 90 +++++------ .../use_dashboards_table.tsx | 7 +- .../services/dashboard_service.test.ts | 146 +----------------- .../application/services/dashboard_service.ts | 90 +---------- .../ml/public/embeddables/constants.ts | 4 +- x-pack/plugins/ml/public/plugin.ts | 4 + .../translations/translations/ja-JP.json | 3 - .../translations/translations/zh-CN.json | 3 - .../ml/anomaly_detection/anomaly_explorer.ts | 2 +- .../services/ml/anomaly_explorer.ts | 24 +-- 17 files changed, 162 insertions(+), 444 deletions(-) diff --git a/x-pack/plugins/ml/kibana.json b/x-pack/plugins/ml/kibana.json index 577e41b8816cd0..6c76a61139714f 100644 --- a/x-pack/plugins/ml/kibana.json +++ b/x-pack/plugins/ml/kibana.json @@ -28,7 +28,8 @@ "management", "licenseManagement", "maps", - "usageCollection" + "usageCollection", + "dashboard" ], "server": true, "ui": true, diff --git a/x-pack/plugins/ml/public/application/app.tsx b/x-pack/plugins/ml/public/application/app.tsx index b6d0626fff7cde..e61549efe8adc9 100644 --- a/x-pack/plugins/ml/public/application/app.tsx +++ b/x-pack/plugins/ml/public/application/app.tsx @@ -87,6 +87,7 @@ const App: FC = ({ coreStart, deps, appMountParams }) => { dataVisualizer: deps.dataVisualizer, usageCollection: deps.usageCollection, fieldFormats: deps.fieldFormats, + dashboard: deps.dashboard, ...coreStart, }; diff --git a/x-pack/plugins/ml/public/application/contexts/kibana/kibana_context.ts b/x-pack/plugins/ml/public/application/contexts/kibana/kibana_context.ts index 10c00098d82d56..a72ce380eef857 100644 --- a/x-pack/plugins/ml/public/application/contexts/kibana/kibana_context.ts +++ b/x-pack/plugins/ml/public/application/contexts/kibana/kibana_context.ts @@ -22,6 +22,7 @@ import type { MapsStartApi } from '../../../../../maps/public'; import type { DataVisualizerPluginStart } from '../../../../../data_visualizer/public'; import type { TriggersAndActionsUIPublicPluginStart } from '../../../../../triggers_actions_ui/public'; import type { FieldFormatsRegistry } from '../../../../../../../src/plugins/field_formats/common'; +import type { DashboardSetup } from '../../../../../../../src/plugins/dashboard/public'; interface StartPlugins { data: DataPublicPluginStart; @@ -34,6 +35,7 @@ interface StartPlugins { dataVisualizer?: DataVisualizerPluginStart; usageCollection?: UsageCollectionSetup; fieldFormats: FieldFormatsRegistry; + dashboard: DashboardSetup; } export type StartServices = CoreStart & StartPlugins & { diff --git a/x-pack/plugins/ml/public/application/explorer/anomaly_context_menu.tsx b/x-pack/plugins/ml/public/application/explorer/anomaly_context_menu.tsx index 0cd92bd06bbbef..60f5de6a7335a9 100644 --- a/x-pack/plugins/ml/public/application/explorer/anomaly_context_menu.tsx +++ b/x-pack/plugins/ml/public/application/explorer/anomaly_context_menu.tsx @@ -43,6 +43,7 @@ export const AnomalyContextMenu: FC = ({ const [isAddDashboardsActive, setIsAddDashboardActive] = useState(false); const canEditDashboards = capabilities.dashboard?.createNew ?? false; + const menuItems = useMemo(() => { const items = []; if (canEditDashboards) { @@ -91,20 +92,17 @@ export const AnomalyContextMenu: FC = ({ )} - {isAddDashboardsActive && selectedJobs && ( + {isAddDashboardsActive && selectedJobs ? ( { + onClose={async () => { setIsAddDashboardActive(false); - if (callback) { - await callback(); - } }} selectedCells={selectedCells} bounds={bounds} interval={interval} jobIds={jobIds} /> - )} + ) : null} ); }; diff --git a/x-pack/plugins/ml/public/application/explorer/dashboard_controls/add_anomaly_charts_to_dashboard_controls.tsx b/x-pack/plugins/ml/public/application/explorer/dashboard_controls/add_anomaly_charts_to_dashboard_controls.tsx index dd08abf8e895e3..bb134666b08d17 100644 --- a/x-pack/plugins/ml/public/application/explorer/dashboard_controls/add_anomaly_charts_to_dashboard_controls.tsx +++ b/x-pack/plugins/ml/public/application/explorer/dashboard_controls/add_anomaly_charts_to_dashboard_controls.tsx @@ -6,7 +6,7 @@ */ import React, { FC, useCallback, useState } from 'react'; import { FormattedMessage } from '@kbn/i18n-react'; -import { EuiFieldNumber, EuiFormRow, formatDate } from '@elastic/eui'; +import { EuiFieldNumber, EuiFormRow, formatDate, htmlIdGenerator } from '@elastic/eui'; import { useDashboardTable } from './use_dashboards_table'; import { AddToDashboardControl } from './add_to_dashboard_controls'; import { useAddToDashboardActions } from './use_add_to_dashboard_actions'; @@ -22,7 +22,7 @@ import { MAX_ANOMALY_CHARTS_ALLOWED } from '../../../embeddables/anomaly_charts/ function getDefaultEmbeddablePanelConfig(jobIds: JobId[]) { return { - type: ANOMALY_EXPLORER_CHARTS_EMBEDDABLE_TYPE, + id: htmlIdGenerator()(), title: getDefaultExplorerChartsPanelTitle(jobIds), }; } @@ -48,7 +48,7 @@ export const AddAnomalyChartsToDashboardControl: FC const [severity] = useTableSeverity(); const [maxSeriesToPlot, setMaxSeriesToPlot] = useState(DEFAULT_MAX_SERIES_TO_PLOT); - const getPanelsData = useCallback(async () => { + const getEmbeddableInput = useCallback(() => { let timeRange: TimeRange | undefined; if (selectedCells !== undefined && interval !== undefined && bounds !== undefined) { const { earliestMs, latestMs } = getSelectionTimeRange(selectedCells, interval, bounds); @@ -60,25 +60,21 @@ export const AddAnomalyChartsToDashboardControl: FC } const config = getDefaultEmbeddablePanelConfig(jobIds); - return [ - { - ...config, - embeddableConfig: { - jobIds, - maxSeriesToPlot: maxSeriesToPlot ?? DEFAULT_MAX_SERIES_TO_PLOT, - severityThreshold: severity.val, - ...(timeRange ?? {}), - }, - }, - ]; + + return { + ...config, + jobIds, + maxSeriesToPlot: maxSeriesToPlot ?? DEFAULT_MAX_SERIES_TO_PLOT, + severityThreshold: severity.val, + ...(timeRange ?? {}), + }; }, [selectedCells, interval, bounds, jobIds, maxSeriesToPlot, severity]); - const { selectedItems, selection, dashboardItems, isLoading, search } = useDashboardTable(); - const { addToDashboardAndEditCallback, addToDashboardCallback } = useAddToDashboardActions({ - onClose, - getPanelsData, - selectedDashboards: selectedItems, - }); + const { dashboardItems, isLoading, search } = useDashboardTable(); + const { addToDashboardAndEditCallback } = useAddToDashboardActions( + ANOMALY_EXPLORER_CHARTS_EMBEDDABLE_TYPE, + getEmbeddableInput + ); const title = ( /> ); - const disabled = selectedItems.length < 1 && !Array.isArray(jobIds === undefined); - const extraControls = ( return ( {extraControls} diff --git a/x-pack/plugins/ml/public/application/explorer/dashboard_controls/add_swimlane_to_dashboard_controls.tsx b/x-pack/plugins/ml/public/application/explorer/dashboard_controls/add_swimlane_to_dashboard_controls.tsx index d343f88ce78320..519bbede140299 100644 --- a/x-pack/plugins/ml/public/application/explorer/dashboard_controls/add_swimlane_to_dashboard_controls.tsx +++ b/x-pack/plugins/ml/public/application/explorer/dashboard_controls/add_swimlane_to_dashboard_controls.tsx @@ -6,7 +6,13 @@ */ import React, { FC, useCallback, useState } from 'react'; -import { EuiFormRow, EuiCheckboxGroup, EuiInMemoryTableProps, EuiSpacer } from '@elastic/eui'; +import { + EuiFormRow, + EuiInMemoryTableProps, + EuiSpacer, + EuiRadioGroup, + htmlIdGenerator, +} from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; import { DashboardSavedObject } from '../../../../../../../src/plugins/dashboard/public'; @@ -29,8 +35,8 @@ export type EuiTableProps = EuiInMemoryTableProps; function getDefaultEmbeddablePanelConfig(jobIds: JobId[]) { return { - type: ANOMALY_SWIMLANE_EMBEDDABLE_TYPE, title: getDefaultSwimlanePanelTitle(jobIds), + id: htmlIdGenerator()(), }; } @@ -48,44 +54,25 @@ export const AddSwimlaneToDashboardControl: FC = ({ jobIds, viewBy, }) => { - const { selectedItems, selection, dashboardItems, isLoading, search } = useDashboardTable(); + const { dashboardItems, isLoading, search } = useDashboardTable(); - const [selectedSwimlanes, setSelectedSwimlanes] = useState<{ [key in SwimlaneType]: boolean }>({ - [SWIMLANE_TYPE.OVERALL]: true, - [SWIMLANE_TYPE.VIEW_BY]: false, - }); + const [selectedSwimlane, setSelectedSwimlane] = useState(SWIMLANE_TYPE.OVERALL); - const getPanelsData = useCallback(async () => { - const swimlanes = Object.entries(selectedSwimlanes) - .filter(([, isSelected]) => isSelected) - .map(([swimlaneType]) => swimlaneType); + const getEmbeddableInput = useCallback(() => { + const config = getDefaultEmbeddablePanelConfig(jobIds); - return swimlanes.map((swimlaneType) => { - const config = getDefaultEmbeddablePanelConfig(jobIds); - if (swimlaneType === SWIMLANE_TYPE.VIEW_BY) { - return { - ...config, - embeddableConfig: { - jobIds, - swimlaneType, - viewBy, - }, - }; - } - return { - ...config, - embeddableConfig: { - jobIds, - swimlaneType, - }, - }; - }); - }, [selectedSwimlanes, selectedItems]); - const { addToDashboardAndEditCallback, addToDashboardCallback } = useAddToDashboardActions({ - onClose, - getPanelsData, - selectedDashboards: selectedItems, - }); + return { + ...config, + jobIds, + swimlaneType: selectedSwimlane, + ...(selectedSwimlane === SWIMLANE_TYPE.VIEW_BY ? { viewBy } : {}), + }; + }, [selectedSwimlane]); + + const { addToDashboardAndEditCallback } = useAddToDashboardActions( + ANOMALY_SWIMLANE_EMBEDDABLE_TYPE, + getEmbeddableInput + ); const swimlaneTypeOptions = [ { @@ -103,8 +90,6 @@ export const AddSwimlaneToDashboardControl: FC = ({ }, ]; - const noSwimlaneSelected = Object.values(selectedSwimlanes).every((isSelected) => !isSelected); - const extraControls = ( <> = ({ /> } > - { - const newSelection = { - ...selectedSwimlanes, - [optionId]: !selectedSwimlanes[optionId as SwimlaneType], - }; - setSelectedSwimlanes(newSelection); + setSelectedSwimlane(optionId as SwimlaneType); }} data-test-subj="mlAddToDashboardSwimlaneTypeSelector" /> @@ -135,22 +116,18 @@ export const AddSwimlaneToDashboardControl: FC = ({ const title = ( ); - const disabled = noSwimlaneSelected || selectedItems.length === 0; return ( {extraControls} diff --git a/x-pack/plugins/ml/public/application/explorer/dashboard_controls/add_to_dashboard_controls.tsx b/x-pack/plugins/ml/public/application/explorer/dashboard_controls/add_to_dashboard_controls.tsx index 0231e5d03aab3e..d030cfc9b92b62 100644 --- a/x-pack/plugins/ml/public/application/explorer/dashboard_controls/add_to_dashboard_controls.tsx +++ b/x-pack/plugins/ml/public/application/explorer/dashboard_controls/add_to_dashboard_controls.tsx @@ -6,7 +6,6 @@ */ import React, { FC } from 'react'; import { - EuiButton, EuiButtonEmpty, EuiFormRow, EuiInMemoryTable, @@ -18,46 +17,67 @@ import { } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; -import { EuiTableProps, useDashboardTable } from './use_dashboards_table'; - -export const columns: EuiTableProps['columns'] = [ - { - field: 'title', - name: i18n.translate('xpack.ml.explorer.dashboardsTable.titleColumnHeader', { - defaultMessage: 'Title', - }), - sortable: true, - truncateText: true, - }, - { - field: 'description', - name: i18n.translate('xpack.ml.explorer.dashboardsTable.descriptionColumnHeader', { - defaultMessage: 'Description', - }), - truncateText: true, - }, -]; +import { DashboardItem, EuiTableProps, useDashboardTable } from './use_dashboards_table'; interface AddToDashboardControlProps extends ReturnType { onClose: (callback?: () => Promise) => void; - addToDashboardAndEditCallback: () => Promise; - addToDashboardCallback: () => Promise; + addToDashboardAndEditCallback: (dashboardItem: DashboardItem) => Promise; title: React.ReactNode; disabled: boolean; children?: React.ReactElement; } export const AddToDashboardControl: FC = ({ onClose, - selection, dashboardItems, isLoading, search, addToDashboardAndEditCallback, - addToDashboardCallback, title, disabled, children, }) => { + const columns: EuiTableProps['columns'] = [ + { + field: 'title', + name: i18n.translate('xpack.ml.explorer.dashboardsTable.titleColumnHeader', { + defaultMessage: 'Title', + }), + sortable: true, + truncateText: true, + }, + { + field: 'description', + name: i18n.translate('xpack.ml.explorer.dashboardsTable.descriptionColumnHeader', { + defaultMessage: 'Description', + }), + truncateText: true, + }, + { + field: 'description', + name: i18n.translate('xpack.ml.explorer.dashboardsTable.actionsHeader', { + defaultMessage: 'Actions', + }), + width: '80px', + actions: [ + { + name: i18n.translate('xpack.ml.explorer.dashboardsTable.editActionName', { + defaultMessage: 'Add to dashboard', + }), + description: i18n.translate('xpack.ml.explorer.dashboardsTable.editActionName', { + defaultMessage: 'Add to dashboard', + }), + icon: 'documentEdit', + type: 'icon', + enabled: () => !disabled, + onClick: async (item) => { + await addToDashboardAndEditCallback(item); + }, + 'data-test-subj': 'mlEmbeddableAddAndEditDashboard', + }, + ], + }, + ]; + return ( @@ -77,8 +97,8 @@ export const AddToDashboardControl: FC = ({ > = ({ defaultMessage="Cancel" /> - - - - - - ); diff --git a/x-pack/plugins/ml/public/application/explorer/dashboard_controls/use_add_to_dashboard_actions.tsx b/x-pack/plugins/ml/public/application/explorer/dashboard_controls/use_add_to_dashboard_actions.tsx index 450266125e1a9e..21d3a320ee5915 100644 --- a/x-pack/plugins/ml/public/application/explorer/dashboard_controls/use_add_to_dashboard_actions.tsx +++ b/x-pack/plugins/ml/public/application/explorer/dashboard_controls/use_add_to_dashboard_actions.tsx @@ -5,66 +5,50 @@ * 2.0. */ -import React, { useCallback } from 'react'; -import { FormattedMessage } from '@kbn/i18n-react'; +import { useCallback } from 'react'; import { DashboardItem } from './use_dashboards_table'; -import { SavedDashboardPanel } from '../../../../../../../src/plugins/dashboard/common/types'; import { useMlKibana } from '../../contexts/kibana'; import { useDashboardService } from '../../services/dashboard_service'; +import { DashboardConstants } from '../../../../../../../src/plugins/dashboard/public'; +import { + ANOMALY_EXPLORER_CHARTS_EMBEDDABLE_TYPE, + ANOMALY_SWIMLANE_EMBEDDABLE_TYPE, + AnomalyChartsEmbeddableInput, + AnomalySwimlaneEmbeddableInput, +} from '../../../embeddables'; -export const useAddToDashboardActions = ({ - onClose, - getPanelsData, - selectedDashboards, -}: { - onClose: (callback?: () => Promise) => void; - getPanelsData: ( - selectedDashboards: DashboardItem[] - ) => Promise>>; - selectedDashboards: DashboardItem[]; -}) => { +export function useAddToDashboardActions< + T extends typeof ANOMALY_SWIMLANE_EMBEDDABLE_TYPE | typeof ANOMALY_EXPLORER_CHARTS_EMBEDDABLE_TYPE +>( + type: T, + getEmbeddableInput: () => Partial< + T extends typeof ANOMALY_SWIMLANE_EMBEDDABLE_TYPE + ? AnomalySwimlaneEmbeddableInput + : AnomalyChartsEmbeddableInput + > +) { const { - notifications: { toasts }, - services: { - application: { navigateToUrl }, - }, + services: { embeddable }, } = useMlKibana(); const dashboardService = useDashboardService(); - const addToDashboardCallback = useCallback(async () => { - const panelsData = await getPanelsData(selectedDashboards); - for (const selectedDashboard of selectedDashboards) { - try { - await dashboardService.attachPanels( - selectedDashboard.id, - selectedDashboard.attributes, - panelsData - ); - toasts.success({ - title: ( - - ), - toastLifeTimeMs: 3000, - }); - } catch (e) { - toasts.danger({ - body: e, - }); - } - } - }, [selectedDashboards, getPanelsData]); + const addToDashboardAndEditCallback = useCallback( + async (selectedDashboard: DashboardItem) => { + const stateTransfer = embeddable.getStateTransfer(); + const selectedDashboardId = selectedDashboard.id; + + const dashboardPath = await dashboardService.getDashboardEditUrl(selectedDashboardId); - const addToDashboardAndEditCallback = useCallback(async () => { - onClose(async () => { - await addToDashboardCallback(); - const selectedDashboardId = selectedDashboards[0].id; - await navigateToUrl(await dashboardService.getDashboardEditUrl(selectedDashboardId)); - }); - }, [addToDashboardCallback, selectedDashboards, navigateToUrl]); + await stateTransfer.navigateToWithEmbeddablePackage(DashboardConstants.DASHBOARDS_ID, { + path: dashboardPath, + state: { + type, + input: getEmbeddableInput(), + }, + }); + }, + [getEmbeddableInput] + ); - return { addToDashboardCallback, addToDashboardAndEditCallback }; -}; + return { addToDashboardAndEditCallback }; +} diff --git a/x-pack/plugins/ml/public/application/explorer/dashboard_controls/use_dashboards_table.tsx b/x-pack/plugins/ml/public/application/explorer/dashboard_controls/use_dashboards_table.tsx index 8721de497eedcc..b114797bbc5502 100644 --- a/x-pack/plugins/ml/public/application/explorer/dashboard_controls/use_dashboards_table.tsx +++ b/x-pack/plugins/ml/public/application/explorer/dashboard_controls/use_dashboards_table.tsx @@ -51,7 +51,6 @@ export const useDashboardTable = () => { }, []); const [dashboardItems, setDashboardItems] = useState([]); - const [selectedItems, setSelectedItems] = useState([]); const fetchDashboards = useCallback( debounce(async (query?: string) => { @@ -75,8 +74,6 @@ export const useDashboardTable = () => { }, 500), [] ); - const selection: EuiTableProps['selection'] = { - onSelectionChange: setSelectedItems, - }; - return { dashboardItems, selectedItems, selection, search, isLoading }; + + return { dashboardItems, search, isLoading }; }; diff --git a/x-pack/plugins/ml/public/application/services/dashboard_service.test.ts b/x-pack/plugins/ml/public/application/services/dashboard_service.test.ts index 9fb4a22a4942bd..79e2cff4da3022 100644 --- a/x-pack/plugins/ml/public/application/services/dashboard_service.test.ts +++ b/x-pack/plugins/ml/public/application/services/dashboard_service.test.ts @@ -7,30 +7,14 @@ import { dashboardServiceProvider } from './dashboard_service'; import { savedObjectsServiceMock } from '../../../../../../src/core/public/mocks'; -import { DashboardSavedObject } from '../../../../../../src/plugins/dashboard/public/saved_dashboards'; -import { - DashboardUrlGenerator, - SavedDashboardPanel, -} from '../../../../../../src/plugins/dashboard/public'; - -jest.mock('@elastic/eui', () => { - return { - htmlIdGenerator: jest.fn(() => { - return jest.fn(() => 'test-panel-id'); - }), - }; -}); +import type { DashboardAppLocator } from '../../../../../../src/plugins/dashboard/public'; describe('DashboardService', () => { const mockSavedObjectClient = savedObjectsServiceMock.createStartContract().client; const dashboardUrlGenerator = { - createUrl: jest.fn(), - } as unknown as DashboardUrlGenerator; - const dashboardService = dashboardServiceProvider( - mockSavedObjectClient, - '8.0.0', - dashboardUrlGenerator - ); + getUrl: jest.fn(), + } as unknown as DashboardAppLocator; + const dashboardService = dashboardServiceProvider(mockSavedObjectClient, dashboardUrlGenerator); test('should fetch dashboard', () => { // act @@ -44,132 +28,12 @@ describe('DashboardService', () => { }); }); - test('should attach panel to the dashboard', () => { - // act - dashboardService.attachPanels( - 'test-dashboard', - { - title: 'ML Test', - hits: 0, - description: '', - panelsJSON: JSON.stringify([ - { - version: '8.0.0', - type: 'ml_anomaly_swimlane', - gridData: { x: 0, y: 0, w: 24, h: 15, i: 'i63c960b1-ab1b-11ea-809d-f5c60c43347f' }, - panelIndex: 'i63c960b1-ab1b-11ea-809d-f5c60c43347f', - embeddableConfig: { - title: 'Panel test!', - jobIds: ['cw_multi_1'], - swimlaneType: 'overall', - }, - title: 'Panel test!', - }, - { - version: '8.0.0', - type: 'ml_anomaly_swimlane', - gridData: { x: 24, y: 0, w: 24, h: 15, i: '0aa334bd-8308-4ded-9462-80dbd37680ee' }, - panelIndex: '0aa334bd-8308-4ded-9462-80dbd37680ee', - embeddableConfig: { - title: 'ML anomaly swim lane for fb_population_1', - jobIds: ['fb_population_1'], - limit: 5, - swimlaneType: 'overall', - }, - title: 'ML anomaly swim lane for fb_population_1', - }, - { - version: '8.0.0', - gridData: { x: 0, y: 15, w: 24, h: 15, i: 'abd36eb7-4774-4216-891e-12100752b46d' }, - panelIndex: 'abd36eb7-4774-4216-891e-12100752b46d', - embeddableConfig: {}, - panelRefName: 'panel_2', - }, - ]), - optionsJSON: '{"hidePanelTitles":false,"useMargins":true}', - version: 1, - timeRestore: false, - kibanaSavedObjectMeta: { - searchSourceJSON: '{"query":{"language":"kuery","query":""},"filter":[]}', - }, - } as unknown as DashboardSavedObject, - [{ title: 'Test title', type: 'test-panel', embeddableConfig: { testConfig: '' } }] - ); - // assert - expect(mockSavedObjectClient.update).toHaveBeenCalledWith('dashboard', 'test-dashboard', { - title: 'ML Test', - hits: 0, - description: '', - panelsJSON: JSON.stringify([ - { - version: '8.0.0', - type: 'ml_anomaly_swimlane', - gridData: { x: 0, y: 0, w: 24, h: 15, i: 'i63c960b1-ab1b-11ea-809d-f5c60c43347f' }, - panelIndex: 'i63c960b1-ab1b-11ea-809d-f5c60c43347f', - embeddableConfig: { - title: 'Panel test!', - jobIds: ['cw_multi_1'], - swimlaneType: 'overall', - }, - title: 'Panel test!', - }, - { - version: '8.0.0', - type: 'ml_anomaly_swimlane', - gridData: { x: 24, y: 0, w: 24, h: 15, i: '0aa334bd-8308-4ded-9462-80dbd37680ee' }, - panelIndex: '0aa334bd-8308-4ded-9462-80dbd37680ee', - embeddableConfig: { - title: 'ML anomaly swim lane for fb_population_1', - jobIds: ['fb_population_1'], - limit: 5, - swimlaneType: 'overall', - }, - title: 'ML anomaly swim lane for fb_population_1', - }, - { - version: '8.0.0', - gridData: { x: 0, y: 15, w: 24, h: 15, i: 'abd36eb7-4774-4216-891e-12100752b46d' }, - panelIndex: 'abd36eb7-4774-4216-891e-12100752b46d', - embeddableConfig: {}, - panelRefName: 'panel_2', - }, - { - panelIndex: 'test-panel-id', - embeddableConfig: { testConfig: '' }, - title: 'Test title', - type: 'test-panel', - version: '8.0.0', - gridData: { h: 15, i: 'test-panel-id', w: 24, x: 24, y: 15 }, - }, - ]), - optionsJSON: '{"hidePanelTitles":false,"useMargins":true}', - version: 1, - timeRestore: false, - kibanaSavedObjectMeta: { - searchSourceJSON: '{"query":{"language":"kuery","query":""},"filter":[]}', - }, - }); - }); - test('should generate edit url to the dashboard', () => { dashboardService.getDashboardEditUrl('test-id'); - expect(dashboardUrlGenerator.createUrl).toHaveBeenCalledWith({ + expect(dashboardUrlGenerator.getUrl).toHaveBeenCalledWith({ dashboardId: 'test-id', useHash: false, viewMode: 'edit', }); }); - - test('should find the panel positioned at the end', () => { - expect( - dashboardService.getLastPanel([ - { gridData: { y: 15, x: 7 } }, - { gridData: { y: 17, x: 9 } }, - { gridData: { y: 15, x: 1 } }, - { gridData: { y: 17, x: 10 } }, - { gridData: { y: 15, x: 22 } }, - { gridData: { y: 17, x: 9 } }, - ] as SavedDashboardPanel[]) - ).toEqual({ gridData: { y: 17, x: 10 } }); - }); }); diff --git a/x-pack/plugins/ml/public/application/services/dashboard_service.ts b/x-pack/plugins/ml/public/application/services/dashboard_service.ts index b010ea1e8631e6..f8eb23eae9f4c4 100644 --- a/x-pack/plugins/ml/public/application/services/dashboard_service.ts +++ b/x-pack/plugins/ml/public/application/services/dashboard_service.ts @@ -6,13 +6,10 @@ */ import { SavedObjectsClientContract } from 'kibana/public'; -import { htmlIdGenerator } from '@elastic/eui'; import { useMemo } from 'react'; import { - DASHBOARD_APP_URL_GENERATOR, - DashboardUrlGenerator, - SavedDashboardPanel, DashboardSavedObject, + DashboardAppLocator, } from '../../../../../../src/plugins/dashboard/public'; import { useMlKibana } from '../contexts/kibana'; import { ViewMode } from '../../../../../../src/plugins/embeddable/public'; @@ -21,13 +18,8 @@ export type DashboardService = ReturnType; export function dashboardServiceProvider( savedObjectClient: SavedObjectsClientContract, - kibanaVersion: string, - dashboardUrlGenerator: DashboardUrlGenerator + dashboardLocator: DashboardAppLocator ) { - const generateId = htmlIdGenerator(); - const DEFAULT_PANEL_WIDTH = 24; - const DEFAULT_PANEL_HEIGHT = 15; - return { /** * Fetches dashboards @@ -40,75 +32,14 @@ export function dashboardServiceProvider( searchFields: ['title^3', 'description'], }); }, - /** - * Resolves the last positioned panel from the collection. - */ - getLastPanel(panels: SavedDashboardPanel[]): SavedDashboardPanel | null { - return panels.length > 0 - ? panels.reduce((prev, current) => - prev.gridData.y >= current.gridData.y - ? prev.gridData.y === current.gridData.y - ? prev.gridData.x > current.gridData.x - ? prev - : current - : prev - : current - ) - : null; - }, - /** - * Attaches embeddable panels to the dashboard - */ - async attachPanels( - dashboardId: string, - dashboardAttributes: DashboardSavedObject, - panelsData: Array> - ) { - const panels = JSON.parse(dashboardAttributes.panelsJSON) as SavedDashboardPanel[]; - const version = kibanaVersion; - const rowWidth = DEFAULT_PANEL_WIDTH * 2; - - for (const panelData of panelsData) { - const panelIndex = generateId(); - const lastPanel = this.getLastPanel(panels); - - const xOffset = lastPanel ? lastPanel.gridData.w + lastPanel.gridData.x : 0; - const availableRowSpace = rowWidth - xOffset; - const xPosition = availableRowSpace - DEFAULT_PANEL_WIDTH >= 0 ? xOffset : 0; - - panels.push({ - panelIndex, - embeddableConfig: panelData.embeddableConfig as { [key: string]: any }, - title: panelData.title, - type: panelData.type, - version, - gridData: { - h: DEFAULT_PANEL_HEIGHT, - i: panelIndex, - w: DEFAULT_PANEL_WIDTH, - x: xPosition, - y: lastPanel - ? xPosition > 0 - ? lastPanel.gridData.y - : lastPanel.gridData.y + lastPanel.gridData.h - : 0, - }, - }); - } - - await savedObjectClient.update('dashboard', dashboardId, { - ...dashboardAttributes, - panelsJSON: JSON.stringify(panels), - }); - }, /** * Generates dashboard url with edit mode */ async getDashboardEditUrl(dashboardId: string) { - return await dashboardUrlGenerator.createUrl({ + return await dashboardLocator.getUrl({ dashboardId, - useHash: false, viewMode: ViewMode.EDIT, + useHash: false, }); }, }; @@ -121,17 +52,12 @@ export function useDashboardService(): DashboardService { const { services: { savedObjects: { client: savedObjectClient }, - kibanaVersion, - share: { urlGenerators }, + dashboard: { locator: dashboardLocator }, }, } = useMlKibana(); + return useMemo( - () => - dashboardServiceProvider( - savedObjectClient, - kibanaVersion, - urlGenerators.getUrlGenerator(DASHBOARD_APP_URL_GENERATOR) - ), - [savedObjectClient, kibanaVersion] + () => dashboardServiceProvider(savedObjectClient, dashboardLocator!), + [savedObjectClient, dashboardLocator] ); } diff --git a/x-pack/plugins/ml/public/embeddables/constants.ts b/x-pack/plugins/ml/public/embeddables/constants.ts index 8307eeda23ec6b..afa851e9766e77 100644 --- a/x-pack/plugins/ml/public/embeddables/constants.ts +++ b/x-pack/plugins/ml/public/embeddables/constants.ts @@ -5,5 +5,5 @@ * 2.0. */ -export const ANOMALY_SWIMLANE_EMBEDDABLE_TYPE = 'ml_anomaly_swimlane'; -export const ANOMALY_EXPLORER_CHARTS_EMBEDDABLE_TYPE = 'ml_anomaly_charts'; +export const ANOMALY_SWIMLANE_EMBEDDABLE_TYPE = 'ml_anomaly_swimlane' as const; +export const ANOMALY_EXPLORER_CHARTS_EMBEDDABLE_TYPE = 'ml_anomaly_charts' as const; diff --git a/x-pack/plugins/ml/public/plugin.ts b/x-pack/plugins/ml/public/plugin.ts index 59419303d7a6f5..2a5cb2ab4ae2af 100644 --- a/x-pack/plugins/ml/public/plugin.ts +++ b/x-pack/plugins/ml/public/plugin.ts @@ -49,6 +49,7 @@ import type { FieldFormatsSetup, FieldFormatsStart, } from '../../../../src/plugins/field_formats/public'; +import type { DashboardSetup, DashboardStart } from '../../../../src/plugins/dashboard/public'; export interface MlStartDependencies { data: DataPublicPluginStart; @@ -60,6 +61,7 @@ export interface MlStartDependencies { triggersActionsUi?: TriggersAndActionsUIPublicPluginStart; dataVisualizer: DataVisualizerPluginStart; fieldFormats: FieldFormatsStart; + dashboard: DashboardStart; } export interface MlSetupDependencies { @@ -76,6 +78,7 @@ export interface MlSetupDependencies { alerting?: AlertingSetup; usageCollection?: UsageCollectionSetup; fieldFormats: FieldFormatsSetup; + dashboard: DashboardSetup; } export type MlCoreSetup = CoreSetup; @@ -120,6 +123,7 @@ export class MlPlugin implements Plugin { dataVisualizer: pluginsStart.dataVisualizer, usageCollection: pluginsSetup.usageCollection, fieldFormats: pluginsStart.fieldFormats, + dashboard: pluginsStart.dashboard, }, params ); diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index f03b4d07d336be..9a3bdd0ad0df57 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -16306,10 +16306,7 @@ "xpack.ml.explorer.charts.viewLabel": "表示", "xpack.ml.explorer.clearSelectionLabel": "選択した項目をクリア", "xpack.ml.explorer.createNewJobLinkText": "ジョブを作成", - "xpack.ml.explorer.dashboardsTable.addAndEditDashboardLabel": "ダッシュボードの追加と編集", - "xpack.ml.explorer.dashboardsTable.addToDashboardLabel": "ダッシュボードに追加", "xpack.ml.explorer.dashboardsTable.descriptionColumnHeader": "説明", - "xpack.ml.explorer.dashboardsTable.savedSuccessfullyTitle": "ダッシュボード「{dashboardTitle}」は正常に更新されました", "xpack.ml.explorer.dashboardsTable.titleColumnHeader": "タイトル", "xpack.ml.explorer.distributionChart.anomalyScoreLabel": "異常スコア", "xpack.ml.explorer.distributionChart.entityLabel": "エンティティ", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 440de7312f4375..eaf7f9f33edadf 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -16519,10 +16519,7 @@ "xpack.ml.explorer.charts.viewLabel": "查看", "xpack.ml.explorer.clearSelectionLabel": "清除所选内容", "xpack.ml.explorer.createNewJobLinkText": "创建作业", - "xpack.ml.explorer.dashboardsTable.addAndEditDashboardLabel": "添加并编辑仪表板", - "xpack.ml.explorer.dashboardsTable.addToDashboardLabel": "添加到仪表板", "xpack.ml.explorer.dashboardsTable.descriptionColumnHeader": "描述", - "xpack.ml.explorer.dashboardsTable.savedSuccessfullyTitle": "仪表板“{dashboardTitle}”已成功更新", "xpack.ml.explorer.dashboardsTable.titleColumnHeader": "标题", "xpack.ml.explorer.distributionChart.anomalyScoreLabel": "异常分数", "xpack.ml.explorer.distributionChart.entityLabel": "实体", diff --git a/x-pack/test/functional/apps/ml/anomaly_detection/anomaly_explorer.ts b/x-pack/test/functional/apps/ml/anomaly_detection/anomaly_explorer.ts index ad933ae8f86feb..93907743d144d4 100644 --- a/x-pack/test/functional/apps/ml/anomaly_detection/anomaly_explorer.ts +++ b/x-pack/test/functional/apps/ml/anomaly_detection/anomaly_explorer.ts @@ -337,7 +337,7 @@ export default function ({ getService }: FtrProviderContext) { it('adds swim lane embeddable to a dashboard', async () => { // should be the last step because it navigates away from the Anomaly Explorer page await ml.testExecution.logTestStep( - 'should allow to attach anomaly swimlane embeddable to the dashboard' + 'should allow to attach anomaly swim lane embeddable to the dashboard' ); await ml.anomalyExplorer.openAddToDashboardControl(); await ml.anomalyExplorer.addAndEditSwimlaneInDashboard('ML Test'); diff --git a/x-pack/test/functional/services/ml/anomaly_explorer.ts b/x-pack/test/functional/services/ml/anomaly_explorer.ts index aa85ee7145d07d..08b026bbb308fc 100644 --- a/x-pack/test/functional/services/ml/anomaly_explorer.ts +++ b/x-pack/test/functional/services/ml/anomaly_explorer.ts @@ -89,9 +89,7 @@ export function MachineLearningAnomalyExplorerProvider({ async addAndEditSwimlaneInDashboard(dashboardTitle: string) { await retry.tryForTime(30 * 1000, async () => { await this.filterDashboardSearchWithSearchString(dashboardTitle); - await this.selectAllDashboards(); - await this.waitForAddAndEditDashboardButtonEnabled(); - await testSubjects.clickWhenNotDisabled('mlAddAndEditDashboardButton'); + await testSubjects.clickWhenNotDisabled('~mlEmbeddableAddAndEditDashboard'); // make sure the dashboard page actually loaded const dashboardItemCount = await dashboardPage.getSharedItemsCount(); @@ -102,7 +100,7 @@ export function MachineLearningAnomalyExplorerProvider({ const swimlane = await embeddable.findByClassName('mlSwimLaneContainer'); expect(await swimlane.isDisplayed()).to.eql( true, - 'Anomaly swimlane should be displayed in dashboard' + 'Anomaly swim lane should be displayed in dashboard' ); }, @@ -114,13 +112,6 @@ export function MachineLearningAnomalyExplorerProvider({ await testSubjects.existOrFail('mlDashboardSelectionTable loaded', { timeout: 60 * 1000 }); }, - async waitForAddAndEditDashboardButtonEnabled() { - await retry.tryForTime(3000, async () => { - const isEnabled = await testSubjects.isEnabled('mlAddAndEditDashboardButton'); - expect(isEnabled).to.eql(true, 'Button to add and edit dashboard should be enabled'); - }); - }, - async filterDashboardSearchWithSearchString(filter: string, expectedRowCount: number = 1) { await retry.tryForTime(20 * 1000, async () => { await this.waitForDashboardsToLoad(); @@ -147,17 +138,6 @@ export function MachineLearningAnomalyExplorerProvider({ ); }, - async selectAllDashboards() { - await retry.tryForTime(3000, async () => { - await testSubjects.clickWhenNotDisabled( - 'mlDashboardSelectionTable loaded > checkboxSelectAll' - ); - expect( - await testSubjects.isChecked('mlDashboardSelectionTable loaded > checkboxSelectAll') - ).to.eql(true, 'Checkbox to select all dashboards should be selected'); - }); - }, - async assertClearSelectionButtonVisible(expectVisible: boolean) { if (expectVisible) { await testSubjects.existOrFail('mlAnomalyTimelineClearSelection'); From de7d48a55f52b3045efa21e53274432c3b35e761 Mon Sep 17 00:00:00 2001 From: Lisa Cawley Date: Wed, 19 Jan 2022 01:21:06 -0800 Subject: [PATCH 037/108] Update ML URLs in doc link service (#123328) --- docs/user/ml/index.asciidoc | 6 ++---- src/core/public/doc_links/doc_links_service.ts | 18 +++++++++--------- .../ml/common/constants/messages.test.ts | 18 +++++++++--------- 3 files changed, 20 insertions(+), 22 deletions(-) diff --git a/docs/user/ml/index.asciidoc b/docs/user/ml/index.asciidoc index 842d7cb054f320..f6a47d7b9d6186 100644 --- a/docs/user/ml/index.asciidoc +++ b/docs/user/ml/index.asciidoc @@ -47,10 +47,8 @@ pane: [role="screenshot"] image::user/ml/images/ml-job-management.png[Job Management] -You can use the *Settings* pane to create and edit -{ml-docs}/ml-ad-finding-anomalies.html#ml-ad-calendars[calendars] and the -filters that are used in -{ml-docs}/ml-ad-finding-anomalies.html#ml-ad-rules[custom rules]: +You can use the *Settings* pane to create and edit calendars and the +filters that are used in custom rules: [role="screenshot"] image::user/ml/images/ml-settings.png[Calendar Management] diff --git a/src/core/public/doc_links/doc_links_service.ts b/src/core/public/doc_links/doc_links_service.ts index c4e9ee553f5c30..4db97c1b9e256b 100644 --- a/src/core/public/doc_links/doc_links_service.ts +++ b/src/core/public/doc_links/doc_links_service.ts @@ -350,19 +350,19 @@ export class DocLinksService { anomalyDetection: `${ELASTIC_WEBSITE_URL}guide/en/machine-learning/${DOC_LINK_VERSION}/ml-ad-overview.html`, anomalyDetectionJobs: `${ELASTIC_WEBSITE_URL}guide/en/machine-learning/${DOC_LINK_VERSION}/ml-ad-finding-anomalies.html`, anomalyDetectionConfiguringCategories: `${ELASTIC_WEBSITE_URL}guide/en/machine-learning/${DOC_LINK_VERSION}/ml-configuring-categories.html`, - anomalyDetectionBucketSpan: `${ELASTIC_WEBSITE_URL}guide/en/machine-learning/${DOC_LINK_VERSION}/ml-ad-finding-anomalies.html#ml-ad-bucket-span`, - anomalyDetectionCardinality: `${ELASTIC_WEBSITE_URL}guide/en/machine-learning/${DOC_LINK_VERSION}/ml-ad-finding-anomalies.html#ml-ad-cardinality`, - anomalyDetectionCreateJobs: `${ELASTIC_WEBSITE_URL}guide/en/machine-learning/${DOC_LINK_VERSION}/ml-ad-finding-anomalies.html#ml-ad-create-job`, - anomalyDetectionDetectors: `${ELASTIC_WEBSITE_URL}guide/en/machine-learning/${DOC_LINK_VERSION}/ml-ad-finding-anomalies.html#ml-ad-detectors`, - anomalyDetectionInfluencers: `${ELASTIC_WEBSITE_URL}guide/en/machine-learning/${DOC_LINK_VERSION}/ml-ad-finding-anomalies.html#ml-ad-influencers`, + anomalyDetectionBucketSpan: `${ELASTIC_WEBSITE_URL}guide/en/machine-learning/${DOC_LINK_VERSION}/ml-ad-finding-anomalies.html`, + anomalyDetectionCardinality: `${ELASTIC_WEBSITE_URL}guide/en/machine-learning/${DOC_LINK_VERSION}/ml-ad-finding-anomalies.html`, + anomalyDetectionCreateJobs: `${ELASTIC_WEBSITE_URL}guide/en/machine-learning/${DOC_LINK_VERSION}/ml-ad-finding-anomalies.html`, + anomalyDetectionDetectors: `${ELASTIC_WEBSITE_URL}guide/en/machine-learning/${DOC_LINK_VERSION}/ml-ad-finding-anomalies.html`, + anomalyDetectionInfluencers: `${ELASTIC_WEBSITE_URL}guide/en/machine-learning/${DOC_LINK_VERSION}/ml-ad-finding-anomalies.html`, anomalyDetectionJobResource: `${ELASTICSEARCH_DOCS}ml-put-job.html#ml-put-job-path-parms`, anomalyDetectionJobResourceAnalysisConfig: `${ELASTICSEARCH_DOCS}ml-put-job.html#put-analysisconfig`, - anomalyDetectionJobTips: `${ELASTIC_WEBSITE_URL}guide/en/machine-learning/${DOC_LINK_VERSION}/ml-ad-finding-anomalies.html#ml-ad-job-tips`, + anomalyDetectionJobTips: `${ELASTIC_WEBSITE_URL}guide/en/machine-learning/${DOC_LINK_VERSION}/ml-ad-finding-anomalies.html`, alertingRules: `${ELASTIC_WEBSITE_URL}guide/en/machine-learning/${DOC_LINK_VERSION}/ml-configuring-alerts.html`, - anomalyDetectionModelMemoryLimits: `${ELASTIC_WEBSITE_URL}guide/en/machine-learning/${DOC_LINK_VERSION}/ml-ad-finding-anomalies.html#ml-ad-model-memory-limits`, - calendars: `${ELASTIC_WEBSITE_URL}guide/en/machine-learning/${DOC_LINK_VERSION}/ml-ad-finding-anomalies.html#ml-ad-calendars`, + anomalyDetectionModelMemoryLimits: `${ELASTIC_WEBSITE_URL}guide/en/machine-learning/${DOC_LINK_VERSION}/ml-ad-finding-anomalies.html`, + calendars: `${ELASTIC_WEBSITE_URL}guide/en/machine-learning/${DOC_LINK_VERSION}/ml-ad-finding-anomalies.html`, classificationEvaluation: `${ELASTIC_WEBSITE_URL}guide/en/machine-learning/${DOC_LINK_VERSION}/ml-dfa-classification.html#ml-dfanalytics-classification-evaluation`, - customRules: `${ELASTIC_WEBSITE_URL}guide/en/machine-learning/${DOC_LINK_VERSION}/ml-ad-finding-anomalies.html#ml-ad-rules`, + customRules: `${ELASTIC_WEBSITE_URL}guide/en/machine-learning/${DOC_LINK_VERSION}/ml-ad-finding-anomalies.html`, customUrls: `${ELASTIC_WEBSITE_URL}guide/en/machine-learning/${DOC_LINK_VERSION}/ml-configuring-url.html`, dataFrameAnalytics: `${ELASTIC_WEBSITE_URL}guide/en/machine-learning/${DOC_LINK_VERSION}/ml-dfanalytics.html`, featureImportance: `${ELASTIC_WEBSITE_URL}guide/en/machine-learning/${DOC_LINK_VERSION}/ml-feature-importance.html`, diff --git a/x-pack/plugins/ml/common/constants/messages.test.ts b/x-pack/plugins/ml/common/constants/messages.test.ts index afebdf9f14cbe5..13ef103ae0ff17 100644 --- a/x-pack/plugins/ml/common/constants/messages.test.ts +++ b/x-pack/plugins/ml/common/constants/messages.test.ts @@ -32,7 +32,7 @@ describe('Constants: Messages parseMessages()', () => { id: 'detectors_function_not_empty', status: 'success', text: 'Presence of detector functions validated in all detectors.', - url: 'https://www.elastic.co/guide/en/machine-learning/mocked-test-branch/ml-ad-finding-anomalies.html#ml-ad-detectors', + url: 'https://www.elastic.co/guide/en/machine-learning/mocked-test-branch/ml-ad-finding-anomalies.html', }, { bucketSpan: '15m', @@ -40,7 +40,7 @@ describe('Constants: Messages parseMessages()', () => { id: 'success_bucket_span', status: 'success', text: 'Format of "15m" is valid and passed validation checks.', - url: 'https://www.elastic.co/guide/en/machine-learning/mocked-test-branch/ml-ad-finding-anomalies.html#ml-ad-bucket-span', + url: 'https://www.elastic.co/guide/en/machine-learning/mocked-test-branch/ml-ad-finding-anomalies.html', }, { heading: 'Time range', @@ -53,7 +53,7 @@ describe('Constants: Messages parseMessages()', () => { id: 'success_mml', status: 'success', text: 'Valid and within the estimated model memory limit.', - url: 'https://www.elastic.co/guide/en/machine-learning/mocked-test-branch/ml-ad-finding-anomalies.html#ml-ad-model-memory-limits', + url: 'https://www.elastic.co/guide/en/machine-learning/mocked-test-branch/ml-ad-finding-anomalies.html', }, ]); }); @@ -71,7 +71,7 @@ describe('Constants: Messages parseMessages()', () => { id: 'detectors_function_not_empty', status: 'success', text: 'Presence of detector functions validated in all detectors.', - url: 'https://www.elastic.co/guide/en/machine-learning/mocked-test-branch/ml-ad-finding-anomalies.html#ml-ad-detectors', + url: 'https://www.elastic.co/guide/en/machine-learning/mocked-test-branch/ml-ad-finding-anomalies.html', }, { bucketSpan: '15m', @@ -103,7 +103,7 @@ describe('Constants: Messages parseMessages()', () => { id: 'detectors_function_not_empty', status: 'success', text: 'Presence of detector functions validated in all detectors.', - url: 'https://www.elastic.co/guide/en/machine-learning/mocked-test-branch/ml-ad-finding-anomalies.html#ml-ad-detectors', + url: 'https://www.elastic.co/guide/en/machine-learning/mocked-test-branch/ml-ad-finding-anomalies.html', }, { id: 'cardinality_model_plot_high', @@ -115,14 +115,14 @@ describe('Constants: Messages parseMessages()', () => { id: 'cardinality_partition_field', status: 'warning', text: 'Cardinality of partition_field "order_id" is above 1000 and might result in high memory usage.', - url: 'https://www.elastic.co/guide/en/machine-learning/mocked-test-branch/ml-ad-finding-anomalies.html#ml-ad-cardinality', + url: 'https://www.elastic.co/guide/en/machine-learning/mocked-test-branch/ml-ad-finding-anomalies.html', }, { heading: 'Bucket span', id: 'bucket_span_high', status: 'info', text: 'Bucket span is 1 day or more. Be aware that days are considered as UTC days, not local days.', - url: 'https://www.elastic.co/guide/en/machine-learning/mocked-test-branch/ml-ad-finding-anomalies.html#ml-ad-bucket-span', + url: 'https://www.elastic.co/guide/en/machine-learning/mocked-test-branch/ml-ad-finding-anomalies.html', }, { bucketSpanCompareFactor: 25, @@ -136,14 +136,14 @@ describe('Constants: Messages parseMessages()', () => { id: 'success_influencers', status: 'success', text: 'Influencer configuration passed the validation checks.', - url: 'https://www.elastic.co/guide/en/machine-learning/mocked-test-branch/ml-ad-finding-anomalies.html#ml-ad-influencers', + url: 'https://www.elastic.co/guide/en/machine-learning/mocked-test-branch/ml-ad-finding-anomalies.html', }, { id: 'half_estimated_mml_greater_than_mml', mml: '1MB', status: 'warning', text: 'The specified model memory limit is less than half of the estimated model memory limit and will likely hit the hard limit.', - url: 'https://www.elastic.co/guide/en/machine-learning/mocked-test-branch/ml-ad-finding-anomalies.html#ml-ad-model-memory-limits', + url: 'https://www.elastic.co/guide/en/machine-learning/mocked-test-branch/ml-ad-finding-anomalies.html', }, { id: 'missing_summary_count_field_name', From 3514fa667aa5a84604cf3f19b2c9be401d5a3bab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20S=C3=A1nchez?= Date: Wed, 19 Jan 2022 11:03:44 +0100 Subject: [PATCH 038/108] Update text button changes (#123170) --- .../pages/event_filters/view/components/flyout/index.tsx | 2 +- .../host_isolation_exceptions/view/components/form_flyout.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/security_solution/public/management/pages/event_filters/view/components/flyout/index.tsx b/x-pack/plugins/security_solution/public/management/pages/event_filters/view/components/flyout/index.tsx index ec0a1308df2a47..9bffd2fc418715 100644 --- a/x-pack/plugins/security_solution/public/management/pages/event_filters/view/components/flyout/index.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/event_filters/view/components/flyout/index.tsx @@ -190,7 +190,7 @@ export const EventFiltersFlyout: React.FC = memo( {id ? ( ) : data ? ( ) : ( Date: Wed, 19 Jan 2022 12:29:21 +0100 Subject: [PATCH 039/108] Update dependency elastic-apm-node to ^3.27.0 (#123322) Co-authored-by: Renovate Bot --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 53eb65b4455fed..07b75529823065 100644 --- a/package.json +++ b/package.json @@ -227,7 +227,7 @@ "deep-freeze-strict": "^1.1.1", "deepmerge": "^4.2.2", "del": "^5.1.0", - "elastic-apm-node": "^3.26.0", + "elastic-apm-node": "^3.27.0", "execa": "^4.0.2", "exit-hook": "^2.2.0", "expiry-js": "0.1.7", diff --git a/yarn.lock b/yarn.lock index 802e94f30ea6c6..b73679a1945c3d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12539,10 +12539,10 @@ elastic-apm-http-client@^10.3.0: readable-stream "^3.4.0" stream-chopper "^3.0.1" -elastic-apm-node@^3.26.0: - version "3.26.0" - resolved "https://registry.yarnpkg.com/elastic-apm-node/-/elastic-apm-node-3.26.0.tgz#551eb425eb85bf16c6ce9567fe92013b038018ab" - integrity sha512-MwYFlBTlcHI8GGQXLnnEm70JJ4RRFkHCY1D3Wt2027l8T/Ye5tgssMSiKyRbjb9bVdibbte73Xn8HF8i35UaxA== +elastic-apm-node@^3.27.0: + version "3.27.0" + resolved "https://registry.yarnpkg.com/elastic-apm-node/-/elastic-apm-node-3.27.0.tgz#0de441e36519e7384e66f6d420ec9a00a2669a1a" + integrity sha512-x8rWjGBgwKYcYN9IQWUv3dzq88RxEVnVIC6KMXQpFkRBG6XtWG4FeMvLaDSeTdXVnDBKTDVGCF9np5HdGhYbBw== dependencies: "@elastic/ecs-pino-format" "^1.2.0" after-all-results "^2.0.0" From 8b40fc2054b36b3b547430ec1bc0bb0893880c46 Mon Sep 17 00:00:00 2001 From: Dmitry Tomashevich <39378793+Dmitriynj@users.noreply.github.com> Date: Wed, 19 Jan 2022 14:58:57 +0300 Subject: [PATCH 040/108] [Discover] Fix saved search hidden chart can't be opened when returning to Discover (#122745) * [Discover] fix hide chart * [Discover] fix unit test * [Discover] fix state persistence on stateContainer updates * [Discover] fix functional tests * [Discover] add functional test * [Discover] apply suggestions * [Discover] return unnecessary code position change Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../main/components/chart/discover_chart.tsx | 26 +++++----- .../components/chart/use_chart_panels.test.ts | 26 +--------- .../main/components/chart/use_chart_panels.ts | 9 ++-- .../components/layout/discover_layout.tsx | 3 +- .../main/utils/get_state_defaults.ts | 4 +- .../main/utils/use_discover_state.test.ts | 46 +--------------- .../main/utils/use_discover_state.ts | 20 ++----- .../apps/discover/_discover_histogram.ts | 52 +++++++++++++++++-- 8 files changed, 78 insertions(+), 108 deletions(-) diff --git a/src/plugins/discover/public/application/main/components/chart/discover_chart.tsx b/src/plugins/discover/public/application/main/components/chart/discover_chart.tsx index abda176ab7b760..0c3d83e256525d 100644 --- a/src/plugins/discover/public/application/main/components/chart/discover_chart.tsx +++ b/src/plugins/discover/public/application/main/components/chart/discover_chart.tsx @@ -18,7 +18,7 @@ import { import { i18n } from '@kbn/i18n'; import { HitsCounter } from '../hits_counter'; import { SavedSearch } from '../../../../services/saved_searches'; -import { AppState, GetStateReturn } from '../../services/discover_state'; +import { GetStateReturn } from '../../services/discover_state'; import { DiscoverHistogram } from './histogram'; import { DataCharts$, DataTotalHits$ } from '../../utils/use_saved_search'; import { DiscoverServices } from '../../../../build_services'; @@ -35,22 +35,24 @@ export function DiscoverChart({ savedSearchDataChart$, savedSearchDataTotalHits$, services, - state, stateContainer, isTimeBased, viewMode, setDiscoverViewMode, + hideChart, + interval, }: { resetSavedSearch: () => void; savedSearch: SavedSearch; savedSearchDataChart$: DataCharts$; savedSearchDataTotalHits$: DataTotalHits$; services: DiscoverServices; - state: AppState; stateContainer: GetStateReturn; isTimeBased: boolean; viewMode: VIEW_MODE; setDiscoverViewMode: (viewMode: VIEW_MODE) => void; + hideChart?: boolean; + interval?: string; }) { const [showChartOptionsPopover, setShowChartOptionsPopover] = useState(false); const showViewModeToggle = services.uiSettings.get(SHOW_FIELD_STATISTICS) ?? false; @@ -74,14 +76,14 @@ export function DiscoverChart({ if (chartRef.current.moveFocus && chartRef.current.element) { chartRef.current.element.focus(); } - }, [state.hideChart]); + }, [hideChart]); const toggleHideChart = useCallback(() => { - const newHideChart = !state.hideChart; - stateContainer.setAppState({ hideChart: newHideChart }); + const newHideChart = !hideChart; chartRef.current.moveFocus = !newHideChart; storage.set(CHART_HIDDEN_KEY, newHideChart); - }, [state.hideChart, stateContainer, storage]); + stateContainer.setAppState({ hideChart: newHideChart }); + }, [hideChart, stateContainer, storage]); const timefilterUpdateHandler = useCallback( (ranges: { from: number; to: number }) => { @@ -94,11 +96,11 @@ export function DiscoverChart({ [data] ); const panels = useChartPanels( - state, - savedSearchDataChart$, toggleHideChart, - (interval) => stateContainer.setAppState({ interval }), - () => setShowChartOptionsPopover(false) + (newInterval) => stateContainer.setAppState({ interval: newInterval }), + () => setShowChartOptionsPopover(false), + hideChart, + interval ); return ( @@ -150,7 +152,7 @@ export function DiscoverChart({ )} - {isTimeBased && !state.hideChart && ( + {isTimeBased && !hideChart && (
(chartRef.current.element = element)} diff --git a/src/plugins/discover/public/application/main/components/chart/use_chart_panels.test.ts b/src/plugins/discover/public/application/main/components/chart/use_chart_panels.test.ts index 20f19ec4719e98..fc6adcd3dd598c 100644 --- a/src/plugins/discover/public/application/main/components/chart/use_chart_panels.test.ts +++ b/src/plugins/discover/public/application/main/components/chart/use_chart_panels.test.ts @@ -9,25 +9,12 @@ import { renderHook } from '@testing-library/react-hooks'; import { useChartPanels } from './use_chart_panels'; -import { AppState } from '../../services/discover_state'; -import { BehaviorSubject } from 'rxjs'; -import { DataCharts$ } from '../../utils/use_saved_search'; -import { FetchStatus } from '../../../types'; import { EuiContextMenuPanelDescriptor } from '@elastic/eui'; describe('test useChartPanels', () => { test('useChartsPanel when hideChart is true', async () => { - const charts$ = new BehaviorSubject({ - fetchStatus: FetchStatus.COMPLETE, - }) as DataCharts$; const { result } = renderHook(() => { - return useChartPanels( - { hideChart: true, interval: 'auto' } as AppState, - charts$, - jest.fn(), - jest.fn(), - jest.fn() - ); + return useChartPanels(jest.fn(), jest.fn(), jest.fn(), true, 'auto'); }); const panels: EuiContextMenuPanelDescriptor[] = result.current; const panel0: EuiContextMenuPanelDescriptor = result.current[0]; @@ -35,17 +22,8 @@ describe('test useChartPanels', () => { expect(panel0!.items![0].icon).toBe('eye'); }); test('useChartsPanel when hideChart is false', async () => { - const charts$ = new BehaviorSubject({ - fetchStatus: FetchStatus.COMPLETE, - }) as DataCharts$; const { result } = renderHook(() => { - return useChartPanels( - { hideChart: false, interval: 'auto' } as AppState, - charts$, - jest.fn(), - jest.fn(), - jest.fn() - ); + return useChartPanels(jest.fn(), jest.fn(), jest.fn(), false, 'auto'); }); const panels: EuiContextMenuPanelDescriptor[] = result.current; const panel0: EuiContextMenuPanelDescriptor = result.current[0]; diff --git a/src/plugins/discover/public/application/main/components/chart/use_chart_panels.ts b/src/plugins/discover/public/application/main/components/chart/use_chart_panels.ts index cf09506c4f552f..30b3089ad2f2cd 100644 --- a/src/plugins/discover/public/application/main/components/chart/use_chart_panels.ts +++ b/src/plugins/discover/public/application/main/components/chart/use_chart_panels.ts @@ -11,17 +11,14 @@ import type { EuiContextMenuPanelDescriptor, } from '@elastic/eui'; import { search } from '../../../../../../data/public'; -import { AppState } from '../../services/discover_state'; -import { DataCharts$ } from '../../utils/use_saved_search'; export function useChartPanels( - state: AppState, - savedSearchDataChart$: DataCharts$, toggleHideChart: () => void, onChangeInterval: (value: string) => void, - closePopover: () => void + closePopover: () => void, + hideChart?: boolean, + interval?: string ) { - const { interval, hideChart } = state; const selectedOptionIdx = search.aggs.intervalOptions.findIndex((opt) => opt.val === interval); const intervalDisplay = selectedOptionIdx > -1 diff --git a/src/plugins/discover/public/application/main/components/layout/discover_layout.tsx b/src/plugins/discover/public/application/main/components/layout/discover_layout.tsx index 881d097f314a8b..e98605326cc32c 100644 --- a/src/plugins/discover/public/application/main/components/layout/discover_layout.tsx +++ b/src/plugins/discover/public/application/main/components/layout/discover_layout.tsx @@ -304,7 +304,6 @@ export function DiscoverLayout({ > diff --git a/src/plugins/discover/public/application/main/utils/get_state_defaults.ts b/src/plugins/discover/public/application/main/utils/get_state_defaults.ts index 4694bec4057b07..10ef04ca8643ef 100644 --- a/src/plugins/discover/public/application/main/utils/get_state_defaults.ts +++ b/src/plugins/discover/public/application/main/utils/get_state_defaults.ts @@ -48,7 +48,7 @@ export function getStateDefaults({ const query = searchSource.getField('query') || data.query.queryString.getDefaultQuery(); const sort = getSortArray(savedSearch.sort ?? [], indexPattern!); const columns = getDefaultColumns(savedSearch, config); - const chartHidden = Boolean(storage.get(CHART_HIDDEN_KEY)); + const chartHidden = storage.get(CHART_HIDDEN_KEY); const defaultState = { query, @@ -59,7 +59,7 @@ export function getStateDefaults({ index: indexPattern?.id, interval: 'auto', filters: cloneDeep(searchSource.getOwnField('filter')), - hideChart: chartHidden ? chartHidden : undefined, + hideChart: typeof chartHidden === 'boolean' ? chartHidden : undefined, viewMode: undefined, hideAggregatedPreview: undefined, savedQuery: undefined, diff --git a/src/plugins/discover/public/application/main/utils/use_discover_state.test.ts b/src/plugins/discover/public/application/main/utils/use_discover_state.test.ts index bac6d085acf05b..e77ea5787705ff 100644 --- a/src/plugins/discover/public/application/main/utils/use_discover_state.test.ts +++ b/src/plugins/discover/public/application/main/utils/use_discover_state.test.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { renderHook, act } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react-hooks'; import { createSearchSessionMock } from '../../../__mocks__/search_session'; import { discoverServiceMock } from '../../../__mocks__/services'; import { savedSearchMock } from '../../../__mocks__/saved_search'; @@ -42,50 +42,6 @@ describe('test useDiscoverState', () => { }); expect(result.current.state.index).toBe(indexPatternMock.id); expect(result.current.stateContainer).toBeInstanceOf(Object); - expect(result.current.setState).toBeInstanceOf(Function); expect(result.current.searchSource).toBeInstanceOf(SearchSource); }); - - test('setState', async () => { - const { history } = createSearchSessionMock(); - - const { result } = renderHook(() => { - return useDiscoverState({ - services: discoverServiceMock, - history, - savedSearch: savedSearchMock, - setExpandedDoc: jest.fn(), - }); - }); - await act(async () => { - result.current.setState({ columns: ['123'] }); - }); - expect(result.current.state.columns).toEqual(['123']); - }); - - test('resetSavedSearch', async () => { - const { history } = createSearchSessionMock(); - - const { result, waitForValueToChange } = renderHook(() => { - return useDiscoverState({ - services: discoverServiceMock, - history, - savedSearch: savedSearchMock, - setExpandedDoc: jest.fn(), - }); - }); - - const initialColumns = result.current.state.columns; - await act(async () => { - result.current.setState({ columns: ['123'] }); - }); - expect(result.current.state.columns).toEqual(['123']); - - result.current.resetSavedSearch('the-saved-search-id'); - await waitForValueToChange(() => { - return result.current.state; - }); - - expect(result.current.state.columns).toEqual(initialColumns); - }); }); diff --git a/src/plugins/discover/public/application/main/utils/use_discover_state.ts b/src/plugins/discover/public/application/main/utils/use_discover_state.ts index f5270e9f306df3..baf0195c4539c0 100644 --- a/src/plugins/discover/public/application/main/utils/use_discover_state.ts +++ b/src/plugins/discover/public/application/main/utils/use_discover_state.ts @@ -99,8 +99,13 @@ export function useDiscoverState({ useNewFieldsApi, }); + /** + * Sync URL state with local app state on saved search load + * or dataView / savedSearch switch + */ useEffect(() => { const stopSync = stateContainer.initializeAndSync(indexPattern, filterManager, data); + setState(stateContainer.appStateContainer.getState()); return () => stopSync(); }, [stateContainer, filterManager, data, indexPattern]); @@ -207,21 +212,6 @@ export function useDiscoverState({ [refetch$, searchSessionManager] ); - useEffect(() => { - if (!savedSearch || !savedSearch.id) { - return; - } - // handling pushing to state of a persisted saved object - const newAppState = getStateDefaults({ - config, - data, - savedSearch, - storage, - }); - stateContainer.replaceUrlAppState(newAppState); - setState(newAppState); - }, [config, data, savedSearch, reset, stateContainer, storage]); - /** * Trigger data fetching on indexPattern or savedSearch changes */ diff --git a/test/functional/apps/discover/_discover_histogram.ts b/test/functional/apps/discover/_discover_histogram.ts index 62d6ede323054e..5932e995421afa 100644 --- a/test/functional/apps/discover/_discover_histogram.ts +++ b/test/functional/apps/discover/_discover_histogram.ts @@ -102,20 +102,28 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const to = 'Mar 21, 2019 @ 00:00:00.000'; const savedSearch = 'persisted hidden histogram'; await prepareTest({ from, to }); + + // close chart for saved search await testSubjects.click('discoverChartOptionsToggle'); await testSubjects.click('discoverChartToggle'); let canvasExists = await elasticChart.canvasExists(); expect(canvasExists).to.be(false); + + // save search await PageObjects.discover.saveSearch(savedSearch); await PageObjects.header.waitUntilLoadingHasFinished(); + // open new search await PageObjects.discover.clickNewSearchButton(); await PageObjects.header.waitUntilLoadingHasFinished(); - await PageObjects.discover.loadSavedSearch('persisted hidden histogram'); + // load saved search + await PageObjects.discover.loadSavedSearch(savedSearch); await PageObjects.header.waitUntilLoadingHasFinished(); canvasExists = await elasticChart.canvasExists(); expect(canvasExists).to.be(false); + + // open chart for saved search await testSubjects.click('discoverChartOptionsToggle'); await testSubjects.click('discoverChartToggle'); await retry.waitFor(`Discover histogram to be displayed`, async () => { @@ -123,14 +131,52 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { return canvasExists; }); - await PageObjects.discover.saveSearch('persisted hidden histogram'); + // save search + await PageObjects.discover.saveSearch(savedSearch); await PageObjects.header.waitUntilLoadingHasFinished(); + // open new search await PageObjects.discover.clickNewSearchButton(); - await PageObjects.discover.loadSavedSearch('persisted hidden histogram'); + await PageObjects.header.waitUntilLoadingHasFinished(); + + // load saved search + await PageObjects.discover.loadSavedSearch(savedSearch); + await PageObjects.header.waitUntilLoadingHasFinished(); + canvasExists = await elasticChart.canvasExists(); + expect(canvasExists).to.be(true); + }); + it('should show permitted hidden histogram state when returning back to discover', async () => { + // close chart + await testSubjects.click('discoverChartOptionsToggle'); + await testSubjects.click('discoverChartToggle'); + let canvasExists = await elasticChart.canvasExists(); + expect(canvasExists).to.be(false); + + // save search + await PageObjects.discover.saveSearch('persisted hidden histogram'); + await PageObjects.header.waitUntilLoadingHasFinished(); + + // open chart + await testSubjects.click('discoverChartOptionsToggle'); + await testSubjects.click('discoverChartToggle'); + canvasExists = await elasticChart.canvasExists(); + expect(canvasExists).to.be(true); + + // go to dashboard + await PageObjects.common.navigateToApp('dashboard'); + await PageObjects.header.waitUntilLoadingHasFinished(); + + // go to discover + await PageObjects.common.navigateToApp('discover'); await PageObjects.header.waitUntilLoadingHasFinished(); canvasExists = await elasticChart.canvasExists(); expect(canvasExists).to.be(true); + + // close chart + await testSubjects.click('discoverChartOptionsToggle'); + await testSubjects.click('discoverChartToggle'); + canvasExists = await elasticChart.canvasExists(); + expect(canvasExists).to.be(false); }); }); } From 3280400b7418af5f3087e3908a5cd72071c18df3 Mon Sep 17 00:00:00 2001 From: Miriam <31922082+MiriamAparicio@users.noreply.github.com> Date: Wed, 19 Jan 2022 13:56:06 +0000 Subject: [PATCH 041/108] Improve copy in update jobs callout (#123355) Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../plugins/apm/public/components/shared/ml_callout/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/apm/public/components/shared/ml_callout/index.tsx b/x-pack/plugins/apm/public/components/shared/ml_callout/index.tsx index 9fa8bb5f04960e..e169b653cffb02 100644 --- a/x-pack/plugins/apm/public/components/shared/ml_callout/index.tsx +++ b/x-pack/plugins/apm/public/components/shared/ml_callout/index.tsx @@ -107,7 +107,7 @@ export function MLCallout({ ), text: i18n.translate('xpack.apm.mlCallout.updateAvailableCalloutText', { defaultMessage: - 'We have updated the anomaly detection jobs that provide insights into degraded performance and added detectors for throughput and failed transaction rate. If you choose to upgrade, we will create the new jobs and close the existing legacy jobs. The data shown in the APM app will automatically switch to the new.', + 'We have updated the anomaly detection jobs that provide insights into degraded performance and added detectors for throughput and failed transaction rate. If you choose to upgrade, we will create the new jobs and close the existing legacy jobs. The data shown in the APM app will automatically switch to the new. Please note that the option to migrate all existing jobs will not be available if you choose to create a new job.', }), color: 'success', icon: 'wrench', From d1eb0df19097d2e173abcc03ebd7c906581af088 Mon Sep 17 00:00:00 2001 From: Jonathan Buttner <56361221+jonathan-buttner@users.noreply.github.com> Date: Wed, 19 Jan 2022 09:27:26 -0500 Subject: [PATCH 042/108] [ResponseOps][Cases] Set case alert attachment rule info to null (#123094) * Setting rule info to null * Renaming variables * Addressing PR feedback Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../user_actions/comment/alert.test.tsx | 138 ++++++++++++ .../components/user_actions/comment/alert.tsx | 72 +++++-- .../migrations/comments.test.ts | 77 +++++++ .../saved_object_types/migrations/comments.ts | 35 +++ .../migrations/user_actions/alerts.test.ts | 181 ++++++++++++++++ .../migrations/user_actions/alerts.ts | 99 +++++++++ .../migrations/user_actions/connector_id.ts | 6 +- .../migrations/user_actions/index.ts | 2 + .../migrations/user_actions/types.ts | 2 +- .../tests/common/comments/migrations.ts | 42 +++- .../tests/common/user_actions/migrations.ts | 49 ++++- .../kbn_archiver/cases/7.13.2/alerts.json | 202 ++++++++++++++++++ 12 files changed, 882 insertions(+), 23 deletions(-) create mode 100644 x-pack/plugins/cases/public/components/user_actions/comment/alert.test.tsx create mode 100644 x-pack/plugins/cases/server/saved_object_types/migrations/user_actions/alerts.test.ts create mode 100644 x-pack/plugins/cases/server/saved_object_types/migrations/user_actions/alerts.ts create mode 100644 x-pack/test/functional/fixtures/kbn_archiver/cases/7.13.2/alerts.json diff --git a/x-pack/plugins/cases/public/components/user_actions/comment/alert.test.tsx b/x-pack/plugins/cases/public/components/user_actions/comment/alert.test.tsx new file mode 100644 index 00000000000000..bdffe3c50c4a44 --- /dev/null +++ b/x-pack/plugins/cases/public/components/user_actions/comment/alert.test.tsx @@ -0,0 +1,138 @@ +/* + * 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 { CommentResponseAlertsType } from '../../../../common/api'; +import { SnakeToCamelCase } from '../../../../common/types'; +import { getRuleId, getRuleName } from './alert'; +import { Ecs } from '../../../containers/types'; + +describe('rule getters', () => { + describe.each([ + ['getRuleId', getRuleId], + ['getRuleName', getRuleName], + ])('%s null checks', (name, funcToExec) => { + it('returns null if the comment field is an empty string', () => { + const comment = { + rule: { + id: '', + name: '', + }, + } as unknown as SnakeToCamelCase; + + expect(funcToExec(comment)).toBeNull(); + }); + + it('returns null if the comment field is an empty string in an array', () => { + const comment = { + rule: { + id: [''], + name: [''], + }, + } as unknown as SnakeToCamelCase; + + expect(funcToExec(comment)).toBeNull(); + }); + + it('returns null if the comment does not have a rule field', () => { + const comment = {} as unknown as SnakeToCamelCase; + + expect(funcToExec(comment)).toBeNull(); + }); + + it('returns null if the signals and alert field is an empty string', () => { + const comment = {} as unknown as SnakeToCamelCase; + const alert = { + signal: { rule: { id: '', name: '' } }, + kibana: { alert: { rule: { uuid: '', name: '' } } }, + } as unknown as Ecs; + + expect(funcToExec(comment, alert)).toBeNull(); + }); + }); + + describe.each([ + ['getRuleId', getRuleId, '1'], + ['getRuleName', getRuleName, 'Rule name1'], + ])('%s', (name, funcToExec, expectedResult) => { + it('returns the first entry in the comment field', () => { + const comment = { + rule: { + id: ['1', '2'], + name: ['Rule name1', 'Rule name2'], + }, + } as unknown as SnakeToCamelCase; + + expect(funcToExec(comment)).toEqual(expectedResult); + }); + + it('returns signal field', () => { + const comment = {} as unknown as SnakeToCamelCase; + const alert = { signal: { rule: { id: '1', name: 'Rule name1' } } } as unknown as Ecs; + + expect(funcToExec(comment, alert)).toEqual(expectedResult); + }); + + it('returns kibana alert field', () => { + const comment = {} as unknown as SnakeToCamelCase; + const alert = { + kibana: { alert: { rule: { uuid: '1', name: 'Rule name1' } } }, + } as unknown as Ecs; + + expect(funcToExec(comment, alert)).toEqual(expectedResult); + }); + + it('returns signal field even when kibana alert field is defined', () => { + const comment = {} as unknown as SnakeToCamelCase; + const alert = { + signal: { rule: { id: '1', name: 'Rule name1' } }, + kibana: { alert: { rule: { uuid: 'rule id1', name: 'other rule name1' } } }, + } as unknown as Ecs; + + expect(funcToExec(comment, alert)).toEqual(expectedResult); + }); + + it('returns the first entry in the signals field', () => { + const comment = {} as unknown as SnakeToCamelCase; + const alert = { + signal: { rule: { id: '1', name: 'Rule name1' } }, + kibana: { alert: { rule: { uuid: 'rule id1', name: 'other rule name1' } } }, + } as unknown as Ecs; + + expect(funcToExec(comment, alert)).toEqual(expectedResult); + }); + + it('returns the alert field if the signals field is an empty string', () => { + const comment = {} as unknown as SnakeToCamelCase; + const alert = { + signal: { rule: { id: '', name: '' } }, + kibana: { alert: { rule: { uuid: '1', name: 'Rule name1' } } }, + } as unknown as Ecs; + + expect(funcToExec(comment, alert)).toEqual(expectedResult); + }); + + it('returns the alert field if the signals field is an empty string in an array', () => { + const comment = {} as unknown as SnakeToCamelCase; + const alert = { + signal: { rule: { id: [''], name: [''] } }, + kibana: { alert: { rule: { uuid: '1', name: 'Rule name1' } } }, + } as unknown as Ecs; + + expect(funcToExec(comment, alert)).toEqual(expectedResult); + }); + + it('returns the alert field first item if the signals field is an empty string in an array', () => { + const comment = {} as unknown as SnakeToCamelCase; + const alert = { + signal: { rule: { id: [''], name: [''] } }, + kibana: { alert: { rule: { uuid: ['1', '2'], name: ['Rule name1', 'Rule name2'] } } }, + } as unknown as Ecs; + + expect(funcToExec(comment, alert)).toEqual(expectedResult); + }); + }); +}); diff --git a/x-pack/plugins/cases/public/components/user_actions/comment/alert.tsx b/x-pack/plugins/cases/public/components/user_actions/comment/alert.tsx index 0341af259e4022..91752261d1471d 100644 --- a/x-pack/plugins/cases/public/components/user_actions/comment/alert.tsx +++ b/x-pack/plugins/cases/public/components/user_actions/comment/alert.tsx @@ -18,6 +18,7 @@ import { UserActionUsernameWithAvatar } from '../avatar_username'; import { AlertCommentEvent } from './alert_event'; import { UserActionCopyLink } from '../copy_link'; import { UserActionShowAlert } from './show_alert'; +import { Ecs } from '../../../containers/types'; type BuilderArgs = Pick< UserActionBuilderArgs, @@ -29,9 +30,6 @@ type BuilderArgs = Pick< | 'onShowAlertDetails' > & { comment: SnakeToCamelCase }; -const getFirstItem = (items: string | string[]) => - Array.isArray(items) ? (items.length > 0 ? items[0] : '') : items; - export const createAlertAttachmentUserActionBuilder = ({ userAction, comment, @@ -42,24 +40,16 @@ export const createAlertAttachmentUserActionBuilder = ({ onShowAlertDetails, }: BuilderArgs): ReturnType => ({ build: () => { - const alertId = getFirstItem(comment.alertId); - const alertIndex = getFirstItem(comment.index); + const alertId = getNonEmptyField(comment.alertId); + const alertIndex = getNonEmptyField(comment.index); - if (isEmpty(alertId)) { + if (!alertId || !alertIndex) { return []; } - const ruleId = - comment?.rule?.id ?? - alertData[alertId]?.signal?.rule?.id?.[0] ?? - get(alertData[alertId], ALERT_RULE_UUID)[0] ?? - null; - - const ruleName = - comment?.rule?.name ?? - alertData[alertId]?.signal?.rule?.name?.[0] ?? - get(alertData[alertId], ALERT_RULE_NAME)[0] ?? - null; + const alertField: Ecs | undefined = alertData[alertId]; + const ruleId = getRuleId(comment, alertField); + const ruleName = getRuleName(comment, alertField); return [ { @@ -104,3 +94,51 @@ export const createAlertAttachmentUserActionBuilder = ({ ]; }, }); + +const getFirstItem = (items?: string | string[] | null): string | null => { + return Array.isArray(items) ? items[0] : items ?? null; +}; + +export const getRuleId = (comment: BuilderArgs['comment'], alertData?: Ecs): string | null => + getRuleField({ + commentRuleField: comment?.rule?.id, + alertData, + signalRuleFieldPath: 'signal.rule.id', + kibanaAlertFieldPath: ALERT_RULE_UUID, + }); + +export const getRuleName = (comment: BuilderArgs['comment'], alertData?: Ecs): string | null => + getRuleField({ + commentRuleField: comment?.rule?.name, + alertData, + signalRuleFieldPath: 'signal.rule.name', + kibanaAlertFieldPath: ALERT_RULE_NAME, + }); + +const getRuleField = ({ + commentRuleField, + alertData, + signalRuleFieldPath, + kibanaAlertFieldPath, +}: { + commentRuleField: string | string[] | null | undefined; + alertData: Ecs | undefined; + signalRuleFieldPath: string; + kibanaAlertFieldPath: string; +}): string | null => { + const field = + getNonEmptyField(commentRuleField) ?? + getNonEmptyField(get(alertData, signalRuleFieldPath)) ?? + getNonEmptyField(get(alertData, kibanaAlertFieldPath)); + + return field; +}; + +function getNonEmptyField(field: string | string[] | undefined | null): string | null { + const firstItem = getFirstItem(field); + if (firstItem == null || isEmpty(firstItem)) { + return null; + } + + return firstItem; +} diff --git a/x-pack/plugins/cases/server/saved_object_types/migrations/comments.test.ts b/x-pack/plugins/cases/server/saved_object_types/migrations/comments.test.ts index 1983ae0db51d31..77a9382f123895 100644 --- a/x-pack/plugins/cases/server/saved_object_types/migrations/comments.test.ts +++ b/x-pack/plugins/cases/server/saved_object_types/migrations/comments.test.ts @@ -9,12 +9,14 @@ import { createCommentsMigrations, mergeMigrationFunctionMaps, migrateByValueLensVisualizations, + removeRuleInformation, stringifyCommentWithoutTrailingNewline, } from './comments'; import { getLensVisualizations, parseCommentString, } from '../../../common/utils/markdown_plugins/utils'; +import { CommentType } from '../../../common/api'; import { savedObjectsServiceMock } from '../../../../../../src/core/server/mocks'; import { makeLensEmbeddableFactory } from '../../../../lens/server/embeddable/make_lens_embeddable_factory'; @@ -396,4 +398,79 @@ describe('comments migrations', () => { ); }); }); + + describe('removeRuleInformation', () => { + it('does not modify non-alert comment', () => { + const doc = { + id: '123', + attributes: { + type: 'user', + }, + type: 'abc', + references: [], + }; + + expect(removeRuleInformation(doc)).toEqual(doc); + }); + + it('sets the rule fields to null', () => { + const doc = { + id: '123', + type: 'abc', + attributes: { + type: CommentType.alert, + rule: { + id: '123', + name: 'hello', + }, + }, + }; + + expect(removeRuleInformation(doc)).toEqual({ + ...doc, + attributes: { ...doc.attributes, rule: { id: null, name: null } }, + references: [], + }); + }); + + it('sets the rule fields to null for a generated alert', () => { + const doc = { + id: '123', + type: 'abc', + attributes: { + type: CommentType.generatedAlert, + rule: { + id: '123', + name: 'hello', + }, + }, + }; + + expect(removeRuleInformation(doc)).toEqual({ + ...doc, + attributes: { ...doc.attributes, rule: { id: null, name: null } }, + references: [], + }); + }); + + it('preserves the references field', () => { + const doc = { + id: '123', + type: 'abc', + attributes: { + type: CommentType.alert, + rule: { + id: '123', + name: 'hello', + }, + }, + references: [{ id: '123', name: 'hi', type: 'awesome' }], + }; + + expect(removeRuleInformation(doc)).toEqual({ + ...doc, + attributes: { ...doc.attributes, rule: { id: null, name: null } }, + }); + }); + }); }); diff --git a/x-pack/plugins/cases/server/saved_object_types/migrations/comments.ts b/x-pack/plugins/cases/server/saved_object_types/migrations/comments.ts index 0af9db13fce406..5ab1dab784f56f 100644 --- a/x-pack/plugins/cases/server/saved_object_types/migrations/comments.ts +++ b/x-pack/plugins/cases/server/saved_object_types/migrations/comments.ts @@ -98,6 +98,15 @@ export const createCommentsMigrations = ( ): SavedObjectSanitizedDoc => { return addOwnerToSO(doc); }, + /* + * This is to fix the issue here: https://github.com/elastic/kibana/issues/123089 + * Instead of migrating the rule information in the references array which was risky for 8.0 + * we decided to remove the information since the UI will do the look up for the rule information if + * the backend returns it as null. + * + * The downside is it incurs extra query overhead. + **/ + '8.0.0': removeRuleInformation, }; return mergeMigrationFunctionMaps(commentsMigrations, embeddableMigrations); @@ -175,3 +184,29 @@ export const mergeMigrationFunctionMaps = ( return mergeWith({ ...obj1 }, obj2, customizer); }; + +export const removeRuleInformation = ( + doc: SavedObjectUnsanitizedDoc> +): SavedObjectSanitizedDoc => { + if ( + doc.attributes.type === CommentType.alert || + doc.attributes.type === CommentType.generatedAlert + ) { + return { + ...doc, + attributes: { + ...doc.attributes, + rule: { + id: null, + name: null, + }, + }, + references: doc.references ?? [], + }; + } + + return { + ...doc, + references: doc.references ?? [], + }; +}; diff --git a/x-pack/plugins/cases/server/saved_object_types/migrations/user_actions/alerts.test.ts b/x-pack/plugins/cases/server/saved_object_types/migrations/user_actions/alerts.test.ts new file mode 100644 index 00000000000000..77059d5b3c3380 --- /dev/null +++ b/x-pack/plugins/cases/server/saved_object_types/migrations/user_actions/alerts.test.ts @@ -0,0 +1,181 @@ +/* + * 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 { + SavedObject, + SavedObjectMigrationContext, + SavedObjectsMigrationLogger, +} from 'kibana/server'; +import { cloneDeep, omit } from 'lodash'; +import { migrationMocks } from 'src/core/server/mocks'; +import { removeRuleInformation } from './alerts'; + +describe('alert user actions', () => { + describe('removeRuleInformation', () => { + let context: jest.Mocked; + + beforeEach(() => { + context = migrationMocks.createContext(); + }); + + it('does not modify non-alert user action', () => { + const doc = { + id: '123', + attributes: { + action: 'create', + action_field: ['description'], + }, + type: 'abc', + references: [], + }; + + expect(removeRuleInformation(doc, context)).toEqual(doc); + }); + + it('does not modify the document when it fails to decode the new_value field', () => { + const doc = { + id: '123', + attributes: { + action: 'create', + action_field: ['comment'], + new_value: '{"type":"alert",', + }, + type: 'abc', + references: [], + }; + + expect(removeRuleInformation(doc, context)).toEqual(doc); + + const log = context.log as jest.Mocked; + expect(log.error.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + "Failed to migrate user action alerts with doc id: 123 version: 8.0.0 error: Unexpected end of JSON input", + Object { + "migrations": Object { + "userAction": Object { + "id": "123", + }, + }, + }, + ] + `); + }); + + it('does not modify the document when new_value is null', () => { + const doc = { + id: '123', + attributes: { + action: 'create', + action_field: ['comment'], + new_value: null, + }, + type: 'abc', + references: [], + }; + + expect(removeRuleInformation(doc, context)).toEqual(doc); + }); + + it('does not modify the document when new_value is undefined', () => { + const doc = { + id: '123', + attributes: { + action: 'create', + action_field: ['comment'], + }, + type: 'abc', + references: [], + }; + + expect(removeRuleInformation(doc, context)).toEqual(doc); + }); + + it('does not modify the document when the comment type is not an alert', () => { + const doc = { + id: '123', + attributes: { + action: 'create', + action_field: ['comment'], + new_value: + '{"type":"not_an_alert","alertId":"4eb4cd05b85bc65c7b9f22b776e0136f970f7538eb0d1b2e6e8c7d35b2e875cb","index":".internal.alerts-security.alerts-default-000001","rule":{"id":"43104810-7875-11ec-abc6-6f72e72f6004","name":"A rule"},"owner":"securitySolution"}', + }, + type: 'abc', + references: [], + }; + + expect(removeRuleInformation(doc, context)).toEqual(doc); + }); + + it('sets the rule fields to null', () => { + const doc = { + id: '123', + attributes: { + action: 'create', + action_field: ['comment'], + new_value: + '{"type":"alert","alertId":"4eb4cd05b85bc65c7b9f22b776e0136f970f7538eb0d1b2e6e8c7d35b2e875cb","index":".internal.alerts-security.alerts-default-000001","rule":{"id":"43104810-7875-11ec-abc6-6f72e72f6004","name":"A rule"},"owner":"securitySolution"}', + }, + type: 'abc', + references: [], + }; + + const newDoc = removeRuleInformation(doc, context) as SavedObject<{ new_value: string }>; + ensureRuleFieldsAreNull(newDoc); + + expect(docWithoutNewValue(newDoc)).toEqual(docWithoutNewValue(doc)); + }); + + it('sets the rule fields to null for a generated alert', () => { + const doc = { + id: '123', + attributes: { + action: 'create', + action_field: ['comment'], + new_value: + '{"type":"generated_alert","alertId":"4eb4cd05b85bc65c7b9f22b776e0136f970f7538eb0d1b2e6e8c7d35b2e875cb","index":".internal.alerts-security.alerts-default-000001","rule":{"id":"43104810-7875-11ec-abc6-6f72e72f6004","name":"A rule"},"owner":"securitySolution"}', + }, + type: 'abc', + references: [], + }; + + const newDoc = removeRuleInformation(doc, context) as SavedObject<{ new_value: string }>; + ensureRuleFieldsAreNull(newDoc); + + expect(docWithoutNewValue(newDoc)).toEqual(docWithoutNewValue(doc)); + }); + + it('preserves the references field', () => { + const doc = { + id: '123', + attributes: { + action: 'create', + action_field: ['comment'], + new_value: + '{"type":"generated_alert","alertId":"4eb4cd05b85bc65c7b9f22b776e0136f970f7538eb0d1b2e6e8c7d35b2e875cb","index":".internal.alerts-security.alerts-default-000001","rule":{"id":"43104810-7875-11ec-abc6-6f72e72f6004","name":"A rule"},"owner":"securitySolution"}', + }, + type: 'abc', + references: [{ id: '123', name: 'hi', type: 'awesome' }], + }; + + const newDoc = removeRuleInformation(doc, context) as SavedObject<{ new_value: string }>; + ensureRuleFieldsAreNull(newDoc); + + expect(docWithoutNewValue(newDoc)).toEqual(docWithoutNewValue(doc)); + }); + }); +}); + +const docWithoutNewValue = (doc: {}) => { + const copyOfDoc = cloneDeep(doc); + return omit(copyOfDoc, 'attributes.new_value'); +}; + +const ensureRuleFieldsAreNull = (doc: SavedObject<{ new_value: string }>) => { + const decodedNewValue = JSON.parse(doc.attributes.new_value); + + expect(decodedNewValue.rule).toEqual({ id: null, name: null }); +}; diff --git a/x-pack/plugins/cases/server/saved_object_types/migrations/user_actions/alerts.ts b/x-pack/plugins/cases/server/saved_object_types/migrations/user_actions/alerts.ts new file mode 100644 index 00000000000000..b2a825b80fd6e4 --- /dev/null +++ b/x-pack/plugins/cases/server/saved_object_types/migrations/user_actions/alerts.ts @@ -0,0 +1,99 @@ +/* + * 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 { + SavedObjectMigrationContext, + SavedObjectSanitizedDoc, + SavedObjectUnsanitizedDoc, +} from 'kibana/server'; +import { CommentRequestAlertType, CommentType } from '../../../../common/api'; +import { logError } from '../utils'; +import { UserActionVersion800 } from './types'; + +/* eslint-disable @typescript-eslint/naming-convention */ + +export function removeRuleInformation( + doc: SavedObjectUnsanitizedDoc, + context: SavedObjectMigrationContext +): SavedObjectSanitizedDoc { + const originalDocWithReferences = { ...doc, references: doc.references ?? [] }; + + try { + const { new_value, action, action_field } = doc.attributes; + + const decodedNewValueData = decodeNewValue(new_value); + + if (!isAlertUserAction(action, action_field, decodedNewValueData)) { + return originalDocWithReferences; + } + + const encodedValue = JSON.stringify({ + ...decodedNewValueData, + rule: { + id: null, + name: null, + }, + }); + + return { + ...doc, + attributes: { + ...doc.attributes, + new_value: encodedValue, + }, + references: doc.references ?? [], + }; + } catch (error) { + logError({ + id: doc.id, + context, + error, + docType: 'user action alerts', + docKey: 'userAction', + }); + + return originalDocWithReferences; + } +} + +function decodeNewValue(data?: string | null): unknown | null { + if (data === undefined || data === null) { + return null; + } + + return JSON.parse(data); +} + +function isAlertUserAction( + action?: string, + actionFields?: string[], + newValue?: unknown | null +): newValue is AlertCommentOptional { + return isCreateComment(action, actionFields) && isAlertObject(newValue); +} + +function isCreateComment(action?: string, actionFields?: string[]): boolean { + return ( + action === 'create' && + actionFields !== null && + actionFields !== undefined && + actionFields.includes('comment') + ); +} + +type AlertCommentOptional = Partial; + +function isAlertObject(data?: unknown | null): boolean { + const unsafeAlertData = data as AlertCommentOptional; + + return ( + unsafeAlertData !== undefined && + unsafeAlertData !== null && + (unsafeAlertData.type === CommentType.generatedAlert || + unsafeAlertData.type === CommentType.alert) + ); +} diff --git a/x-pack/plugins/cases/server/saved_object_types/migrations/user_actions/connector_id.ts b/x-pack/plugins/cases/server/saved_object_types/migrations/user_actions/connector_id.ts index 1c61b7162a0624..00261cd5782394 100644 --- a/x-pack/plugins/cases/server/saved_object_types/migrations/user_actions/connector_id.ts +++ b/x-pack/plugins/cases/server/saved_object_types/migrations/user_actions/connector_id.ts @@ -28,7 +28,7 @@ import { } from '../../../common/constants'; import { getNoneCaseConnector } from '../../../common/utils'; import { ACTION_SAVED_OBJECT_TYPE } from '../../../../../actions/server'; -import { UserActionUnmigratedConnectorDocument } from './types'; +import { UserActionVersion800 } from './types'; import { logError } from '../utils'; import { USER_ACTION_OLD_ID_REF_NAME, USER_ACTION_OLD_PUSH_ID_REF_NAME } from './constants'; @@ -306,7 +306,7 @@ export function isConnectorUserAction(action?: string, actionFields?: string[]): } export function formatDocumentWithConnectorReferences( - doc: SavedObjectUnsanitizedDoc + doc: SavedObjectUnsanitizedDoc ): SavedObjectSanitizedDoc { const { new_value, old_value, action, action_field, ...restAttributes } = doc.attributes; const { references = [] } = doc; @@ -342,7 +342,7 @@ export function formatDocumentWithConnectorReferences( // 8.1.0 migration util functions export function userActionsConnectorIdMigration( - doc: SavedObjectUnsanitizedDoc, + doc: SavedObjectUnsanitizedDoc, context: SavedObjectMigrationContext ): SavedObjectSanitizedDoc { const originalDocWithReferences = { ...doc, references: doc.references ?? [] }; diff --git a/x-pack/plugins/cases/server/saved_object_types/migrations/user_actions/index.ts b/x-pack/plugins/cases/server/saved_object_types/migrations/user_actions/index.ts index 7288b68483b87b..d977e470a7fe3d 100644 --- a/x-pack/plugins/cases/server/saved_object_types/migrations/user_actions/index.ts +++ b/x-pack/plugins/cases/server/saved_object_types/migrations/user_actions/index.ts @@ -14,6 +14,7 @@ import { } from '../../../../../../../src/core/server'; import { ConnectorTypes } from '../../../../common/api'; +import { removeRuleInformation } from './alerts'; import { userActionsConnectorIdMigration } from './connector_id'; import { payloadMigration } from './payload'; import { UserActions } from './types'; @@ -63,5 +64,6 @@ export const userActionsMigrations = { return addOwnerToSO(doc); }, '7.16.0': userActionsConnectorIdMigration, + '8.0.0': removeRuleInformation, '8.1.0': payloadMigration, }; diff --git a/x-pack/plugins/cases/server/saved_object_types/migrations/user_actions/types.ts b/x-pack/plugins/cases/server/saved_object_types/migrations/user_actions/types.ts index 65f566143b0eef..0c905dc784b11b 100644 --- a/x-pack/plugins/cases/server/saved_object_types/migrations/user_actions/types.ts +++ b/x-pack/plugins/cases/server/saved_object_types/migrations/user_actions/types.ts @@ -15,7 +15,7 @@ export interface UserActions { owner: string; } -export interface UserActionUnmigratedConnectorDocument { +export interface UserActionVersion800 { action?: string; action_field?: string[]; new_value?: string | null; diff --git a/x-pack/test/cases_api_integration/security_and_spaces/tests/common/comments/migrations.ts b/x-pack/test/cases_api_integration/security_and_spaces/tests/common/comments/migrations.ts index 67e30987fabaca..0711b78159d077 100644 --- a/x-pack/test/cases_api_integration/security_and_spaces/tests/common/comments/migrations.ts +++ b/x-pack/test/cases_api_integration/security_and_spaces/tests/common/comments/migrations.ts @@ -11,12 +11,15 @@ import { CASES_URL, SECURITY_SOLUTION_OWNER, } from '../../../../../../plugins/cases/common/constants'; -import { getComment } from '../../../../common/lib/utils'; +import { deleteAllCaseItems, getComment } from '../../../../common/lib/utils'; +import { CommentResponseAlertsType } from '../../../../../../plugins/cases/common/api'; // eslint-disable-next-line import/no-default-export export default function createGetTests({ getService }: FtrProviderContext) { const supertest = getService('supertest'); const esArchiver = getService('esArchiver'); + const es = getService('es'); + const kibanaServer = getService('kibanaServer'); describe('migrations', () => { describe('7.11.0', () => { @@ -59,5 +62,42 @@ export default function createGetTests({ getService }: FtrProviderContext) { expect(comment.owner).to.be(SECURITY_SOLUTION_OWNER); }); }); + + describe('8.0.0', () => { + before(async () => { + await kibanaServer.importExport.load( + 'x-pack/test/functional/fixtures/kbn_archiver/cases/7.13.2/alerts.json' + ); + }); + + after(async () => { + await kibanaServer.importExport.unload( + 'x-pack/test/functional/fixtures/kbn_archiver/cases/7.13.2/alerts.json' + ); + await deleteAllCaseItems(es); + }); + + it('removes the rule information from alert attachments', async () => { + const comment = (await getComment({ + supertest, + caseId: 'e49ad6e0-cf9d-11eb-a603-13e7747d215c', + commentId: 'ee59cdd0-cf9d-11eb-a603-13e7747d215c', + })) as CommentResponseAlertsType; + + expect(comment).to.have.property('rule'); + expect(comment.rule.id).to.be(null); + expect(comment.rule.name).to.be(null); + }); + + it('does not modify non-alert attachments', async () => { + const comment = (await getComment({ + supertest, + caseId: 'e49ad6e0-cf9d-11eb-a603-13e7747d215c', + commentId: 'ae59cdd0-cf9d-11eb-a603-13e7747d215c', + })) as CommentResponseAlertsType; + + expect(comment).to.not.have.property('rule'); + }); + }); }); } diff --git a/x-pack/test/cases_api_integration/security_and_spaces/tests/common/user_actions/migrations.ts b/x-pack/test/cases_api_integration/security_and_spaces/tests/common/user_actions/migrations.ts index 62d1ba17ff4db2..782af13ca6b5f7 100644 --- a/x-pack/test/cases_api_integration/security_and_spaces/tests/common/user_actions/migrations.ts +++ b/x-pack/test/cases_api_integration/security_and_spaces/tests/common/user_actions/migrations.ts @@ -12,7 +12,7 @@ import { SECURITY_SOLUTION_OWNER, } from '../../../../../../plugins/cases/common/constants'; import { deleteAllCaseItems, getCaseUserActions } from '../../../../common/lib/utils'; -import { CaseUserActionsResponse } from '../../../../../../plugins/cases/common/api'; +import { CaseUserActionsResponse, CommentType } from '../../../../../../plugins/cases/common/api'; // eslint-disable-next-line import/no-default-export export default function createGetTests({ getService }: FtrProviderContext) { @@ -661,6 +661,53 @@ export default function createGetTests({ getService }: FtrProviderContext) { }); describe('8.0.0', () => { + before(async () => { + await kibanaServer.importExport.load( + 'x-pack/test/functional/fixtures/kbn_archiver/cases/7.13.2/alerts.json' + ); + }); + + after(async () => { + await kibanaServer.importExport.unload( + 'x-pack/test/functional/fixtures/kbn_archiver/cases/7.13.2/alerts.json' + ); + await deleteAllCaseItems(es); + }); + + it('removes the rule information from alert user action', async () => { + const userActions = await getCaseUserActions({ + supertest, + caseID: 'e49ad6e0-cf9d-11eb-a603-13e7747d215c', + }); + + const userAction = getUserActionById(userActions, 'a5509250-cf9d-11eb-a603-13e7747d215c')!; + + expect(userAction.payload.comment.type).to.be(CommentType.alert); + expect(userAction.payload.comment.alertId).to.be( + '4eb4cd05b85bc65c7b9f22b776e0136f970f7538eb0d1b2e6e8c7d35b2e875cb' + ); + expect(userAction.payload.comment.index).to.be( + '.internal.alerts-security.alerts-default-000001' + ); + expect(userAction.payload.comment.rule.id).to.be(null); + expect(userAction.payload.comment.rule.name).to.be(null); + }); + + it('does not modify non-alert attachments', async () => { + const userActions = await getCaseUserActions({ + supertest, + caseID: 'e49ad6e0-cf9d-11eb-a603-13e7747d215c', + }); + + const userAction = getUserActionById(userActions, 'e5509250-cf9d-11eb-a603-13e7747d215c')!; + + expect(userAction.payload).to.not.have.property('rule'); + expect(userAction.payload.status).to.be('open'); + expect(userAction.payload.title).to.be('A case'); + }); + }); + + describe('8.1.0', () => { const CASE_ID = '5257a000-5e7d-11ec-9ee9-cd64f0b77b3c'; before(async () => { diff --git a/x-pack/test/functional/fixtures/kbn_archiver/cases/7.13.2/alerts.json b/x-pack/test/functional/fixtures/kbn_archiver/cases/7.13.2/alerts.json new file mode 100644 index 00000000000000..e7976cb49938dc --- /dev/null +++ b/x-pack/test/functional/fixtures/kbn_archiver/cases/7.13.2/alerts.json @@ -0,0 +1,202 @@ +{ + "attributes": { + "closed_at": null, + "closed_by": null, + "connector": { + "fields": [ + { + "key": "issueType", + "value": "10002" + }, + { + "key": "parent", + "value": null + }, + { + "key": "priority", + "value": null + } + ], + "id": "d68508f0-cf9d-11eb-a603-13e7747d215c", + "name": "Test Jira", + "type": ".jira" + }, + "created_at": "2021-06-17T18:57:41.682Z", + "created_by": { + "email": null, + "full_name": "j@j.com", + "username": "711621466" + }, + "description": "asdf", + "external_service": { + "connector_id": "d68508f0-cf9d-11eb-a603-13e7747d215c", + "connector_name": "Test Jira", + "external_id": "10106", + "external_title": "TPN-99", + "external_url": "https://cases-testing.atlassian.net/browse/TPN-99", + "pushed_at": "2021-06-17T18:57:45.524Z", + "pushed_by": { + "email": null, + "full_name": "j@j.com", + "username": "711621466" + } + }, + "settings": { + "syncAlerts": true + }, + "status": "open", + "tags": [ + "some tag" + ], + "title": "A case", + "type": "individual", + "updated_at": "2021-06-17T18:57:58.037Z", + "updated_by": { + "email": null, + "full_name": "j@j.com", + "username": "711621466" + } + }, + "id": "e49ad6e0-cf9d-11eb-a603-13e7747d215c", + "coreMigrationVersion": "7.13.2", + "migrationVersion": { + "cases": "7.12.0" + }, + "references": [ + ], + "type": "cases", + "updated_at": "2021-06-17T18:57:58.076Z" +} + +{ + "attributes": { + "associationType": "case", + "alertId": "123", + "index": "index", + "rule": {"id": "id", "name": "name"}, + "created_at": "2021-06-17T18:57:58.037Z", + "created_by": { + "email": null, + "full_name": "j@j.com", + "username": "711621466" + }, + "pushed_at": null, + "pushed_by": null, + "type": "alert", + "updated_at": null, + "updated_by": null + }, + "coreMigrationVersion": "7.13.2", + "migrationVersion": { + "cases-comments": "7.12.0" + }, + "id": "ee59cdd0-cf9d-11eb-a603-13e7747d215c", + "references": [ + { + "id": "e49ad6e0-cf9d-11eb-a603-13e7747d215c", + "name": "associated-cases", + "type": "cases" + } + ], + "type": "cases-comments", + "updated_at": "2021-06-17T18:57:58.087Z" +} + +{ + "attributes": { + "associationType": "case", + "comment": "a comment", + "created_at": "2021-06-17T18:57:58.037Z", + "created_by": { + "email": null, + "full_name": "j@j.com", + "username": "711621466" + }, + "pushed_at": null, + "pushed_by": null, + "type": "user", + "updated_at": null, + "updated_by": null + }, + "coreMigrationVersion": "7.13.2", + "migrationVersion": { + "cases-comments": "7.12.0" + }, + "id": "ae59cdd0-cf9d-11eb-a603-13e7747d215c", + "references": [ + { + "id": "e49ad6e0-cf9d-11eb-a603-13e7747d215c", + "name": "associated-cases", + "type": "cases" + } + ], + "type": "cases-comments", + "updated_at": "2021-06-17T18:57:58.087Z" +} + +{ + "attributes": { + "action": "create", + "action_at": "2021-06-17T18:57:41.682Z", + "action_by": { + "email": null, + "full_name": "j@j.com", + "username": "711621466" + }, + "action_field": [ + "description", + "status", + "tags", + "title", + "connector", + "settings" + ], + "new_value": "{\"type\":\"individual\",\"title\":\"A case\",\"tags\":[\"some tag\"],\"description\":\"asdf\",\"connector\":{\"id\":\"d68508f0-cf9d-11eb-a603-13e7747d215c\",\"name\":\"Test Jira\",\"type\":\".jira\",\"fields\":{\"issueType\":\"10002\",\"parent\":null,\"priority\":null}},\"settings\":{\"syncAlerts\":true}}", + "old_value": null + }, + "coreMigrationVersion": "7.13.2", + "migrationVersion": { + "cases-user-actions": "7.10.0" + }, + "id": "e5509250-cf9d-11eb-a603-13e7747d215c", + "references": [ + { + "id": "e49ad6e0-cf9d-11eb-a603-13e7747d215c", + "name": "associated-cases", + "type": "cases" + } + ], + "type": "cases-user-actions", + "updated_at": "2021-06-17T18:57:42.925Z" +} + +{ + "attributes": { + "action": "create", + "action_at": "2021-06-17T18:57:41.682Z", + "action_by": { + "email": null, + "full_name": "j@j.com", + "username": "711621466" + }, + "action_field": [ + "comment" + ], + "new_value": "{\"type\":\"alert\",\"alertId\":\"4eb4cd05b85bc65c7b9f22b776e0136f970f7538eb0d1b2e6e8c7d35b2e875cb\",\"index\":\".internal.alerts-security.alerts-default-000001\",\"rule\":{\"id\":\"43104810-7875-11ec-abc6-6f72e72f6004\",\"name\":\"A rule\"}}", + "old_value": null + }, + "coreMigrationVersion": "7.13.2", + "migrationVersion": { + "cases-user-actions": "7.10.0" + }, + "id": "a5509250-cf9d-11eb-a603-13e7747d215c", + "references": [ + { + "id": "e49ad6e0-cf9d-11eb-a603-13e7747d215c", + "name": "associated-cases", + "type": "cases" + } + ], + "type": "cases-user-actions", + "updated_at": "2021-06-17T18:57:42.925Z" +} From d19a2f3d05875bc6cafaf16fbea9c699bda0a407 Mon Sep 17 00:00:00 2001 From: ymao1 Date: Wed, 19 Jan 2022 09:45:19 -0500 Subject: [PATCH 043/108] [Connectors] Checking for undefined config and secrets during connector validation (#122696) * Checking for undefined config and secrets during connector validation * Adding functional tests Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../server/lib/action_executor.test.ts | 2 +- .../server/lib/validate_with_schema.test.ts | 57 +++++++++++++++++-- .../server/lib/validate_with_schema.ts | 20 +++++-- .../spaces_only/tests/actions/migrations.ts | 30 ++++++++++ .../functional/es_archives/actions/data.json | 32 +++++++++++ 5 files changed, 132 insertions(+), 9 deletions(-) diff --git a/x-pack/plugins/actions/server/lib/action_executor.test.ts b/x-pack/plugins/actions/server/lib/action_executor.test.ts index 4175649454f71e..30d4ed92e03f8e 100644 --- a/x-pack/plugins/actions/server/lib/action_executor.test.ts +++ b/x-pack/plugins/actions/server/lib/action_executor.test.ts @@ -308,7 +308,7 @@ test('throws an error when connector is invalid', async () => { actionId: '1', status: 'error', retry: false, - message: `error validating action type connector: error`, + message: `error validating action type connector: config must be defined`, }); }); diff --git a/x-pack/plugins/actions/server/lib/validate_with_schema.test.ts b/x-pack/plugins/actions/server/lib/validate_with_schema.test.ts index 4f0a11252eb48f..49db953506d224 100644 --- a/x-pack/plugins/actions/server/lib/validate_with_schema.test.ts +++ b/x-pack/plugins/actions/server/lib/validate_with_schema.test.ts @@ -68,6 +68,7 @@ test('should validate when validators return incoming value', () => { params: selfValidator, config: selfValidator, secrets: selfValidator, + connector: () => null, }, }; @@ -83,7 +84,7 @@ test('should validate when validators return incoming value', () => { result = validateSecrets(actionType, testValue); expect(result).toEqual(testValue); - result = validateConnector(actionType, { config: testValue }); + result = validateConnector(actionType, { config: testValue, secrets: { user: 'test' } }); expect(result).toBeNull(); }); @@ -99,6 +100,7 @@ test('should validate when validators return different values', () => { params: selfValidator, config: selfValidator, secrets: selfValidator, + connector: () => null, }, }; @@ -133,9 +135,7 @@ test('should throw with expected error when validators fail', () => { params: erroringValidator, config: erroringValidator, secrets: erroringValidator, - connector: () => { - return 'test error'; - }, + connector: () => 'test error', }, }; @@ -180,3 +180,52 @@ test('should work with @kbn/config-schema', () => { `"error validating action params: [foo]: expected value of type [string] but got [undefined]"` ); }); + +describe('validateConnectors', () => { + const testValue = { any: ['old', 'thing'] }; + const selfValidator = { validate: (value: Record) => value }; + const actionType: ActionType = { + id: 'foo', + name: 'bar', + minimumLicenseRequired: 'basic', + executor, + validate: { + params: selfValidator, + config: selfValidator, + secrets: selfValidator, + connector: () => null, + }, + }; + + test('should throw error when connector config is null', () => { + expect(() => + validateConnector(actionType, { config: null, secrets: { user: 'test' } }) + ).toThrowErrorMatchingInlineSnapshot( + `"error validating action type connector: config must be defined"` + ); + }); + + test('should throw error when connector config is undefined', () => { + expect(() => + validateConnector(actionType, { config: undefined, secrets: { user: 'test' } }) + ).toThrowErrorMatchingInlineSnapshot( + `"error validating action type connector: config must be defined"` + ); + }); + + test('should throw error when connector secrets is null', () => { + expect(() => + validateConnector(actionType, { config: testValue, secrets: null }) + ).toThrowErrorMatchingInlineSnapshot( + `"error validating action type connector: secrets must be defined"` + ); + }); + + test('should throw error when connector secrets is undefined', () => { + expect(() => + validateConnector(actionType, { config: testValue, secrets: undefined }) + ).toThrowErrorMatchingInlineSnapshot( + `"error validating action type connector: secrets must be defined"` + ); + }); +}); diff --git a/x-pack/plugins/actions/server/lib/validate_with_schema.ts b/x-pack/plugins/actions/server/lib/validate_with_schema.ts index 8ff0a3666c4b7a..b8a861566acd27 100644 --- a/x-pack/plugins/actions/server/lib/validate_with_schema.ts +++ b/x-pack/plugins/actions/server/lib/validate_with_schema.ts @@ -42,10 +42,22 @@ export function validateConnector< ExecutorResultData = void >(actionType: ActionType, value: unknown) { if (actionType.validate && actionType.validate.connector) { - const connectorValue = value as { config: Config; secrets: Secrets }; - const result = actionType.validate.connector(connectorValue.config, connectorValue.secrets); - if (result !== null) { - throw Boom.badRequest(`error validating action type connector: ${result}`); + try { + const connectorValue = value as { config: Config; secrets: Secrets }; + + // Connector config and secrets should be defined + if (connectorValue.config == null) { + throw new Error(`config must be defined`); + } + if (connectorValue.secrets == null) { + throw new Error(`secrets must be defined`); + } + const result = actionType.validate.connector(connectorValue.config, connectorValue.secrets); + if (result !== null) { + throw new Error(result); + } + } catch (err) { + throw Boom.badRequest(`error validating action type connector: ${err.message}`); } } return null; diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/actions/migrations.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/actions/migrations.ts index 9b88dace13239b..7b28161c18238e 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/actions/migrations.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/actions/migrations.ts @@ -82,5 +82,35 @@ export default function createGetTests({ getService }: FtrProviderContext) { expect(connectorWithoutService.body.config).key('service'); expect(connectorWithoutService.body.config.service).to.eql('other'); }); + + it('decryption error during migration', async () => { + const badEmailConnector = await supertest.get( + `${getUrlPrefix(``)}/api/actions/connector/0f8f2810-0a59-11ec-9a7c-fd0c2b83ff7d` + ); + + expect(badEmailConnector.status).to.eql(200); + expect(badEmailConnector.body.secrets).to.eql(undefined); + + const response = await supertest + .post( + `${getUrlPrefix(``)}/api/actions/connector/0f8f2810-0a59-11ec-9a7c-fd0c2b83ff7d/_execute` + ) + .set('kbn-xsrf', 'foo') + .send({ + params: { + message: 'am i working?', + to: ['user@test.com'], + subject: 'test', + }, + }); + + expect(response.status).to.eql(200); + expect(response.body).to.eql({ + connector_id: '0f8f2810-0a59-11ec-9a7c-fd0c2b83ff7d', + status: 'error', + message: `error validating action type connector: secrets must be defined`, + retry: false, + }); + }); }); } diff --git a/x-pack/test/functional/es_archives/actions/data.json b/x-pack/test/functional/es_archives/actions/data.json index 31d10005c0939f..79e7920872ab02 100644 --- a/x-pack/test/functional/es_archives/actions/data.json +++ b/x-pack/test/functional/es_archives/actions/data.json @@ -174,3 +174,35 @@ } } } + +{ + "type": "doc", + "value": { + "id": "action:0f8f2810-0a59-11ec-9a7c-fd0c2b83ff7d", + "index": ".kibana_1", + "source": { + "action": { + "actionTypeId" : ".email", + "name" : "test email connector cant decrypt", + "isMissingSecrets" : false, + "config" : { + "hasAuth" : true, + "from" : "me@test.com", + "host" : "some.non.existent.com", + "port" : 465, + "service" : "other", + "secure" : true + }, + "secrets" : "V2EJEtTv3yTFi1kdglhNahasdfnKYWCS+J7aWCJQU+eEqGPZEz6n7G1NsBWoh7IY0FteLTilTteQXyY/Eg3k/7bb0G8Mz+WBZ1mRvUggGTFqgoOptyUsvHoBhv0R/1bCTCabN3Pe88AfnC+VDXqwuMifpmgKEEsKF3H8VONv7TYO02FW" + }, + "migrationVersion": { + "action": "7.14.0" + }, + "coreMigrationVersion" : "7.15.0", + "references": [ + ], + "type": "action", + "updated_at": "2021-08-31T12:43:37.117Z" + } + } +} \ No newline at end of file From 4ce9221378ff19d6a66ba2c70fab8a82b5a0726c Mon Sep 17 00:00:00 2001 From: Marco Liberati Date: Wed, 19 Jan 2022 15:52:24 +0100 Subject: [PATCH 044/108] [Lens] Multi terms dnd support in Lens (#119841) * start working on multi field terms * fix filter builder * fix other buket * add tests * make other filter behave nice * clean up * :sparkles: first implemenetation draft * :label: Fix type issue * :bug: Fix circular dependency issue * :bug: Fix test warnings * :pencil: fix label * :white_check_mark: Test plan * :bug: quick fixes * :wrench: Extend canvas mock to all test files as for now * adjust tests * :bug: + :white_check_mark: Add tests for multi terms and fix other bugs * :label: Fix type issue with latest main * :label: Fix test types * :label: Fix last type error * :white_check_mark: Add field input tests * :bug: + :white_check_mark: Improved time shift handling for edge cases + tests * :white_check_mark: Complete test suites and fix multi terms filters * :white_check_mark: Fix tests after some refactoring * :sparkles: Add dnd support for multi terms * :bug: Fix dnd control key for new field * Apply suggestions from code review Co-authored-by: Marta Bondyra * :ok_hand: Limit the number of terms allowed * :bug: Allow truncation to be disabled as default by operation * :sparkles: Implement limited terms for dnd * :lipstick: Fix field select width alignment * :label: Fix type issue * :bug: Fix filtering multi terms * :ok_hand: Fix issues based on feedback * :wrench: Change default separator for multi terms formatter * :ok_hand: Integrated feedback * :bug: Fix dimension drop bug * :bug: fix multiple scenarios of merging * :bug: Fix a bug when same source field was used * :loud_sound: Update announcements for combine * :bug: Fix incompatible drop action * :recycle: Refactor truncation logic * :wrench: Fix i18n check issue * :bug: Fix broken test * :bug: Fix merge bug * :lipstick: Update icon * :white_check_mark: First batch of tests for new terms API * :bug: Fix control key issue with combine columns * :white_check_mark: Add more unit tests * :white_check_mark: Add combine keyboard test * :bug: fix scenario with partial overlap between columns * :white_check_mark: Add tests for partial columns case * Update x-pack/plugins/lens/public/drag_drop/drag_drop.tsx Co-authored-by: Marta Bondyra * :white_check_mark: Skip keyboard dnd test + add more simulated tests * :fire: Remove flacky test * :sparkles: Add scripted fields check + more tests * :fire: remove skipped test Co-authored-by: Joe Reuter Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Marta Bondyra --- .../lens/public/drag_drop/drag_drop.tsx | 38 +- .../drag_drop/providers/announcements.tsx | 124 ++++++ .../lens/public/drag_drop/providers/types.tsx | 1 + .../buttons/draggable_dimension_button.tsx | 10 +- .../buttons/drop_targets_utils.tsx | 68 +++- .../droppable/droppable.test.ts | 374 +++++++++++++++++- .../droppable/get_drop_props.ts | 105 +++-- .../droppable/on_drop_handler.ts | 109 ++++- .../indexpattern_datasource/loader.test.ts | 8 + .../public/indexpattern_datasource/mocks.ts | 80 +--- .../operations/definitions/index.ts | 25 +- .../operations/definitions/terms/index.tsx | 97 ++++- .../definitions/terms/terms.test.tsx | 267 +++++++++++++ .../operations/layer_helpers.test.ts | 36 ++ .../operations/layer_helpers.ts | 11 +- .../operations/operations.ts | 33 ++ x-pack/plugins/lens/public/types.ts | 5 +- .../functional/apps/lens/drag_and_drop.ts | 59 +++ .../test/functional/page_objects/lens_page.ts | 76 +++- 19 files changed, 1358 insertions(+), 168 deletions(-) diff --git a/x-pack/plugins/lens/public/drag_drop/drag_drop.tsx b/x-pack/plugins/lens/public/drag_drop/drag_drop.tsx index 6896142aa7bf01..2543687a422089 100644 --- a/x-pack/plugins/lens/public/drag_drop/drag_drop.tsx +++ b/x-pack/plugins/lens/public/drag_drop/drag_drop.tsx @@ -274,11 +274,18 @@ const DragInner = memo(function DragInner({ ); const modifierHandlers = useMemo(() => { const onKeyUp = (e: KeyboardEvent) => { - if ((e.key === 'Shift' || e.key === 'Alt') && activeDropTarget?.id) { + if (activeDropTarget?.id && ['Shift', 'Alt', 'Control'].includes(e.key)) { if (e.altKey) { setTargetOfIndex(activeDropTarget.id, 1); } else if (e.shiftKey) { setTargetOfIndex(activeDropTarget.id, 2); + } else if (e.ctrlKey) { + // the control option is available either for new or existing cases, + // so need to offset based on some flags + const offsetIndex = + Number(activeDropTarget.humanData.canSwap) + + Number(activeDropTarget.humanData.canDuplicate); + setTargetOfIndex(activeDropTarget.id, offsetIndex + 1); } else { setTargetOfIndex(activeDropTarget.id, 0); } @@ -289,6 +296,13 @@ const DragInner = memo(function DragInner({ setTargetOfIndex(activeDropTarget.id, 1); } else if (e.key === 'Shift' && activeDropTarget?.id) { setTargetOfIndex(activeDropTarget.id, 2); + } else if (e.key === 'Control' && activeDropTarget?.id) { + // the control option is available either for new or existing cases, + // so need to offset based on some flags + const offsetIndex = + Number(activeDropTarget.humanData.canSwap) + + Number(activeDropTarget.humanData.canDuplicate); + setTargetOfIndex(activeDropTarget.id, offsetIndex + 1); } }; return { onKeyDown, onKeyUp }; @@ -360,6 +374,8 @@ const DragInner = memo(function DragInner({ setTargetOfIndex(nextTarget.id, 1); } else if (e.shiftKey && nextTarget?.id) { setTargetOfIndex(nextTarget.id, 2); + } else if (e.ctrlKey && nextTarget?.id) { + setTargetOfIndex(nextTarget.id, 3); } else { setTarget(nextTarget, true); } @@ -517,6 +533,8 @@ const DropsInner = memo(function DropsInner(props: DropsInnerProps) { return dropTypes[1]; } else if (e.shiftKey && dropTypes[2]) { return dropTypes[2]; + } else if (e.ctrlKey && (dropTypes.length > 3 ? dropTypes[3] : dropTypes[1])) { + return dropTypes.length > 3 ? dropTypes[3] : dropTypes[1]; } } return dropType; @@ -625,11 +643,10 @@ const DropsInner = memo(function DropsInner(props: DropsInnerProps) { return (
@@ -649,11 +666,10 @@ const DropsInner = memo(function DropsInner(props: DropsInnerProps) { gutterSize="none" direction="column" data-test-subj="lnsDragDropExtraDrops" - className={ - isInZone || activeDropTarget?.id === value.id - ? 'lnsDragDrop__extraDrops lnsDragDrop__extraDrops-visible' - : 'lnsDragDrop__extraDrops' - } + className={classNames('lnsDragDrop__extraDrops', { + // eslint-disable-next-line @typescript-eslint/naming-convention + 'lnsDragDrop__extraDrops-visible': isInZone || activeDropTarget?.id === value.id, + })} > {dropTypes.slice(1).map((dropType) => { const dropChildren = getCustomDropTarget?.(dropType); diff --git a/x-pack/plugins/lens/public/drag_drop/providers/announcements.tsx b/x-pack/plugins/lens/public/drag_drop/providers/announcements.tsx index 72771edbae9810..0d247825b6a170 100644 --- a/x-pack/plugins/lens/public/drag_drop/providers/announcements.tsx +++ b/x-pack/plugins/lens/public/drag_drop/providers/announcements.tsx @@ -140,6 +140,58 @@ const reorderAnnouncement = { }), }; +const combineAnnouncement = { + selectedTarget: ( + { label, groupLabel, position }: HumanData, + { + label: dropLabel, + groupLabel: dropGroupLabel, + position: dropPosition, + canSwap, + canDuplicate, + canCombine, + }: HumanData, + announceModifierKeys?: boolean + ) => { + if (announceModifierKeys && (canSwap || canDuplicate || canCombine)) { + return i18n.translate('xpack.lens.dragDrop.announce.selectedTarget.combineMain', { + defaultMessage: `You're dragging {label} from {groupLabel} at position {position} over {dropLabel} from {dropGroupLabel} group at position {dropPosition}. Press space or enter to combine {dropLabel} with {label}.{duplicateCopy}{swapCopy}{combineCopy}`, + values: { + label, + groupLabel, + position, + dropLabel, + dropGroupLabel, + dropPosition, + duplicateCopy: canDuplicate ? DUPLICATE_SHORT : '', + swapCopy: canSwap ? SWAP_SHORT : '', + combineCopy: canCombine ? COMBINE_SHORT : '', + }, + }); + } + + return i18n.translate('xpack.lens.dragDrop.announce.selectedTarget.combine', { + defaultMessage: `Combine {dropLabel} in {dropGroupLabel} group at position {dropPosition} with {label}. Press space or enter to combine.`, + values: { + label, + dropLabel, + dropGroupLabel, + dropPosition, + }, + }); + }, + dropped: ({ label }: HumanData, { label: dropLabel, groupLabel, position }: HumanData) => + i18n.translate('xpack.lens.dragDrop.announce.duplicated.combine', { + defaultMessage: 'Combine {dropLabel} with {label} in {groupLabel} at position {position}', + values: { + label, + dropLabel, + groupLabel, + position, + }, + }), +}; + const DUPLICATE_SHORT = i18n.translate('xpack.lens.dragDrop.announce.duplicate.short', { defaultMessage: ' Hold alt or option to duplicate.', }); @@ -148,11 +200,16 @@ const SWAP_SHORT = i18n.translate('xpack.lens.dragDrop.announce.swap.short', { defaultMessage: ' Hold shift to swap.', }); +const COMBINE_SHORT = i18n.translate('xpack.lens.dragDrop.announce.combine.short', { + defaultMessage: ' Hold control to combine', +}); + export const announcements: CustomAnnouncementsType = { selectedTarget: { reorder: reorderAnnouncement.selectedTarget, duplicate_compatible: duplicateAnnouncement.selectedTarget, field_replace: replaceAnnouncement.selectedTarget, + field_combine: combineAnnouncement.selectedTarget, replace_compatible: replaceAnnouncement.selectedTarget, replace_incompatible: ( { label, groupLabel, position }: HumanData, @@ -337,11 +394,45 @@ export const announcements: CustomAnnouncementsType = { nextLabel, }, }), + combine_compatible: ( + { label, groupLabel, position }: HumanData, + { label: dropLabel, groupLabel: dropGroupLabel, position: dropPosition, nextLabel }: HumanData + ) => + i18n.translate('xpack.lens.dragDrop.announce.selectedTarget.combineCompatible', { + defaultMessage: + 'Combine {label} in {groupLabel} group at position {position} with {dropLabel} in {dropGroupLabel} group at position {dropPosition}. Hold Control and press space or enter to combine', + values: { + label, + groupLabel, + position, + dropLabel, + dropGroupLabel, + dropPosition, + }, + }), + combine_incompatible: ( + { label, groupLabel, position }: HumanData, + { label: dropLabel, groupLabel: dropGroupLabel, position: dropPosition, nextLabel }: HumanData + ) => + i18n.translate('xpack.lens.dragDrop.announce.selectedTarget.combineIncompatible', { + defaultMessage: + 'Convert {label} to {nextLabel} in {groupLabel} group at position {position} and combine with {dropLabel} in {dropGroupLabel} group at position {dropPosition}. Hold Control and press space or enter to combine', + values: { + label, + groupLabel, + position, + dropLabel, + dropGroupLabel, + dropPosition, + nextLabel, + }, + }), }, dropped: { reorder: reorderAnnouncement.dropped, duplicate_compatible: duplicateAnnouncement.dropped, field_replace: replaceAnnouncement.dropped, + field_combine: combineAnnouncement.dropped, replace_compatible: replaceAnnouncement.dropped, replace_incompatible: ( { label }: HumanData, @@ -457,6 +548,39 @@ export const announcements: CustomAnnouncementsType = { nextLabel, }, }), + combine_compatible: ( + { label, groupLabel, position }: HumanData, + { label: dropLabel, groupLabel: dropGroupLabel, position: dropPosition }: HumanData + ) => + i18n.translate('xpack.lens.dragDrop.announce.dropped.combineCompatible', { + defaultMessage: + 'Combined {label} to {dropGroupLabel} at position {dropPosition} and {dropLabel} to {groupLabel} group at position {position}', + values: { + label, + groupLabel, + position, + dropLabel, + dropGroupLabel, + dropPosition, + }, + }), + combine_incompatible: ( + { label, groupLabel, position }: HumanData, + { label: dropLabel, groupLabel: dropGroupLabel, position: dropPosition, nextLabel }: HumanData + ) => + i18n.translate('xpack.lens.dragDrop.announce.dropped.combineIncompatible', { + defaultMessage: + 'Converted {label} to {nextLabel} in {groupLabel} group at position {position} and combined with {dropLabel} in {dropGroupLabel} group at position {dropPosition}', + values: { + label, + groupLabel, + position, + dropGroupLabel, + dropLabel, + dropPosition, + nextLabel, + }, + }), }, }; diff --git a/x-pack/plugins/lens/public/drag_drop/providers/types.tsx b/x-pack/plugins/lens/public/drag_drop/providers/types.tsx index 8b28affa455965..921ab897706c04 100644 --- a/x-pack/plugins/lens/public/drag_drop/providers/types.tsx +++ b/x-pack/plugins/lens/public/drag_drop/providers/types.tsx @@ -14,6 +14,7 @@ export interface HumanData { nextLabel?: string; canSwap?: boolean; canDuplicate?: boolean; + canCombine?: boolean; } export interface Ghost { diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/buttons/draggable_dimension_button.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/buttons/draggable_dimension_button.tsx index 365c2c15c493b7..e88b04588d2e0d 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/buttons/draggable_dimension_button.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/buttons/draggable_dimension_button.tsx @@ -81,6 +81,13 @@ export function DraggableDimensionButton({ (dropTypes.includes('swap_incompatible') || dropTypes.includes('swap_compatible')) ); + const canCombine = Boolean( + dropTypes && + (dropTypes.includes('combine_compatible') || + dropTypes.includes('field_combine') || + dropTypes.includes('combine_incompatible')) + ); + const value = useMemo( () => ({ columnId, @@ -91,6 +98,7 @@ export function DraggableDimensionButton({ humanData: { canSwap, canDuplicate, + canCombine, label, groupLabel: group.groupLabel, position: accessorIndex + 1, @@ -108,6 +116,7 @@ export function DraggableDimensionButton({ group.filterOperations, canDuplicate, canSwap, + canCombine, ] ); @@ -129,7 +138,6 @@ export function DraggableDimensionButton({ (droppedItem, selectedDropType) => onDrop(droppedItem, value, selectedDropType), [value, onDrop] ); - return (
{ + const { icon, label, controlKey } = getPropsForDropType(type); return ( - + - - {type === 'duplicate' - ? i18n.translate('xpack.lens.dragDrop.duplicate', { - defaultMessage: 'Duplicate', - }) - : i18n.translate('xpack.lens.dragDrop.swap', { - defaultMessage: 'Swap', - })} - + {label} - - {' '} - {type === 'duplicate' - ? i18n.translate('xpack.lens.dragDrop.altOption', { - defaultMessage: 'Alt/Option', - }) - : i18n.translate('xpack.lens.dragDrop.shift', { - defaultMessage: 'Shift', - })} - + {controlKey} @@ -70,6 +92,9 @@ const customDropTargetsMap: Partial<{ [dropType in DropType]: React.ReactElement replace_duplicate_compatible: getExtraDrop({ type: 'duplicate' }), duplicate_compatible: getExtraDrop({ type: 'duplicate' }), swap_compatible: getExtraDrop({ type: 'swap' }), + field_combine: getExtraDrop({ type: 'combine' }), + combine_compatible: getExtraDrop({ type: 'combine' }), + combine_incompatible: getExtraDrop({ type: 'combine', isIncompatible: true }), }; export const getCustomDropTarget = (dropType: DropType) => customDropTargetsMap?.[dropType] || null; @@ -98,6 +123,7 @@ export const getAdditionalClassesOnDroppable = (dropType?: string) => { 'swap_incompatible', 'duplicate_incompatible', 'replace_duplicate_incompatible', + 'combine_incompatible', ].includes(dropType) ) { return 'lnsDragDrop-notCompatible'; diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable/droppable.test.ts b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable/droppable.test.ts index fa200e8b556266..fab431e886d8ea 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable/droppable.test.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable/droppable.test.ts @@ -244,6 +244,35 @@ describe('IndexPatternDimensionEditorPanel', () => { let setState: jest.Mock; let defaultProps: IndexPatternDimensionEditorProps; + function getStateWithMultiFieldColumn() { + return { + ...state, + layers: { + ...state.layers, + first: { + ...state.layers.first, + columns: { + ...state.layers.first.columns, + col1: { + label: 'Top values of dest', + dataType: 'string', + isBucketed: true, + + // Private + operationType: 'terms', + params: { + orderBy: { type: 'alphabetical' }, + orderDirection: 'desc', + size: 10, + }, + sourceField: 'dest', + } as TermsIndexPatternColumn, + }, + }, + }, + }; + } + beforeEach(() => { state = { indexPatternRefs: [], @@ -398,16 +427,29 @@ describe('IndexPatternDimensionEditorPanel', () => { }) ).toBe(undefined); }); + + it('returns also field_combine if the field is supported by filterOperations and the dropTarget is an existing column that supports multiple fields', () => { + // replace the state with a top values column to enable the multi fields behaviour + state = getStateWithMultiFieldColumn(); + expect( + getDropProps({ + ...defaultProps, + state, + groupId, + dragging: draggingField, + filterOperations: (op: OperationMetadata) => op.dataType !== 'date', + }) + ).toEqual({ dropTypes: ['field_replace', 'field_combine'] }); + }); }); describe('dragging a column', () => { it('returns undefined if the dragged column from different group uses the same field as the dropTarget', () => { - const testState = { ...state }; - testState.layers.first = { + state.layers.first = { indexPatternId: 'foo', columnOrder: ['col1', 'col2', 'col3'], columns: { - col1: testState.layers.first.columns.col1, + col1: state.layers.first.columns.col1, col2: { label: 'Date histogram of timestamp (1)', @@ -438,13 +480,134 @@ describe('IndexPatternDimensionEditorPanel', () => { ).toEqual(undefined); }); + it('returns undefined if the dragged column from different group uses the same fields as the dropTarget', () => { + state = getStateWithMultiFieldColumn(); + const sourceMultiFieldColumn = { + ...state.layers.first.columns.col1, + sourceField: 'bytes', + params: { + ...(state.layers.first.columns.col1 as TermsIndexPatternColumn).params, + secondaryFields: ['dest'], + }, + } as TermsIndexPatternColumn; + // invert the fields + const targetMultiFieldColumn = { + ...state.layers.first.columns.col1, + sourceField: 'dest', + params: { + ...(state.layers.first.columns.col1 as TermsIndexPatternColumn).params, + secondaryFields: ['bytes'], + }, + } as TermsIndexPatternColumn; + state.layers.first = { + indexPatternId: 'foo', + columnOrder: ['col1', 'col2'], + columns: { + col1: sourceMultiFieldColumn, + col2: targetMultiFieldColumn, + }, + }; + + expect( + getDropProps({ + ...defaultProps, + state, + groupId, + dragging: { + ...draggingCol1, + groupId: 'c', + }, + columnId: 'col2', + }) + ).toEqual(undefined); + }); + + it('returns duplicate and replace if the dragged column from different group uses the same field as the dropTarget, but this last one is multifield, and can be swappable', () => { + state = getStateWithMultiFieldColumn(); + state.layers.first = { + indexPatternId: 'foo', + columnOrder: ['col1', 'col2'], + columns: { + col1: state.layers.first.columns.col1, + + col2: { + ...state.layers.first.columns.col1, + sourceField: 'bytes', + params: { + ...(state.layers.first.columns.col1 as TermsIndexPatternColumn).params, + secondaryFields: ['dest'], + }, + } as TermsIndexPatternColumn, + }, + }; + + expect( + getDropProps({ + ...defaultProps, + state, + groupId, + dragging: { + ...draggingCol1, + groupId: 'c', + }, + columnId: 'col2', + }) + ).toEqual({ + dropTypes: ['replace_compatible', 'replace_duplicate_compatible'], + }); + }); + + it('returns swap, duplicate and replace if the dragged column from different group uses the same field as the dropTarget, but this last one is multifield', () => { + state = getStateWithMultiFieldColumn(); + state.layers.first = { + indexPatternId: 'foo', + columnOrder: ['col1', 'col2'], + columns: { + col1: state.layers.first.columns.col1, + + col2: { + ...state.layers.first.columns.col1, + sourceField: 'bytes', + params: { + ...(state.layers.first.columns.col1 as TermsIndexPatternColumn).params, + secondaryFields: ['dest'], + }, + } as TermsIndexPatternColumn, + }, + }; + + expect( + getDropProps({ + ...defaultProps, + state, + // make it swappable + dimensionGroups: [ + { + accessors: [{ columnId: 'col1' }], + filterOperations: jest.fn(() => true), + groupId, + groupLabel: '', + supportsMoreColumns: false, + }, + ], + groupId, + dragging: { + ...draggingCol1, + groupId: 'c', + }, + columnId: 'col2', + }) + ).toEqual({ + dropTypes: ['replace_compatible', 'replace_duplicate_compatible', 'swap_compatible'], + }); + }); + it('returns reorder if drop target and droppedItem columns are from the same group and both are existing', () => { - const testState = { ...state }; - testState.layers.first = { + state.layers.first = { indexPatternId: 'foo', columnOrder: ['col1', 'col2', 'col3'], columns: { - col1: testState.layers.first.columns.col1, + col1: state.layers.first.columns.col1, col2: { label: 'Sum of bytes', @@ -500,12 +663,11 @@ describe('IndexPatternDimensionEditorPanel', () => { }); it('returns incompatible drop target types if dropping column to existing incompatible column', () => { - const testState = { ...state }; - testState.layers.first = { + state.layers.first = { indexPatternId: 'foo', columnOrder: ['col1', 'col2', 'col3'], columns: { - col1: testState.layers.first.columns.col1, + col1: state.layers.first.columns.col1, col2: { label: 'Sum of bytes', @@ -541,12 +703,11 @@ describe('IndexPatternDimensionEditorPanel', () => { }); it('does not return swap_incompatible if current dropTarget column cannot be swapped to the group of dragging column', () => { - const testState = { ...state }; - testState.layers.first = { + state.layers.first = { indexPatternId: 'foo', columnOrder: ['col1', 'col2', 'col3'], columns: { - col1: testState.layers.first.columns.col1, + col1: state.layers.first.columns.col1, col2: { label: 'Count of records', @@ -578,6 +739,117 @@ describe('IndexPatternDimensionEditorPanel', () => { nextLabel: 'Unique count', }); }); + + it('returns combine_compatible drop type if the dragged column is compatible and the target one support multiple fields', () => { + state = getStateWithMultiFieldColumn(); + state.layers.first = { + indexPatternId: 'foo', + columnOrder: ['col1', 'col2'], + columns: { + col1: state.layers.first.columns.col1, + + col2: { + ...state.layers.first.columns.col1, + sourceField: 'bytes', + }, + }, + }; + + expect( + getDropProps({ + ...defaultProps, + state, + groupId, + dragging: { + ...draggingCol1, + groupId: 'c', + }, + columnId: 'col2', + }) + ).toEqual({ + dropTypes: ['replace_compatible', 'replace_duplicate_compatible', 'combine_compatible'], + }); + }); + + it('returns no combine drop type if the dragged column is compatible, the target one supports multiple fields but there are too many fields', () => { + state = getStateWithMultiFieldColumn(); + state.layers.first = { + indexPatternId: 'foo', + columnOrder: ['col1', 'col2'], + columns: { + col1: state.layers.first.columns.col1, + + col2: { + ...state.layers.first.columns.col1, + sourceField: 'source', + params: { + ...(state.layers.first.columns.col1 as TermsIndexPatternColumn).params, + secondaryFields: ['memory', 'bytes', 'geo.src'], // too many fields here + }, + } as TermsIndexPatternColumn, + }, + }; + + expect( + getDropProps({ + ...defaultProps, + state, + groupId, + dragging: { + ...draggingCol1, + groupId: 'c', + }, + columnId: 'col2', + }) + ).toEqual({ + dropTypes: ['replace_compatible', 'replace_duplicate_compatible'], + }); + }); + + it('returns combine_incompatible drop target types if dropping column to existing incompatible column which supports multiple fields', () => { + state = getStateWithMultiFieldColumn(); + state.layers.first = { + indexPatternId: 'foo', + columnOrder: ['col1', 'col2', 'col3'], + columns: { + col1: state.layers.first.columns.col1, + + col2: { + label: 'Sum of bytes', + dataType: 'number', + isBucketed: false, + + // Private + operationType: 'sum', + sourceField: 'bytes', + }, + }, + }; + + expect( + getDropProps({ + ...defaultProps, + state, + groupId, + // drag the sum over the top values + dragging: { + ...draggingCol2, + groupId: 'c', + filterOperation: undefined, + }, + columnId: 'col1', + filterOperations: (op: OperationMetadata) => op.isBucketed, + }) + ).toEqual({ + dropTypes: [ + 'replace_incompatible', + 'replace_duplicate_incompatible', + 'swap_incompatible', + 'combine_incompatible', + ], + nextLabel: 'Top values', + }); + }); }); }); @@ -748,6 +1020,33 @@ describe('IndexPatternDimensionEditorPanel', () => { }, }); }); + + it('appends the new field to the column that supports multiple fields when a field is dropped', () => { + state = getStateWithMultiFieldColumn(); + onDrop({ + ...defaultProps, + state, + droppedItem: draggingField, + filterOperations: (op: OperationMetadata) => op.dataType === 'number', + dropType: 'field_combine', + }); + + expect(setState).toBeCalledTimes(1); + expect(setState).toHaveBeenCalledWith({ + ...state, + layers: { + first: expect.objectContaining({ + columns: expect.objectContaining({ + col1: expect.objectContaining({ + dataType: 'string', + sourceField: 'dest', + params: expect.objectContaining({ secondaryFields: ['bytes'] }), + }), + }), + }), + }, + }); + }); }); describe('dropping a dimension', () => { @@ -1335,6 +1634,57 @@ describe('IndexPatternDimensionEditorPanel', () => { }); }); + it('when combine compatible columns should append dropped column fields into the target one', () => { + state = getStateWithMultiFieldColumn(); + state.layers.first.columns = { + ...state.layers.first.columns, + col2: { + isBucketed: true, + label: 'Top values of source', + operationType: 'terms', + sourceField: 'bytes', + dataType: 'number', + params: { + orderBy: { + type: 'alphabetical', + }, + orderDirection: 'desc', + size: 10, + }, + } as TermsIndexPatternColumn, + }; + onDrop({ + ...defaultProps, + state, + droppedItem: { + columnId: 'col2', + groupId: 'a', + layerId: 'first', + id: 'col2', + humanData: { label: 'Label' }, + }, + filterOperations: (op: OperationMetadata) => op.isBucketed, + dropType: 'combine_compatible', + columnId: 'col1', + }); + + expect(setState).toBeCalledTimes(1); + expect(setState).toHaveBeenCalledWith({ + ...state, + layers: { + first: expect.objectContaining({ + columns: expect.objectContaining({ + col1: expect.objectContaining({ + dataType: 'string', + sourceField: 'dest', + params: expect.objectContaining({ secondaryFields: ['bytes'] }), + }), + }), + }), + }, + }); + }); + describe('dimension group aware ordering and copying', () => { let testState: IndexPatternPrivateState; beforeEach(() => { diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable/get_drop_props.ts b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable/get_drop_props.ts index 87daef0d40f620..d85cbd438ffe71 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable/get_drop_props.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable/get_drop_props.ts @@ -12,7 +12,11 @@ import { DropType, VisualizationDimensionGroupConfig, } from '../../../types'; -import { getOperationDisplay } from '../../operations'; +import { + getCurrentFieldsForOperation, + getOperationDisplay, + hasOperationSupportForMultipleFields, +} from '../../operations'; import { hasField, isDraggedField } from '../../pure_utils'; import { DragContextState } from '../../../drag_drop/providers'; import { OperationMetadata } from '../../../types'; @@ -85,14 +89,21 @@ export function getDropProps(props: GetDropProps) { ) { const sourceColumn = state.layers[dragging.layerId].columns[dragging.columnId]; const targetColumn = state.layers[layerId].columns[columnId]; + const layerIndexPattern = state.indexPatterns[state.layers[layerId].indexPatternId]; const isSameGroup = groupId === dragging.groupId; if (isSameGroup) { return getDropPropsForSameGroup(targetColumn); + } else if (filterOperations(sourceColumn)) { + return getDropPropsForCompatibleGroup( + props.dimensionGroups, + dragging.columnId, + sourceColumn, + targetColumn, + layerIndexPattern + ); } else if (hasTheSameField(sourceColumn, targetColumn)) { return; - } else if (filterOperations(sourceColumn)) { - return getDropPropsForCompatibleGroup(props.dimensionGroups, dragging.columnId, targetColumn); } else { return getDropPropsFromIncompatibleGroup({ ...props, dragging }); } @@ -103,11 +114,12 @@ function hasTheSameField( sourceColumn: GenericIndexPatternColumn, targetColumn?: GenericIndexPatternColumn ) { + const targetFields = targetColumn ? getCurrentFieldsForOperation(targetColumn) : []; + const sourceFields = new Set(getCurrentFieldsForOperation(sourceColumn)); + return ( - targetColumn && - hasField(targetColumn) && - hasField(sourceColumn) && - targetColumn.sourceField === sourceColumn.sourceField + targetFields.length === sourceFields.size && + targetFields.every((field) => sourceFields.has(field)) ); } @@ -131,10 +143,22 @@ function getDropPropsForField({ (hasField(targetColumn) && targetColumn.sourceField !== dragging.field.name) || !hasField(targetColumn) ) { - return { - dropTypes: ['field_replace'], - nextLabel, - }; + const layerIndexPattern = state.indexPatterns[state.layers[layerId].indexPatternId]; + return hasField(targetColumn) && + layerIndexPattern && + hasOperationSupportForMultipleFields( + layerIndexPattern, + targetColumn, + undefined, + dragging.field + ) + ? { + dropTypes: ['field_replace', 'field_combine'], + } + : { + dropTypes: ['field_replace'], + nextLabel, + }; } } return; @@ -147,23 +171,45 @@ function getDropPropsForSameGroup(targetColumn?: GenericIndexPatternColumn): Dro function getDropPropsForCompatibleGroup( dimensionGroups: VisualizationDimensionGroupConfig[], sourceId: string, - targetColumn?: GenericIndexPatternColumn + sourceColumn?: GenericIndexPatternColumn, + targetColumn?: GenericIndexPatternColumn, + indexPattern?: IndexPattern ): DropProps { + const hasSameField = sourceColumn && hasTheSameField(sourceColumn, targetColumn); + const canSwap = targetColumn && + !hasSameField && dimensionGroups .find((group) => group.accessors.some((accessor) => accessor.columnId === sourceId)) ?.filterOperations(targetColumn); - const dropTypes: DropProps = { - dropTypes: targetColumn - ? ['replace_compatible', 'replace_duplicate_compatible'] - : ['move_compatible', 'duplicate_compatible'], - }; + const swapType: DropType[] = canSwap ? ['swap_compatible'] : []; + + if (!targetColumn) { + return { dropTypes: ['move_compatible', 'duplicate_compatible', ...swapType] }; + } + if (!indexPattern || !hasField(targetColumn)) { + return { dropTypes: ['replace_compatible', 'replace_duplicate_compatible', ...swapType] }; + } + // With multi fields operations there are more combination of drops now + const dropTypes: DropType[] = []; + if (!hasSameField) { + dropTypes.push('replace_compatible', 'replace_duplicate_compatible'); + } if (canSwap) { - dropTypes.dropTypes.push('swap_compatible'); + dropTypes.push('swap_compatible'); } - return dropTypes; + if (hasOperationSupportForMultipleFields(indexPattern, targetColumn, sourceColumn)) { + dropTypes.push('combine_compatible'); + } + // return undefined if no drop action is available + if (!dropTypes.length) { + return; + } + return { + dropTypes, + }; } function getDropPropsFromIncompatibleGroup({ @@ -185,14 +231,23 @@ function getDropPropsFromIncompatibleGroup({ if (newOperationForSource) { const targetField = getField(targetColumn, layerIndexPattern); - const canSwap = !!getNewOperation(targetField, dragging.filterOperations, sourceColumn); + const canSwap = Boolean(getNewOperation(targetField, dragging.filterOperations, sourceColumn)); + + const dropTypes: DropType[] = []; + if (targetColumn) { + dropTypes.push('replace_incompatible', 'replace_duplicate_incompatible'); + if (canSwap) { + dropTypes.push('swap_incompatible'); + } + if (hasOperationSupportForMultipleFields(layerIndexPattern, targetColumn, sourceColumn)) { + dropTypes.push('combine_incompatible'); + } + } else { + dropTypes.push('move_incompatible', 'duplicate_incompatible'); + } return { - dropTypes: targetColumn - ? canSwap - ? ['replace_incompatible', 'replace_duplicate_incompatible', 'swap_incompatible'] - : ['replace_incompatible', 'replace_duplicate_incompatible'] - : ['move_incompatible', 'duplicate_incompatible'], + dropTypes, nextLabel: operationLabels[newOperationForSource].displayName, }; } diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable/on_drop_handler.ts b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable/on_drop_handler.ts index 1b5679786e717e..c9e806050caad9 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable/on_drop_handler.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable/on_drop_handler.ts @@ -11,6 +11,9 @@ import { getColumnOrder, reorderByGroups, copyColumn, + hasOperationSupportForMultipleFields, + getOperationHelperForMultipleFields, + replaceColumn, } from '../../operations'; import { mergeLayer } from '../../state_helpers'; import { isDraggedField } from '../../pure_utils'; @@ -25,7 +28,7 @@ type DropHandlerProps = DatasourceDimensionDropHandlerProps) { const { droppedItem, dropType } = props; - if (dropType === 'field_add' || dropType === 'field_replace') { + if (dropType === 'field_add' || dropType === 'field_replace' || dropType === 'field_combine') { return operationOnDropMap[dropType]({ ...props, droppedItem: droppedItem as DraggedField, @@ -40,6 +43,7 @@ export function onDrop(props: DatasourceDimensionDropHandlerProps) => onFieldDrop(props, true), reorder: onReorder, @@ -56,9 +60,72 @@ const operationOnDropMap = { swap_compatible: onSwapCompatible, swap_incompatible: onSwapIncompatible, + combine_compatible: onCombineCompatible, + combine_incompatible: onCombineCompatible, }; -function onFieldDrop(props: DropHandlerProps) { +function onCombineCompatible({ + columnId, + setState, + state, + layerId, + droppedItem, + dimensionGroups, + groupId, +}: DropHandlerProps) { + const layer = state.layers[layerId]; + const sourceId = droppedItem.columnId; + const targetId = columnId; + const indexPattern = state.indexPatterns[layer.indexPatternId]; + const sourceColumn = layer.columns[sourceId]; + const targetColumn = layer.columns[targetId]; + + // extract the field from the source column + const sourceField = getField(sourceColumn, indexPattern); + const targetField = getField(targetColumn, indexPattern); + if (!sourceField || !targetField) { + return false; + } + // pass it to the target column and delete the source column + const initialParams = { + params: + getOperationHelperForMultipleFields(targetColumn.operationType)?.({ + targetColumn, + sourceColumn, + indexPattern, + }) ?? {}, + }; + + const modifiedLayer = replaceColumn({ + layer, + columnId, + indexPattern, + op: targetColumn.operationType, + field: targetField, + visualizationGroups: dimensionGroups, + targetGroup: groupId, + initialParams, + shouldCombineField: true, + }); + const newLayer = deleteColumn({ + layer: modifiedLayer, + columnId: sourceId, + indexPattern, + }); + + // Time to replace + setState( + mergeLayer({ + state, + layerId, + newLayer, + }) + ); + + return { deleted: sourceId }; +} + +function onFieldDrop(props: DropHandlerProps, shouldAddField?: boolean) { const { columnId, setState, @@ -77,25 +144,45 @@ function onFieldDrop(props: DropHandlerProps) { const layer = state.layers[layerId]; const indexPattern = state.indexPatterns[layer.indexPatternId]; const targetColumn = layer.columns[columnId]; - const newOperation = getNewOperation( - droppedItem.field, - filterOperations, - targetColumn, - prioritizedOperation - ); - - if (!isDraggedField(droppedItem) || !newOperation) { + const newOperation = shouldAddField + ? targetColumn.operationType + : getNewOperation(droppedItem.field, filterOperations, targetColumn, prioritizedOperation); + + if ( + !isDraggedField(droppedItem) || + !newOperation || + (shouldAddField && + !hasOperationSupportForMultipleFields( + indexPattern, + targetColumn, + undefined, + droppedItem.field + )) + ) { return false; } + const field = shouldAddField ? getField(targetColumn, indexPattern) : droppedItem.field; + const initialParams = shouldAddField + ? { + params: + getOperationHelperForMultipleFields(targetColumn.operationType)?.({ + targetColumn, + field: droppedItem.field, + indexPattern, + }) || {}, + } + : undefined; const newLayer = insertOrReplaceColumn({ layer, columnId, indexPattern, op: newOperation, - field: droppedItem.field, + field, visualizationGroups: dimensionGroups, targetGroup: groupId, + shouldCombineField: shouldAddField, + initialParams, }); trackUiEvent('drop_onto_dimension'); diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/loader.test.ts b/x-pack/plugins/lens/public/indexpattern_datasource/loader.test.ts index 431b8a84341e88..d2922ed86614ae 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/loader.test.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/loader.test.ts @@ -94,6 +94,14 @@ const indexPattern1 = { searchable: true, esTypes: ['keyword'], }, + { + name: 'geo.src', + displayName: 'geo.src', + type: 'string', + aggregatable: true, + searchable: true, + esTypes: ['keyword'], + }, { name: 'scripted', displayName: 'Scripted', diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/mocks.ts b/x-pack/plugins/lens/public/indexpattern_datasource/mocks.ts index 4545e42b2ff997..b8b5b9a4e6293a 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/mocks.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/mocks.ts @@ -12,6 +12,16 @@ import type { IndexPattern, IndexPatternField } from './types'; export const createMockedIndexPatternWithoutType = ( typeToFilter: IndexPatternField['type'] ): IndexPattern => { + const { fields, ...otherIndexPatternProps } = createMockedIndexPattern(); + const filteredFields = fields.filter(({ type }) => type !== typeToFilter); + return { + ...otherIndexPatternProps, + fields: filteredFields, + getFieldByName: getFieldByNameFactory(filteredFields), + }; +}; + +export const createMockedIndexPattern = (): IndexPattern => { const fields = [ { name: 'timestamp', @@ -65,74 +75,8 @@ export const createMockedIndexPatternWithoutType = ( esTypes: ['keyword'], }, { - name: 'scripted', - displayName: 'Scripted', - type: 'string', - searchable: true, - aggregatable: true, - scripted: true, - lang: 'painless' as const, - script: '1234', - }, - ].filter(({ type }) => type !== typeToFilter); - return { - id: '1', - title: 'my-fake-index-pattern', - timeFieldName: 'timestamp', - hasRestrictions: false, - fields, - getFieldByName: getFieldByNameFactory(fields), - }; -}; - -export const createMockedIndexPattern = (): IndexPattern => { - const fields = [ - { - name: 'timestamp', - displayName: 'timestampLabel', - type: 'date', - aggregatable: true, - searchable: true, - }, - { - name: 'start_date', - displayName: 'start_date', - type: 'date', - aggregatable: true, - searchable: true, - }, - { - name: 'bytes', - displayName: 'bytes', - type: 'number', - aggregatable: true, - searchable: true, - }, - { - name: 'memory', - displayName: 'memory', - type: 'number', - aggregatable: true, - searchable: true, - }, - { - name: 'source', - displayName: 'source', - type: 'string', - aggregatable: true, - searchable: true, - esTypes: ['keyword'], - }, - { - name: 'unsupported', - displayName: 'unsupported', - type: 'geo', - aggregatable: true, - searchable: true, - }, - { - name: 'dest', - displayName: 'dest', + name: 'geo.src', + displayName: 'geo.src', type: 'string', aggregatable: true, searchable: true, diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/index.ts b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/index.ts index ccf86be7d2b08e..3a1a53ba1a5f00 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/index.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/index.ts @@ -191,7 +191,7 @@ export interface HelpProps { export type TimeScalingMode = 'disabled' | 'mandatory' | 'optional'; -interface BaseOperationDefinitionProps { +interface BaseOperationDefinitionProps { type: C['operationType']; /** * The priority of the operation. If multiple operations are possible in @@ -310,10 +310,28 @@ interface BaseOperationDefinitionProps { * React component for operation field specific behaviour */ renderFieldInput?: React.ComponentType>; + /** + * Builds the correct parameter for field additions + */ + getParamsForMultipleFields?: (props: { + targetColumn: C; + sourceColumn?: GenericIndexPatternColumn; + field?: IndexPatternField; + indexPattern: IndexPattern; + }) => Partial

; /** * Verify if the a new field can be added to the column */ - canAddNewField?: (column: C, field: IndexPatternField) => boolean; + canAddNewField?: (props: { + targetColumn: C; + sourceColumn?: GenericIndexPatternColumn; + field?: IndexPatternField; + indexPattern: IndexPattern; + }) => boolean; + /** + * Returns the list of current fields for a multi field operation + */ + getCurrentFields?: (targetColumn: C) => string[]; /** * Operation can influence some visual default settings. This function is used to collect default values offered */ @@ -408,8 +426,9 @@ interface FieldBasedOperationDefinition C; + onFieldChange: (oldColumn: C, field: IndexPatternField, params?: Partial

) => C; /** * Function turning a column into an agg config passed to the `esaggs` function * together with the agg configs returned from other columns. diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/index.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/index.tsx index a1164396f30e28..be286532ad75bb 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/index.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/index.tsx @@ -25,13 +25,14 @@ import type { DataType } from '../../../../types'; import { OperationDefinition } from '../index'; import { FieldBasedIndexPatternColumn } from '../column_types'; import { ValuesInput } from './values_input'; -import { getInvalidFieldMessage } from '../helpers'; +import { getInvalidFieldMessage, isColumnOfType } from '../helpers'; import { FieldInputs, MAX_MULTI_FIELDS_SIZE } from './field_inputs'; import { FieldInput as FieldInputBase, getErrorMessage, } from '../../../dimension_panel/field_input'; import type { TermsIndexPatternColumn } from './types'; +import type { IndexPattern, IndexPatternField } from '../../../types'; import { getDisallowedTermsMessage, getMultiTermsScriptedFieldErrorMessage, @@ -70,6 +71,16 @@ function ofName(name?: string, count: number = 0, rare: boolean = false) { }); } +function isScriptedField(field: IndexPatternField): boolean; +function isScriptedField(fieldName: string, indexPattern: IndexPattern): boolean; +function isScriptedField(fieldName: string | IndexPatternField, indexPattern?: IndexPattern) { + if (typeof fieldName === 'string') { + const field = indexPattern?.getFieldByName(fieldName); + return field && field.scripted; + } + return fieldName.scripted; +} + const idPrefix = htmlIdGenerator()(); const DEFAULT_SIZE = 3; // Elasticsearch limit @@ -84,8 +95,67 @@ export const termsOperation: OperationDefinition { - return (column.params?.secondaryFields?.length ?? 0) < MAX_MULTI_FIELDS_SIZE; + getCurrentFields: (targetColumn) => { + return [targetColumn.sourceField, ...(targetColumn?.params?.secondaryFields ?? [])]; + }, + getParamsForMultipleFields: ({ targetColumn, sourceColumn, field, indexPattern }) => { + const secondaryFields = new Set(); + if (targetColumn.params?.secondaryFields?.length) { + targetColumn.params.secondaryFields.forEach((fieldName) => { + if (!isScriptedField(fieldName, indexPattern)) { + secondaryFields.add(fieldName); + } + }); + } + if (sourceColumn && 'sourceField' in sourceColumn && sourceColumn?.sourceField) { + if (!isScriptedField(sourceColumn.sourceField, indexPattern)) { + secondaryFields.add(sourceColumn.sourceField); + } + } + if (sourceColumn && isColumnOfType('terms', sourceColumn)) { + if (sourceColumn?.params?.secondaryFields?.length) { + sourceColumn.params.secondaryFields.forEach((fieldName) => { + if (!isScriptedField(fieldName, indexPattern)) { + secondaryFields.add(fieldName); + } + }); + } + } + if (field && !isScriptedField(field)) { + secondaryFields.add(field.name); + } + return { + secondaryFields: [...secondaryFields].filter((f) => targetColumn.sourceField !== f), + }; + }, + canAddNewField: ({ targetColumn, sourceColumn, field, indexPattern }) => { + // first step: collect the fields from the targetColumn + const originalTerms = new Set([ + targetColumn.sourceField, + ...(targetColumn.params?.secondaryFields ?? []), + ]); + // now check how many fields can be added + let counter = field && !isScriptedField(field) && !originalTerms.has(field.name) ? 1 : 0; + if (sourceColumn) { + if ('sourceField' in sourceColumn) { + counter += + !isScriptedField(sourceColumn.sourceField, indexPattern) && + !originalTerms.has(sourceColumn.sourceField) + ? 1 + : 0; + if (isColumnOfType('terms', sourceColumn)) { + counter += + sourceColumn.params.secondaryFields?.filter((f) => { + return !isScriptedField(f, indexPattern) && !originalTerms.has(f); + }).length ?? 0; + } + } + } + // reject when there are no new fields to add + if (!counter) { + return false; + } + return counter + (targetColumn.params?.secondaryFields?.length ?? 0) <= MAX_MULTI_FIELDS_SIZE; }, getDefaultVisualSettings: (column) => ({ truncateText: Boolean(!column.params?.secondaryFields?.length), @@ -96,7 +166,11 @@ export const termsOperation: OperationDefinition { @@ -206,16 +280,23 @@ export const termsOperation: OperationDefinition { - // reset the secondary fields - const newParams = { ...oldColumn.params, secondaryFields: undefined }; + onFieldChange: (oldColumn, field, params) => { + const newParams = { + ...oldColumn.params, + secondaryFields: undefined, + ...(params as Partial), + }; if ('format' in newParams && field.type !== 'number') { delete newParams.format; } return { ...oldColumn, dataType: field.type as DataType, - label: ofName(field.displayName, 0, newParams.orderBy.type === 'rare'), + label: ofName( + field.displayName, + newParams.secondaryFields?.length, + newParams.orderBy.type === 'rare' + ), sourceField: field.name, params: newParams, }; diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/terms.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/terms.test.tsx index 2cf702d4b149fe..bc1106ad3debf7 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/terms.test.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/terms.test.tsx @@ -89,6 +89,28 @@ describe('terms', () => { }; }); + function createMultiTermsColumn(terms: string | string[]): TermsIndexPatternColumn { + const termsArray = Array.isArray(terms) ? terms : [terms]; + + const [sourceField, ...secondaryFields] = termsArray; + + return { + operationType: 'terms', + sourceField, + label: 'Top values of source', + isBucketed: true, + dataType: 'string', + params: { + size: 5, + orderBy: { + type: 'alphabetical', + }, + orderDirection: 'asc', + secondaryFields, + }, + }; + } + describe('toEsAggsFn', () => { it('should reflect params correctly', () => { const termsColumn = layer.columns.col1 as TermsIndexPatternColumn; @@ -236,6 +258,32 @@ describe('terms', () => { const column = termsOperation.onFieldChange(oldColumn, newStringField); expect(column.params.secondaryFields).toBeUndefined(); }); + + it('should merge secondaryFields when coming from partial column argument', () => { + const oldColumn: TermsIndexPatternColumn = { + operationType: 'terms', + sourceField: 'bytes', + label: 'Top values of bytes', + isBucketed: true, + dataType: 'number', + params: { + size: 5, + orderBy: { + type: 'alphabetical', + }, + orderDirection: 'asc', + format: { id: 'number', params: { decimals: 0 } }, + secondaryFields: ['dest'], + }, + }; + const indexPattern = createMockedIndexPattern(); + const sanemStringField = indexPattern.fields.find((i) => i.name === 'bytes')!; + + const column = termsOperation.onFieldChange(oldColumn, sanemStringField, { + secondaryFields: ['dest', 'geo.src'], + }); + expect(column.params.secondaryFields).toEqual(expect.arrayContaining(['dest', 'geo.src'])); + }); }); describe('getPossibleOperationForField', () => { @@ -1854,4 +1902,223 @@ describe('terms', () => { }); }); }); + + describe('canAddNewField', () => { + it("should reject if there's only sourceField but is not new", () => { + expect( + termsOperation.canAddNewField?.({ + targetColumn: createMultiTermsColumn('source'), + sourceColumn: createMultiTermsColumn('source'), + indexPattern: defaultProps.indexPattern, + }) + ).toEqual(false); + }); + + it("should reject if there's no additional field to add", () => { + expect( + termsOperation.canAddNewField?.({ + targetColumn: createMultiTermsColumn(['source', 'bytes', 'dest']), + sourceColumn: createMultiTermsColumn(['source', 'dest']), + indexPattern: defaultProps.indexPattern, + }) + ).toEqual(false); + }); + + it('should reject if the passed field is already present', () => { + const indexPattern = createMockedIndexPattern(); + const field = indexPattern.getFieldByName('source')!; + + expect( + termsOperation.canAddNewField?.({ + targetColumn: createMultiTermsColumn('source'), + field, + indexPattern, + }) + ).toEqual(false); + }); + + it('should be positive if only the sourceField can be added', () => { + expect( + termsOperation.canAddNewField?.({ + targetColumn: createMultiTermsColumn(['source', 'dest']), + sourceColumn: createMultiTermsColumn(['bytes', 'dest']), + indexPattern: defaultProps.indexPattern, + }) + ).toEqual(true); + }); + + it('should be positive if some field can be added', () => { + expect( + termsOperation.canAddNewField?.({ + targetColumn: createMultiTermsColumn(['source', 'dest']), + sourceColumn: createMultiTermsColumn(['dest', 'bytes', 'memory']), + indexPattern: defaultProps.indexPattern, + }) + ).toEqual(true); + }); + + it('should be positive if the entire column can be added', () => { + expect( + termsOperation.canAddNewField?.({ + targetColumn: createMultiTermsColumn(['source', 'dest']), + sourceColumn: createMultiTermsColumn(['bytes', 'memory']), + indexPattern: defaultProps.indexPattern, + }) + ).toEqual(true); + }); + + it('should reject if all fields can be added but will overpass the terms limit', () => { + // limit is 5 terms + expect( + termsOperation.canAddNewField?.({ + targetColumn: createMultiTermsColumn(['source', 'dest']), + sourceColumn: createMultiTermsColumn(['bytes', 'geo.src', 'dest', 'memory']), + indexPattern: defaultProps.indexPattern, + }) + ).toEqual(false); + }); + + it('should be positive if the passed field is new', () => { + const indexPattern = createMockedIndexPattern(); + const field = indexPattern.getFieldByName('bytes')!; + + expect( + termsOperation.canAddNewField?.({ + targetColumn: createMultiTermsColumn('source'), + field, + indexPattern, + }) + ).toEqual(true); + }); + + it('should reject if the passed field is new but it will overpass the terms limit', () => { + const indexPattern = createMockedIndexPattern(); + const field = indexPattern.getFieldByName('bytes')!; + + expect( + termsOperation.canAddNewField?.({ + targetColumn: createMultiTermsColumn(['bytes', 'geo.src', 'dest', 'memory', 'source']), + field, + indexPattern, + }) + ).toEqual(false); + }); + + it('should reject if the passed field is a scripted field', () => { + const indexPattern = createMockedIndexPattern(); + const field = indexPattern.getFieldByName('scripted')!; + + expect( + termsOperation.canAddNewField?.({ + targetColumn: createMultiTermsColumn(['bytes', 'source', 'dest', 'memory']), + field, + indexPattern, + }) + ).toEqual(false); + }); + + it('should reject if the entire column has scripted field', () => { + expect( + termsOperation.canAddNewField?.({ + targetColumn: createMultiTermsColumn(['source', 'dest']), + sourceColumn: createMultiTermsColumn(['scripted', 'scripted']), + indexPattern: defaultProps.indexPattern, + }) + ).toEqual(false); + }); + + it('should be positive if the entire column can be added (because ignoring scripted fields)', () => { + expect( + termsOperation.canAddNewField?.({ + targetColumn: createMultiTermsColumn(['source', 'dest']), + sourceColumn: createMultiTermsColumn(['bytes', 'memory', 'dest', 'scripted']), + indexPattern: defaultProps.indexPattern, + }) + ).toEqual(true); + }); + }); + + describe('getParamsForMultipleFields', () => { + it('should return existing multiterms with multiple fields from source column', () => { + expect( + termsOperation.getParamsForMultipleFields?.({ + targetColumn: createMultiTermsColumn(['source', 'dest']), + sourceColumn: createMultiTermsColumn(['bytes', 'memory']), + indexPattern: defaultProps.indexPattern, + }) + ).toEqual({ secondaryFields: expect.arrayContaining(['dest', 'bytes', 'memory']) }); + }); + + it('should return existing multiterms with only new fields from source column', () => { + expect( + termsOperation.getParamsForMultipleFields?.({ + targetColumn: createMultiTermsColumn(['source', 'dest']), + sourceColumn: createMultiTermsColumn(['bytes', 'dest']), + indexPattern: defaultProps.indexPattern, + }) + ).toEqual({ secondaryFields: expect.arrayContaining(['dest', 'bytes']) }); + }); + + it('should return existing multiterms with only multiple new fields from source column', () => { + expect( + termsOperation.getParamsForMultipleFields?.({ + targetColumn: createMultiTermsColumn(['source', 'dest']), + sourceColumn: createMultiTermsColumn(['dest', 'bytes', 'memory']), + indexPattern: defaultProps.indexPattern, + }) + ).toEqual({ secondaryFields: expect.arrayContaining(['dest', 'bytes', 'memory']) }); + }); + + it('should append field to multiterms', () => { + const indexPattern = createMockedIndexPattern(); + const field = indexPattern.getFieldByName('bytes')!; + + expect( + termsOperation.getParamsForMultipleFields?.({ + targetColumn: createMultiTermsColumn('source'), + field, + indexPattern, + }) + ).toEqual({ secondaryFields: expect.arrayContaining(['bytes']) }); + }); + + it('should not append scripted field to multiterms', () => { + const indexPattern = createMockedIndexPattern(); + const field = indexPattern.getFieldByName('scripted')!; + + expect( + termsOperation.getParamsForMultipleFields?.({ + targetColumn: createMultiTermsColumn('source'), + field, + indexPattern, + }) + ).toEqual({ secondaryFields: [] }); + }); + + it('should add both sourceColumn and field (as last term) to the targetColumn', () => { + const indexPattern = createMockedIndexPattern(); + const field = indexPattern.getFieldByName('bytes')!; + expect( + termsOperation.getParamsForMultipleFields?.({ + targetColumn: createMultiTermsColumn(['source', 'dest']), + sourceColumn: createMultiTermsColumn(['memory']), + field, + indexPattern, + }) + ).toEqual({ secondaryFields: expect.arrayContaining(['dest', 'memory', 'bytes']) }); + }); + + it('should not add sourceColumn field if it has only scripted field', () => { + const indexPattern = createMockedIndexPattern(); + const field = indexPattern.getFieldByName('bytes')!; + expect( + termsOperation.getParamsForMultipleFields?.({ + targetColumn: createMultiTermsColumn(['source', 'dest']), + sourceColumn: createMultiTermsColumn(['scripted']), + field, + indexPattern, + }) + ).toEqual({ secondaryFields: expect.arrayContaining(['dest', 'bytes']) }); + }); + }); }); diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/layer_helpers.test.ts b/x-pack/plugins/lens/public/indexpattern_datasource/operations/layer_helpers.test.ts index 66ed0e83c97e45..9066641b522d98 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/layer_helpers.test.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/layer_helpers.test.ts @@ -1392,6 +1392,42 @@ describe('state_helpers', () => { ); }); + it('should combine multiple partial params if the column supports multiple fields', () => { + const termsColumn: TermsIndexPatternColumn = { + label: 'Top values of source', + dataType: 'string', + isBucketed: true, + + // Private + operationType: 'terms', + sourceField: 'source', + params: { + orderBy: { type: 'alphabetical', fallback: true }, + orderDirection: 'desc', + size: 5, + }, + }; + + replaceColumn({ + layer: { + indexPatternId: '1', + columnOrder: ['col1'], + columns: { + col1: termsColumn, + }, + }, + indexPattern, + columnId: 'col1', + op: 'cumulative_sum', + visualizationGroups: [], + field: indexPattern.getFieldByName(termsColumn.sourceField), + initialParams: { + params: { secondaryFields: ['dest'] }, + }, + shouldCombineField: true, + }); + }); + describe('switching from non-reference to reference test cases', () => { it('should wrap around the previous operation as a reference if possible (case new1)', () => { const expectedColumn = { diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/layer_helpers.ts b/x-pack/plugins/lens/public/indexpattern_datasource/operations/layer_helpers.ts index dda1b16bc6c7b8..7985500798b385 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/layer_helpers.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/layer_helpers.ts @@ -55,6 +55,7 @@ interface ColumnChange { visualizationGroups: VisualizationDimensionGroupConfig[]; targetGroup?: string; shouldResetLabel?: boolean; + shouldCombineField?: boolean; incompleteParams?: ColumnAdvancedParams; initialParams?: { params: Record }; // TODO: bind this to the op parameter } @@ -374,7 +375,9 @@ export function replaceColumn({ op, field, visualizationGroups, + initialParams, shouldResetLabel, + shouldCombineField, }: ColumnChange): IndexPatternLayer { const previousColumn = layer.columns[columnId]; if (!previousColumn) { @@ -641,10 +644,14 @@ export function replaceColumn({ operationDefinition.input === 'field' && field && 'sourceField' in previousColumn && - previousColumn.sourceField !== field.name + (previousColumn.sourceField !== field.name || operationDefinition?.getParamsForMultipleFields) ) { // Same operation, new field - let newColumn = operationDefinition.onFieldChange(previousColumn, field); + let newColumn = operationDefinition.onFieldChange( + previousColumn, + field, + shouldCombineField ? initialParams?.params : undefined + ); if (!shouldResetLabel) { newColumn = copyCustomLabel(newColumn, previousColumn); } diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/operations.ts b/x-pack/plugins/lens/public/indexpattern_datasource/operations/operations.ts index fc70be257c8ad9..82093b31a09d98 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/operations.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/operations.ts @@ -13,9 +13,11 @@ import { GenericOperationDefinition, OperationType, renameOperationsMapping, + BaseIndexPatternColumn, } from './definitions'; import { IndexPattern, IndexPatternField } from '../types'; import { documentField } from '../document_field'; +import { hasField } from '../pure_utils'; export { operationDefinitionMap } from './definitions'; /** @@ -61,6 +63,37 @@ export function getSortScoreByPriority( return (b.priority || Number.NEGATIVE_INFINITY) - (a.priority || Number.NEGATIVE_INFINITY); } +export function getCurrentFieldsForOperation(targetColumn: BaseIndexPatternColumn) { + if (!hasField(targetColumn)) { + return []; + } + return ( + operationDefinitionMap[targetColumn.operationType]?.getCurrentFields?.(targetColumn) ?? [ + targetColumn.sourceField, + ] + ); +} + +export function getOperationHelperForMultipleFields(operationType: string) { + return operationDefinitionMap[operationType]?.getParamsForMultipleFields; +} + +export function hasOperationSupportForMultipleFields( + indexPattern: IndexPattern, + targetColumn: BaseIndexPatternColumn, + sourceColumn?: BaseIndexPatternColumn, + field?: IndexPatternField +) { + return Boolean( + operationDefinitionMap[targetColumn.operationType]?.canAddNewField?.({ + targetColumn, + sourceColumn, + field, + indexPattern, + }) + ); +} + /** * Returns all `OperationType`s that can build a column using `buildColumn` based on the * passed in field. diff --git a/x-pack/plugins/lens/public/types.ts b/x-pack/plugins/lens/public/types.ts index 27a214cd2fb2e5..aa41025b818ebb 100644 --- a/x-pack/plugins/lens/public/types.ts +++ b/x-pack/plugins/lens/public/types.ts @@ -147,7 +147,10 @@ export type DropType = | 'swap_compatible' | 'replace_duplicate_incompatible' | 'duplicate_incompatible' - | 'swap_incompatible'; + | 'swap_incompatible' + | 'field_combine' + | 'combine_compatible' + | 'combine_incompatible'; export interface DatasourceSuggestion { state: T; diff --git a/x-pack/test/functional/apps/lens/drag_and_drop.ts b/x-pack/test/functional/apps/lens/drag_and_drop.ts index e7b7ba18d62fbf..2858ff1588f7cb 100644 --- a/x-pack/test/functional/apps/lens/drag_and_drop.ts +++ b/x-pack/test/functional/apps/lens/drag_and_drop.ts @@ -162,6 +162,65 @@ export default function ({ getPageObjects }: FtrProviderContext) { 'Top values of @message.raw' ); }); + + it('should combine breakdown dimension with the horizontal one', async () => { + await PageObjects.lens.removeLayer(); + await PageObjects.lens.dragFieldToWorkspace('clientip'); + await PageObjects.lens.dragFieldToWorkspace('@message.raw'); + + await PageObjects.lens.dragDimensionToExtraDropType( + 'lnsXY_splitDimensionPanel > lns-dimensionTrigger', + 'lnsXY_xDimensionPanel', + 'combine' + ); + expect(await PageObjects.lens.getDimensionTriggerText('lnsXY_xDimensionPanel')).to.eql( + 'Top values of clientip + 1 other' + ); + }); + + it('should combine field to existing horizontal dimension', async () => { + await PageObjects.lens.removeLayer(); + await PageObjects.lens.dragFieldToWorkspace('clientip'); + + await PageObjects.lens.dragFieldToExtraDropType( + '@message.raw', + 'lnsXY_xDimensionPanel', + 'combine' + ); + expect(await PageObjects.lens.getDimensionTriggerText('lnsXY_xDimensionPanel')).to.eql( + 'Top values of clientip + 1 other' + ); + }); + + it('should combine two multi terms dimensions', async () => { + await PageObjects.lens.removeLayer(); + await PageObjects.lens.dragFieldToWorkspace('clientip'); + + await PageObjects.lens.dragFieldToExtraDropType( + '@message.raw', + 'lnsXY_xDimensionPanel', + 'combine' + ); + + await PageObjects.lens.dragFieldToDimensionTrigger( + '@message.raw', + 'lnsXY_splitDimensionPanel > lns-empty-dimension' + ); + await PageObjects.lens.dragFieldToExtraDropType( + 'geo.src', + 'lnsXY_splitDimensionPanel', + 'combine' + ); + await PageObjects.lens.dragDimensionToExtraDropType( + 'lnsXY_splitDimensionPanel > lns-dimensionTrigger', + 'lnsXY_xDimensionPanel', + 'combine' + ); + + expect(await PageObjects.lens.getDimensionTriggerText('lnsXY_xDimensionPanel')).to.eql( + 'Top values of clientip + 2 others' + ); + }); }); describe('keyboard drag and drop', () => { diff --git a/x-pack/test/functional/page_objects/lens_page.ts b/x-pack/test/functional/page_objects/lens_page.ts index 0a892e96381cb5..6f402ac4426484 100644 --- a/x-pack/test/functional/page_objects/lens_page.ts +++ b/x-pack/test/functional/page_objects/lens_page.ts @@ -289,6 +289,30 @@ export function LensPageProvider({ getService, getPageObjects }: FtrProviderCont }); }, + async pressMetaKey(metaKey: 'shift' | 'alt' | 'ctrl') { + const metaToAction = { + shift: 'duplicate', + alt: 'swap', + ctrl: 'combine', + }; + const waitTime = 1000; + log.debug(`Wait ${waitTime}ms for the extra dop options to show up`); + await setTimeoutAsync(waitTime); + const browserKey = + metaKey === 'shift' + ? browser.keys.SHIFT + : metaKey === 'alt' + ? browser.keys.ALT + : browser.keys.COMMAND; + log.debug(`Press ${metaKey} with keyboard`); + await retry.try(async () => { + await browser.pressKeys(browserKey); + await find.existsByCssSelector( + `.lnsDragDrop__extraDrop > [data-test-subj="lnsDragDrop-${metaToAction[metaKey]}"].lnsDragDrop-isActiveDropTarget` + ); + }); + }, + /** * Copies field to chosen destination that is defined by distance of `steps` * (right arrow presses) from it @@ -297,7 +321,12 @@ export function LensPageProvider({ getService, getPageObjects }: FtrProviderCont * @param steps - number of steps user has to press right * @param reverse - defines the direction of going through drops * */ - async dragFieldWithKeyboard(fieldName: string, steps = 1, reverse = false) { + async dragFieldWithKeyboard( + fieldName: string, + steps = 1, + reverse = false, + metaKey?: 'shift' | 'alt' | 'ctrl' + ) { const field = await find.byCssSelector( `[data-test-subj="lnsDragDrop_draggable-${fieldName}"] [data-test-subj="lnsDragDrop-keyboardHandler"]` ); @@ -309,6 +338,9 @@ export function LensPageProvider({ getService, getPageObjects }: FtrProviderCont for (let i = 0; i < steps; i++) { await browser.pressKeys(reverse ? browser.keys.LEFT : browser.keys.RIGHT); } + if (metaKey) { + this.pressMetaKey(metaKey); + } await browser.pressKeys(browser.keys.ENTER); await this.waitForLensDragDropToFinish(); @@ -323,7 +355,13 @@ export function LensPageProvider({ getService, getPageObjects }: FtrProviderCont * @param steps - number of steps of presses right or left * @param reverse - defines the direction of going through drops * */ - async dimensionKeyboardDragDrop(group: string, index = 0, steps = 1, reverse = false) { + async dimensionKeyboardDragDrop( + group: string, + index = 0, + steps = 1, + reverse = false, + metaKey?: 'shift' | 'alt' | 'ctrl' + ) { const elements = await find.allByCssSelector( `[data-test-subj="${group}"] [data-test-subj="lnsDragDrop-keyboardHandler"]` ); @@ -333,6 +371,9 @@ export function LensPageProvider({ getService, getPageObjects }: FtrProviderCont for (let i = 0; i < steps; i++) { await browser.pressKeys(reverse ? browser.keys.LEFT : browser.keys.RIGHT); } + if (metaKey) { + this.pressMetaKey(metaKey); + } await browser.pressKeys(browser.keys.ENTER); await this.waitForLensDragDropToFinish(); @@ -389,7 +430,7 @@ export function LensPageProvider({ getService, getPageObjects }: FtrProviderCont }, /** - * Drags field to dimension trigger + * Drags from a dimension to another dimension trigger * * @param from - the selector of the dimension being moved * @param to - the selector of the dimension being dropped to @@ -1196,13 +1237,38 @@ export function LensPageProvider({ getService, getPageObjects }: FtrProviderCont }, /** - * Drags field to dimension trigger to extra drop type + * Drags from a dimension to another dimension trigger to extra drop type * * @param from - the selector of the dimension being moved * @param to - the selector of the main drop type of dimension being dropped to * @param type - extra drop type * */ - async dragDimensionToExtraDropType(from: string, to: string, type: 'duplicate' | 'swap') { + async dragFieldToExtraDropType( + field: string, + to: string, + type: 'duplicate' | 'swap' | 'combine' + ) { + const from = `lnsFieldListPanelField-${field}`; + await this.dragEnterDrop( + testSubjects.getCssSelector(from), + testSubjects.getCssSelector(`${to} > lnsDragDrop`), + testSubjects.getCssSelector(`${to} > lnsDragDrop-${type}`) + ); + await PageObjects.header.waitUntilLoadingHasFinished(); + }, + + /** + * Drags from a dimension to another dimension trigger to extra drop type + * + * @param from - the selector of the dimension being moved + * @param to - the selector of the main drop type of dimension being dropped to + * @param type - extra drop type + * */ + async dragDimensionToExtraDropType( + from: string, + to: string, + type: 'duplicate' | 'swap' | 'combine' + ) { await this.dragEnterDrop( testSubjects.getCssSelector(from), testSubjects.getCssSelector(`${to} > lnsDragDrop`), From ef14e7ff0149fab33cc5908dab81c8b38a6cb72e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yulia=20=C4=8Cech?= <6585477+yuliacech@users.noreply.github.com> Date: Wed, 19 Jan 2022 16:06:42 +0100 Subject: [PATCH 045/108] [Upgrade Assistant] Fixed functional test failures on Cloud (#123260) [Upgrade Assistant] Fixed functional test failures on Cloud [Upgrade Assistant] Fixed functional test failures on Cloud [Upgrade Assistant] Adding logging to debug Revert "[Upgrade Assistant] Adding logging to debug" This reverts commit 84e23083b2d4bb2ce48a397a13261393810d4d1e. Revert "[Upgrade Assistant] Fixed functional test failures on Cloud" This reverts commit 94f337f3912161a8a5d8903db607378ed86f4a7a. [Upgrade Assistant] Skipping not backed up status on cloud Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../apis/upgrade_assistant/cloud_backup_status.ts | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/x-pack/test/api_integration/apis/upgrade_assistant/cloud_backup_status.ts b/x-pack/test/api_integration/apis/upgrade_assistant/cloud_backup_status.ts index 0652911839742d..680b51d55ebd06 100644 --- a/x-pack/test/api_integration/apis/upgrade_assistant/cloud_backup_status.ts +++ b/x-pack/test/api_integration/apis/upgrade_assistant/cloud_backup_status.ts @@ -12,6 +12,7 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ getService }: FtrProviderContext) { const supertest = getService('supertest'); const es = getService('es'); + const deployment = getService('deployment'); const CLOUD_SNAPSHOT_REPOSITORY = 'found-snapshots'; @@ -50,16 +51,16 @@ export default function ({ getService }: FtrProviderContext) { }; describe('Cloud backup status', function () { - // file system repositories are not supported in cloud - this.tags(['skipCloud']); - describe('get', () => { describe('with backups present', () => { // Needs SnapshotInfo type https://github.com/elastic/elasticsearch-specification/issues/685 let mostRecentSnapshot: any; before(async () => { - await createCloudRepository(); + const isCloud = await deployment.isCloud(); + if (!isCloud) { + await createCloudRepository(); + } await createCloudSnapshot('test_snapshot_1'); mostRecentSnapshot = (await createCloudSnapshot('test_snapshot_2')).snapshot; }); @@ -81,6 +82,8 @@ export default function ({ getService }: FtrProviderContext) { }); describe('without backups present', () => { + // snapshot repository on Cloud always has a snapshot so the status is returned as backed up + this.tags(['skipCloud']); it('returns not-backed-up status', async () => { const { body: cloudBackupStatus } = await supertest .get('/api/upgrade_assistant/cloud_backup_status') From 1f6ea432d25c4f72be3197084e8513a4e0a44327 Mon Sep 17 00:00:00 2001 From: Chris Roberson Date: Wed, 19 Jan 2022 10:29:02 -0500 Subject: [PATCH 046/108] [ResponseOps] Store success, failure and success ratio on the rule saved object (#122716) * Success and failure ratio * New shape * Fix these tests * Ensure we apply this at creation time too, and update tests to account for it * Find more places * Update tests * Add more tests * Fix test * Add 200 cap * Add debugging * Change order * Remove debug and add clarifying comment * Add client side tests * Add timestamp * Fix tests * PR feedback Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- x-pack/plugins/alerting/common/alert.ts | 13 + .../server/rules_client/rules_client.ts | 2 + .../server/rules_client/tests/create.test.ts | 25 ++ .../alerting/server/saved_objects/index.ts | 4 +- .../server/saved_objects/mappings.json | 25 ++ .../server/task_runner/task_runner.test.ts | 359 +++++++++++++++++- .../server/task_runner/task_runner.ts | 58 ++- x-pack/plugins/alerting/server/types.ts | 2 + .../application/lib/monitoring_utils.test.ts | 14 + .../application/lib/monitoring_utils.ts | 12 + .../components/alerts_list.test.tsx | 41 ++ .../alerts_list/components/alerts_list.tsx | 31 ++ .../plugins/alerts/server/alert_types.ts | 40 ++ .../fixtures/plugins/alerts/server/plugin.ts | 3 + .../tests/alerting/create.ts | 1 + .../tests/alerting/find.ts | 2 + .../security_and_spaces/tests/alerting/get.ts | 1 + .../tests/alerting/update.ts | 5 + .../spaces_only/tests/alerting/create.ts | 3 + .../spaces_only/tests/alerting/find.ts | 2 + .../spaces_only/tests/alerting/get.ts | 2 + .../spaces_only/tests/alerting/index.ts | 2 + .../spaces_only/tests/alerting/monitoring.ts | 127 +++++++ .../spaces_only/tests/alerting/update.ts | 2 + 24 files changed, 761 insertions(+), 15 deletions(-) create mode 100644 x-pack/plugins/triggers_actions_ui/public/application/lib/monitoring_utils.test.ts create mode 100644 x-pack/plugins/triggers_actions_ui/public/application/lib/monitoring_utils.ts create mode 100644 x-pack/test/alerting_api_integration/spaces_only/tests/alerting/monitoring.ts diff --git a/x-pack/plugins/alerting/common/alert.ts b/x-pack/plugins/alerting/common/alert.ts index 8064f6d920217e..6f07d4b7950639 100644 --- a/x-pack/plugins/alerting/common/alert.ts +++ b/x-pack/plugins/alerting/common/alert.ts @@ -82,6 +82,7 @@ export interface Alert { muteAll: boolean; mutedInstanceIds: string[]; executionStatus: AlertExecutionStatus; + monitoring?: RuleMonitoring; } export type SanitizedAlert = Omit, 'apiKey'>; @@ -135,3 +136,15 @@ export interface ActionVariable { deprecated?: boolean; useWithTripleBracesInTemplates?: boolean; } + +export interface RuleMonitoring extends SavedObjectAttributes { + execution: { + history: Array<{ + success: boolean; + timestamp: number; + }>; + calculated_metrics: { + success_ratio: number; + }; + }; +} diff --git a/x-pack/plugins/alerting/server/rules_client/rules_client.ts b/x-pack/plugins/alerting/server/rules_client/rules_client.ts index 50a93a5630d42b..3603a60baadb1e 100644 --- a/x-pack/plugins/alerting/server/rules_client/rules_client.ts +++ b/x-pack/plugins/alerting/server/rules_client/rules_client.ts @@ -77,6 +77,7 @@ import { getRuleExecutionStatusPending } from '../lib/rule_execution_status'; import { AlertInstance } from '../alert_instance'; import { EVENT_LOG_ACTIONS } from '../plugin'; import { createAlertEventLogRecordObject } from '../lib/create_alert_event_log_record_object'; +import { getDefaultRuleMonitoring } from '../task_runner/task_runner'; export interface RegistryAlertTypeWithAuth extends RegistryRuleType { authorizedConsumers: string[]; @@ -362,6 +363,7 @@ export class RulesClient { mutedInstanceIds: [], notifyWhen, executionStatus: getRuleExecutionStatusPending(new Date().toISOString()), + monitoring: getDefaultRuleMonitoring(), }; this.auditLogger?.log( diff --git a/x-pack/plugins/alerting/server/rules_client/tests/create.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/create.test.ts index aa8ecfd73bb611..4061917b151977 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/create.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/create.test.ts @@ -20,6 +20,7 @@ import { auditServiceMock } from '../../../../security/server/audit/index.mock'; import { httpServerMock } from '../../../../../../src/core/server/mocks'; import { getBeforeSetup, setGlobalDate } from './lib'; import { RecoveredActionGroup } from '../../../common'; +import { getDefaultRuleMonitoring } from '../../task_runner/task_runner'; jest.mock('../../../../../../src/core/server/saved_objects/service/lib/utils', () => ({ SavedObjectsUtils: { @@ -407,6 +408,14 @@ describe('create()', () => { "meta": Object { "versionApiKeyLastmodified": "v8.0.0", }, + "monitoring": Object { + "execution": Object { + "calculated_metrics": Object { + "success_ratio": 0, + }, + "history": Array [], + }, + }, "muteAll": false, "mutedInstanceIds": Array [], "name": "abc", @@ -600,6 +609,14 @@ describe('create()', () => { "meta": Object { "versionApiKeyLastmodified": "v7.10.0", }, + "monitoring": Object { + "execution": Object { + "calculated_metrics": Object { + "success_ratio": 0, + }, + "history": Array [], + }, + }, "muteAll": false, "mutedInstanceIds": Array [], "name": "abc", @@ -1014,6 +1031,7 @@ describe('create()', () => { lastExecutionDate: '2019-02-12T21:01:22.479Z', status: 'pending', }, + monitoring: getDefaultRuleMonitoring(), meta: { versionApiKeyLastmodified: kibanaVersion }, muteAll: false, mutedInstanceIds: [], @@ -1210,6 +1228,7 @@ describe('create()', () => { lastExecutionDate: '2019-02-12T21:01:22.479Z', status: 'pending', }, + monitoring: getDefaultRuleMonitoring(), meta: { versionApiKeyLastmodified: kibanaVersion }, muteAll: false, mutedInstanceIds: [], @@ -1375,6 +1394,7 @@ describe('create()', () => { lastExecutionDate: '2019-02-12T21:01:22.479Z', status: 'pending', }, + monitoring: getDefaultRuleMonitoring(), meta: { versionApiKeyLastmodified: kibanaVersion }, muteAll: false, mutedInstanceIds: [], @@ -1548,6 +1568,7 @@ describe('create()', () => { status: 'pending', error: null, }, + monitoring: getDefaultRuleMonitoring(), }, { id: 'mock-saved-object-id', @@ -1676,6 +1697,7 @@ describe('create()', () => { status: 'pending', error: null, }, + monitoring: getDefaultRuleMonitoring(), }, { id: 'mock-saved-object-id', @@ -1804,6 +1826,7 @@ describe('create()', () => { status: 'pending', error: null, }, + monitoring: getDefaultRuleMonitoring(), }, { id: 'mock-saved-object-id', @@ -2155,6 +2178,7 @@ describe('create()', () => { status: 'pending', error: null, }, + monitoring: getDefaultRuleMonitoring(), }, { id: 'mock-saved-object-id', @@ -2254,6 +2278,7 @@ describe('create()', () => { status: 'pending', error: null, }, + monitoring: getDefaultRuleMonitoring(), }, { id: 'mock-saved-object-id', diff --git a/x-pack/plugins/alerting/server/saved_objects/index.ts b/x-pack/plugins/alerting/server/saved_objects/index.ts index d53635ec4f05d2..4768a1f7795429 100644 --- a/x-pack/plugins/alerting/server/saved_objects/index.ts +++ b/x-pack/plugins/alerting/server/saved_objects/index.ts @@ -29,6 +29,7 @@ export const AlertAttributesExcludedFromAAD = [ 'updatedBy', 'updatedAt', 'executionStatus', + 'monitoring', ]; // useful for Pick which is a @@ -41,7 +42,8 @@ export type AlertAttributesExcludedFromAADType = | 'mutedInstanceIds' | 'updatedBy' | 'updatedAt' - | 'executionStatus'; + | 'executionStatus' + | 'monitoring'; export function setupSavedObjects( savedObjects: SavedObjectsServiceSetup, diff --git a/x-pack/plugins/alerting/server/saved_objects/mappings.json b/x-pack/plugins/alerting/server/saved_objects/mappings.json index 05e221a47499c9..6923c94ec60a0a 100644 --- a/x-pack/plugins/alerting/server/saved_objects/mappings.json +++ b/x-pack/plugins/alerting/server/saved_objects/mappings.json @@ -93,6 +93,31 @@ } } }, + "monitoring": { + "properties": { + "execution": { + "properties": { + "history": { + "properties": { + "success": { + "type": "boolean" + }, + "timestamp": { + "type": "date" + } + } + }, + "calculated_metrics": { + "properties": { + "success_ratio": { + "type": "float" + } + } + } + } + } + } + }, "executionStatus": { "properties": { "status": { diff --git a/x-pack/plugins/alerting/server/task_runner/task_runner.test.ts b/x-pack/plugins/alerting/server/task_runner/task_runner.test.ts index eb5529a9db8538..61d41e674c209f 100644 --- a/x-pack/plugins/alerting/server/task_runner/task_runner.test.ts +++ b/x-pack/plugins/alerting/server/task_runner/task_runner.test.ts @@ -21,7 +21,7 @@ import { TaskStatus, } from '../../../task_manager/server'; import { TaskRunnerContext } from './task_runner_factory'; -import { TaskRunner } from './task_runner'; +import { TaskRunner, getDefaultRuleMonitoring } from './task_runner'; import { encryptedSavedObjectsMock } from '../../../encrypted_saved_objects/server/mocks'; import { loggingSystemMock, @@ -176,6 +176,7 @@ describe('Task Runner', () => { status: 'unknown', lastExecutionDate: new Date('2020-08-20T19:23:38Z'), }, + monitoring: getDefaultRuleMonitoring(), }; beforeEach(() => { @@ -192,6 +193,8 @@ describe('Task Runner', () => { taskRunnerFactoryInitializerParams.executionContext.withContext.mockImplementation((ctx, fn) => fn() ); + mockedRuleTypeSavedObject.monitoring!.execution.history = []; + mockedRuleTypeSavedObject.monitoring!.execution.calculated_metrics.success_ratio = 0; }); test('successfully executes the task', async () => { @@ -219,6 +222,19 @@ describe('Task Runner', () => { const runnerResult = await taskRunner.run(); expect(runnerResult).toMatchInlineSnapshot(` Object { + "monitoring": Object { + "execution": Object { + "calculated_metrics": Object { + "success_ratio": 1, + }, + "history": Array [ + Object { + "success": true, + "timestamp": 0, + }, + ], + }, + }, "schedule": Object { "interval": "10s", }, @@ -337,6 +353,19 @@ describe('Task Runner', () => { 'alert', '1', { + monitoring: { + execution: { + calculated_metrics: { + success_ratio: 1, + }, + history: [ + { + success: true, + timestamp: 0, + }, + ], + }, + }, executionStatus: { error: null, lastDuration: 0, @@ -2303,8 +2332,22 @@ describe('Task Runner', () => { }, references: [], }); - expect(await taskRunner.run()).toMatchInlineSnapshot(` + const runnerResult = await taskRunner.run(); + expect(runnerResult).toMatchInlineSnapshot(` Object { + "monitoring": Object { + "execution": Object { + "calculated_metrics": Object { + "success_ratio": 0, + }, + "history": Array [ + Object { + "success": false, + "timestamp": 0, + }, + ], + }, + }, "schedule": Object { "interval": "10s", }, @@ -2404,8 +2447,22 @@ describe('Task Runner', () => { references: [], }); - expect(await taskRunner.run()).toMatchInlineSnapshot(` + const runnerResult = await taskRunner.run(); + expect(runnerResult).toMatchInlineSnapshot(` Object { + "monitoring": Object { + "execution": Object { + "calculated_metrics": Object { + "success_ratio": 1, + }, + "history": Array [ + Object { + "success": true, + "timestamp": 0, + }, + ], + }, + }, "schedule": Object { "interval": "30s", }, @@ -2454,6 +2511,19 @@ describe('Task Runner', () => { expect(runnerResult).toMatchInlineSnapshot(` Object { + "monitoring": Object { + "execution": Object { + "calculated_metrics": Object { + "success_ratio": 0, + }, + "history": Array [ + Object { + "success": false, + "timestamp": 0, + }, + ], + }, + }, "schedule": Object { "interval": "10s", }, @@ -2561,6 +2631,19 @@ describe('Task Runner', () => { expect(runnerResult).toMatchInlineSnapshot(` Object { + "monitoring": Object { + "execution": Object { + "calculated_metrics": Object { + "success_ratio": 0, + }, + "history": Array [ + Object { + "success": false, + "timestamp": 0, + }, + ], + }, + }, "schedule": Object { "interval": "10s", }, @@ -2677,6 +2760,19 @@ describe('Task Runner', () => { expect(runnerResult).toMatchInlineSnapshot(` Object { + "monitoring": Object { + "execution": Object { + "calculated_metrics": Object { + "success_ratio": 0, + }, + "history": Array [ + Object { + "success": false, + "timestamp": 0, + }, + ], + }, + }, "schedule": Object { "interval": "10s", }, @@ -2793,6 +2889,19 @@ describe('Task Runner', () => { expect(runnerResult).toMatchInlineSnapshot(` Object { + "monitoring": Object { + "execution": Object { + "calculated_metrics": Object { + "success_ratio": 0, + }, + "history": Array [ + Object { + "success": false, + "timestamp": 0, + }, + ], + }, + }, "schedule": Object { "interval": "10s", }, @@ -2908,6 +3017,19 @@ describe('Task Runner', () => { expect(runnerResult).toMatchInlineSnapshot(` Object { + "monitoring": Object { + "execution": Object { + "calculated_metrics": Object { + "success_ratio": 0, + }, + "history": Array [ + Object { + "success": false, + "timestamp": 0, + }, + ], + }, + }, "schedule": Object { "interval": "10s", }, @@ -3027,6 +3149,19 @@ describe('Task Runner', () => { expect(runnerResult).toMatchInlineSnapshot(` Object { + "monitoring": Object { + "execution": Object { + "calculated_metrics": Object { + "success_ratio": 0, + }, + "history": Array [ + Object { + "success": false, + "timestamp": 0, + }, + ], + }, + }, "schedule": Object { "interval": "5m", }, @@ -4270,6 +4405,19 @@ describe('Task Runner', () => { const runnerResult = await taskRunner.run(); expect(runnerResult).toMatchInlineSnapshot(` Object { + "monitoring": Object { + "execution": Object { + "calculated_metrics": Object { + "success_ratio": 1, + }, + "history": Array [ + Object { + "success": true, + "timestamp": 0, + }, + ], + }, + }, "schedule": Object { "interval": "10s", }, @@ -4388,6 +4536,19 @@ describe('Task Runner', () => { 'alert', '1', { + monitoring: { + execution: { + calculated_metrics: { + success_ratio: 1, + }, + history: [ + { + success: true, + timestamp: 0, + }, + ], + }, + }, executionStatus: { error: null, lastDuration: 0, @@ -4478,4 +4639,196 @@ describe('Task Runner', () => { message: 'test:1: execution failed', }); }); + + test('successfully stores successful runs', async () => { + const taskRunner = new TaskRunner( + ruleType, + mockedTaskInstance, + taskRunnerFactoryInitializerParams + ); + + rulesClient.get.mockResolvedValue(mockedRuleTypeSavedObject); + encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValueOnce({ + id: '1', + type: 'alert', + attributes: { + apiKey: Buffer.from('123:abc').toString('base64'), + enabled: true, + }, + references: [], + }); + const runnerResult = await taskRunner.run(); + expect(runnerResult).toMatchInlineSnapshot(` + Object { + "monitoring": Object { + "execution": Object { + "calculated_metrics": Object { + "success_ratio": 1, + }, + "history": Array [ + Object { + "success": true, + "timestamp": 0, + }, + ], + }, + }, + "schedule": Object { + "interval": "10s", + }, + "state": Object { + "alertInstances": Object {}, + "alertTypeState": undefined, + "previousStartedAt": 1970-01-01T00:00:00.000Z, + }, + } + `); + }); + + test('successfully stores failure runs', async () => { + const taskRunner = new TaskRunner( + ruleType, + mockedTaskInstance, + taskRunnerFactoryInitializerParams + ); + rulesClient.get.mockResolvedValue(mockedRuleTypeSavedObject); + encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValueOnce({ + id: '1', + type: 'alert', + attributes: { + apiKey: Buffer.from('123:abc').toString('base64'), + enabled: true, + }, + references: [], + }); + ruleType.executor.mockImplementation( + async ({ + services: executorServices, + }: AlertExecutorOptions< + AlertTypeParams, + AlertTypeState, + AlertInstanceState, + AlertInstanceContext, + string + >) => { + throw new Error('OMG'); + } + ); + const runnerResult = await taskRunner.run(); + expect(runnerResult).toMatchInlineSnapshot(` + Object { + "monitoring": Object { + "execution": Object { + "calculated_metrics": Object { + "success_ratio": 0, + }, + "history": Array [ + Object { + "success": false, + "timestamp": 0, + }, + ], + }, + }, + "schedule": Object { + "interval": "10s", + }, + "state": Object {}, + } + `); + }); + + test('successfully stores the success ratio', async () => { + const taskRunner = new TaskRunner( + ruleType, + mockedTaskInstance, + taskRunnerFactoryInitializerParams + ); + rulesClient.get.mockResolvedValue(mockedRuleTypeSavedObject); + encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValue({ + id: '1', + type: 'alert', + attributes: { + apiKey: Buffer.from('123:abc').toString('base64'), + enabled: true, + }, + references: [], + }); + await taskRunner.run(); + await taskRunner.run(); + await taskRunner.run(); + + ruleType.executor.mockImplementation( + async ({ + services: executorServices, + }: AlertExecutorOptions< + AlertTypeParams, + AlertTypeState, + AlertInstanceState, + AlertInstanceContext, + string + >) => { + throw new Error('OMG'); + } + ); + const runnerResult = await taskRunner.run(); + ruleType.executor.mockClear(); + expect(runnerResult).toMatchInlineSnapshot(` + Object { + "monitoring": Object { + "execution": Object { + "calculated_metrics": Object { + "success_ratio": 0.75, + }, + "history": Array [ + Object { + "success": true, + "timestamp": 0, + }, + Object { + "success": true, + "timestamp": 0, + }, + Object { + "success": true, + "timestamp": 0, + }, + Object { + "success": false, + "timestamp": 0, + }, + ], + }, + }, + "schedule": Object { + "interval": "10s", + }, + "state": Object {}, + } + `); + }); + + test('caps monitoring history at 200', async () => { + const taskRunner = new TaskRunner( + ruleType, + mockedTaskInstance, + taskRunnerFactoryInitializerParams + ); + rulesClient.get.mockResolvedValue(mockedRuleTypeSavedObject); + encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValue({ + id: '1', + type: 'alert', + attributes: { + apiKey: Buffer.from('123:abc').toString('base64'), + enabled: true, + }, + references: [], + }); + + for (let i = 0; i < 300; i++) { + await taskRunner.run(); + } + const runnerResult = await taskRunner.run(); + expect(runnerResult.monitoring?.execution.history.length).toBe(200); + }); }); diff --git a/x-pack/plugins/alerting/server/task_runner/task_runner.ts b/x-pack/plugins/alerting/server/task_runner/task_runner.ts index 9f7d71143152a4..b4fa5a1927fee5 100644 --- a/x-pack/plugins/alerting/server/task_runner/task_runner.ts +++ b/x-pack/plugins/alerting/server/task_runner/task_runner.ts @@ -33,6 +33,8 @@ import { AlertExecutionStatus, AlertExecutionStatusErrorReasons, RuleTypeRegistry, + RuleMonitoring, + RawRuleExecutionStatus, } from '../types'; import { promiseResult, map, Resultable, asOk, asErr, resolveErr } from '../lib/result_type'; import { taskInstanceToAlertTaskInstance } from './alert_task_instance'; @@ -58,12 +60,23 @@ import { import { createAbortableEsClientFactory } from '../lib/create_abortable_es_client_factory'; const FALLBACK_RETRY_INTERVAL = '5m'; +const MONITORING_HISTORY_LIMIT = 200; // 1,000,000 nanoseconds in 1 millisecond const Millis2Nanos = 1000 * 1000; +export const getDefaultRuleMonitoring = (): RuleMonitoring => ({ + execution: { + history: [], + calculated_metrics: { + success_ratio: 0, + }, + }, +}); + interface RuleTaskRunResult { state: RuleTaskState; + monitoring: RuleMonitoring | undefined; schedule: IntervalSchedule | undefined; } @@ -211,15 +224,12 @@ export class TaskRunner< }); } - private async updateRuleExecutionStatus( + private async updateRuleSavedObject( ruleId: string, namespace: string | undefined, - executionStatus: AlertExecutionStatus + attributes: { executionStatus?: RawRuleExecutionStatus; monitoring?: RuleMonitoring } ) { const client = this.context.internalSavedObjectsRepository; - const attributes = { - executionStatus: ruleExecutionStatusToRaw(executionStatus), - }; try { await partiallyUpdateAlert(client, ruleId, attributes, { @@ -228,9 +238,7 @@ export class TaskRunner< refresh: false, }); } catch (err) { - this.logger.error( - `error updating rule execution status for ${this.ruleType.id}:${ruleId} ${err.message}` - ); + this.logger.error(`error updating rule for ${this.ruleType.id}:${ruleId} ${err.message}`); } } @@ -556,7 +564,15 @@ export class TaskRunner< } catch (err) { throw new ErrorWithReason(AlertExecutionStatusErrorReasons.License, err); } + + if (rule.monitoring) { + if (rule.monitoring.execution.history.length >= MONITORING_HISTORY_LIMIT) { + // Remove the first (oldest) record + rule.monitoring.execution.history.shift(); + } + } return { + monitoring: asOk(rule.monitoring), state: await promiseResult( this.validateAndExecuteRule(services, apiKey, rule, event) ), @@ -622,10 +638,14 @@ export class TaskRunner< }); eventLogger.logEvent(startEvent); - const { state, schedule } = await errorAsRuleTaskRunResult( + const { state, schedule, monitoring } = await errorAsRuleTaskRunResult( this.loadRuleAttributesAndRun(event) ); + const ruleMonitoring = + resolveErr(monitoring, () => { + return getDefaultRuleMonitoring(); + }) ?? getDefaultRuleMonitoring(); const executionStatus: AlertExecutionStatus = map( state, (ruleTaskState: RuleTaskState) => executionStatusFromState(ruleTaskState), @@ -659,6 +679,10 @@ export class TaskRunner< executionStatus.lastDuration = Math.round(event.event?.duration / Millis2Nanos); } + const monitoringHistory = { + success: true, + timestamp: +new Date(), + }; // if executionStatus indicates an error, fill in fields in // event from it if (executionStatus.error) { @@ -670,8 +694,13 @@ export class TaskRunner< if (!event.message) { event.message = `${this.ruleType.id}:${ruleId}: execution failed`; } + monitoringHistory.success = false; } + ruleMonitoring.execution.history.push(monitoringHistory); + ruleMonitoring.execution.calculated_metrics.success_ratio = + ruleMonitoring.execution.history.filter(({ success }) => success).length / + ruleMonitoring.execution.history.length; eventLogger.logEvent(event); if (!this.cancelled) { @@ -680,7 +709,10 @@ export class TaskRunner< executionStatus )}` ); - await this.updateRuleExecutionStatus(ruleId, namespace, executionStatus); + await this.updateRuleSavedObject(ruleId, namespace, { + executionStatus: ruleExecutionStatusToRaw(executionStatus), + monitoring: ruleMonitoring, + }); } return { @@ -714,6 +746,7 @@ export class TaskRunner< } return { interval: taskSchedule?.interval ?? FALLBACK_RETRY_INTERVAL }; }), + monitoring: ruleMonitoring, }; } @@ -784,7 +817,9 @@ export class TaskRunner< this.logger.debug( `Updating rule task for ${this.ruleType.id} rule with id ${ruleId} - execution error due to timeout` ); - await this.updateRuleExecutionStatus(ruleId, namespace, executionStatus); + await this.updateRuleSavedObject(ruleId, namespace, { + executionStatus: ruleExecutionStatusToRaw(executionStatus), + }); } } @@ -1104,6 +1139,7 @@ async function errorAsRuleTaskRunResult( return { state: asErr(e), schedule: asErr(e), + monitoring: asErr(e), }; } } diff --git a/x-pack/plugins/alerting/server/types.ts b/x-pack/plugins/alerting/server/types.ts index f87a2889fe6fe4..866c8665ddb658 100644 --- a/x-pack/plugins/alerting/server/types.ts +++ b/x-pack/plugins/alerting/server/types.ts @@ -33,6 +33,7 @@ import { WithoutReservedActionGroups, ActionVariable, SanitizedRuleConfig, + RuleMonitoring, } from '../common'; import { LicenseType } from '../../licensing/server'; import { IAbortableClusterClient } from './lib/create_abortable_es_client_factory'; @@ -238,6 +239,7 @@ export interface RawRule extends SavedObjectAttributes { mutedInstanceIds: string[]; meta?: AlertMeta; executionStatus: RawRuleExecutionStatus; + monitoring?: RuleMonitoring; } export type AlertInfoParams = Pick< diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/monitoring_utils.test.ts b/x-pack/plugins/triggers_actions_ui/public/application/lib/monitoring_utils.test.ts new file mode 100644 index 00000000000000..291a786c1590fe --- /dev/null +++ b/x-pack/plugins/triggers_actions_ui/public/application/lib/monitoring_utils.test.ts @@ -0,0 +1,14 @@ +/* + * 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 { getFormattedSuccessRatio } from './monitoring_utils'; + +describe('monitoring_utils', () => { + it('should return a decimal as a percent', () => { + expect(getFormattedSuccessRatio(0.66)).toEqual('66%'); + expect(getFormattedSuccessRatio(0.75345345345345)).toEqual('75%'); + }); +}); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/monitoring_utils.ts b/x-pack/plugins/triggers_actions_ui/public/application/lib/monitoring_utils.ts new file mode 100644 index 00000000000000..412a0ece3fbec7 --- /dev/null +++ b/x-pack/plugins/triggers_actions_ui/public/application/lib/monitoring_utils.ts @@ -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. + */ +import numeral from '@elastic/numeral'; + +export function getFormattedSuccessRatio(successRatio: number) { + const formatted = numeral(successRatio! * 100).format('0,0'); + return `${formatted}%`; +} diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.test.tsx index c8e1f5d05ecc0c..352fd76b098360 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.test.tsx @@ -176,6 +176,14 @@ describe('alerts_list component with items', () => { lastExecutionDate: new Date('2020-08-20T19:23:38Z'), error: null, }, + monitoring: { + execution: { + history: [{ success: true }, { success: true }, { success: false }], + calculated_metrics: { + success_ratio: 0.66, + }, + }, + }, }, { id: '2', @@ -199,6 +207,14 @@ describe('alerts_list component with items', () => { lastExecutionDate: new Date('2020-08-20T19:23:38Z'), error: null, }, + monitoring: { + execution: { + history: [{ success: true }, { success: true }], + calculated_metrics: { + success_ratio: 1, + }, + }, + }, }, { id: '3', @@ -222,6 +238,14 @@ describe('alerts_list component with items', () => { lastExecutionDate: new Date('2020-08-20T19:23:38Z'), error: null, }, + monitoring: { + execution: { + history: [{ success: false }], + calculated_metrics: { + success_ratio: 0, + }, + }, + }, }, { id: '4', @@ -433,6 +457,23 @@ describe('alerts_list component with items', () => { 'License Error' ); + // Monitoring column + expect( + wrapper.find('EuiTableRowCell[data-test-subj="alertsTableCell-successRatio"]').length + ).toEqual(mockedAlertsData.length); + const ratios = wrapper.find( + 'EuiTableRowCell[data-test-subj="alertsTableCell-successRatio"] span[data-test-subj="successRatio"]' + ); + mockedAlertsData.forEach((rule, index) => { + if (rule.monitoring) { + expect(ratios.at(index).text()).toEqual( + `${rule.monitoring.execution.calculated_metrics.success_ratio * 100}%` + ); + } else { + expect(ratios.at(index).text()).toEqual(`N/A`); + } + }); + // Clearing all mocks will also reset fake timers. jest.clearAllMocks(); }); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.tsx index 6c146680e94764..60929d8fd3ac67 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.tsx @@ -85,6 +85,7 @@ import { formatMillisForDisplay, shouldShowDurationWarning, } from '../../../lib/execution_duration_utils'; +import { getFormattedSuccessRatio } from '../../../lib/monitoring_utils'; const ENTER_KEY = 13; @@ -583,6 +584,36 @@ export const AlertsList: React.FunctionComponent = () => { ); }, }, + { + field: 'monitoring.execution.calculated_metrics.success_ratio', + width: '12%', + name: ( + + + Success ratio{' '} + + + + ), + sortable: true, + truncateText: false, + 'data-test-subj': 'alertsTableCell-successRatio', + render: (value: number) => { + return ( + + {value !== undefined ? getFormattedSuccessRatio(value) : 'N/A'} + + ); + }, + }, { field: 'executionStatus.status', name: i18n.translate( diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/server/alert_types.ts b/x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/server/alert_types.ts index 1a93ee375d9b60..a99de22181766e 100644 --- a/x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/server/alert_types.ts +++ b/x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/server/alert_types.ts @@ -465,6 +465,45 @@ function getPatternFiringAlertType() { return result; } +function getPatternSuccessOrFailureAlertType() { + const paramsSchema = schema.object({ + pattern: schema.arrayOf(schema.oneOf([schema.boolean(), schema.string()])), + }); + type ParamsType = TypeOf; + interface State extends AlertTypeState { + patternIndex?: number; + } + const result: RuleType = { + id: 'test.patternSuccessOrFailure', + name: 'Test: Succeeding or failing on a Pattern', + actionGroups: [{ id: 'default', name: 'Default' }], + producer: 'alertsFixture', + defaultActionGroupId: 'default', + minimumLicenseRequired: 'basic', + isExportable: true, + async executor(alertExecutorOptions) { + const { state, params } = alertExecutorOptions; + const pattern = params.pattern; + if (!Array.isArray(pattern)) throw new Error('pattern is not an array'); + + // get the pattern index, return if past it + const patternIndex = state.patternIndex ?? 0; + if (patternIndex >= pattern.length) { + return { patternIndex }; + } + + if (!pattern[patternIndex]) { + throw new Error('Failed to execute alert type'); + } + + return { + patternIndex: patternIndex + 1, + }; + }, + }; + return result; +} + function getLongRunningPatternRuleType(cancelAlertsOnRuleTimeout: boolean = true) { let globalPatternIndex = 0; const paramsSchema = schema.object({ @@ -685,4 +724,5 @@ export function defineAlertTypes( alerting.registerType(getLongRunningPatternRuleType()); alerting.registerType(getLongRunningPatternRuleType(false)); alerting.registerType(getCancellableRuleType()); + alerting.registerType(getPatternSuccessOrFailureAlertType()); } diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/server/plugin.ts b/x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/server/plugin.ts index 5674e644f9c21f..7937a9a2db92c6 100644 --- a/x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/server/plugin.ts +++ b/x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/server/plugin.ts @@ -59,6 +59,7 @@ export class FixturePlugin implements Plugin>( @@ -435,6 +437,7 @@ export default function createAlertTests({ getService }: FtrProviderContext) { createdAt: response.body.createdAt, updatedAt: response.body.updatedAt, executionStatus: response.body.executionStatus, + monitoring: response.body.monitoring, }); expect(Date.parse(response.body.createdAt)).to.be.greaterThan(0); expect(Date.parse(response.body.updatedAt)).to.be.greaterThan(0); diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/find.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/find.ts index 191bcb1bb52f0c..729bf42817bd77 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/find.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/find.ts @@ -69,6 +69,7 @@ export default function createFindTests({ getService }: FtrProviderContext) { created_at: match.created_at, updated_at: match.updated_at, execution_status: match.execution_status, + monitoring: match.monitoring, }); expect(Date.parse(match.created_at)).to.be.greaterThan(0); expect(Date.parse(match.updated_at)).to.be.greaterThan(0); @@ -155,6 +156,7 @@ export default function createFindTests({ getService }: FtrProviderContext) { createdAt: match.createdAt, updatedAt: match.updatedAt, executionStatus: match.executionStatus, + monitoring: match.monitoring, }); expect(Date.parse(match.createdAt)).to.be.greaterThan(0); expect(Date.parse(match.updatedAt)).to.be.greaterThan(0); diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/get.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/get.ts index 5245488dcb7b43..4c2ff47e82b7fe 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/get.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/get.ts @@ -53,6 +53,7 @@ export default function createGetTests({ getService }: FtrProviderContext) { created_at: response.body.created_at, updated_at: response.body.updated_at, execution_status: response.body.execution_status, + monitoring: response.body.monitoring, }); expect(Date.parse(response.body.created_at)).to.be.greaterThan(0); expect(Date.parse(response.body.updated_at)).to.be.greaterThan(0); @@ -118,6 +119,7 @@ export default function createGetTests({ getService }: FtrProviderContext) { createdAt: response.body.createdAt, updatedAt: response.body.updatedAt, executionStatus: response.body.executionStatus, + monitoring: response.body.monitoring, }); expect(Date.parse(response.body.createdAt)).to.be.greaterThan(0); expect(Date.parse(response.body.updatedAt)).to.be.greaterThan(0); diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/index.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/index.ts index c364b1f054a9dc..242c6ffcba10f4 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/index.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/index.ts @@ -26,6 +26,7 @@ export default function alertingTests({ loadTestFile, getService }: FtrProviderC loadTestFile(require.resolve('./rule_types')); loadTestFile(require.resolve('./event_log')); loadTestFile(require.resolve('./execution_status')); + loadTestFile(require.resolve('./monitoring')); loadTestFile(require.resolve('./mute_all')); loadTestFile(require.resolve('./mute_instance')); loadTestFile(require.resolve('./unmute_all')); @@ -42,6 +43,7 @@ export default function alertingTests({ loadTestFile, getService }: FtrProviderC loadTestFile(require.resolve('./ephemeral')); loadTestFile(require.resolve('./event_log_alerts')); loadTestFile(require.resolve('./scheduled_task_id')); + // Do not place test files here, due to https://github.com/elastic/kibana/issues/123059 // note that this test will destroy existing spaces loadTestFile(require.resolve('./migrations')); diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/monitoring.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/monitoring.ts new file mode 100644 index 00000000000000..aa3f50eb0e4bed --- /dev/null +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/monitoring.ts @@ -0,0 +1,127 @@ +/* + * 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 { Spaces } from '../../scenarios'; +import { getUrlPrefix, getTestAlertData, ObjectRemover } from '../../../common/lib'; +import { FtrProviderContext } from '../../../common/ftr_provider_context'; + +// eslint-disable-next-line import/no-default-export +export default function monitoringAlertTests({ getService }: FtrProviderContext) { + const supertest = getService('supertest'); + + describe('monitoring', () => { + const objectRemover = new ObjectRemover(supertest); + + after(async () => await objectRemover.removeAll()); + + it('should return an accurate history for a single success', async () => { + const createResponse = await supertest + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) + .set('kbn-xsrf', 'foo') + .send(getTestAlertData({ schedule: { interval: '3s' } })); + expect(createResponse.status).to.eql(200); + objectRemover.add(Spaces.space1.id, createResponse.body.id, 'rule', 'alerting'); + + // Allow at least one execution + await waitForExecutionCount(1, createResponse.body.id); + + const getResponse = await supertest.get( + `${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule/${createResponse.body.id}` + ); + expect(getResponse.status).to.eql(200); + + expect(getResponse.body.monitoring.execution.history.length).to.be(1); + expect(getResponse.body.monitoring.execution.history[0].success).to.be(true); + expect(getResponse.body.monitoring.execution.calculated_metrics.success_ratio).to.be(1); + }); + + it('should return an accurate history for multiple success', async () => { + const createResponse = await supertest + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) + .set('kbn-xsrf', 'foo') + .send(getTestAlertData({ schedule: { interval: '3s' } })); + expect(createResponse.status).to.eql(200); + objectRemover.add(Spaces.space1.id, createResponse.body.id, 'rule', 'alerting'); + + // Allow at least three executions + await waitForExecutionCount(3, createResponse.body.id); + + const getResponse = await supertest.get( + `${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule/${createResponse.body.id}` + ); + expect(getResponse.status).to.eql(200); + + expect(getResponse.body.monitoring.execution.history.length).to.be(3); + expect(getResponse.body.monitoring.execution.history[0].success).to.be(true); + expect(getResponse.body.monitoring.execution.history[1].success).to.be(true); + expect(getResponse.body.monitoring.execution.history[2].success).to.be(true); + expect(getResponse.body.monitoring.execution.calculated_metrics.success_ratio).to.be(1); + }); + + it('should return an accurate history for some successes and some failures', async () => { + const pattern = [true, true, true, false, false]; // Once we start failing, the rule type doesn't update state so the failures have to be at the end + const createResponse = await supertest + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) + .set('kbn-xsrf', 'foo') + .send( + getTestAlertData({ + rule_type_id: 'test.patternSuccessOrFailure', + schedule: { interval: '3s' }, + params: { + pattern, + }, + }) + ); + expect(createResponse.status).to.eql(200); + objectRemover.add(Spaces.space1.id, createResponse.body.id, 'rule', 'alerting'); + + // Allow at least three executions + await waitForExecutionCount(5, createResponse.body.id); + + const getResponse = await supertest.get( + `${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule/${createResponse.body.id}` + ); + expect(getResponse.status).to.eql(200); + + expect(getResponse.body.monitoring.execution.history.length).to.be(5); + expect(getResponse.body.monitoring.execution.history[0].success).to.be(true); + expect(getResponse.body.monitoring.execution.history[1].success).to.be(true); + expect(getResponse.body.monitoring.execution.history[2].success).to.be(true); + expect(getResponse.body.monitoring.execution.history[3].success).to.be(false); + expect(getResponse.body.monitoring.execution.history[4].success).to.be(false); + expect(getResponse.body.monitoring.execution.calculated_metrics.success_ratio).to.be(0.6); + }); + }); + + const MAX_ATTEMPTS = 25; + let attempts = 0; + async function waitForExecutionCount(count: number, id: string): Promise { + if (attempts++ >= MAX_ATTEMPTS) { + expect().fail(`waiting for execution of alert ${id} to hit ${count}`); + return true; + } + const getResponse = await supertest.get( + `${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule/${id}` + ); + expect(getResponse.status).to.eql(200); + if (getResponse.body.monitoring.execution.history.length >= count) { + attempts = 0; + return true; + } + // eslint-disable-next-line no-console + console.log( + `found ${getResponse.body.monitoring.execution.history.length} and looking for ${count}, waiting 3s then retrying` + ); + await delay(3000); + return waitForExecutionCount(count, id); + } + + async function delay(millis: number): Promise { + await new Promise((resolve) => setTimeout(resolve, millis)); + } +} diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/update.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/update.ts index 326fb0bfac4656..f6d5ed99d36bf3 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/update.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/update.ts @@ -61,6 +61,7 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { created_at: response.body.created_at, updated_at: response.body.updated_at, execution_status: response.body.execution_status, + monitoring: response.body.monitoring, }); expect(Date.parse(response.body.created_at)).to.be.greaterThan(0); expect(Date.parse(response.body.updated_at)).to.be.greaterThan(0); @@ -149,6 +150,7 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { createdAt: response.body.createdAt, updatedAt: response.body.updatedAt, executionStatus: response.body.executionStatus, + monitoring: response.body.monitoring, }); expect(Date.parse(response.body.createdAt)).to.be.greaterThan(0); expect(Date.parse(response.body.updatedAt)).to.be.greaterThan(0); From e02a1f70e1851250737ae4298bbdff268a6ee7f0 Mon Sep 17 00:00:00 2001 From: "Lucas F. da Costa" Date: Wed, 19 Jan 2022 15:42:23 +0000 Subject: [PATCH 047/108] [Uptime] Avoid duplicate requests when loading monitor steps (#121889) --- .../synthetics/check_steps/use_check_steps.ts | 31 ++-- .../public/lib/helper/helper_with_redux.tsx | 44 ++++-- .../uptime/public/lib/helper/rtl_helpers.tsx | 25 ++- .../synthetics/synthetics_checks.test.tsx | 143 ++++++++++++++---- .../public/state/effects/journey.test.ts | 104 +++++++++++++ .../uptime/public/state/effects/journey.ts | 11 +- 6 files changed, 294 insertions(+), 64 deletions(-) create mode 100644 x-pack/plugins/uptime/public/state/effects/journey.test.ts diff --git a/x-pack/plugins/uptime/public/components/synthetics/check_steps/use_check_steps.ts b/x-pack/plugins/uptime/public/components/synthetics/check_steps/use_check_steps.ts index da40b900fdcc2e..c936005a08c124 100644 --- a/x-pack/plugins/uptime/public/components/synthetics/check_steps/use_check_steps.ts +++ b/x-pack/plugins/uptime/public/components/synthetics/check_steps/use_check_steps.ts @@ -5,25 +5,34 @@ * 2.0. */ +import { useEffect } from 'react'; import { useParams } from 'react-router-dom'; -import { FETCH_STATUS, useFetcher } from '../../../../../observability/public'; -import { fetchJourneySteps } from '../../../state/api/journey'; +import { useDispatch, useSelector } from 'react-redux'; +import { AppState } from '../../../state'; +import { getJourneySteps } from '../../../state/actions/journey'; import { JourneyState } from '../../../state/reducers/journey'; export const useCheckSteps = (): JourneyState => { const { checkGroupId } = useParams<{ checkGroupId: string }>(); + const dispatch = useDispatch(); - const { data, status, error } = useFetcher(() => { - return fetchJourneySteps({ - checkGroup: checkGroupId, - }); - }, [checkGroupId]); + useEffect(() => { + dispatch( + getJourneySteps({ + checkGroup: checkGroupId, + }) + ); + }, [checkGroupId, dispatch]); + + const checkGroup = useSelector((state: AppState) => { + return state.journeys[checkGroupId]; + }); return { - error, checkGroup: checkGroupId, - steps: data?.steps ?? [], - details: data?.details, - loading: status === FETCH_STATUS.LOADING || status === FETCH_STATUS.PENDING, + steps: checkGroup?.steps ?? [], + details: checkGroup?.details, + loading: checkGroup?.loading ?? false, + error: checkGroup?.error, }; }; diff --git a/x-pack/plugins/uptime/public/lib/helper/helper_with_redux.tsx b/x-pack/plugins/uptime/public/lib/helper/helper_with_redux.tsx index 8c4ec2fa611fc9..8602ff81dec447 100644 --- a/x-pack/plugins/uptime/public/lib/helper/helper_with_redux.tsx +++ b/x-pack/plugins/uptime/public/lib/helper/helper_with_redux.tsx @@ -6,19 +6,37 @@ */ import React from 'react'; +import type { Store } from 'redux'; +import { createStore as createReduxStore, applyMiddleware } from 'redux'; + import { Provider as ReduxProvider } from 'react-redux'; +import createSagaMiddleware from 'redux-saga'; + import { AppState } from '../../state'; +import { rootReducer } from '../../state/reducers'; +import { rootEffect } from '../../state/effects'; + +const createRealStore = (): Store => { + const sagaMW = createSagaMiddleware(); + const store = createReduxStore(rootReducer, applyMiddleware(sagaMW)); + sagaMW.run(rootEffect); + return store; +}; + +export const MountWithReduxProvider: React.FC<{ state?: AppState; useRealStore?: boolean }> = ({ + children, + state, + useRealStore, +}) => { + const store = useRealStore + ? createRealStore() + : { + dispatch: jest.fn(), + getState: jest.fn().mockReturnValue(state || { selectedFilters: null }), + subscribe: jest.fn(), + replaceReducer: jest.fn(), + [Symbol.observable]: jest.fn(), + }; -export const MountWithReduxProvider: React.FC<{ state?: AppState }> = ({ children, state }) => ( - - {children} - -); + return {children}; +}; diff --git a/x-pack/plugins/uptime/public/lib/helper/rtl_helpers.tsx b/x-pack/plugins/uptime/public/lib/helper/rtl_helpers.tsx index a0de792c40d72e..9374012d094ab7 100644 --- a/x-pack/plugins/uptime/public/lib/helper/rtl_helpers.tsx +++ b/x-pack/plugins/uptime/public/lib/helper/rtl_helpers.tsx @@ -14,7 +14,7 @@ import { RenderOptions, Nullish, } from '@testing-library/react'; -import { Router } from 'react-router-dom'; +import { Router, Route } from 'react-router-dom'; import { merge } from 'lodash'; import { createMemoryHistory, History } from 'history'; import { CoreStart } from 'kibana/public'; @@ -57,6 +57,7 @@ interface MockKibanaProviderProps extends KibanaProviderOptions extends MockKibanaProviderProps { history?: History; + path?: string; } type Url = @@ -71,6 +72,7 @@ interface RenderRouterOptions extends KibanaProviderOptions; state?: Partial | DeepPartial; url?: Url; + path?: string; } function getSetting(key: string): T { @@ -121,6 +123,9 @@ const mockCore: () => Partial = () => { get: getSetting, get$: setSetting$, }, + usageCollection: { + reportUiCounter: () => {}, + }, triggersActionsUi: triggersActionsUiMock.createStart(), storage: createMockStore(), data: dataPluginMock.createStartContract(), @@ -163,13 +168,14 @@ export function MockKibanaProvider({ export function MockRouter({ children, core, + path, history = createMemoryHistory(), kibanaProps, }: MockRouterProps) { return ( - {children} + {children} ); @@ -180,10 +186,13 @@ export const MockRedux = ({ state, history = createMemoryHistory(), children, + path, }: { state: Partial; history?: History; children: React.ReactNode; + path?: string; + useRealStore?: boolean; }) => { const testState: AppState = { ...mockState, @@ -192,7 +201,9 @@ export const MockRedux = ({ return ( - {children} + + {children} + ); }; @@ -207,7 +218,9 @@ export function render( renderOptions, state, url, - }: RenderRouterOptions = {} + path, + useRealStore, + }: RenderRouterOptions & { useRealStore?: boolean } = {} ) { const testState: AppState = merge({}, mockState, state); @@ -217,8 +230,8 @@ export function render( return { ...reactTestLibRender( - - + + {ui} , diff --git a/x-pack/plugins/uptime/public/pages/synthetics/synthetics_checks.test.tsx b/x-pack/plugins/uptime/public/pages/synthetics/synthetics_checks.test.tsx index fda203f3ff14bf..cfe1b03e6305cc 100644 --- a/x-pack/plugins/uptime/public/pages/synthetics/synthetics_checks.test.tsx +++ b/x-pack/plugins/uptime/public/pages/synthetics/synthetics_checks.test.tsx @@ -7,53 +7,95 @@ import React from 'react'; import { render } from '../../lib/helper/rtl_helpers'; -import { spyOnUseFetcher } from '../../lib/helper/spy_use_fetcher'; import { SyntheticsCheckSteps, SyntheticsCheckStepsPageHeader, SyntheticsCheckStepsPageRightSideItem, } from './synthetics_checks'; +import { fetchJourneySteps } from '../../state/api/journey'; +import { createMemoryHistory } from 'history'; +import { SYNTHETIC_CHECK_STEPS_ROUTE } from '../../../common/constants'; + +jest.mock('../../state/api/journey', () => ({ + fetchJourneySteps: jest.fn(), +})); + +// We must mock all other API calls because we're using the real store +// in this test. Using the real store causes actions and effects to actually +// run, which could trigger API calls. +jest.mock('../../state/api/utils.ts', () => ({ + apiService: { get: jest.fn().mockResolvedValue([]) }, +})); + +const getRelevantPageHistory = () => { + const history = createMemoryHistory(); + const checkStepsHistoryFrame = SYNTHETIC_CHECK_STEPS_ROUTE.replace( + /:checkGroupId/g, + 'my-check-group-id' + ); + + history.push(checkStepsHistoryFrame); + + return history; +}; describe('SyntheticsCheckStepsPageHeader component', () => { - it('returns the monitor name', () => { - spyOnUseFetcher({ + afterAll(() => { + jest.restoreAllMocks(); + }); + + it('returns the monitor name', async () => { + (fetchJourneySteps as jest.Mock).mockResolvedValueOnce({ + checkGroup: 'my-check-group-id', details: { journey: { - monitor: { - name: 'test-name', - id: 'test-id', - }, + monitor: { name: 'test-name' }, }, }, }); - const { getByText } = render(); - expect(getByText('test-name')); + + const { findByText } = render(, { + history: getRelevantPageHistory(), + path: SYNTHETIC_CHECK_STEPS_ROUTE, + useRealStore: true, + }); + + expect(await findByText('test-name')); }); - it('returns the monitor ID when no name is provided', () => { - spyOnUseFetcher({ + it('returns the monitor ID when no name is provided', async () => { + (fetchJourneySteps as jest.Mock).mockResolvedValueOnce({ + checkGroup: 'my-check-group-id', details: { journey: { - monitor: { - id: 'test-id', - }, + monitor: { name: 'test-id' }, }, }, }); - const { getByText } = render(); - expect(getByText('test-id')); + + const { findByText } = render(, { + history: getRelevantPageHistory(), + path: SYNTHETIC_CHECK_STEPS_ROUTE, + useRealStore: true, + }); + expect(await findByText('test-id')); }); }); describe('SyntheticsCheckStepsPageRightSideItem component', () => { it('returns null when there are no details', () => { - spyOnUseFetcher(null); - const { container } = render(); + (fetchJourneySteps as jest.Mock).mockResolvedValueOnce(null); + const { container } = render(, { + history: getRelevantPageHistory(), + path: SYNTHETIC_CHECK_STEPS_ROUTE, + useRealStore: true, + }); expect(container.firstChild).toBeNull(); }); - it('renders navigation element if details exist', () => { - spyOnUseFetcher({ + it('renders navigation element if details exist', async () => { + (fetchJourneySteps as jest.Mock).mockResolvedValueOnce({ + checkGroup: 'my-check-group-id', details: { timestamp: '20031104', journey: { @@ -64,22 +106,54 @@ describe('SyntheticsCheckStepsPageRightSideItem component', () => { }, }, }); - const { getByText } = render(); - expect(getByText('Nov 4, 2003 12:00:00 AM')); - expect(getByText('Next check')); - expect(getByText('Previous check')); + + const { findByText } = render(, { + history: getRelevantPageHistory(), + path: SYNTHETIC_CHECK_STEPS_ROUTE, + useRealStore: true, + }); + expect(await findByText('Nov 4, 2003 12:00:00 AM')); + expect(await findByText('Next check')); + expect(await findByText('Previous check')); }); }); describe('SyntheticsCheckSteps component', () => { - it('renders empty steps list', () => { - const { getByText } = render(); - expect(getByText('0 Steps - all failed or skipped')); - expect(getByText('This journey did not contain any steps.')); + it('renders empty steps list', async () => { + (fetchJourneySteps as jest.Mock).mockResolvedValueOnce({ + checkGroup: 'my-check-group-id', + details: { + timestamp: '20031104', + journey: { + monitor: { + name: 'test-name', + id: 'test-id', + }, + }, + }, + }); + + const { findByText } = render(, { + history: getRelevantPageHistory(), + path: SYNTHETIC_CHECK_STEPS_ROUTE, + useRealStore: true, + }); + expect(await findByText('0 Steps - all failed or skipped')); + expect(await findByText('This journey did not contain any steps.')); }); - it('renders steps', () => { - spyOnUseFetcher({ + it('renders steps', async () => { + (fetchJourneySteps as jest.Mock).mockResolvedValueOnce({ + checkGroup: 'my-check-group-id', + details: { + timestamp: '20031104', + journey: { + monitor: { + name: 'test-name', + id: 'test-id', + }, + }, + }, steps: [ { _id: 'step-1', @@ -94,7 +168,12 @@ describe('SyntheticsCheckSteps component', () => { }, ], }); - const { getByText } = render(); - expect(getByText('1 Steps - all failed or skipped')); + + const { findByText } = render(, { + history: getRelevantPageHistory(), + path: SYNTHETIC_CHECK_STEPS_ROUTE, + useRealStore: true, + }); + expect(await findByText('1 Steps - all failed or skipped')); }); }); diff --git a/x-pack/plugins/uptime/public/state/effects/journey.test.ts b/x-pack/plugins/uptime/public/state/effects/journey.test.ts new file mode 100644 index 00000000000000..cbf5fc72a07169 --- /dev/null +++ b/x-pack/plugins/uptime/public/state/effects/journey.test.ts @@ -0,0 +1,104 @@ +/* + * 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 type { Store } from 'redux'; +import createSagaMiddleware from 'redux-saga'; +import { createStore as createReduxStore, applyMiddleware } from 'redux'; + +import { rootReducer } from '../reducers'; +import { fetchJourneyStepsEffect } from '../effects/journey'; + +import { getJourneySteps } from '../actions/journey'; + +import { fetchJourneySteps } from '../api/journey'; + +jest.mock('../api/journey', () => ({ + fetchJourneySteps: jest.fn(), +})); + +const createTestStore = (): Store => { + const sagaMW = createSagaMiddleware(); + const store = createReduxStore(rootReducer, applyMiddleware(sagaMW)); + sagaMW.run(fetchJourneyStepsEffect); + return store; +}; + +describe('journey effect', () => { + afterEach(() => jest.resetAllMocks()); + afterAll(() => jest.restoreAllMocks()); + + it('fetches only once when dispatching multiple getJourneySteps for a particular ID', () => { + (fetchJourneySteps as jest.Mock).mockResolvedValue({ + checkGroup: 'saga-test', + details: { + journey: { + monitor: { name: 'test-name' }, + }, + }, + }); + + const store = createTestStore(); + + // Actually dispatched + store.dispatch(getJourneySteps({ checkGroup: 'saga-test' })); + + // Skipped + store.dispatch(getJourneySteps({ checkGroup: 'saga-test' })); + + expect(fetchJourneySteps).toHaveBeenCalledTimes(1); + }); + + it('fetches multiple times for different IDs', () => { + (fetchJourneySteps as jest.Mock).mockResolvedValue({ + checkGroup: 'saga-test', + details: { + journey: { + monitor: { name: 'test-name' }, + }, + }, + }); + + const store = createTestStore(); + + // Actually dispatched + store.dispatch(getJourneySteps({ checkGroup: 'saga-test' })); + + // Skipped + store.dispatch(getJourneySteps({ checkGroup: 'saga-test' })); + + // Actually dispatched because it has a different ID + store.dispatch(getJourneySteps({ checkGroup: 'saga-test-second' })); + + expect(fetchJourneySteps).toHaveBeenCalledTimes(2); + }); + + it('can re-fetch after an ID is fetched', async () => { + (fetchJourneySteps as jest.Mock).mockResolvedValue({ + checkGroup: 'saga-test', + details: { + journey: { + monitor: { name: 'test-name' }, + }, + }, + }); + + const store = createTestStore(); + + const waitForStateUpdate = (): Promise => + new Promise((resolve) => store.subscribe(() => resolve())); + + // Actually dispatched + store.dispatch(getJourneySteps({ checkGroup: 'saga-test' })); + + await waitForStateUpdate(); + + // Also dispatched given its initial request is not in-flight anymore + store.dispatch(getJourneySteps({ checkGroup: 'saga-test' })); + + expect(fetchJourneySteps).toHaveBeenCalledTimes(2); + }); +}); diff --git a/x-pack/plugins/uptime/public/state/effects/journey.ts b/x-pack/plugins/uptime/public/state/effects/journey.ts index 8898eb0e5c5219..f7c1e23742e69c 100644 --- a/x-pack/plugins/uptime/public/state/effects/journey.ts +++ b/x-pack/plugins/uptime/public/state/effects/journey.ts @@ -6,7 +6,7 @@ */ import { Action } from 'redux-actions'; -import { call, put, takeLatest } from 'redux-saga/effects'; +import { call, put, takeEvery } from 'redux-saga/effects'; import { getJourneySteps, getJourneyStepsSuccess, @@ -16,9 +16,14 @@ import { import { fetchJourneySteps } from '../api/journey'; import type { SyntheticsJourneyApiResponse } from '../../../common/runtime_types'; +const inFlightStepRequests: Record = {}; + export function* fetchJourneyStepsEffect(): Generator { - yield takeLatest(getJourneySteps, function* (action: Action) { + yield takeEvery(getJourneySteps, function* (action: Action) { + if (inFlightStepRequests[action.payload.checkGroup]) return; + try { + inFlightStepRequests[action.payload.checkGroup] = true; const response = (yield call( fetchJourneySteps, action.payload @@ -26,6 +31,8 @@ export function* fetchJourneyStepsEffect(): Generator { yield put(getJourneyStepsSuccess(response)); } catch (e) { yield put(getJourneyStepsFail({ checkGroup: action.payload.checkGroup, error: e })); + } finally { + delete inFlightStepRequests[action.payload.checkGroup]; } }); } From 57ce4373bcbf1870dfa3e9752db37e26e31bc2ec Mon Sep 17 00:00:00 2001 From: Quynh Nguyen <43350163+qn895@users.noreply.github.com> Date: Wed, 19 Jan 2022 10:07:49 -0600 Subject: [PATCH 048/108] [ML] Add warnings for actions for managed Anomaly detection jobs and Transforms (#122305) * Add managed badge * Add managed to module configs * Fix message * Add management to managed transforms * Update texts * Handle bool in custom settings table * Change message * Add modal/warnings for resetting and closing. Move start warning to modal. * Not clone AD managed settings * Not clone transform managed settings * Fix translations * Fix translations id * Remove showEditJobConfirmModal * Consolidate call out messages * Consolidate call out messages * Add tooltip message * Add tooltip message * Remove warning message for start transform * Remove managed flag in route instead of in client * Add message for delete in space permission * Add remove managed setting during clone in route * Add stopDatafeeds to declaration file * Add call out when editing managed transform * Delete attr instead of setting it to false Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../anomaly_detection_jobs/summary_job.ts | 2 + .../delete_job_check_modal.tsx | 70 ++++++--- .../close_jobs_confirm_modal.tsx | 136 +++++++++++++++++ .../managed_jobs_warning_callout.tsx | 38 +++++ .../stop_datafeeds_confirm_modal.tsx | 137 ++++++++++++++++++ .../delete_job_modal/delete_job_modal.tsx | 37 +++-- .../edit_job_flyout/edit_job_flyout.js | 18 +++ .../components/job_actions/management.js | 17 ++- .../job_details/extract_job_details.js | 2 +- .../components/job_details/format_values.js | 4 + .../components/jobs_list/jobs_list.js | 32 +++- .../jobs_list_view/jobs_list_view.js | 36 +++++ .../multi_job_actions/actions_menu.js | 15 +- .../multi_job_actions/multi_job_actions.js | 4 + .../reset_job_modal/reset_job_modal.tsx | 22 +++ .../start_datafeed_modal.js | 6 + .../time_range_selector.js | 21 ++- .../jobs/jobs_list/components/utils.d.ts | 2 + .../ml/public/application/jobs/jobs_utils.ts | 17 +++ .../new_job/common/job_creator/job_creator.ts | 1 + .../apm_transaction/ml/apm_tx_metrics.json | 3 +- .../logs_ui_analysis/ml/log_entry_rate.json | 1 + .../ml/log_entry_categories_count.json | 1 + .../ml/hosts_memory_usage.json | 1 + .../metrics_ui_hosts/ml/hosts_network_in.json | 1 + .../ml/hosts_network_out.json | 1 + .../metrics_ui_k8s/ml/k8s_memory_usage.json | 1 + .../metrics_ui_k8s/ml/k8s_network_in.json | 1 + .../metrics_ui_k8s/ml/k8s_network_out.json | 1 + .../ml/server/models/job_service/jobs.ts | 8 + .../app/common/managed_transforms_utils.ts | 12 ++ .../transform/public/app/common/transform.ts | 12 +- .../clone_transform_section.tsx | 5 +- .../action_delete/delete_action_modal.tsx | 32 +++- .../action_delete/use_delete_action.tsx | 2 - .../action_start/start_action_modal.tsx | 1 - .../action_start/use_start_action.tsx | 2 - .../action_stop/stop_action_modal.tsx | 54 +++++++ .../action_stop/use_stop_action.tsx | 38 ++++- .../edit_transform_flyout.tsx | 10 ++ .../managed_transforms_callout/index.ts | 6 + .../managed_transforms_callout.tsx | 34 +++++ .../transform_list/transform_list.tsx | 13 +- .../components/transform_list/use_actions.tsx | 3 + .../components/transform_list/use_columns.tsx | 18 ++- 45 files changed, 815 insertions(+), 63 deletions(-) create mode 100644 x-pack/plugins/ml/public/application/jobs/jobs_list/components/confirm_modals/close_jobs_confirm_modal.tsx create mode 100644 x-pack/plugins/ml/public/application/jobs/jobs_list/components/confirm_modals/managed_jobs_warning_callout.tsx create mode 100644 x-pack/plugins/ml/public/application/jobs/jobs_list/components/confirm_modals/stop_datafeeds_confirm_modal.tsx create mode 100644 x-pack/plugins/ml/public/application/jobs/jobs_utils.ts create mode 100644 x-pack/plugins/transform/public/app/common/managed_transforms_utils.ts create mode 100644 x-pack/plugins/transform/public/app/sections/transform_management/components/action_stop/stop_action_modal.tsx create mode 100644 x-pack/plugins/transform/public/app/sections/transform_management/components/managed_transforms_callout/index.ts create mode 100644 x-pack/plugins/transform/public/app/sections/transform_management/components/managed_transforms_callout/managed_transforms_callout.tsx diff --git a/x-pack/plugins/ml/common/types/anomaly_detection_jobs/summary_job.ts b/x-pack/plugins/ml/common/types/anomaly_detection_jobs/summary_job.ts index 8c53e7b1f5a87e..6bcba719deaee5 100644 --- a/x-pack/plugins/ml/common/types/anomaly_detection_jobs/summary_job.ts +++ b/x-pack/plugins/ml/common/types/anomaly_detection_jobs/summary_job.ts @@ -7,6 +7,7 @@ import { Moment } from 'moment'; +import { MlCustomSettings } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import type { CombinedJob, CombinedJobWithStats } from './combined_job'; import type { MlAnomalyDetectionAlertRule } from '../alerts'; import type { MlJobBlocked } from './job'; @@ -39,6 +40,7 @@ export interface MlSummaryJob { alertingRules?: MlAnomalyDetectionAlertRule[]; jobTags: Record; bucketSpanSeconds: number; + customSettings?: MlCustomSettings; } export interface AuditMessage { diff --git a/x-pack/plugins/ml/public/application/components/delete_job_check_modal/delete_job_check_modal.tsx b/x-pack/plugins/ml/public/application/components/delete_job_check_modal/delete_job_check_modal.tsx index 5507cbfe155b43..6834f16386ce2e 100644 --- a/x-pack/plugins/ml/public/application/components/delete_job_check_modal/delete_job_check_modal.tsx +++ b/x-pack/plugins/ml/public/application/components/delete_job_check_modal/delete_job_check_modal.tsx @@ -20,10 +20,12 @@ import { EuiButton, EuiLoadingSpinner, EuiText, + EuiSpacer, } from '@elastic/eui'; import { JobType, CanDeleteJobResponse } from '../../../../common/types/saved_objects'; import { useMlApiContext } from '../../contexts/kibana'; import { useToastNotificationService } from '../../services/toast_notification_service'; +import { ManagedJobsWarningCallout } from '../../jobs/jobs_list/components/confirm_modals/managed_jobs_warning_callout'; const shouldUnTagLabel = i18n.translate('xpack.ml.deleteJobCheckModal.shouldUnTagLabel', { defaultMessage: 'Remove job from current space', @@ -58,7 +60,8 @@ function getRespSummary(resp: CanDeleteJobResponse): JobCheckRespSummary { function getModalContent( jobIds: string[], - respSummary: JobCheckRespSummary + respSummary: JobCheckRespSummary, + hasManagedJob?: boolean ): ModalContentReturnType { const { canDelete, canRemoveFromSpace, canTakeAnyAction } = respSummary; @@ -107,13 +110,30 @@ function getModalContent( /> ), modalText: ( - - - + <> + {hasManagedJob ? ( + <> + + + + ) : null} + + + + + ), }; } else if (canRemoveFromSpace) { @@ -125,13 +145,27 @@ function getModalContent( /> ), modalText: ( - - - + <> + {hasManagedJob ? ( + <> + + + + ) : null} + + + + + ), }; } else { @@ -146,6 +180,7 @@ interface Props { jobType: JobType; jobIds: string[]; setDidUntag?: React.Dispatch>; + hasManagedJob?: boolean; } export const DeleteJobCheckModal: FC = ({ @@ -155,6 +190,7 @@ export const DeleteJobCheckModal: FC = ({ jobType, jobIds, setDidUntag, + hasManagedJob, }) => { const [buttonContent, setButtonContent] = useState(); const [modalContent, setModalContent] = useState(); @@ -180,7 +216,7 @@ export const DeleteJobCheckModal: FC = ({ return; } setJobCheckRespSummary(respSummary); - const { buttonText, modalText } = getModalContent(jobIds, respSummary); + const { buttonText, modalText } = getModalContent(jobIds, respSummary, hasManagedJob); setButtonContent(buttonText); setModalContent(modalText); }); @@ -188,7 +224,7 @@ export const DeleteJobCheckModal: FC = ({ setDidUntag(false); } setIsLoading(false); - }, []); + }, [hasManagedJob]); const onUntagClick = async () => { setIsUntagging(true); diff --git a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/confirm_modals/close_jobs_confirm_modal.tsx b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/confirm_modals/close_jobs_confirm_modal.tsx new file mode 100644 index 00000000000000..5e7b7a18e33632 --- /dev/null +++ b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/confirm_modals/close_jobs_confirm_modal.tsx @@ -0,0 +1,136 @@ +/* + * 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 React, { FC, useState, useEffect, useCallback, useMemo } from 'react'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { + EuiSpacer, + EuiModal, + EuiModalHeader, + EuiModalHeaderTitle, + EuiModalBody, + EuiModalFooter, + EuiButtonEmpty, + EuiButton, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { MlSummaryJob } from '../../../../../../common/types/anomaly_detection_jobs'; +import { isManagedJob } from '../../../jobs_utils'; +import { closeJobs } from '../utils'; +import { ManagedJobsWarningCallout } from './managed_jobs_warning_callout'; + +type ShowFunc = (jobs: MlSummaryJob[]) => void; + +interface Props { + setShowFunction(showFunc: ShowFunc): void; + unsetShowFunction(): void; + refreshJobs(): void; +} + +export const CloseJobsConfirmModal: FC = ({ + setShowFunction, + unsetShowFunction, + refreshJobs, +}) => { + const [modalVisible, setModalVisible] = useState(false); + const [hasManagedJob, setHasManaged] = useState(true); + const [jobsToReset, setJobsToReset] = useState([]); + + const jobIds = useMemo(() => jobsToReset.map(({ id }) => id), [jobsToReset]); + + useEffect(() => { + if (typeof setShowFunction === 'function') { + setShowFunction(showModal); + } + return () => { + if (typeof unsetShowFunction === 'function') { + unsetShowFunction(); + } + }; + }, []); + + const showModal = useCallback((jobs: MlSummaryJob[]) => { + setJobsToReset(jobs); + + if (jobs.some((j) => isManagedJob(j))) { + setModalVisible(true); + setHasManaged(true); + } + }, []); + + const closeModal = useCallback(() => { + setModalVisible(false); + setHasManaged(false); + }, []); + + if (modalVisible === false) { + return null; + } + + if (hasManagedJob) { + const title = ( + + ); + + return ( + + + {title} + + + + + <> + + + + + + + { + closeJobs(jobsToReset, refreshJobs); + closeModal(); + }} + fill + color="danger" + data-test-subj="mlCloseJobsConfirmModalButton" + > + + + + + + ); + } else { + return <>; + } +}; diff --git a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/confirm_modals/managed_jobs_warning_callout.tsx b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/confirm_modals/managed_jobs_warning_callout.tsx new file mode 100644 index 00000000000000..5d6a72e927ecb9 --- /dev/null +++ b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/confirm_modals/managed_jobs_warning_callout.tsx @@ -0,0 +1,38 @@ +/* + * 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 { EuiCallOut, EuiSpacer } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n-react'; +import React from 'react'; + +export const ManagedJobsWarningCallout = ({ + jobsCount, + action, + message, +}: { + jobsCount: number; + action?: string; + message?: string; +}) => { + return ( + <> + + + {message ?? ( + + )} + + + ); +}; diff --git a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/confirm_modals/stop_datafeeds_confirm_modal.tsx b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/confirm_modals/stop_datafeeds_confirm_modal.tsx new file mode 100644 index 00000000000000..1a6d9e1e433ff1 --- /dev/null +++ b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/confirm_modals/stop_datafeeds_confirm_modal.tsx @@ -0,0 +1,137 @@ +/* + * 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 React, { FC, useState, useEffect, useCallback, useMemo } from 'react'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { + EuiSpacer, + EuiModal, + EuiModalHeader, + EuiModalHeaderTitle, + EuiModalBody, + EuiModalFooter, + EuiButtonEmpty, + EuiButton, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { MlSummaryJob } from '../../../../../../common/types/anomaly_detection_jobs'; +import { isManagedJob } from '../../../jobs_utils'; +import { stopDatafeeds } from '../utils'; +import { ManagedJobsWarningCallout } from './managed_jobs_warning_callout'; + +type ShowFunc = (jobs: MlSummaryJob[]) => void; + +interface Props { + setShowFunction(showFunc: ShowFunc): void; + unsetShowFunction(): void; + refreshJobs(): void; + showStopDatafeedsFlyout(job: MlSummaryJob[]): void; +} + +export const StopDatafeedsConfirmModal: FC = ({ + setShowFunction, + unsetShowFunction, + refreshJobs, +}) => { + const [modalVisible, setModalVisible] = useState(false); + const [hasManagedJob, setHasManaged] = useState(true); + const [jobsToStop, setJobsToStop] = useState([]); + + const jobIds = useMemo(() => jobsToStop.map(({ id }) => id), [jobsToStop]); + + useEffect(() => { + if (typeof setShowFunction === 'function') { + setShowFunction(showModal); + } + return () => { + if (typeof unsetShowFunction === 'function') { + unsetShowFunction(); + } + }; + }, []); + + const showModal = useCallback((jobs: MlSummaryJob[]) => { + setJobsToStop(jobs); + + if (jobs.some((j) => isManagedJob(j))) { + setModalVisible(true); + setHasManaged(true); + } + }, []); + + const closeModal = useCallback(() => { + setModalVisible(false); + setHasManaged(false); + }, []); + + if (modalVisible === false) { + return null; + } + + if (hasManagedJob) { + const title = ( + + ); + + return ( + + + {title} + + + + + <> + + + + + + + { + stopDatafeeds(jobsToStop, refreshJobs); + closeModal(); + }} + fill + color="danger" + data-test-subj="mlStopDatafeedsConfirmModalButton" + > + + + + + + ); + } else { + return <>; + } +}; diff --git a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/delete_job_modal/delete_job_modal.tsx b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/delete_job_modal/delete_job_modal.tsx index 2f04e8ae86e73c..49c09761bc8150 100644 --- a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/delete_job_modal/delete_job_modal.tsx +++ b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/delete_job_modal/delete_job_modal.tsx @@ -20,10 +20,13 @@ import { EuiText, } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; import { deleteJobs } from '../utils'; import { DELETING_JOBS_REFRESH_INTERVAL_MS } from '../../../../../../common/constants/jobs_list'; import { DeleteJobCheckModal } from '../../../../components/delete_job_check_modal'; import { MlSummaryJob } from '../../../../../../common/types/anomaly_detection_jobs'; +import { isManagedJob } from '../../../jobs_utils'; +import { ManagedJobsWarningCallout } from '../confirm_modals/managed_jobs_warning_callout'; type ShowFunc = (jobs: MlSummaryJob[]) => void; @@ -38,6 +41,7 @@ export const DeleteJobModal: FC = ({ setShowFunction, unsetShowFunction, const [modalVisible, setModalVisible] = useState(false); const [jobIds, setJobIds] = useState([]); const [canDelete, setCanDelete] = useState(false); + const [hasManagedJob, setHasManagedJob] = useState(false); useEffect(() => { if (typeof setShowFunction === 'function') { @@ -52,6 +56,7 @@ export const DeleteJobModal: FC = ({ setShowFunction, unsetShowFunction, const showModal = useCallback((jobs: MlSummaryJob[]) => { setJobIds(jobs.map(({ id }) => id)); + setHasManagedJob(jobs.some((job) => isManagedJob(job))); setModalVisible(true); setDeleting(false); }, []); @@ -104,17 +109,30 @@ export const DeleteJobModal: FC = ({ setShowFunction, unsetShowFunction,

) : ( - - - + values={{ + jobsCount: jobIds.length, + }} + /> + + )}

@@ -155,6 +173,7 @@ export const DeleteJobModal: FC = ({ setShowFunction, unsetShowFunction, }} onCloseCallback={closeModal} refreshJobsCallback={refreshJobs} + hasManagedJob={hasManagedJob} /> ); diff --git a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/edit_job_flyout/edit_job_flyout.js b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/edit_job_flyout/edit_job_flyout.js index c278f8790984fc..3ede5cf813f448 100644 --- a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/edit_job_flyout/edit_job_flyout.js +++ b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/edit_job_flyout/edit_job_flyout.js @@ -22,6 +22,7 @@ import { EuiFlexItem, EuiTabbedContent, EuiConfirmModal, + EuiSpacer, } from '@elastic/eui'; import { JobDetails, Detectors, Datafeed, CustomUrls } from './tabs'; @@ -33,6 +34,8 @@ import { ml } from '../../../../services/ml_api_service'; import { withKibana } from '../../../../../../../../../src/plugins/kibana_react/public'; import { collapseLiteralStrings } from '../../../../../../shared_imports'; import { DATAFEED_STATE, JOB_STATE } from '../../../../../../common/constants/states'; +import { isManagedJob } from '../../../jobs_utils'; +import { ManagedJobsWarningCallout } from '../confirm_modals/managed_jobs_warning_callout'; export class EditJobFlyoutUI extends Component { _initialJobFormState = null; @@ -412,6 +415,21 @@ export class EditJobFlyoutUI extends Component { /> + + {isManagedJob(job) ? ( + <> + + + + ) : null} {}} /> diff --git a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/job_actions/management.js b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/job_actions/management.js index 64bc7f4a517c28..5b8b4b386213d4 100644 --- a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/job_actions/management.js +++ b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/job_actions/management.js @@ -19,12 +19,15 @@ import { isResettable, } from '../utils'; import { i18n } from '@kbn/i18n'; +import { isManagedJob } from '../../../jobs_utils'; export function actionsMenuContent( showEditJobFlyout, showDeleteJobModal, showResetJobModal, showStartDatafeedModal, + showCloseJobsConfirmModal, + showStopDatafeedsConfirmModal, refreshJobs, showCreateAlertFlyout ) { @@ -65,7 +68,12 @@ export function actionsMenuContent( enabled: (item) => isJobBlocked(item) === false && canStartStopDatafeed, available: (item) => isStoppable([item]), onClick: (item) => { - stopDatafeeds([item], refreshJobs); + if (isManagedJob(item)) { + showStopDatafeedsConfirmModal([item]); + } else { + stopDatafeeds([item], refreshJobs); + } + closeMenu(true); }, 'data-test-subj': 'mlActionButtonStopDatafeed', @@ -97,7 +105,12 @@ export function actionsMenuContent( enabled: (item) => isJobBlocked(item) === false && canCloseJob, available: (item) => isClosable([item]), onClick: (item) => { - closeJobs([item], refreshJobs); + if (isManagedJob(item)) { + showCloseJobsConfirmModal([item]); + } else { + closeJobs([item], refreshJobs); + } + closeMenu(true); }, 'data-test-subj': 'mlActionButtonCloseJob', diff --git a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/job_details/extract_job_details.js b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/job_details/extract_job_details.js index dea8fdd30e3727..fd00058e647130 100644 --- a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/job_details/extract_job_details.js +++ b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/job_details/extract_job_details.js @@ -42,7 +42,7 @@ export function extractJobDetails(job, basePath, refreshJobList) { defaultMessage: 'Custom settings', }), position: 'right', - items: settings ? filterObjects(settings, true, true) : [], + items: settings ? filterObjects(settings, true, true).map(formatValues) : [], }; const jobTags = { diff --git a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/job_details/format_values.js b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/job_details/format_values.js index 92bbc720d8dddb..6bbbe9e59f783b 100644 --- a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/job_details/format_values.js +++ b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/job_details/format_values.js @@ -80,6 +80,10 @@ export function formatValues(obj) { typeof value === 'number' ? roundToDecimalPlace(value, 3).toLocaleString() : value, ]; + // boolean + case 'managed': + return [key, value.toString()]; + default: return [key, value]; } diff --git a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/jobs_list/jobs_list.js b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/jobs_list/jobs_list.js index 5fe005c4b34ff8..71a6b7d88fe1a5 100644 --- a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/jobs_list/jobs_list.js +++ b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/jobs_list/jobs_list.js @@ -24,10 +24,12 @@ import { EuiIcon, EuiScreenReaderOnly, EuiToolTip, + EuiBadge, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; import { AnomalyDetectionJobIdLink } from './job_id_link'; +import { isManagedJob } from '../../../jobs_utils'; const PAGE_SIZE_OPTIONS = [10, 25, 50]; @@ -169,7 +171,31 @@ export class JobsList extends Component { truncateText: false, width: '15%', scope: 'row', - render: isManagementTable ? (id) => this.getJobIdLink(id) : undefined, + render: isManagementTable + ? (id) => this.getJobIdLink(id) + : (id, item) => { + if (!isManagedJob(item)) return id; + + return ( + <> + + {id}   + + + {i18n.translate('xpack.ml.jobsList.managedBadgeLabel', { + defaultMessage: 'Managed', + })} + + + + + ); + }, }, { field: 'auditMessage', @@ -340,6 +366,8 @@ export class JobsList extends Component { this.props.showDeleteJobModal, this.props.showResetJobModal, this.props.showStartDatafeedModal, + this.props.showCloseJobsConfirmModal, + this.props.showStopDatafeedsConfirmModal, this.props.refreshJobs, this.props.showCreateAlertFlyout ), @@ -414,7 +442,9 @@ JobsList.propTypes = { showEditJobFlyout: PropTypes.func, showDeleteJobModal: PropTypes.func, showStartDatafeedModal: PropTypes.func, + showCloseJobsConfirmModal: PropTypes.func, showCreateAlertFlyout: PropTypes.func, + showStopDatafeedsConfirmModal: PropTypes.func, refreshJobs: PropTypes.func, selectedJobsCount: PropTypes.number.isRequired, loading: PropTypes.bool, diff --git a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/jobs_list_view/jobs_list_view.js b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/jobs_list_view/jobs_list_view.js index edcb38c6305efa..539d0c475bb00b 100644 --- a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/jobs_list_view/jobs_list_view.js +++ b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/jobs_list_view/jobs_list_view.js @@ -29,6 +29,8 @@ import { RefreshJobsListButton } from '../refresh_jobs_list_button'; import { DELETING_JOBS_REFRESH_INTERVAL_MS } from '../../../../../../common/constants/jobs_list'; import { JobListMlAnomalyAlertFlyout } from '../../../../../alerting/ml_alerting_flyout'; +import { StopDatafeedsConfirmModal } from '../confirm_modals/stop_datafeeds_confirm_modal'; +import { CloseJobsConfirmModal } from '../confirm_modals/close_jobs_confirm_modal'; let blockingJobsRefreshTimeout = null; @@ -58,6 +60,8 @@ export class JobsListView extends Component { this.updateFunctions = {}; this.showEditJobFlyout = () => {}; + this.showStopDatafeedsConfirmModal = () => {}; + this.showCloseJobsConfirmModal = () => {}; this.showDeleteJobModal = () => {}; this.showResetJobModal = () => {}; this.showStartDatafeedModal = () => {}; @@ -193,6 +197,22 @@ export class JobsListView extends Component { this.showEditJobFlyout = () => {}; }; + setShowStopDatafeedsConfirmModalFunction = (func) => { + this.showStopDatafeedsConfirmModal = func; + }; + + unsetShowStopDatafeedsConfirmModalFunction = () => { + this.showStopDatafeedsConfirmModal = () => {}; + }; + + setShowCloseJobsConfirmModalFunction = (func) => { + this.showCloseJobsConfirmModal = func; + }; + + unsetShowCloseJobsConfirmModalFunction = () => { + this.showCloseJobsConfirmModal = () => {}; + }; + setShowDeleteJobModalFunction = (func) => { this.showDeleteJobModal = func; }; @@ -490,10 +510,12 @@ export class JobsListView extends Component { this.refreshJobSummaryList(true)} /> this.refreshJobSummaryList(true)} jobsViewState={this.props.jobsViewState} onJobsViewStateUpdate={this.props.onJobsViewStateUpdate} @@ -524,6 +548,18 @@ export class JobsListView extends Component { refreshJobs={() => this.refreshJobSummaryList(true)} allJobIds={jobIds} /> + this.refreshJobSummaryList(true)} + allJobIds={jobIds} + /> + + this.refreshJobSummaryList(true)} + /> { - closeJobs(this.props.jobs); + if (this.props.jobs.some((j) => isManagedJob(j))) { + this.props.showCloseJobsConfirmModal(this.props.jobs); + } else { + closeJobs(this.props.jobs); + } + this.closePopover(); }} data-test-subj="mlADJobListMultiSelectCloseJobActionButton" @@ -139,7 +145,11 @@ class MultiJobActionsMenuUI extends Component { icon="stop" disabled={this.canStartStopDatafeed === false} onClick={() => { - stopDatafeeds(this.props.jobs, this.props.refreshJobs); + if (this.props.jobs.some((j) => isManagedJob(j))) { + this.props.showStopDatafeedsConfirmModal(this.props.jobs); + } else { + stopDatafeeds(this.props.jobs, this.props.refreshJobs); + } this.closePopover(); }} data-test-subj="mlADJobListMultiSelectStopDatafeedActionButton" @@ -211,6 +221,7 @@ MultiJobActionsMenuUI.propTypes = { jobs: PropTypes.array.isRequired, showStartDatafeedModal: PropTypes.func.isRequired, showDeleteJobModal: PropTypes.func.isRequired, + showStopDatafeedsConfirmModal: PropTypes.func.isRequired, refreshJobs: PropTypes.func.isRequired, showCreateAlertFlyout: PropTypes.func.isRequired, }; diff --git a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/multi_job_actions/multi_job_actions.js b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/multi_job_actions/multi_job_actions.js index 148f1a9276c502..eede9d45732255 100644 --- a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/multi_job_actions/multi_job_actions.js +++ b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/multi_job_actions/multi_job_actions.js @@ -64,9 +64,11 @@ export class MultiJobActions extends Component { @@ -81,8 +83,10 @@ MultiJobActions.propTypes = { selectedJobs: PropTypes.array.isRequired, allJobIds: PropTypes.array.isRequired, showStartDatafeedModal: PropTypes.func.isRequired, + showCloseJobsConfirmModal: PropTypes.func.isRequired, showDeleteJobModal: PropTypes.func.isRequired, showResetJobModal: PropTypes.func.isRequired, + showStopDatafeedsConfirmModal: PropTypes.func.isRequired, refreshJobs: PropTypes.func.isRequired, showCreateAlertFlyout: PropTypes.func.isRequired, }; diff --git a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/reset_job_modal/reset_job_modal.tsx b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/reset_job_modal/reset_job_modal.tsx index 45e928cdf39055..49a2b810c10002 100644 --- a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/reset_job_modal/reset_job_modal.tsx +++ b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/reset_job_modal/reset_job_modal.tsx @@ -19,10 +19,13 @@ import { EuiText, } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; import { resetJobs } from '../utils'; import type { MlSummaryJob } from '../../../../../../common/types/anomaly_detection_jobs'; import { RESETTING_JOBS_REFRESH_INTERVAL_MS } from '../../../../../../common/constants/jobs_list'; import { OpenJobsWarningCallout } from './open_jobs_warning_callout'; +import { isManagedJob } from '../../../jobs_utils'; +import { ManagedJobsWarningCallout } from '../confirm_modals/managed_jobs_warning_callout'; type ShowFunc = (jobs: MlSummaryJob[]) => void; @@ -37,6 +40,7 @@ export const ResetJobModal: FC = ({ setShowFunction, unsetShowFunction, r const [modalVisible, setModalVisible] = useState(false); const [jobIds, setJobIds] = useState([]); const [jobs, setJobs] = useState([]); + const [hasManagedJob, setHasManagedJob] = useState(false); useEffect(() => { if (typeof setShowFunction === 'function') { @@ -52,6 +56,8 @@ export const ResetJobModal: FC = ({ setShowFunction, unsetShowFunction, r const showModal = useCallback((tempJobs: MlSummaryJob[]) => { setJobIds(tempJobs.map(({ id }) => id)); setJobs(tempJobs); + setHasManagedJob(tempJobs.some((j) => isManagedJob(j))); + setModalVisible(true); setResetting(false); }, []); @@ -90,6 +96,22 @@ export const ResetJobModal: FC = ({ setShowFunction, unsetShowFunction, r <> + + {hasManagedJob === true ? ( + <> + + + + ) : null} + 0; + this.setState({ jobs, isModalVisible: true, @@ -98,6 +101,7 @@ export class StartDatafeedModal extends Component { allowCreateAlert, createAlert: false, now, + hasManagedJob: jobs.some((j) => isManagedJob(j)), }); }; @@ -164,6 +168,8 @@ export class StartDatafeedModal extends Component { setEndTime={this.setEndTime} now={now} setTimeRangeValid={this.setTimeRangeValid} + hasManagedJob={this.state.hasManagedJob} + jobsCount={startableJobs.length} /> {this.state.endTime === undefined && (
diff --git a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/start_datafeed_modal/time_range_selector/time_range_selector.js b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/start_datafeed_modal/time_range_selector/time_range_selector.js index 20ffba0e11d4c0..4300a918b948f0 100644 --- a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/start_datafeed_modal/time_range_selector/time_range_selector.js +++ b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/start_datafeed_modal/time_range_selector/time_range_selector.js @@ -9,12 +9,13 @@ import './_time_range_selector.scss'; import PropTypes from 'prop-types'; import React, { Component, useState, useEffect } from 'react'; -import { EuiDatePicker, EuiFieldText } from '@elastic/eui'; +import { EuiDatePicker, EuiFieldText, EuiSpacer } from '@elastic/eui'; import moment from 'moment'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; import { TIME_FORMAT } from '../../../../../../../common/constants/time_format'; +import { ManagedJobsWarningCallout } from '../../confirm_modals/managed_jobs_warning_callout'; export class TimeRangeSelector extends Component { constructor(props) { @@ -162,6 +163,24 @@ export class TimeRangeSelector extends Component { const { startItems, endItems } = this.getTabItems(); return (
+ {this.props.hasManagedJob === true && this.state.endTab !== 0 ? ( + <> + + + + ) : null}
, callback?: () => void): Promise; +export function closeJobs(jobs: Array<{ id: string }>, callback?: () => void): Promise; export function deleteJobs(jobs: Array<{ id: string }>, callback?: () => void): Promise; export function resetJobs(jobIds: string[], callback?: () => void): Promise; export function loadFullJob(jobId: string): Promise; diff --git a/x-pack/plugins/ml/public/application/jobs/jobs_utils.ts b/x-pack/plugins/ml/public/application/jobs/jobs_utils.ts new file mode 100644 index 00000000000000..103f079b88ff3b --- /dev/null +++ b/x-pack/plugins/ml/public/application/jobs/jobs_utils.ts @@ -0,0 +1,17 @@ +/* + * 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 { MlJob } from '@elastic/elasticsearch/lib/api/types'; +import { isPopulatedObject } from '../../../common'; +import { MlSummaryJob } from '../../../common/types/anomaly_detection_jobs'; + +export const isManagedJob = (job: MlSummaryJob | MlJob) => { + return ( + (isPopulatedObject(job, ['customSettings']) && job.customSettings.managed === true) || + (isPopulatedObject(job, ['custom_settings']) && job.custom_settings.managed === true) + ); +}; diff --git a/x-pack/plugins/ml/public/application/jobs/new_job/common/job_creator/job_creator.ts b/x-pack/plugins/ml/public/application/jobs/new_job/common/job_creator/job_creator.ts index 9cea7aef2e1177..804a368174c76b 100644 --- a/x-pack/plugins/ml/public/application/jobs/new_job/common/job_creator/job_creator.ts +++ b/x-pack/plugins/ml/public/application/jobs/new_job/common/job_creator/job_creator.ts @@ -767,6 +767,7 @@ export class JobCreator { this._detectors = this._job_config.analysis_config.detectors; this._influencers = this._job_config.analysis_config.influencers!; + if (this._job_config.groups === undefined) { this._job_config.groups = []; } diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/apm_transaction/ml/apm_tx_metrics.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/apm_transaction/ml/apm_tx_metrics.json index f93b4fb009a143..9f67527ba677da 100644 --- a/x-pack/plugins/ml/server/models/data_recognizer/modules/apm_transaction/ml/apm_tx_metrics.json +++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/apm_transaction/ml/apm_tx_metrics.json @@ -48,6 +48,7 @@ }, "results_index_name" : "custom-apm", "custom_settings": { - "created_by": "ml-module-apm-transaction" + "created_by": "ml-module-apm-transaction", + "managed": true } } diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/logs_ui_analysis/ml/log_entry_rate.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/logs_ui_analysis/ml/log_entry_rate.json index 42ba15591e5c4c..0cd99ae71765da 100644 --- a/x-pack/plugins/ml/server/models/data_recognizer/modules/logs_ui_analysis/ml/log_entry_rate.json +++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/logs_ui_analysis/ml/log_entry_rate.json @@ -25,6 +25,7 @@ "enabled": true }, "custom_settings": { + "managed": true, "created_by": "ml-module-logs-ui-analysis", "job_revision": 2 } diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/logs_ui_categories/ml/log_entry_categories_count.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/logs_ui_categories/ml/log_entry_categories_count.json index 90f88275cb6d0b..74f434f36e4ed5 100644 --- a/x-pack/plugins/ml/server/models/data_recognizer/modules/logs_ui_categories/ml/log_entry_categories_count.json +++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/logs_ui_categories/ml/log_entry_categories_count.json @@ -37,6 +37,7 @@ "enabled": true }, "custom_settings": { + "managed": true, "created_by": "ml-module-logs-ui-categories", "job_revision": 2 } diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/metrics_ui_hosts/ml/hosts_memory_usage.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/metrics_ui_hosts/ml/hosts_memory_usage.json index c5f62105613ba7..07f2c7fe9a927b 100644 --- a/x-pack/plugins/ml/server/models/data_recognizer/modules/metrics_ui_hosts/ml/hosts_memory_usage.json +++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/metrics_ui_hosts/ml/hosts_memory_usage.json @@ -39,6 +39,7 @@ "model_memory_limit": "64mb" }, "custom_settings": { + "managed": true, "created_by": "ml-module-metrics-ui-hosts", "custom_urls": [ { diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/metrics_ui_hosts/ml/hosts_network_in.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/metrics_ui_hosts/ml/hosts_network_in.json index 258fb87f5260c7..6025777e49d056 100644 --- a/x-pack/plugins/ml/server/models/data_recognizer/modules/metrics_ui_hosts/ml/hosts_network_in.json +++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/metrics_ui_hosts/ml/hosts_network_in.json @@ -26,6 +26,7 @@ "model_memory_limit": "32mb" }, "custom_settings": { + "managed": true, "created_by": "ml-module-metrics-ui-hosts", "custom_urls": [ { diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/metrics_ui_hosts/ml/hosts_network_out.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/metrics_ui_hosts/ml/hosts_network_out.json index 381bc09bac46c3..95b3950dfc35a6 100644 --- a/x-pack/plugins/ml/server/models/data_recognizer/modules/metrics_ui_hosts/ml/hosts_network_out.json +++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/metrics_ui_hosts/ml/hosts_network_out.json @@ -26,6 +26,7 @@ "model_memory_limit": "32mb" }, "custom_settings": { + "managed": true, "created_by": "ml-module-metrics-ui-hosts", "custom_urls": [ { diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/metrics_ui_k8s/ml/k8s_memory_usage.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/metrics_ui_k8s/ml/k8s_memory_usage.json index ef57612e9f90ee..8b76b328a05dbb 100644 --- a/x-pack/plugins/ml/server/models/data_recognizer/modules/metrics_ui_k8s/ml/k8s_memory_usage.json +++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/metrics_ui_k8s/ml/k8s_memory_usage.json @@ -42,6 +42,7 @@ "model_memory_limit": "64mb" }, "custom_settings": { + "managed": true, "created_by": "ml-module-metrics-ui-k8s", "custom_urls": [ { diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/metrics_ui_k8s/ml/k8s_network_in.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/metrics_ui_k8s/ml/k8s_network_in.json index 91f855a59add59..de591577d2d351 100644 --- a/x-pack/plugins/ml/server/models/data_recognizer/modules/metrics_ui_k8s/ml/k8s_network_in.json +++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/metrics_ui_k8s/ml/k8s_network_in.json @@ -28,6 +28,7 @@ "model_memory_limit": "32mb" }, "custom_settings": { + "managed": true, "created_by": "ml-module-metrics-ui-k8s", "custom_urls": [ { diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/metrics_ui_k8s/ml/k8s_network_out.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/metrics_ui_k8s/ml/k8s_network_out.json index e68866a655acf2..61ce7b25eacc08 100644 --- a/x-pack/plugins/ml/server/models/data_recognizer/modules/metrics_ui_k8s/ml/k8s_network_out.json +++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/metrics_ui_k8s/ml/k8s_network_out.json @@ -28,6 +28,7 @@ "model_memory_limit": "32mb" }, "custom_settings": { + "managed": true, "created_by": "ml-module-metrics-ui-k8s", "custom_urls": [ { diff --git a/x-pack/plugins/ml/server/models/job_service/jobs.ts b/x-pack/plugins/ml/server/models/job_service/jobs.ts index ffc07e06db0f93..a79093caabbefc 100644 --- a/x-pack/plugins/ml/server/models/job_service/jobs.ts +++ b/x-pack/plugins/ml/server/models/job_service/jobs.ts @@ -220,6 +220,7 @@ export function jobsProvider( const tempJob: MlSummaryJob = { id: job.job_id, description: job.description || '', + customSettings: job.custom_settings, groups: Array.isArray(job.groups) ? job.groups.sort() : [], processed_record_count: job.data_counts?.processed_record_count, earliestStartTimestampMs: getEarliestDatafeedStartTime( @@ -319,12 +320,19 @@ export function jobsProvider( if (jobResults && jobResults.jobs) { const job = jobResults.jobs.find((j) => j.job_id === jobId); if (job) { + removeUnClonableCustomSettings(job); result.job = job; } } return result; } + function removeUnClonableCustomSettings(job: Job) { + if (isPopulatedObject(job.custom_settings)) { + delete job.custom_settings.managed; + } + } + async function createFullJobsList(jobIds: string[] = []) { const jobs: CombinedJobWithStats[] = []; const groups: { [jobId: string]: string[] } = {}; diff --git a/x-pack/plugins/transform/public/app/common/managed_transforms_utils.ts b/x-pack/plugins/transform/public/app/common/managed_transforms_utils.ts new file mode 100644 index 00000000000000..5164245646d6ee --- /dev/null +++ b/x-pack/plugins/transform/public/app/common/managed_transforms_utils.ts @@ -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. + */ + +import type { TransformListRow } from './transform_list'; + +export const isManagedTransform = (transform: Partial) => { + return transform.config?._meta?.managed; +}; diff --git a/x-pack/plugins/transform/public/app/common/transform.ts b/x-pack/plugins/transform/public/app/common/transform.ts index c1f8f58657d5e7..09fc1c24303d89 100644 --- a/x-pack/plugins/transform/public/app/common/transform.ts +++ b/x-pack/plugins/transform/public/app/common/transform.ts @@ -9,8 +9,8 @@ import { useEffect } from 'react'; import { BehaviorSubject } from 'rxjs'; import { filter, distinctUntilChanged } from 'rxjs/operators'; import { Subscription } from 'rxjs'; - -import { TransformId } from '../../../common/types/transform'; +import { cloneDeep } from 'lodash'; +import type { TransformConfigUnion, TransformId } from '../../../common/types/transform'; // Via https://github.com/elastic/elasticsearch/blob/master/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/transform/utils/TransformStrings.java#L24 // Matches a string that contains lowercase characters, digits, hyphens, underscores or dots. @@ -78,3 +78,11 @@ export const useRefreshTransformList = ( }, }; }; + +export const overrideTransformForCloning = (originalConfig: TransformConfigUnion) => { + // 'Managed' means job is preconfigured and deployed by other solutions + // we should not clone this setting + const clonedConfig = cloneDeep(originalConfig); + delete clonedConfig._meta?.managed; + return clonedConfig; +}; diff --git a/x-pack/plugins/transform/public/app/sections/clone_transform/clone_transform_section.tsx b/x-pack/plugins/transform/public/app/sections/clone_transform/clone_transform_section.tsx index 76a3b06ef5574c..c84f7cb97c9598 100644 --- a/x-pack/plugins/transform/public/app/sections/clone_transform/clone_transform_section.tsx +++ b/x-pack/plugins/transform/public/app/sections/clone_transform/clone_transform_section.tsx @@ -19,7 +19,6 @@ import { EuiPageHeader, EuiSpacer, } from '@elastic/eui'; - import { APP_CREATE_TRANSFORM_CLUSTER_PRIVILEGES } from '../../../../common/constants'; import { TransformConfigUnion } from '../../../../common/types/transform'; @@ -32,8 +31,10 @@ import { breadcrumbService, docTitleService, BREADCRUMB_SECTION } from '../../se import { PrivilegesWrapper } from '../../lib/authorization'; import { Wizard } from '../create_transform/components/wizard'; +import { overrideTransformForCloning } from '../../common/transform'; type Props = RouteComponentProps<{ transformId: string }>; + export const CloneTransformSection: FC = ({ match, location }) => { const { indexPatternId }: Record = parse(location.search, { sort: false, @@ -82,7 +83,7 @@ export const CloneTransformSection: FC = ({ match, location }) => { setSavedObjectId(indexPatternId); - setTransformConfig(transformConfigs.transforms[0]); + setTransformConfig(overrideTransformForCloning(transformConfigs.transforms[0])); setErrorMessage(undefined); setIsInitialized(true); } catch (e) { diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_delete/delete_action_modal.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_delete/delete_action_modal.tsx index 2986fcce554e81..d5436d51c218bb 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_delete/delete_action_modal.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_delete/delete_action_modal.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { FC } from 'react'; +import React, { FC, useMemo } from 'react'; import { i18n } from '@kbn/i18n'; import { EUI_MODAL_CONFIRM_BUTTON, @@ -15,8 +15,9 @@ import { EuiSpacer, EuiSwitch, } from '@elastic/eui'; - import { DeleteAction } from './use_delete_action'; +import { isManagedTransform } from '../../../../common/managed_transforms_utils'; +import { ManagedTransformsWarningCallout } from '../managed_transforms_callout/managed_transforms_callout'; export const DeleteActionModal: FC = ({ closeModal, @@ -31,6 +32,7 @@ export const DeleteActionModal: FC = ({ userCanDeleteIndex, userCanDeleteDataView, }) => { + const hasManagedTransforms = useMemo(() => items.some((t) => isManagedTransform(t)), [items]); const isBulkAction = items.length > 1; const bulkDeleteModalTitle = i18n.translate( @@ -47,6 +49,19 @@ export const DeleteActionModal: FC = ({ const bulkDeleteModalContent = ( <> + {hasManagedTransforms ? ( + <> + + + + ) : null} + { = ({ const deleteModalContent = ( <> + {hasManagedTransforms ? ( + <> + + + + ) : null} + {userCanDeleteIndex && ( { }; const openModal = (newItems: TransformListRow[]) => { - // EUI issue: Might trigger twice, one time as an array, - // one time as a single object. See https://github.com/elastic/eui/issues/3679 if (Array.isArray(newItems)) { setItems(newItems); setModalVisible(true); diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/start_action_modal.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/start_action_modal.tsx index fb4fee986f6e08..7ad6897034e105 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/start_action_modal.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/start_action_modal.tsx @@ -8,7 +8,6 @@ import React, { FC } from 'react'; import { i18n } from '@kbn/i18n'; import { EuiConfirmModal, EUI_MODAL_CONFIRM_BUTTON } from '@elastic/eui'; - import { StartAction } from './use_start_action'; export const StartActionModal: FC = ({ closeModal, items, startAndCloseModal }) => { diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/use_start_action.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/use_start_action.tsx index 2c45da45509e59..20910cf5fa0a56 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/use_start_action.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/use_start_action.tsx @@ -32,8 +32,6 @@ export const useStartAction = (forceDisable: boolean, transformNodes: number) => }; const openModal = (newItems: TransformListRow[]) => { - // EUI issue: Might trigger twice, one time as an array, - // one time as a single object. See https://github.com/elastic/eui/issues/3679 if (Array.isArray(newItems)) { setItems(newItems); setModalVisible(true); diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_stop/stop_action_modal.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_stop/stop_action_modal.tsx new file mode 100644 index 00000000000000..ed53bb3b8d936c --- /dev/null +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_stop/stop_action_modal.tsx @@ -0,0 +1,54 @@ +/* + * 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 React, { FC, useMemo } from 'react'; +import { i18n } from '@kbn/i18n'; +import { EuiConfirmModal, EUI_MODAL_CONFIRM_BUTTON } from '@elastic/eui'; +import { StopAction } from './use_stop_action'; +import { isManagedTransform } from '../../../../common/managed_transforms_utils'; +import { ManagedTransformsWarningCallout } from '../managed_transforms_callout/managed_transforms_callout'; + +export const StopActionModal: FC = ({ closeModal, items, stopAndCloseModal }) => { + const hasManagedTransforms = useMemo(() => items.some((t) => isManagedTransform(t)), [items]); + + const isBulkAction = items.length > 1; + + const bulkStopModalTitle = i18n.translate('xpack.transform.transformList.bulkStopModalTitle', { + defaultMessage: 'Stop {count} {count, plural, one {transform} other {transforms}}?', + values: { count: items && items.length }, + }); + const stopModalTitle = i18n.translate('xpack.transform.transformList.stopModalTitle', { + defaultMessage: 'Stop {transformId}?', + values: { transformId: items[0] && items[0].config.id }, + }); + + return ( + stopAndCloseModal(items)} + cancelButtonText={i18n.translate('xpack.transform.transformList.startModalCancelButton', { + defaultMessage: 'Cancel', + })} + confirmButtonText={i18n.translate('xpack.transform.transformList.startModalStopButton', { + defaultMessage: 'Stop', + })} + defaultFocusedButton={EUI_MODAL_CONFIRM_BUTTON} + buttonColor="primary" + > + {hasManagedTransforms ? ( + + ) : null} + + ); +}; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_stop/use_stop_action.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_stop/use_stop_action.tsx index f498008bfd5596..ac53ee83f6f655 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_stop/use_stop_action.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_stop/use_stop_action.tsx @@ -5,21 +5,39 @@ * 2.0. */ -import React, { useCallback, useContext, useMemo } from 'react'; - +import React, { useCallback, useContext, useMemo, useState } from 'react'; import { TRANSFORM_STATE } from '../../../../../../common/constants'; - import { AuthorizationContext } from '../../../../lib/authorization'; import { TransformListAction, TransformListRow } from '../../../../common'; import { useStopTransforms } from '../../../../hooks'; - import { isStopActionDisabled, stopActionNameText, StopActionName } from './stop_action_name'; +import { isManagedTransform } from '../../../../common/managed_transforms_utils'; export type StopAction = ReturnType; + export const useStopAction = (forceDisable: boolean) => { const { canStartStopTransform } = useContext(AuthorizationContext).capabilities; const stopTransforms = useStopTransforms(); + const [isModalVisible, setModalVisible] = useState(false); + const [items, setItems] = useState([]); + + const closeModal = () => setModalVisible(false); + + const openModal = (newItems: TransformListRow[]) => { + if (Array.isArray(newItems)) { + setItems(newItems); + setModalVisible(true); + } + }; + + const stopAndCloseModal = useCallback( + (transformSelection: TransformListRow[]) => { + setModalVisible(false); + stopTransforms(transformSelection.map((t) => ({ id: t.id, state: t.stats.state }))); + }, + [stopTransforms] + ); const clickHandler = useCallback( (i: TransformListRow) => stopTransforms([{ id: i.id, state: i.stats.state }]), @@ -37,11 +55,17 @@ export const useStopAction = (forceDisable: boolean) => { description: stopActionNameText, icon: 'stop', type: 'icon', - onClick: clickHandler, + onClick: (item: TransformListRow) => { + if (isManagedTransform(item)) { + openModal([item]); + } else { + clickHandler(item); + } + }, 'data-test-subj': 'transformActionStop', }), - [canStartStopTransform, forceDisable, clickHandler] + [canStartStopTransform, clickHandler, forceDisable] ); - return { action }; + return { action, closeModal, openModal, isModalVisible, items, stopAndCloseModal }; }; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/edit_transform_flyout/edit_transform_flyout.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/edit_transform_flyout/edit_transform_flyout.tsx index 55225e0ff45c03..fd8360d02eca02 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/edit_transform_flyout/edit_transform_flyout.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/edit_transform_flyout/edit_transform_flyout.tsx @@ -38,6 +38,8 @@ import { applyFormFieldsToTransformConfig, useEditTransformFlyout, } from './use_edit_transform_flyout'; +import { ManagedTransformsWarningCallout } from '../managed_transforms_callout/managed_transforms_callout'; +import { isManagedTransform } from '../../../../common/managed_transforms_utils'; interface EditTransformFlyoutProps { closeFlyout: () => void; @@ -99,6 +101,14 @@ export const EditTransformFlyout: FC = ({ + {isManagedTransform({ config }) ? ( + + ) : null} }> { + return ( + <> + + + + + + ); +}; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.tsx index 8b7aaf1cf8fd24..cdf0c14409fdd0 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.tsx @@ -31,7 +31,6 @@ import { TransformListRow, TRANSFORM_LIST_COLUMN, } from '../../../../common'; -import { useStopTransforms } from '../../../../hooks'; import { AuthorizationContext } from '../../../../lib/authorization'; import { CreateTransformButton } from '../create_transform_button'; @@ -43,7 +42,7 @@ import { DeleteActionModal, } from '../action_delete'; import { useStartAction, StartActionName, StartActionModal } from '../action_start'; -import { StopActionName } from '../action_stop'; +import { StopActionName, useStopAction } from '../action_stop'; import { ItemIdToExpandedRowMap } from './common'; import { useColumns } from './use_columns'; @@ -52,6 +51,7 @@ import { transformFilters, filterTransforms } from './transform_search_bar_filte import { useTableSettings } from './use_table_settings'; import { useAlertRuleFlyout } from '../../../../../alerting/transform_alerting_flyout'; import { TransformHealthAlertRule } from '../../../../../../common/types/alerting'; +import { StopActionModal } from '../action_stop/stop_action_modal'; function getItemIdToExpandedRowMap( itemIds: TransformId[], @@ -92,9 +92,9 @@ export const TransformList: FC = ({ const [isActionsMenuOpen, setIsActionsMenuOpen] = useState(false); const bulkStartAction = useStartAction(false, transformNodes); const bulkDeleteAction = useDeleteAction(false); + const bulkStopAction = useStopAction(false); const [searchError, setSearchError] = useState(undefined); - const stopTransforms = useStopTransforms(); const { capabilities } = useContext(AuthorizationContext); const disabled = @@ -189,9 +189,9 @@ export const TransformList: FC = ({
,
- stopTransforms(transformSelection.map((t) => ({ id: t.id, state: t.stats.state }))) - } + onClick={() => { + bulkStopAction.openModal(transformSelection); + }} > @@ -283,6 +283,7 @@ export const TransformList: FC = ({ {/* Bulk Action Modals */} {bulkStartAction.isModalVisible && } {bulkDeleteAction.isModalVisible && } + {bulkStopAction.isModalVisible && } {/* Single Action Modals */} {singleActionModals} diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/use_actions.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/use_actions.tsx index 40b40cfa8c7ba3..853c839a096faa 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/use_actions.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/use_actions.tsx @@ -19,6 +19,7 @@ import { useEditAction } from '../action_edit'; import { useStartAction, StartActionModal } from '../action_start'; import { useStopAction } from '../action_stop'; import { useCreateAlertRuleAction } from '../action_create_alert'; +import { StopActionModal } from '../action_stop/stop_action_modal'; export const useActions = ({ forceDisable, @@ -42,6 +43,8 @@ export const useActions = ({ modals: ( <> {startAction.isModalVisible && } + {stopAction.isModalVisible && } + {editAction.config && editAction.isFlyoutVisible && ( { - if (item.config?._meta?.managed !== true) return transformId; + if (!isManagedTransform(item)) return transformId; return ( <> {transformId}   - - {i18n.translate('xpack.transform.transformList.managedBadgeLabel', { - defaultMessage: 'Managed', + + > + + {i18n.translate('xpack.transform.transformList.managedBadgeLabel', { + defaultMessage: 'Managed', + })} + + ); }, From 20c31b2fcee6881a922966b584e807d1841f3fd9 Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Wed, 19 Jan 2022 17:08:03 +0100 Subject: [PATCH 049/108] fix `getDefaultDataView` overrides existing default data view (#123182) --- .../common/data_views/data_views.test.ts | 94 +++++++++++++++---- .../common/data_views/data_views.ts | 35 ++++--- .../data_views/ensure_default_data_view.ts | 22 +---- 3 files changed, 102 insertions(+), 49 deletions(-) diff --git a/src/plugins/data_views/common/data_views/data_views.test.ts b/src/plugins/data_views/common/data_views/data_views.test.ts index 7ed3e1f2c5434a..7f566464add2ff 100644 --- a/src/plugins/data_views/common/data_views/data_views.test.ts +++ b/src/plugins/data_views/common/data_views/data_views.test.ts @@ -12,6 +12,7 @@ import { fieldFormatsMock } from '../../../field_formats/common/mocks'; import { UiSettingsCommon, SavedObjectsClientCommon, SavedObject } from '../types'; import { stubbedSavedObjectIndexPattern } from '../data_view.stub'; +import { FLEET_ASSETS_TO_IGNORE } from '../constants'; const createFieldsFetcher = jest.fn().mockImplementation(() => ({ getFieldsForWildcard: jest.fn().mockImplementation(() => { @@ -54,7 +55,7 @@ describe('IndexPatterns', () => { const uiSettings = { get: () => Promise.resolve(false), getAll: () => {}, - set: () => () => {}, + set: jest.fn(), remove: jest.fn(), } as any as UiSettingsCommon; const indexPatternObj = { id: 'id', version: 'a', attributes: { title: 'title' } }; @@ -308,9 +309,15 @@ describe('IndexPatterns', () => { }); describe('getDefaultDataView', () => { - test('gets default data view', async () => { + beforeEach(() => { indexPatterns.clearCache(); - jest.clearAllMocks(); + jest.resetAllMocks(); + }); + + test('gets default data view', async () => { + uiSettings.get = jest.fn().mockResolvedValue(indexPatternObj.id); + savedObjectsClient.find = jest.fn().mockResolvedValue([indexPatternObj]); + savedObjectsClient.get = jest.fn().mockResolvedValue(indexPatternObj); expect(await indexPatterns.getDefaultDataView()).toBeInstanceOf(DataView); // make sure we're not pulling from cache @@ -319,22 +326,15 @@ describe('IndexPatterns', () => { }); test('returns undefined if no data views exist', async () => { - savedObjectsClient.find = jest.fn( - () => Promise.resolve([]) as Promise>> - ); - savedObjectsClient.get = jest.fn(() => Promise.resolve(undefined) as Promise); - indexPatterns.clearCache(); - expect(await indexPatterns.getDefaultDataView()).toBeUndefined(); + uiSettings.get = jest.fn().mockResolvedValue('foo'); + savedObjectsClient.find = jest.fn().mockResolvedValue([]); + + expect(await indexPatterns.getDefaultDataView()).toBeNull(); }); test("default doesn't exist, grabs another data view", async () => { - indexPatterns.clearCache(); - jest.clearAllMocks(); - uiSettings.get = jest.fn().mockResolvedValue(['bar']); - - savedObjectsClient.find = jest.fn( - () => Promise.resolve([indexPatternObj]) as Promise>> - ); + uiSettings.get = jest.fn().mockResolvedValue('foo'); + savedObjectsClient.find = jest.fn().mockResolvedValue([indexPatternObj]); savedObjectsClient.get = jest.fn().mockResolvedValue({ id: 'bar', @@ -349,6 +349,68 @@ describe('IndexPatterns', () => { expect(savedObjectsClient.get).toBeCalledTimes(1); expect(savedObjectsClient.find).toBeCalledTimes(1); expect(uiSettings.remove).toBeCalledTimes(1); + expect(uiSettings.set).toBeCalledTimes(1); + }); + + test("when default exists, it isn't overridden with first data view", async () => { + uiSettings.get = jest.fn().mockResolvedValue('id2'); + + savedObjectsClient.find = jest.fn().mockResolvedValue([ + { id: 'id1', version: 'a', attributes: { title: 'title' } }, + { id: 'id2', version: 'a', attributes: { title: 'title' } }, + ]); + + savedObjectsClient.get = jest + .fn() + .mockImplementation((type: string, id: string) => + Promise.resolve({ id, version: 'a', attributes: { title: 'title' } }) + ); + + const defaultDataViewResult = await indexPatterns.getDefaultDataView(); + expect(defaultDataViewResult).toBeInstanceOf(DataView); + expect(defaultDataViewResult?.id).toBe('id2'); + + // make sure we're not pulling from cache + expect(savedObjectsClient.get).toBeCalledTimes(1); + expect(savedObjectsClient.find).toBeCalledTimes(1); + expect(uiSettings.remove).toBeCalledTimes(0); + expect(uiSettings.set).toBeCalledTimes(0); + }); + + test('when setting default it prefers user created data views', async () => { + savedObjectsClient.find = jest.fn().mockResolvedValue([ + { + id: 'id1', + version: 'a', + attributes: { title: FLEET_ASSETS_TO_IGNORE.LOGS_INDEX_PATTERN }, + }, + { + id: 'id2', + version: 'a', + attributes: { title: FLEET_ASSETS_TO_IGNORE.METRICS_INDEX_PATTERN }, + }, + { + id: 'id3', + version: 'a', + attributes: { title: 'user-data-view' }, + }, + ]); + + savedObjectsClient.get = jest + .fn() + .mockImplementation((type: string, id: string) => + Promise.resolve({ id, version: 'a', attributes: { title: 'title' } }) + ); + + const defaultDataViewResult = await indexPatterns.getDefaultDataView(); + expect(defaultDataViewResult).toBeInstanceOf(DataView); + expect(defaultDataViewResult?.id).toBe('id3'); + + // make sure we're not pulling from cache + expect(savedObjectsClient.get).toBeCalledTimes(1); + expect(savedObjectsClient.find).toBeCalledTimes(1); + expect(uiSettings.remove).toBeCalledTimes(0); + expect(uiSettings.set).toBeCalledTimes(1); }); }); }); diff --git a/src/plugins/data_views/common/data_views/data_views.ts b/src/plugins/data_views/common/data_views/data_views.ts index 1024dc29267862..ae7c9f03afc183 100644 --- a/src/plugins/data_views/common/data_views/data_views.ts +++ b/src/plugins/data_views/common/data_views/data_views.ts @@ -11,7 +11,7 @@ import { i18n } from '@kbn/i18n'; import { PublicMethodsOf } from '@kbn/utility-types'; import { castEsToKbnFieldTypeName } from '@kbn/field-types'; -import { DATA_VIEW_SAVED_OBJECT_TYPE, SavedObjectsClientCommon } from '..'; +import { DATA_VIEW_SAVED_OBJECT_TYPE, FLEET_ASSETS_TO_IGNORE, SavedObjectsClientCommon } from '..'; import { createDataViewCache } from '.'; import type { RuntimeField } from '../types'; @@ -695,29 +695,40 @@ export class DataViewsService { } /** - * Returns the default data view as an object. If no default is found, or it is missing + * Returns the default data view as an object. + * If no default is found, or it is missing * another data view is selected as default and returned. + * If no possible data view found to become a default returns null + * * @returns default data view */ + async getDefaultDataView(): Promise { + const patterns = await this.getIdsWithTitle(); + let defaultId: string | undefined = await this.config.get('defaultIndex'); + const exists = defaultId ? patterns.some((pattern) => pattern.id === defaultId) : false; - async getDefaultDataView() { - const patterns = await this.getIds(); - let defaultId = await this.config.get('defaultIndex'); - let defined = !!defaultId; - const exists = patterns.includes(defaultId); - - if (defined && !exists) { + if (defaultId && !exists) { await this.config.remove('defaultIndex'); - defaultId = defined = false; + defaultId = undefined; } - if (patterns.length >= 1 && (await this.hasUserDataView().catch(() => true))) { - defaultId = patterns[0]; + if (!defaultId && patterns.length >= 1 && (await this.hasUserDataView().catch(() => true))) { + // try to set first user created data view as default, + // otherwise fallback to any data view + const userDataViews = patterns.filter( + (pattern) => + pattern.title !== FLEET_ASSETS_TO_IGNORE.LOGS_INDEX_PATTERN && + pattern.title !== FLEET_ASSETS_TO_IGNORE.METRICS_INDEX_PATTERN + ); + + defaultId = userDataViews[0]?.id ?? patterns[0].id; await this.config.set('defaultIndex', defaultId); } if (defaultId) { return this.get(defaultId); + } else { + return null; } } } diff --git a/src/plugins/data_views/common/data_views/ensure_default_data_view.ts b/src/plugins/data_views/common/data_views/ensure_default_data_view.ts index 2975ddbd107c44..42e984a3fa88a9 100644 --- a/src/plugins/data_views/common/data_views/ensure_default_data_view.ts +++ b/src/plugins/data_views/common/data_views/ensure_default_data_view.ts @@ -6,7 +6,6 @@ * Side Public License, v 1. */ -import { includes } from 'lodash'; import { DataViewsContract } from './data_views'; import { UiSettingsCommon } from '../types'; @@ -21,26 +20,7 @@ export const createEnsureDefaultDataView = ( * one otherwise. */ return async function ensureDefaultDataView(this: DataViewsContract) { - const patterns = await this.getIds(); - let defaultId = await uiSettings.get('defaultIndex'); - let defined = !!defaultId; - const exists = includes(patterns, defaultId); - - if (defined && !exists) { - await uiSettings.remove('defaultIndex'); - defaultId = defined = false; - } - - if (defined) { - return; - } - - // If there is any user index pattern created, set the first as default - // if there is 0 patterns, then don't even call `hasUserDataView()` - if (patterns.length >= 1 && (await this.hasUserDataView().catch(() => true))) { - defaultId = patterns[0]; - await uiSettings.set('defaultIndex', defaultId); - } else { + if (!(await this.getDefaultDataView())) { return onRedirectNoDefaultView(); } }; From d84a5df7bd3dd981267595984998ad5695803289 Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Wed, 19 Jan 2022 17:08:53 +0100 Subject: [PATCH 050/108] Unskip search api tests (#123145) --- .../api_integration/apis/search/search.ts | 170 ++++++++++++++++-- 1 file changed, 157 insertions(+), 13 deletions(-) diff --git a/x-pack/test/api_integration/apis/search/search.ts b/x-pack/test/api_integration/apis/search/search.ts index d36121a102a283..e4596163048438 100644 --- a/x-pack/test/api_integration/apis/search/search.ts +++ b/x-pack/test/api_integration/apis/search/search.ts @@ -6,17 +6,53 @@ */ import expect from '@kbn/expect'; +import type { Context } from 'mocha'; import { FtrProviderContext } from '../../ftr_provider_context'; import { verifyErrorResponse } from '../../../../../test/api_integration/apis/search/verify_error'; export default function ({ getService }: FtrProviderContext) { const supertest = getService('supertest'); const esArchiver = getService('esArchiver'); + const es = getService('es'); + const log = getService('log'); + const retry = getService('retry'); + + const shardDelayAgg = (delay: string) => ({ + aggs: { + delay: { + shard_delay: { + value: delay, + }, + }, + }, + }); + + async function markRequiresShardDelayAgg(testContext: Context) { + const body = await es.info(); + if (!body.version.number.includes('SNAPSHOT')) { + log.debug('Skipping because this build does not have the required shard_delay agg'); + testContext.skip(); + } + } describe('search', () => { - // https://github.com/elastic/kibana/issues/113082 - describe.skip('post', () => { - it('should return 200 with final response if wait_for_completion_timeout is long enough', async () => { + before(async () => { + // ensure es not empty + await es.index({ + index: 'search-api-test', + id: 'search-api-test-doc', + body: { message: 'test doc' }, + refresh: 'wait_for', + }); + }); + after(async () => { + await es.indices.delete({ + index: 'search-api-test', + }); + }); + + describe('post', () => { + it('should return 200 with final response without search id if wait_for_completion_timeout is long enough', async function () { const resp = await supertest .post(`/internal/search/ese`) .set('kbn-xsrf', 'foo') @@ -27,7 +63,7 @@ export default function ({ getService }: FtrProviderContext) { match_all: {}, }, }, - wait_for_completion_timeout: '1000s', + wait_for_completion_timeout: '10s', }, }) .expect(200); @@ -39,7 +75,9 @@ export default function ({ getService }: FtrProviderContext) { expect(resp.body).to.have.property('rawResponse'); }); - it('should return 200 with partial response if wait_for_completion_timeout is not long enough', async () => { + it('should return 200 with search id and partial response if wait_for_completion_timeout is not long enough', async function () { + await markRequiresShardDelayAgg(this); + const resp = await supertest .post(`/internal/search/ese`) .set('kbn-xsrf', 'foo') @@ -49,6 +87,7 @@ export default function ({ getService }: FtrProviderContext) { query: { match_all: {}, }, + ...shardDelayAgg('3s'), }, wait_for_completion_timeout: '1ms', }, @@ -62,7 +101,9 @@ export default function ({ getService }: FtrProviderContext) { expect(resp.body).to.have.property('rawResponse'); }); - it('should retrieve results with id', async () => { + it('should retrieve results from completed search with search id', async function () { + await markRequiresShardDelayAgg(this); + const resp = await supertest .post(`/internal/search/ese`) .set('kbn-xsrf', 'foo') @@ -72,6 +113,7 @@ export default function ({ getService }: FtrProviderContext) { query: { match_all: {}, }, + ...shardDelayAgg('3s'), }, wait_for_completion_timeout: '1ms', }, @@ -79,8 +121,50 @@ export default function ({ getService }: FtrProviderContext) { .expect(200); const { id } = resp.body; + expect(id).not.to.be(undefined); + expect(resp.body.isPartial).to.be(true); + expect(resp.body.isRunning).to.be(true); + + await new Promise((resolve) => setTimeout(resolve, 3000)); + + await retry.tryForTime(10000, async () => { + const resp2 = await supertest + .post(`/internal/search/ese/${id}`) + .set('kbn-xsrf', 'foo') + .send({}) + .expect(200); + + expect(resp2.body.id).not.to.be(undefined); + expect(resp2.body.isPartial).to.be(false); + expect(resp2.body.isRunning).to.be(false); - await new Promise((resolve) => setTimeout(resolve, 2000)); + return true; + }); + }); + + it('should retrieve results from in-progress search with search id', async function () { + await markRequiresShardDelayAgg(this); + + const resp = await supertest + .post(`/internal/search/ese`) + .set('kbn-xsrf', 'foo') + .send({ + params: { + body: { + query: { + match_all: {}, + }, + ...shardDelayAgg('10s'), + }, + wait_for_completion_timeout: '1ms', + }, + }) + .expect(200); + + const { id } = resp.body; + expect(id).not.to.be(undefined); + expect(resp.body.isPartial).to.be(true); + expect(resp.body.isRunning).to.be(true); const resp2 = await supertest .post(`/internal/search/ese/${id}`) @@ -89,8 +173,8 @@ export default function ({ getService }: FtrProviderContext) { .expect(200); expect(resp2.body.id).not.to.be(undefined); - expect(resp2.body.isPartial).to.be(false); - expect(resp2.body.isRunning).to.be(false); + expect(resp2.body.isPartial).to.be(true); + expect(resp2.body.isRunning).to.be(true); }); it('should fail without kbn-xref header', async () => { @@ -147,7 +231,7 @@ export default function ({ getService }: FtrProviderContext) { verifyErrorResponse(resp.body, 400, 'illegal_argument_exception', true); }); - it('should return 404 if unkown id is provided', async () => { + it('should return 404 if unknown id is provided', async () => { const resp = await supertest .post( `/internal/search/ese/FkxOb21iV1g2VGR1S2QzaWVtRU9fMVEbc3JWeWc1VHlUdDZ6MENxcXlYVG1Fdzo2NDg4` @@ -250,8 +334,7 @@ export default function ({ getService }: FtrProviderContext) { }); }); - // FLAKY: https://github.com/elastic/kibana/issues/119272 - describe.skip('delete', () => { + describe('delete', () => { it('should return 404 when no search id provided', async () => { await supertest.delete(`/internal/search/ese`).set('kbn-xsrf', 'foo').send().expect(404); }); @@ -265,7 +348,47 @@ export default function ({ getService }: FtrProviderContext) { verifyErrorResponse(resp.body, 400, 'illegal_argument_exception', true); }); - it('should delete a search', async () => { + it('should delete an in-progress search', async function () { + await markRequiresShardDelayAgg(this); + + const resp = await supertest + .post(`/internal/search/ese`) + .set('kbn-xsrf', 'foo') + .send({ + params: { + body: { + query: { + match_all: {}, + }, + ...shardDelayAgg('10s'), + }, + wait_for_completion_timeout: '1ms', + }, + }) + .expect(200); + + const { id } = resp.body; + expect(id).not.to.be(undefined); + expect(resp.body.isPartial).to.be(true); + expect(resp.body.isRunning).to.be(true); + + await supertest + .delete(`/internal/search/ese/${id}`) + .set('kbn-xsrf', 'foo') + .send() + .expect(200); + + // try to re-fetch + await supertest + .post(`/internal/search/ese/${id}`) + .set('kbn-xsrf', 'foo') + .send({}) + .expect(404); + }); + + it('should delete a completed search', async function () { + await markRequiresShardDelayAgg(this); + const resp = await supertest .post(`/internal/search/ese`) .set('kbn-xsrf', 'foo') @@ -275,6 +398,7 @@ export default function ({ getService }: FtrProviderContext) { query: { match_all: {}, }, + ...shardDelayAgg('3s'), }, wait_for_completion_timeout: '1ms', }, @@ -282,6 +406,26 @@ export default function ({ getService }: FtrProviderContext) { .expect(200); const { id } = resp.body; + expect(id).not.to.be(undefined); + expect(resp.body.isPartial).to.be(true); + expect(resp.body.isRunning).to.be(true); + + await new Promise((resolve) => setTimeout(resolve, 3000)); + + await retry.tryForTime(10000, async () => { + const resp2 = await supertest + .post(`/internal/search/ese/${id}`) + .set('kbn-xsrf', 'foo') + .send({}) + .expect(200); + + expect(resp2.body.id).not.to.be(undefined); + expect(resp2.body.isPartial).to.be(false); + expect(resp2.body.isRunning).to.be(false); + + return true; + }); + await supertest .delete(`/internal/search/ese/${id}`) .set('kbn-xsrf', 'foo') From d40c0abe5bc1d0a1c3514068603f0f9a0dffc7a7 Mon Sep 17 00:00:00 2001 From: Nicolas Chaulet Date: Wed, 19 Jan 2022 11:10:36 -0500 Subject: [PATCH 051/108] [Fleet] Validate policy id when creating an enrollment token (#123298) --- .../components/new_enrollment_key_modal.tsx | 45 +++++++++++++------ x-pack/plugins/fleet/server/errors/index.ts | 1 + .../routes/enrollment_api_key/handler.ts | 12 ++++- .../apis/enrollment_api_keys/crud.ts | 8 ++-- 4 files changed, 48 insertions(+), 18 deletions(-) diff --git a/x-pack/plugins/fleet/public/components/new_enrollment_key_modal.tsx b/x-pack/plugins/fleet/public/components/new_enrollment_key_modal.tsx index 362c6e6bdb0612..82332784839a9f 100644 --- a/x-pack/plugins/fleet/public/components/new_enrollment_key_modal.tsx +++ b/x-pack/plugins/fleet/public/components/new_enrollment_key_modal.tsx @@ -5,13 +5,23 @@ * 2.0. */ -import React, { useState } from 'react'; +import React, { useState, useMemo } from 'react'; import { i18n } from '@kbn/i18n'; import { EuiConfirmModal, EuiForm, EuiFormRow, EuiFieldText, EuiSelect } from '@elastic/eui'; import type { AgentPolicy, EnrollmentAPIKey } from '../types'; import { useInput, useStartServices, sendCreateEnrollmentAPIKey } from '../hooks'; +function validatePolicyId(value: string) { + if (value === '') { + return [ + i18n.translate('xpack.fleet.newEnrollmentKeyForm.policyIdRequireErrorMessage', { + defaultMessage: 'Policy is required', + }), + ]; + } +} + function useCreateApiKeyForm( policyIdDefaultValue: string | undefined, onSuccess: (key: EnrollmentAPIKey) => void, @@ -19,10 +29,13 @@ function useCreateApiKeyForm( ) { const [isLoading, setIsLoading] = useState(false); const apiKeyNameInput = useInput(''); - const policyIdInput = useInput(policyIdDefaultValue); + const policyIdInput = useInput(policyIdDefaultValue, validatePolicyId); const onSubmit = async (event: React.FormEvent) => { event.preventDefault(); + if (!policyIdInput.validate() || !apiKeyNameInput.validate()) { + return; + } setIsLoading(true); try { const res = await sendCreateEnrollmentAPIKey({ @@ -65,7 +78,11 @@ export const NewEnrollmentTokenModal: React.FunctionComponent = ({ const { notifications } = useStartServices(); const policyIdDefaultValue = agentPolicies.find((agentPolicy) => agentPolicy.is_default)?.id; const form = useCreateApiKeyForm( - policyIdDefaultValue, + policyIdDefaultValue + ? policyIdDefaultValue + : agentPolicies.length > 0 + ? agentPolicies[0].id + : undefined, (key: EnrollmentAPIKey) => { onClose(key); notifications.toasts.addSuccess( @@ -81,6 +98,15 @@ export const NewEnrollmentTokenModal: React.FunctionComponent = ({ } ); + const selectPolicyOptions = useMemo(() => { + return agentPolicies + .filter((agentPolicy) => !agentPolicy.is_managed) + .map((agentPolicy) => ({ + value: agentPolicy.id, + text: agentPolicy.name, + })); + }, [agentPolicies]); + const body = (
@@ -106,18 +132,9 @@ export const NewEnrollmentTokenModal: React.FunctionComponent = ({ label={i18n.translate('xpack.fleet.newEnrollmentKey.policyLabel', { defaultMessage: 'Policy', })} + {...form.policyIdInput.formRowProps} > - !agentPolicy.is_managed) - .map((agentPolicy) => ({ - value: agentPolicy.id, - text: agentPolicy.name, - }))} - /> +
diff --git a/x-pack/plugins/fleet/server/errors/index.ts b/x-pack/plugins/fleet/server/errors/index.ts index c72d476e4c466c..380862d36fe016 100644 --- a/x-pack/plugins/fleet/server/errors/index.ts +++ b/x-pack/plugins/fleet/server/errors/index.ts @@ -32,6 +32,7 @@ export class PackageNotFoundError extends IngestManagerError {} export class PackageKeyInvalidError extends IngestManagerError {} export class PackageOutdatedError extends IngestManagerError {} export class AgentPolicyError extends IngestManagerError {} +export class AgentPolicyNotFoundError extends IngestManagerError {} export class AgentNotFoundError extends IngestManagerError {} export class AgentPolicyNameExistsError extends AgentPolicyError {} export class PackageUnsupportedMediaTypeError extends IngestManagerError {} diff --git a/x-pack/plugins/fleet/server/routes/enrollment_api_key/handler.ts b/x-pack/plugins/fleet/server/routes/enrollment_api_key/handler.ts index 7fef583af50cd0..862da50abf71b9 100644 --- a/x-pack/plugins/fleet/server/routes/enrollment_api_key/handler.ts +++ b/x-pack/plugins/fleet/server/routes/enrollment_api_key/handler.ts @@ -21,7 +21,8 @@ import type { PostEnrollmentAPIKeyResponse, } from '../../../common'; import * as APIKeyService from '../../services/api_keys'; -import { defaultIngestErrorHandler } from '../../errors'; +import { agentPolicyService } from '../../services/agent_policy'; +import { defaultIngestErrorHandler, AgentPolicyNotFoundError } from '../../errors'; export const getEnrollmentApiKeysHandler: RequestHandler< undefined, @@ -57,6 +58,15 @@ export const postEnrollmentApiKeyHandler: RequestHandler< const soClient = context.core.savedObjects.client; const esClient = context.core.elasticsearch.client.asInternalUser; try { + // validate policy id + await agentPolicyService.get(soClient, request.body.policy_id).catch((err) => { + if (soClient.errors.isNotFoundError(err)) { + throw new AgentPolicyNotFoundError(`Agent policy "${request.body.policy_id}" not found`); + } + + throw err; + }); + const apiKey = await APIKeyService.generateEnrollmentAPIKey(soClient, esClient, { name: request.body.name, expiration: request.body.expiration, diff --git a/x-pack/test/fleet_api_integration/apis/enrollment_api_keys/crud.ts b/x-pack/test/fleet_api_integration/apis/enrollment_api_keys/crud.ts index 1c584315a1871a..a628add1de8388 100644 --- a/x-pack/test/fleet_api_integration/apis/enrollment_api_keys/crud.ts +++ b/x-pack/test/fleet_api_integration/apis/enrollment_api_keys/crud.ts @@ -92,14 +92,16 @@ export default function (providerContext: FtrProviderContext) { .expect(400); }); - it('should return a 400 if the fleet admin user is modifed outside of Fleet', async () => { - await supertest + it('should return a 400 if the policy_id is not a valid policy', async () => { + const { body: apiResponse } = await supertest .post(`/api/fleet/enrollment_api_keys`) .set('kbn-xsrf', 'xxx') .send({ - raoul: 'raoul', + policy_id: 'idonotexists', }) .expect(400); + + expect(apiResponse.message).to.be('Agent policy "idonotexists" not found'); }); it('should allow to create an enrollment api key with only an agent policy', async () => { From d2a8bb90bec3ac23b3cab027d3f2fdfe9df6fa3e Mon Sep 17 00:00:00 2001 From: Frank Hassanabad Date: Wed, 19 Jan 2022 10:39:47 -0700 Subject: [PATCH 052/108] [Security Solution] Adds telemetry for legacy notifications and regular notifications at a finer grained level (#123332) ## Summary Related and previous PR: https://github.com/elastic/kibana/pull/122472 This removes the above structure from the PR above and instead opts to use a more finer grained level of telemetry. The new structure adds to each rule these four counters to the telemetry: * legacy_notifications_enabled - The number of legacy notifications on rules that are enabled/active * legacy_notifications_disabled - The number of legacy notifications on rules that are disabled/in-active * notifications_enabled - The number of notifications on rules that are enabled/active * notifications_disabled - The number of notifications on rules that are disabled/in-active For pre-built rules you have these booleans: * has_legacy_notification - True if the pre-built rule has a legacy notification attached, otherwise false. * has_notification - True if the pre-built rule has a notification attached, otherwise false. Note, both those booleans are `false` if the pre-built rule has no notifications attached and both can never be `true` together. These will show up within each rule type like for example on a query rule it will look like: ```json "detection_rule_usage": { "query": { "enabled": 2, "disabled": 1, "cases": 0, "legacy_notifications_enabled": 1, <-- New "legacy_notifications_disabled": 0, <-- New "notifications_enabled": 1, <-- New "notifications_disabled": 1 <-- New } ``` Within the counts/total sections it will show up on both the `elastic` rules and the `custom` rules like so: ```json "elastic_total": { "enabled": 0, "disabled": 0, "alerts": 0, "cases": 0, "legacy_notifications_enabled": 0, <-- New "legacy_notifications_disabled": 0, <-- New "notifications_enabled": 0, <-- New "notifications_disabled": 0 <-- New }, "custom_total": { "enabled": 2, "disabled": 1, "alerts": 7218, "cases": 0, "legacy_notifications_enabled": 1, <-- New "legacy_notifications_disabled": 0, <-- New "notifications_enabled": 1, <-- New "notifications_disabled": 1 <-- New } ``` For pre-built it will be: ```json "detection_rule_detail": [ { "rule_name": "Potential Evasion via Filter Manager", "rule_id": "06dceabf-adca-48af-ac79-ffdf4c3b1e9a", "rule_type": "eql", "rule_version": 8, "enabled": false, "elastic_rule": true, "created_on": "2022-01-19T01:29:25.540Z", "updated_on": "2022-01-19T01:29:25.540Z", "alert_count_daily": 0, "cases_count_total": 0, "has_legacy_notification": false, <-- New "has_notification": false <-- New }, ``` Screen shot of it if you go to "Advanced settings -> cluster data": Screen Shot 2022-01-18 at 6 27 14 PM Screen Shot 2022-01-18 at 6 30 33 PM Follow the manual test instructions on https://github.com/elastic/kibana/pull/122472 for how to test this. The same manual testing applies here for seeing how these work out. You should be able to see a higher granularity with these stats. ### Checklist - [ ] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios --- .../legacy_notifications/one_action.json | 2 +- .../server/usage/collector.ts | 130 +- .../detections/detection_rule_helpers.test.ts | 216 ++- .../detections/detection_rule_helpers.ts | 171 ++- .../usage/detections/detections.test.ts | 39 +- .../server/usage/detections/types.ts | 18 +- .../schema/xpack_plugins.json | 184 ++- .../tests/telemetry/README.md | 6 +- .../tests/telemetry/detection_rules.ts | 1233 +++++++++++++++-- .../tests/telemetry/index.ts | 1 - .../tests/telemetry/legacy_notifications.ts | 75 - 11 files changed, 1838 insertions(+), 237 deletions(-) delete mode 100644 x-pack/test/detection_engine_api_integration/security_and_spaces/tests/telemetry/legacy_notifications.ts diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/legacy_notifications/one_action.json b/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/legacy_notifications/one_action.json index bf980e370e3a38..cf03a90dfe72b7 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/legacy_notifications/one_action.json +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/legacy_notifications/one_action.json @@ -3,7 +3,7 @@ "interval": "1m", "actions": [ { - "id": "1fa31c30-3046-11ec-8971-1f3f7bae65af", + "id": "0cae9900-6e54-11ec-a124-bfe603780ab8", "group": "default", "params": { "message": "Hourly\nRule {{context.rule.name}} generated {{state.signals_count}} alerts" diff --git a/x-pack/plugins/security_solution/server/usage/collector.ts b/x-pack/plugins/security_solution/server/usage/collector.ts index d091c2a6e5e8eb..4530dac725c7b1 100644 --- a/x-pack/plugins/security_solution/server/usage/collector.ts +++ b/x-pack/plugins/security_solution/server/usage/collector.ts @@ -10,6 +10,8 @@ import { CollectorFetchContext } from '../../../../../src/plugins/usage_collecti import { CollectorDependencies } from './types'; import { fetchDetectionsMetrics } from './detections'; import { SAVED_OBJECT_TYPES } from '../../../cases/common/constants'; +// eslint-disable-next-line no-restricted-imports +import { legacyRuleActionsSavedObjectType } from '../lib/detection_engine/rule_actions/legacy_saved_object_mappings'; export type RegisterCollector = (deps: CollectorDependencies) => void; export interface UsageData { @@ -19,7 +21,11 @@ export interface UsageData { export async function getInternalSavedObjectsClient(core: CoreSetup) { return core.getStartServices().then(async ([coreStart]) => { // note: we include the "cases" and "alert" hidden types here otherwise we would not be able to query them. If at some point cases and alert is not considered a hidden type this can be removed - return coreStart.savedObjects.createInternalRepository(['alert', ...SAVED_OBJECT_TYPES]); + return coreStart.savedObjects.createInternalRepository([ + 'alert', + legacyRuleActionsSavedObjectType, + ...SAVED_OBJECT_TYPES, + ]); }); } @@ -51,6 +57,22 @@ export const registerCollector: RegisterCollector = ({ type: 'long', _meta: { description: 'Number of cases attached to query detection rule alerts' }, }, + legacy_notifications_enabled: { + type: 'long', + _meta: { description: 'Number of legacy notifications enabled' }, + }, + legacy_notifications_disabled: { + type: 'long', + _meta: { description: 'Number of legacy notifications disabled' }, + }, + notifications_enabled: { + type: 'long', + _meta: { description: 'Number of notifications enabled' }, + }, + notifications_disabled: { + type: 'long', + _meta: { description: 'Number of notifications enabled' }, + }, }, threshold: { enabled: { @@ -71,6 +93,22 @@ export const registerCollector: RegisterCollector = ({ description: 'Number of cases attached to threshold detection rule alerts', }, }, + legacy_notifications_enabled: { + type: 'long', + _meta: { description: 'Number of legacy notifications enabled' }, + }, + legacy_notifications_disabled: { + type: 'long', + _meta: { description: 'Number of legacy notifications disabled' }, + }, + notifications_enabled: { + type: 'long', + _meta: { description: 'Number of notifications enabled' }, + }, + notifications_disabled: { + type: 'long', + _meta: { description: 'Number of notifications enabled' }, + }, }, eql: { enabled: { type: 'long', _meta: { description: 'Number of eql rules enabled' } }, @@ -83,6 +121,22 @@ export const registerCollector: RegisterCollector = ({ type: 'long', _meta: { description: 'Number of cases attached to eql detection rule alerts' }, }, + legacy_notifications_enabled: { + type: 'long', + _meta: { description: 'Number of legacy notifications enabled' }, + }, + legacy_notifications_disabled: { + type: 'long', + _meta: { description: 'Number of legacy notifications disabled' }, + }, + notifications_enabled: { + type: 'long', + _meta: { description: 'Number of notifications enabled' }, + }, + notifications_disabled: { + type: 'long', + _meta: { description: 'Number of notifications enabled' }, + }, }, machine_learning: { enabled: { @@ -103,6 +157,22 @@ export const registerCollector: RegisterCollector = ({ description: 'Number of cases attached to machine_learning detection rule alerts', }, }, + legacy_notifications_enabled: { + type: 'long', + _meta: { description: 'Number of legacy notifications enabled' }, + }, + legacy_notifications_disabled: { + type: 'long', + _meta: { description: 'Number of legacy notifications disabled' }, + }, + notifications_enabled: { + type: 'long', + _meta: { description: 'Number of notifications enabled' }, + }, + notifications_disabled: { + type: 'long', + _meta: { description: 'Number of notifications enabled' }, + }, }, threat_match: { enabled: { @@ -123,11 +193,21 @@ export const registerCollector: RegisterCollector = ({ description: 'Number of cases attached to threat_match detection rule alerts', }, }, - }, - legacy_notifications: { - total: { + legacy_notifications_enabled: { + type: 'long', + _meta: { description: 'Number of legacy notifications enabled' }, + }, + legacy_notifications_disabled: { + type: 'long', + _meta: { description: 'Number of legacy notifications disabled' }, + }, + notifications_enabled: { type: 'long', - _meta: { description: 'Number of legacy notifications still in use' }, + _meta: { description: 'Number of notifications enabled' }, + }, + notifications_disabled: { + type: 'long', + _meta: { description: 'Number of notifications enabled' }, }, }, elastic_total: { @@ -144,6 +224,22 @@ export const registerCollector: RegisterCollector = ({ type: 'long', _meta: { description: 'Number of cases attached to elastic detection rule alerts' }, }, + legacy_notifications_enabled: { + type: 'long', + _meta: { description: 'Number of legacy notifications enabled' }, + }, + legacy_notifications_disabled: { + type: 'long', + _meta: { description: 'Number of legacy notifications disabled' }, + }, + notifications_enabled: { + type: 'long', + _meta: { description: 'Number of notifications enabled' }, + }, + notifications_disabled: { + type: 'long', + _meta: { description: 'Number of notifications enabled' }, + }, }, custom_total: { enabled: { type: 'long', _meta: { description: 'Number of custom rules enabled' } }, @@ -156,6 +252,22 @@ export const registerCollector: RegisterCollector = ({ type: 'long', _meta: { description: 'Number of cases attached to custom detection rule alerts' }, }, + legacy_notifications_enabled: { + type: 'long', + _meta: { description: 'Number of legacy notifications enabled' }, + }, + legacy_notifications_disabled: { + type: 'long', + _meta: { description: 'Number of legacy notifications disabled' }, + }, + notifications_enabled: { + type: 'long', + _meta: { description: 'Number of notifications enabled' }, + }, + notifications_disabled: { + type: 'long', + _meta: { description: 'Number of notifications enabled' }, + }, }, }, detection_rule_detail: { @@ -198,6 +310,14 @@ export const registerCollector: RegisterCollector = ({ type: 'long', _meta: { description: 'The number of total cases generated by a rule' }, }, + has_legacy_notification: { + type: 'boolean', + _meta: { description: 'True if this rule has a legacy notification' }, + }, + has_notification: { + type: 'boolean', + _meta: { description: 'True if this rule has a notification' }, + }, }, }, }, diff --git a/x-pack/plugins/security_solution/server/usage/detections/detection_rule_helpers.test.ts b/x-pack/plugins/security_solution/server/usage/detections/detection_rule_helpers.test.ts index 3c35296bafb46c..c19e7b18f9e72c 100644 --- a/x-pack/plugins/security_solution/server/usage/detections/detection_rule_helpers.test.ts +++ b/x-pack/plugins/security_solution/server/usage/detections/detection_rule_helpers.test.ts @@ -8,13 +8,25 @@ import { initialDetectionRulesUsage, updateDetectionRuleUsage } from './detection_rule_helpers'; import { DetectionRuleMetric, DetectionRulesTypeUsage } from './types'; -const createStubRule = ( - ruleType: string, - enabled: boolean, - elasticRule: boolean, - alertCount: number, - caseCount: number -): DetectionRuleMetric => ({ +interface StubRuleOptions { + ruleType: string; + enabled: boolean; + elasticRule: boolean; + alertCount: number; + caseCount: number; + hasLegacyNotification: boolean; + hasNotification: boolean; +} + +const createStubRule = ({ + ruleType, + enabled, + elasticRule, + alertCount, + caseCount, + hasLegacyNotification, + hasNotification, +}: StubRuleOptions): DetectionRuleMetric => ({ rule_name: 'rule-name', rule_id: 'id-123', rule_type: ruleType, @@ -25,12 +37,22 @@ const createStubRule = ( updated_on: '2022-01-06T20:02:45.306Z', alert_count_daily: alertCount, cases_count_total: caseCount, + has_legacy_notification: hasLegacyNotification, + has_notification: hasNotification, }); describe('Detections Usage and Metrics', () => { describe('Update metrics with rule information', () => { it('Should update elastic and eql rule metric total', async () => { - const stubRule = createStubRule('eql', true, true, 1, 1); + const stubRule = createStubRule({ + ruleType: 'eql', + enabled: true, + elasticRule: true, + alertCount: 1, + caseCount: 1, + hasLegacyNotification: false, + hasNotification: false, + }); const usage = updateDetectionRuleUsage(stubRule, initialDetectionRulesUsage); expect(usage).toEqual({ @@ -40,22 +62,70 @@ describe('Detections Usage and Metrics', () => { cases: 1, disabled: 0, enabled: 1, + legacy_notifications_enabled: 0, + legacy_notifications_disabled: 0, + notifications_enabled: 0, + notifications_disabled: 0, }, eql: { alerts: 1, cases: 1, disabled: 0, enabled: 1, + legacy_notifications_enabled: 0, + legacy_notifications_disabled: 0, + notifications_enabled: 0, + notifications_disabled: 0, }, }); }); it('Should update based on multiple metrics', async () => { - const stubEqlRule = createStubRule('eql', true, true, 1, 1); - const stubQueryRuleOne = createStubRule('query', true, true, 5, 2); - const stubQueryRuleTwo = createStubRule('query', true, false, 5, 2); - const stubMachineLearningOne = createStubRule('machine_learning', false, false, 0, 10); - const stubMachineLearningTwo = createStubRule('machine_learning', true, true, 22, 44); + const stubEqlRule = createStubRule({ + ruleType: 'eql', + enabled: true, + elasticRule: true, + alertCount: 1, + caseCount: 1, + hasLegacyNotification: false, + hasNotification: false, + }); + const stubQueryRuleOne = createStubRule({ + ruleType: 'query', + enabled: true, + elasticRule: true, + alertCount: 5, + caseCount: 2, + hasLegacyNotification: false, + hasNotification: false, + }); + const stubQueryRuleTwo = createStubRule({ + ruleType: 'query', + enabled: true, + elasticRule: false, + alertCount: 5, + caseCount: 2, + hasLegacyNotification: false, + hasNotification: false, + }); + const stubMachineLearningOne = createStubRule({ + ruleType: 'machine_learning', + enabled: false, + elasticRule: false, + alertCount: 0, + caseCount: 10, + hasLegacyNotification: false, + hasNotification: false, + }); + const stubMachineLearningTwo = createStubRule({ + ruleType: 'machine_learning', + enabled: true, + elasticRule: true, + alertCount: 22, + caseCount: 44, + hasLegacyNotification: false, + hasNotification: false, + }); let usage = updateDetectionRuleUsage(stubEqlRule, initialDetectionRulesUsage); usage = updateDetectionRuleUsage(stubQueryRuleOne, usage); @@ -70,32 +140,152 @@ describe('Detections Usage and Metrics', () => { cases: 12, disabled: 1, enabled: 1, + legacy_notifications_enabled: 0, + legacy_notifications_disabled: 0, + notifications_enabled: 0, + notifications_disabled: 0, }, elastic_total: { alerts: 28, cases: 47, disabled: 0, enabled: 3, + legacy_notifications_enabled: 0, + legacy_notifications_disabled: 0, + notifications_enabled: 0, + notifications_disabled: 0, }, eql: { alerts: 1, cases: 1, disabled: 0, enabled: 1, + legacy_notifications_enabled: 0, + legacy_notifications_disabled: 0, + notifications_enabled: 0, + notifications_disabled: 0, }, machine_learning: { alerts: 22, cases: 54, disabled: 1, enabled: 1, + legacy_notifications_enabled: 0, + legacy_notifications_disabled: 0, + notifications_enabled: 0, + notifications_disabled: 0, }, query: { alerts: 10, cases: 4, disabled: 0, enabled: 2, + legacy_notifications_enabled: 0, + legacy_notifications_disabled: 0, + notifications_enabled: 0, + notifications_disabled: 0, }, }); }); + + describe('table tests of "ruleType", "enabled", "elasticRule", and "legacyNotification"', () => { + test.each` + ruleType | enabled | hasLegacyNotification | hasNotification | expectedLegacyNotificationsEnabled | expectedLegacyNotificationsDisabled | expectedNotificationsEnabled | expectedNotificationsDisabled + ${'eql'} | ${true} | ${true} | ${false} | ${1} | ${0} | ${0} | ${0} + ${'eql'} | ${true} | ${false} | ${true} | ${0} | ${0} | ${1} | ${0} + ${'eql'} | ${false} | ${false} | ${true} | ${0} | ${0} | ${0} | ${1} + ${'eql'} | ${true} | ${false} | ${true} | ${0} | ${0} | ${1} | ${0} + ${'eql'} | ${false} | ${true} | ${false} | ${0} | ${1} | ${0} | ${0} + ${'eql'} | ${false} | ${false} | ${false} | ${0} | ${0} | ${0} | ${0} + ${'query'} | ${true} | ${true} | ${false} | ${1} | ${0} | ${0} | ${0} + ${'query'} | ${true} | ${false} | ${true} | ${0} | ${0} | ${1} | ${0} + ${'query'} | ${false} | ${false} | ${true} | ${0} | ${0} | ${0} | ${1} + ${'query'} | ${true} | ${false} | ${true} | ${0} | ${0} | ${1} | ${0} + ${'query'} | ${false} | ${true} | ${false} | ${0} | ${1} | ${0} | ${0} + ${'query'} | ${false} | ${false} | ${false} | ${0} | ${0} | ${0} | ${0} + ${'threshold'} | ${true} | ${true} | ${false} | ${1} | ${0} | ${0} | ${0} + ${'threshold'} | ${true} | ${false} | ${true} | ${0} | ${0} | ${1} | ${0} + ${'threshold'} | ${false} | ${false} | ${true} | ${0} | ${0} | ${0} | ${1} + ${'threshold'} | ${true} | ${false} | ${true} | ${0} | ${0} | ${1} | ${0} + ${'threshold'} | ${false} | ${true} | ${false} | ${0} | ${1} | ${0} | ${0} + ${'threshold'} | ${false} | ${false} | ${false} | ${0} | ${0} | ${0} | ${0} + ${'machine_learning'} | ${true} | ${true} | ${false} | ${1} | ${0} | ${0} | ${0} + ${'machine_learning'} | ${true} | ${false} | ${true} | ${0} | ${0} | ${1} | ${0} + ${'machine_learning'} | ${false} | ${false} | ${true} | ${0} | ${0} | ${0} | ${1} + ${'machine_learning'} | ${true} | ${false} | ${true} | ${0} | ${0} | ${1} | ${0} + ${'machine_learning'} | ${false} | ${true} | ${false} | ${0} | ${1} | ${0} | ${0} + ${'machine_learning'} | ${false} | ${false} | ${false} | ${0} | ${0} | ${0} | ${0} + ${'threat_match'} | ${true} | ${true} | ${false} | ${1} | ${0} | ${0} | ${0} + ${'threat_match'} | ${true} | ${false} | ${true} | ${0} | ${0} | ${1} | ${0} + ${'threat_match'} | ${false} | ${false} | ${true} | ${0} | ${0} | ${0} | ${1} + ${'threat_match'} | ${true} | ${false} | ${true} | ${0} | ${0} | ${1} | ${0} + ${'threat_match'} | ${false} | ${true} | ${false} | ${0} | ${1} | ${0} | ${0} + ${'threat_match'} | ${false} | ${false} | ${false} | ${0} | ${0} | ${0} | ${0} + `( + 'expect { "ruleType": $ruleType, "enabled": $enabled, "hasLegacyNotification": $hasLegacyNotification, "hasNotification": $hasNotification } to equal { legacy_notifications_enabled: $expectedLegacyNotificationsEnabled, legacy_notifications_disabled: $expectedLegacyNotificationsDisabled, notifications_enabled: $expectedNotificationsEnabled, notifications_disabled, $expectedNotificationsDisabled }', + ({ + ruleType, + enabled, + hasLegacyNotification, + hasNotification, + expectedLegacyNotificationsEnabled, + expectedLegacyNotificationsDisabled, + expectedNotificationsEnabled, + expectedNotificationsDisabled, + }) => { + const rule1 = createStubRule({ + ruleType, + enabled, + elasticRule: false, + hasLegacyNotification, + hasNotification, + alertCount: 0, + caseCount: 0, + }); + const usage = updateDetectionRuleUsage(rule1, initialDetectionRulesUsage) as ReturnType< + typeof updateDetectionRuleUsage + > & { [key: string]: unknown }; + expect(usage[ruleType]).toEqual( + expect.objectContaining({ + legacy_notifications_enabled: expectedLegacyNotificationsEnabled, + legacy_notifications_disabled: expectedLegacyNotificationsDisabled, + notifications_enabled: expectedNotificationsEnabled, + notifications_disabled: expectedNotificationsDisabled, + }) + ); + + // extra test where we add everything by 1 to ensure that the addition happens with the correct rule type + const rule2 = createStubRule({ + ruleType, + enabled, + elasticRule: false, + hasLegacyNotification, + hasNotification, + alertCount: 0, + caseCount: 0, + }); + const usageAddedByOne = updateDetectionRuleUsage(rule2, usage) as ReturnType< + typeof updateDetectionRuleUsage + > & { [key: string]: unknown }; + + expect(usageAddedByOne[ruleType]).toEqual( + expect.objectContaining({ + legacy_notifications_enabled: + expectedLegacyNotificationsEnabled !== 0 + ? expectedLegacyNotificationsEnabled + 1 + : 0, + legacy_notifications_disabled: + expectedLegacyNotificationsDisabled !== 0 + ? expectedLegacyNotificationsDisabled + 1 + : 0, + notifications_enabled: + expectedNotificationsEnabled !== 0 ? expectedNotificationsEnabled + 1 : 0, + notifications_disabled: + expectedNotificationsDisabled !== 0 ? expectedNotificationsDisabled + 1 : 0, + }) + ); + } + ); + }); }); }); diff --git a/x-pack/plugins/security_solution/server/usage/detections/detection_rule_helpers.ts b/x-pack/plugins/security_solution/server/usage/detections/detection_rule_helpers.ts index 87e484ae2b3d40..8163a736696745 100644 --- a/x-pack/plugins/security_solution/server/usage/detections/detection_rule_helpers.ts +++ b/x-pack/plugins/security_solution/server/usage/detections/detection_rule_helpers.ts @@ -15,7 +15,6 @@ import { SAVED_QUERY_RULE_TYPE_ID, } from '@kbn/securitysolution-rules'; import { ALERT_RULE_UUID } from '@kbn/rule-data-utils'; -import { LEGACY_NOTIFICATIONS_ID } from '../../../common/constants'; import { CASE_COMMENT_SAVED_OBJECT } from '../../../../cases/common/constants'; import { ElasticsearchClient, SavedObjectsClientContract } from '../../../../../../src/core/server'; @@ -30,6 +29,10 @@ import type { RuleSearchResult, DetectionMetrics, } from './types'; +// eslint-disable-next-line no-restricted-imports +import { legacyRuleActionsSavedObjectType } from '../../lib/detection_engine/rule_actions/legacy_saved_object_mappings'; +// eslint-disable-next-line no-restricted-imports +import { LegacyIRuleActionsAttributesSavedObjectAttributes } from '../../lib/detection_engine/rule_actions/legacy_types'; /** * Initial detection metrics initialized. @@ -63,45 +66,70 @@ export const initialDetectionRulesUsage: DetectionRulesTypeUsage = { disabled: 0, alerts: 0, cases: 0, + legacy_notifications_enabled: 0, + legacy_notifications_disabled: 0, + notifications_enabled: 0, + notifications_disabled: 0, }, threshold: { enabled: 0, disabled: 0, alerts: 0, cases: 0, + legacy_notifications_enabled: 0, + legacy_notifications_disabled: 0, + notifications_enabled: 0, + notifications_disabled: 0, }, eql: { enabled: 0, disabled: 0, alerts: 0, cases: 0, + legacy_notifications_enabled: 0, + legacy_notifications_disabled: 0, + notifications_enabled: 0, + notifications_disabled: 0, }, machine_learning: { enabled: 0, disabled: 0, alerts: 0, cases: 0, + legacy_notifications_enabled: 0, + legacy_notifications_disabled: 0, + notifications_enabled: 0, + notifications_disabled: 0, }, threat_match: { enabled: 0, disabled: 0, alerts: 0, cases: 0, + legacy_notifications_enabled: 0, + legacy_notifications_disabled: 0, + notifications_enabled: 0, + notifications_disabled: 0, }, elastic_total: { enabled: 0, disabled: 0, alerts: 0, cases: 0, - }, - legacy_notifications: { - total: 0, + legacy_notifications_enabled: 0, + legacy_notifications_disabled: 0, + notifications_enabled: 0, + notifications_disabled: 0, }, custom_total: { enabled: 0, disabled: 0, alerts: 0, cases: 0, + legacy_notifications_enabled: 0, + legacy_notifications_disabled: 0, + notifications_enabled: 0, + notifications_disabled: 0, }, }; @@ -112,6 +140,16 @@ export const updateDetectionRuleUsage = ( ): DetectionRulesTypeUsage => { let updatedUsage = usage; + const legacyNotificationEnabled = + detectionRuleMetric.has_legacy_notification && detectionRuleMetric.enabled; + + const legacyNotificationDisabled = + detectionRuleMetric.has_legacy_notification && !detectionRuleMetric.enabled; + + const notificationEnabled = detectionRuleMetric.has_notification && detectionRuleMetric.enabled; + + const notificationDisabled = detectionRuleMetric.has_notification && !detectionRuleMetric.enabled; + if (detectionRuleMetric.rule_type === 'query') { updatedUsage = { ...usage, @@ -121,6 +159,18 @@ export const updateDetectionRuleUsage = ( disabled: !detectionRuleMetric.enabled ? usage.query.disabled + 1 : usage.query.disabled, alerts: usage.query.alerts + detectionRuleMetric.alert_count_daily, cases: usage.query.cases + detectionRuleMetric.cases_count_total, + legacy_notifications_enabled: legacyNotificationEnabled + ? usage.query.legacy_notifications_enabled + 1 + : usage.query.legacy_notifications_enabled, + legacy_notifications_disabled: legacyNotificationDisabled + ? usage.query.legacy_notifications_disabled + 1 + : usage.query.legacy_notifications_disabled, + notifications_enabled: notificationEnabled + ? usage.query.notifications_enabled + 1 + : usage.query.notifications_enabled, + notifications_disabled: notificationDisabled + ? usage.query.notifications_disabled + 1 + : usage.query.notifications_disabled, }, }; } else if (detectionRuleMetric.rule_type === 'threshold') { @@ -136,6 +186,18 @@ export const updateDetectionRuleUsage = ( : usage.threshold.disabled, alerts: usage.threshold.alerts + detectionRuleMetric.alert_count_daily, cases: usage.threshold.cases + detectionRuleMetric.cases_count_total, + legacy_notifications_enabled: legacyNotificationEnabled + ? usage.threshold.legacy_notifications_enabled + 1 + : usage.threshold.legacy_notifications_enabled, + legacy_notifications_disabled: legacyNotificationDisabled + ? usage.threshold.legacy_notifications_disabled + 1 + : usage.threshold.legacy_notifications_disabled, + notifications_enabled: notificationEnabled + ? usage.threshold.notifications_enabled + 1 + : usage.threshold.notifications_enabled, + notifications_disabled: notificationDisabled + ? usage.threshold.notifications_disabled + 1 + : usage.threshold.notifications_disabled, }, }; } else if (detectionRuleMetric.rule_type === 'eql') { @@ -147,6 +209,18 @@ export const updateDetectionRuleUsage = ( disabled: !detectionRuleMetric.enabled ? usage.eql.disabled + 1 : usage.eql.disabled, alerts: usage.eql.alerts + detectionRuleMetric.alert_count_daily, cases: usage.eql.cases + detectionRuleMetric.cases_count_total, + legacy_notifications_enabled: legacyNotificationEnabled + ? usage.eql.legacy_notifications_enabled + 1 + : usage.eql.legacy_notifications_enabled, + legacy_notifications_disabled: legacyNotificationDisabled + ? usage.eql.legacy_notifications_disabled + 1 + : usage.eql.legacy_notifications_disabled, + notifications_enabled: notificationEnabled + ? usage.eql.notifications_enabled + 1 + : usage.eql.notifications_enabled, + notifications_disabled: notificationDisabled + ? usage.eql.notifications_disabled + 1 + : usage.eql.notifications_disabled, }, }; } else if (detectionRuleMetric.rule_type === 'machine_learning') { @@ -162,6 +236,18 @@ export const updateDetectionRuleUsage = ( : usage.machine_learning.disabled, alerts: usage.machine_learning.alerts + detectionRuleMetric.alert_count_daily, cases: usage.machine_learning.cases + detectionRuleMetric.cases_count_total, + legacy_notifications_enabled: legacyNotificationEnabled + ? usage.machine_learning.legacy_notifications_enabled + 1 + : usage.machine_learning.legacy_notifications_enabled, + legacy_notifications_disabled: legacyNotificationDisabled + ? usage.machine_learning.legacy_notifications_disabled + 1 + : usage.machine_learning.legacy_notifications_disabled, + notifications_enabled: notificationEnabled + ? usage.machine_learning.notifications_enabled + 1 + : usage.machine_learning.notifications_enabled, + notifications_disabled: notificationDisabled + ? usage.machine_learning.notifications_disabled + 1 + : usage.machine_learning.notifications_disabled, }, }; } else if (detectionRuleMetric.rule_type === 'threat_match') { @@ -177,6 +263,18 @@ export const updateDetectionRuleUsage = ( : usage.threat_match.disabled, alerts: usage.threat_match.alerts + detectionRuleMetric.alert_count_daily, cases: usage.threat_match.cases + detectionRuleMetric.cases_count_total, + legacy_notifications_enabled: legacyNotificationEnabled + ? usage.threat_match.legacy_notifications_enabled + 1 + : usage.threat_match.legacy_notifications_enabled, + legacy_notifications_disabled: legacyNotificationDisabled + ? usage.threat_match.legacy_notifications_disabled + 1 + : usage.threat_match.legacy_notifications_disabled, + notifications_enabled: notificationEnabled + ? usage.threat_match.notifications_enabled + 1 + : usage.threat_match.notifications_enabled, + notifications_disabled: notificationDisabled + ? usage.threat_match.notifications_disabled + 1 + : usage.threat_match.notifications_disabled, }, }; } @@ -194,6 +292,18 @@ export const updateDetectionRuleUsage = ( : updatedUsage.elastic_total.disabled, alerts: updatedUsage.elastic_total.alerts + detectionRuleMetric.alert_count_daily, cases: updatedUsage.elastic_total.cases + detectionRuleMetric.cases_count_total, + legacy_notifications_enabled: legacyNotificationEnabled + ? updatedUsage.elastic_total.legacy_notifications_enabled + 1 + : updatedUsage.elastic_total.legacy_notifications_enabled, + legacy_notifications_disabled: legacyNotificationDisabled + ? updatedUsage.elastic_total.legacy_notifications_disabled + 1 + : updatedUsage.elastic_total.legacy_notifications_disabled, + notifications_enabled: notificationEnabled + ? updatedUsage.elastic_total.notifications_enabled + 1 + : updatedUsage.elastic_total.notifications_enabled, + notifications_disabled: notificationDisabled + ? updatedUsage.elastic_total.notifications_disabled + 1 + : updatedUsage.elastic_total.notifications_disabled, }, }; } else { @@ -209,6 +319,18 @@ export const updateDetectionRuleUsage = ( : updatedUsage.custom_total.disabled, alerts: updatedUsage.custom_total.alerts + detectionRuleMetric.alert_count_daily, cases: updatedUsage.custom_total.cases + detectionRuleMetric.cases_count_total, + legacy_notifications_enabled: legacyNotificationEnabled + ? updatedUsage.custom_total.legacy_notifications_enabled + 1 + : updatedUsage.custom_total.legacy_notifications_enabled, + legacy_notifications_disabled: legacyNotificationDisabled + ? updatedUsage.custom_total.legacy_notifications_disabled + 1 + : updatedUsage.custom_total.legacy_notifications_disabled, + notifications_enabled: notificationEnabled + ? updatedUsage.custom_total.notifications_enabled + 1 + : updatedUsage.custom_total.notifications_enabled, + notifications_disabled: notificationDisabled + ? updatedUsage.custom_total.notifications_disabled + 1 + : updatedUsage.custom_total.notifications_disabled, }, }; } @@ -287,18 +409,28 @@ export const getDetectionRuleMetrics = async ( filter: `${CASE_COMMENT_SAVED_OBJECT}.attributes.type: alert`, }); - // We get just 1 per a single page so we can get the total count to add to the rulesUsage. // Once we are confident all rules relying on side-car actions SO's have been migrated to SO references we should remove this function. - const legacyNotificationsCount = ( - await savedObjectClient.find({ - type: 'alert', + const legacyRuleActions = + await savedObjectClient.find({ + type: legacyRuleActionsSavedObjectType, page: 1, + perPage: MAX_RESULTS_WINDOW, namespaces: ['*'], - perPage: 1, - filter: `alert.attributes.alertTypeId: ${LEGACY_NOTIFICATIONS_ID}`, - }) - ).total; - rulesUsage = { ...rulesUsage, legacy_notifications: { total: legacyNotificationsCount } }; + }); + + const legacyNotificationRuleIds = legacyRuleActions.saved_objects.reduce( + (cache, legacyNotificationsObject) => { + const ruleRef = legacyNotificationsObject.references.find( + (reference) => reference.name === 'alert_0' && reference.type === 'alert' + ); + if (ruleRef != null) { + const enabled = legacyNotificationsObject.attributes.ruleThrottle !== 'no_actions'; + cache.set(ruleRef.id, { enabled }); + } + return cache; + }, + new Map() + ); const casesCache = cases.saved_objects.reduce((cache, { attributes: casesObject }) => { const ruleId = casesObject.rule.id; @@ -320,6 +452,17 @@ export const getDetectionRuleMetrics = async ( const ruleObjects = ruleResults.hits.hits.map((hit) => { const ruleId = hit._id.split(':')[1]; const isElastic = isElasticRule(hit._source?.alert.tags); + + // Even if the legacy notification is set to "no_actions" we still count the rule as having a legacy notification that is not migrated yet. + const hasLegacyNotification = legacyNotificationRuleIds.get(ruleId) != null; + + // We only count a rule as having a notification and being "enabled" if it is _not_ set to "no_actions"/"muteAll" and it has at least one action within its array. + const hasNotification = + !hasLegacyNotification && + hit._source?.alert.actions != null && + hit._source?.alert.actions.length > 0 && + hit._source?.alert.muteAll !== true; + return { rule_name: hit._source?.alert.name, rule_id: hit._source?.alert.params.ruleId, @@ -331,6 +474,8 @@ export const getDetectionRuleMetrics = async ( updated_on: hit._source?.alert.updatedAt, alert_count_daily: alertsCache.get(ruleId) || 0, cases_count_total: casesCache.get(ruleId) || 0, + has_legacy_notification: hasLegacyNotification, + has_notification: hasNotification, } as DetectionRuleMetric; }); diff --git a/x-pack/plugins/security_solution/server/usage/detections/detections.test.ts b/x-pack/plugins/security_solution/server/usage/detections/detections.test.ts index 7793552510c759..d08f915e4428f5 100644 --- a/x-pack/plugins/security_solution/server/usage/detections/detections.test.ts +++ b/x-pack/plugins/security_solution/server/usage/detections/detections.test.ts @@ -70,6 +70,8 @@ describe('Detections Usage and Metrics', () => { rule_type: 'query', rule_version: 4, updated_on: '2021-03-23T17:15:59.634Z', + has_legacy_notification: false, + has_notification: false, }, ], detection_rule_usage: { @@ -79,15 +81,20 @@ describe('Detections Usage and Metrics', () => { disabled: 1, alerts: 3400, cases: 1, + legacy_notifications_enabled: 0, + legacy_notifications_disabled: 0, + notifications_enabled: 0, + notifications_disabled: 0, }, elastic_total: { alerts: 3400, cases: 1, disabled: 1, enabled: 0, - }, - legacy_notifications: { - total: 4, + legacy_notifications_enabled: 0, + legacy_notifications_disabled: 0, + notifications_enabled: 0, + notifications_disabled: 0, }, }, }, @@ -118,15 +125,20 @@ describe('Detections Usage and Metrics', () => { cases: 1, disabled: 1, enabled: 0, + legacy_notifications_enabled: 0, + legacy_notifications_disabled: 0, + notifications_enabled: 0, + notifications_disabled: 0, }, query: { alerts: 800, cases: 1, disabled: 1, enabled: 0, - }, - legacy_notifications: { - total: 4, + legacy_notifications_enabled: 0, + legacy_notifications_disabled: 0, + notifications_enabled: 0, + notifications_disabled: 0, }, }, }, @@ -144,7 +156,7 @@ describe('Detections Usage and Metrics', () => { savedObjectsClient.find.mockResolvedValue(getMockAlertCasesResponse()); const result = await fetchDetectionsMetrics('', '', esClientMock, savedObjectsClient, mlMock); - expect(result).toEqual({ + expect(result).toEqual({ ...getInitialDetectionMetrics(), detection_rules: { detection_rule_detail: [ @@ -159,6 +171,8 @@ describe('Detections Usage and Metrics', () => { rule_type: 'query', rule_version: 4, updated_on: '2021-03-23T17:15:59.634Z', + has_legacy_notification: false, + has_notification: false, }, ], detection_rule_usage: { @@ -168,15 +182,20 @@ describe('Detections Usage and Metrics', () => { cases: 1, disabled: 1, enabled: 0, + legacy_notifications_enabled: 0, + legacy_notifications_disabled: 0, + notifications_enabled: 0, + notifications_disabled: 0, }, query: { alerts: 0, cases: 1, disabled: 1, enabled: 0, - }, - legacy_notifications: { - total: 4, + legacy_notifications_enabled: 0, + legacy_notifications_disabled: 0, + notifications_enabled: 0, + notifications_disabled: 0, }, }, }, diff --git a/x-pack/plugins/security_solution/server/usage/detections/types.ts b/x-pack/plugins/security_solution/server/usage/detections/types.ts index ed0e8a4e5e99f2..b2a9cf7af48613 100644 --- a/x-pack/plugins/security_solution/server/usage/detections/types.ts +++ b/x-pack/plugins/security_solution/server/usage/detections/types.ts @@ -30,7 +30,9 @@ export interface RuleSearchResult { tags: string[]; createdAt: string; updatedAt: string; + muteAll: boolean | undefined | null; params: DetectionRuleParms; + actions: unknown[]; }; } @@ -55,8 +57,11 @@ interface FeatureTypeUsage { disabled: number; alerts: number; cases: number; + legacy_notifications_enabled: number; + legacy_notifications_disabled: number; + notifications_enabled: number; + notifications_disabled: number; } - export interface DetectionRulesTypeUsage { query: FeatureTypeUsage; threshold: FeatureTypeUsage; @@ -65,7 +70,6 @@ export interface DetectionRulesTypeUsage { threat_match: FeatureTypeUsage; elastic_total: FeatureTypeUsage; custom_total: FeatureTypeUsage; - legacy_notifications: LegacyNotifications; } export interface MlJobsUsage { @@ -129,6 +133,8 @@ export interface DetectionRuleMetric { updated_on: string; alert_count_daily: number; cases_count_total: number; + has_legacy_notification: boolean; + has_notification: boolean; } export interface AlertsAggregationResponse { @@ -162,11 +168,3 @@ export interface DetectionRuleAdoption { detection_rule_detail: DetectionRuleMetric[]; detection_rule_usage: DetectionRulesTypeUsage; } - -/** - * The legacy notifications that are still in use. - * @deprecated Once we are confident all rules relying on side-car actions SO's have been migrated to SO references we should remove this function - */ -export interface LegacyNotifications { - total: number; -} diff --git a/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json b/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json index 02ad35bd0916cf..799b183f7bbd64 100644 --- a/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json +++ b/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json @@ -6986,6 +6986,30 @@ "_meta": { "description": "Number of cases attached to query detection rule alerts" } + }, + "legacy_notifications_enabled": { + "type": "long", + "_meta": { + "description": "Number of legacy notifications enabled" + } + }, + "legacy_notifications_disabled": { + "type": "long", + "_meta": { + "description": "Number of legacy notifications disabled" + } + }, + "notifications_enabled": { + "type": "long", + "_meta": { + "description": "Number of notifications enabled" + } + }, + "notifications_disabled": { + "type": "long", + "_meta": { + "description": "Number of notifications enabled" + } } } }, @@ -7014,6 +7038,30 @@ "_meta": { "description": "Number of cases attached to threshold detection rule alerts" } + }, + "legacy_notifications_enabled": { + "type": "long", + "_meta": { + "description": "Number of legacy notifications enabled" + } + }, + "legacy_notifications_disabled": { + "type": "long", + "_meta": { + "description": "Number of legacy notifications disabled" + } + }, + "notifications_enabled": { + "type": "long", + "_meta": { + "description": "Number of notifications enabled" + } + }, + "notifications_disabled": { + "type": "long", + "_meta": { + "description": "Number of notifications enabled" + } } } }, @@ -7042,6 +7090,30 @@ "_meta": { "description": "Number of cases attached to eql detection rule alerts" } + }, + "legacy_notifications_enabled": { + "type": "long", + "_meta": { + "description": "Number of legacy notifications enabled" + } + }, + "legacy_notifications_disabled": { + "type": "long", + "_meta": { + "description": "Number of legacy notifications disabled" + } + }, + "notifications_enabled": { + "type": "long", + "_meta": { + "description": "Number of notifications enabled" + } + }, + "notifications_disabled": { + "type": "long", + "_meta": { + "description": "Number of notifications enabled" + } } } }, @@ -7070,6 +7142,30 @@ "_meta": { "description": "Number of cases attached to machine_learning detection rule alerts" } + }, + "legacy_notifications_enabled": { + "type": "long", + "_meta": { + "description": "Number of legacy notifications enabled" + } + }, + "legacy_notifications_disabled": { + "type": "long", + "_meta": { + "description": "Number of legacy notifications disabled" + } + }, + "notifications_enabled": { + "type": "long", + "_meta": { + "description": "Number of notifications enabled" + } + }, + "notifications_disabled": { + "type": "long", + "_meta": { + "description": "Number of notifications enabled" + } } } }, @@ -7098,15 +7194,29 @@ "_meta": { "description": "Number of cases attached to threat_match detection rule alerts" } - } - } - }, - "legacy_notifications": { - "properties": { - "total": { + }, + "legacy_notifications_enabled": { + "type": "long", + "_meta": { + "description": "Number of legacy notifications enabled" + } + }, + "legacy_notifications_disabled": { + "type": "long", + "_meta": { + "description": "Number of legacy notifications disabled" + } + }, + "notifications_enabled": { + "type": "long", + "_meta": { + "description": "Number of notifications enabled" + } + }, + "notifications_disabled": { "type": "long", "_meta": { - "description": "Number of legacy notifications still in use" + "description": "Number of notifications enabled" } } } @@ -7136,6 +7246,30 @@ "_meta": { "description": "Number of cases attached to elastic detection rule alerts" } + }, + "legacy_notifications_enabled": { + "type": "long", + "_meta": { + "description": "Number of legacy notifications enabled" + } + }, + "legacy_notifications_disabled": { + "type": "long", + "_meta": { + "description": "Number of legacy notifications disabled" + } + }, + "notifications_enabled": { + "type": "long", + "_meta": { + "description": "Number of notifications enabled" + } + }, + "notifications_disabled": { + "type": "long", + "_meta": { + "description": "Number of notifications enabled" + } } } }, @@ -7164,6 +7298,30 @@ "_meta": { "description": "Number of cases attached to custom detection rule alerts" } + }, + "legacy_notifications_enabled": { + "type": "long", + "_meta": { + "description": "Number of legacy notifications enabled" + } + }, + "legacy_notifications_disabled": { + "type": "long", + "_meta": { + "description": "Number of legacy notifications disabled" + } + }, + "notifications_enabled": { + "type": "long", + "_meta": { + "description": "Number of notifications enabled" + } + }, + "notifications_disabled": { + "type": "long", + "_meta": { + "description": "Number of notifications enabled" + } } } } @@ -7232,6 +7390,18 @@ "_meta": { "description": "The number of total cases generated by a rule" } + }, + "has_legacy_notification": { + "type": "boolean", + "_meta": { + "description": "True if this rule has a legacy notification" + } + }, + "has_notification": { + "type": "boolean", + "_meta": { + "description": "True if this rule has a notification" + } } } } diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/telemetry/README.md b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/telemetry/README.md index cfcf13e1d9f707..2760001a20626a 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/telemetry/README.md +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/telemetry/README.md @@ -1,8 +1,6 @@ These are tests for the telemetry rules within "security_solution/server/usage" * detection_rules -* legacy_notifications -Detection rules are tests around each of the rule types to affirm they work such as query, eql, etc... -Legacy notifications are tests around the legacy notification telemetry. Once legacy notifications are removed, -these tests can be removed too. +Detection rules are tests around each of the rule types to affirm they work such as query, eql, etc... This includes +legacy notifications. Once legacy notifications are moved, those tests can be removed too. diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/telemetry/detection_rules.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/telemetry/detection_rules.ts index bafc36c329eab3..561c8bc3564766 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/telemetry/detection_rules.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/telemetry/detection_rules.ts @@ -8,26 +8,30 @@ import expect from '@kbn/expect'; import { DetectionMetrics } from '../../../../../plugins/security_solution/server/usage/detections/types'; import { - EqlCreateSchema, - QueryCreateSchema, ThreatMatchCreateSchema, ThresholdCreateSchema, } from '../../../../../plugins/security_solution/common/detection_engine/schemas/request'; import { FtrProviderContext } from '../../../common/ftr_provider_context'; import { + createLegacyRuleAction, + createNewAction, createRule, createSignalsIndex, deleteAllAlerts, deleteSignalsIndex, getEqlRuleForSignalTesting, + getRule, getRuleForSignalTesting, + getRuleWithWebHookAction, getSimpleMlRule, + getSimpleRule, getSimpleThreatMatch, getStats, getThresholdRuleForSignalTesting, installPrePackagedRules, waitForRuleSuccessOrStatus, waitForSignalsToBePresent, + updateRule, } from '../../../utils'; import { getInitialDetectionMetrics } from '../../../../../plugins/security_solution/server/usage/detections/detection_rule_helpers'; @@ -64,11 +68,769 @@ export default ({ getService }: FtrProviderContext) => { }); describe('"kql" rule type', () => { - it('should show stats for active rule', async () => { - const rule: QueryCreateSchema = getRuleForSignalTesting(['telemetry']); + it('should show "notifications_enabled", "notifications_disabled" "legacy_notifications_enabled", "legacy_notifications_disabled", all to be "0" for "disabled"/"in-active" rule that does not have any actions', async () => { + const rule = getRuleForSignalTesting(['telemetry'], 'rule-1', false); + await createRule(supertest, log, rule); + await retry.try(async () => { + const stats = await getStats(supertest, log); + const expected: DetectionMetrics = { + ...getInitialDetectionMetrics(), + detection_rules: { + ...getInitialDetectionMetrics().detection_rules, + detection_rule_usage: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, + query: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.query, + disabled: 1, + notifications_enabled: 0, + notifications_disabled: 0, + legacy_notifications_disabled: 0, + legacy_notifications_enabled: 0, + }, + custom_total: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, + disabled: 1, + notifications_enabled: 0, + notifications_disabled: 0, + legacy_notifications_disabled: 0, + legacy_notifications_enabled: 0, + }, + }, + }, + }; + expect(stats).to.eql(expected); + }); + }); + + it('should show "notifications_enabled", "notifications_disabled" "legacy_notifications_enabled", "legacy_notifications_disabled", all to be "0" for "enabled"/"active" rule that does not have any actions', async () => { + const rule = getRuleForSignalTesting(['telemetry']); + const { id } = await createRule(supertest, log, rule); + await waitForRuleSuccessOrStatus(supertest, log, id); + await waitForSignalsToBePresent(supertest, log, 4, [id]); + await retry.try(async () => { + const stats = await getStats(supertest, log); + const expected: DetectionMetrics = { + ...getInitialDetectionMetrics(), + detection_rules: { + ...getInitialDetectionMetrics().detection_rules, + detection_rule_usage: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, + query: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.query, + enabled: 1, + alerts: 4, + notifications_enabled: 0, + notifications_disabled: 0, + legacy_notifications_disabled: 0, + legacy_notifications_enabled: 0, + }, + custom_total: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, + enabled: 1, + alerts: 4, + notifications_enabled: 0, + notifications_disabled: 0, + legacy_notifications_disabled: 0, + legacy_notifications_enabled: 0, + }, + }, + }, + }; + expect(stats).to.eql(expected); + }); + }); + + it('should show "notifications_disabled" to be "1" for rule that has at least "1" action(s) and the alert is "disabled"/"in-active"', async () => { + const rule = getRuleForSignalTesting(['telemetry']); + const hookAction = await createNewAction(supertest, log); + const ruleToCreate = getRuleWithWebHookAction(hookAction.id, false, rule); + await createRule(supertest, log, ruleToCreate); + + await retry.try(async () => { + const stats = await getStats(supertest, log); + const expected: DetectionMetrics = { + ...getInitialDetectionMetrics(), + detection_rules: { + ...getInitialDetectionMetrics().detection_rules, + detection_rule_usage: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, + query: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.query, + notifications_disabled: 1, + disabled: 1, + }, + custom_total: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, + notifications_disabled: 1, + disabled: 1, + }, + }, + }, + }; + expect(stats).to.eql(expected); + }); + }); + + it('should show "notifications_enabled" to be "1" for rule that has at least "1" action(s) and the alert is "enabled"/"active"', async () => { + const rule = getRuleForSignalTesting(['telemetry']); + const hookAction = await createNewAction(supertest, log); + const ruleToCreate = getRuleWithWebHookAction(hookAction.id, true, rule); + const { id } = await createRule(supertest, log, ruleToCreate); + await waitForRuleSuccessOrStatus(supertest, log, id); + await waitForSignalsToBePresent(supertest, log, 4, [id]); + + await retry.try(async () => { + const stats = await getStats(supertest, log); + const expected: DetectionMetrics = { + ...getInitialDetectionMetrics(), + detection_rules: { + ...getInitialDetectionMetrics().detection_rules, + detection_rule_usage: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, + query: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.query, + enabled: 1, + alerts: 4, + notifications_enabled: 1, + }, + custom_total: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, + enabled: 1, + alerts: 4, + notifications_enabled: 1, + }, + }, + }, + }; + expect(stats).to.eql(expected); + }); + }); + + it('should show "legacy_notifications_disabled" to be "1" for rule that has at least "1" legacy action(s) and the alert is "disabled"/"in-active"', async () => { + const rule = getRuleForSignalTesting(['telemetry'], 'rule-1', false); + const { id } = await createRule(supertest, log, rule); + const hookAction = await createNewAction(supertest, log); + await createLegacyRuleAction(supertest, id, hookAction.id); + + await retry.try(async () => { + const stats = await getStats(supertest, log); + const expected: DetectionMetrics = { + ...getInitialDetectionMetrics(), + detection_rules: { + ...getInitialDetectionMetrics().detection_rules, + detection_rule_usage: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, + query: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.query, + disabled: 1, + legacy_notifications_disabled: 1, + }, + custom_total: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, + disabled: 1, + legacy_notifications_disabled: 1, + }, + }, + }, + }; + expect(stats).to.eql(expected); + }); + }); + + it('should show "legacy_notifications_enabled" to be "1" for rule that has at least "1" legacy action(s) and the alert is "enabled"/"active"', async () => { + const rule = getRuleForSignalTesting(['telemetry']); + const { id } = await createRule(supertest, log, rule); + const hookAction = await createNewAction(supertest, log); + await createLegacyRuleAction(supertest, id, hookAction.id); + await waitForRuleSuccessOrStatus(supertest, log, id); + await waitForSignalsToBePresent(supertest, log, 4, [id]); + + await retry.try(async () => { + const stats = await getStats(supertest, log); + const expected: DetectionMetrics = { + ...getInitialDetectionMetrics(), + detection_rules: { + ...getInitialDetectionMetrics().detection_rules, + detection_rule_usage: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, + query: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.query, + alerts: 4, + enabled: 1, + legacy_notifications_enabled: 1, + }, + custom_total: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, + alerts: 4, + enabled: 1, + legacy_notifications_enabled: 1, + }, + }, + }, + }; + expect(stats).to.eql(expected); + }); + }); + }); + + describe('"eql" rule type', () => { + it('should show "notifications_enabled", "notifications_disabled" "legacy_notifications_enabled", "legacy_notifications_disabled", all to be "0" for "disabled"/"in-active" rule that does not have any actions', async () => { + const rule = getEqlRuleForSignalTesting(['telemetry'], 'rule-1', false); + await createRule(supertest, log, rule); + await retry.try(async () => { + const stats = await getStats(supertest, log); + const expected: DetectionMetrics = { + ...getInitialDetectionMetrics(), + detection_rules: { + ...getInitialDetectionMetrics().detection_rules, + detection_rule_usage: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, + eql: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.eql, + disabled: 1, + notifications_enabled: 0, + notifications_disabled: 0, + legacy_notifications_disabled: 0, + legacy_notifications_enabled: 0, + }, + custom_total: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, + disabled: 1, + notifications_enabled: 0, + notifications_disabled: 0, + legacy_notifications_disabled: 0, + legacy_notifications_enabled: 0, + }, + }, + }, + }; + expect(stats).to.eql(expected); + }); + }); + + it('should show "notifications_enabled", "notifications_disabled" "legacy_notifications_enabled", "legacy_notifications_disabled", all to be "0" for "enabled"/"active" rule that does not have any actions', async () => { + const rule = getEqlRuleForSignalTesting(['telemetry']); + const { id } = await createRule(supertest, log, rule); + await waitForRuleSuccessOrStatus(supertest, log, id); + await waitForSignalsToBePresent(supertest, log, 4, [id]); + await retry.try(async () => { + const stats = await getStats(supertest, log); + const expected: DetectionMetrics = { + ...getInitialDetectionMetrics(), + detection_rules: { + ...getInitialDetectionMetrics().detection_rules, + detection_rule_usage: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, + eql: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.eql, + enabled: 1, + alerts: 4, + notifications_enabled: 0, + notifications_disabled: 0, + legacy_notifications_disabled: 0, + legacy_notifications_enabled: 0, + }, + custom_total: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, + enabled: 1, + alerts: 4, + notifications_enabled: 0, + notifications_disabled: 0, + legacy_notifications_disabled: 0, + legacy_notifications_enabled: 0, + }, + }, + }, + }; + expect(stats).to.eql(expected); + }); + }); + + it('should show "notifications_disabled" to be "1" for rule that has at least "1" action(s) and the alert is "disabled"/"in-active"', async () => { + const rule = getEqlRuleForSignalTesting(['telemetry']); + const hookAction = await createNewAction(supertest, log); + const ruleToCreate = getRuleWithWebHookAction(hookAction.id, false, rule); + await createRule(supertest, log, ruleToCreate); + + await retry.try(async () => { + const stats = await getStats(supertest, log); + const expected: DetectionMetrics = { + ...getInitialDetectionMetrics(), + detection_rules: { + ...getInitialDetectionMetrics().detection_rules, + detection_rule_usage: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, + eql: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.eql, + notifications_disabled: 1, + disabled: 1, + }, + custom_total: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, + notifications_disabled: 1, + disabled: 1, + }, + }, + }, + }; + expect(stats).to.eql(expected); + }); + }); + + it('should show "notifications_enabled" to be "1" for rule that has at least "1" action(s) and the alert is "enabled"/"active"', async () => { + const rule = getEqlRuleForSignalTesting(['telemetry']); + const hookAction = await createNewAction(supertest, log); + const ruleToCreate = getRuleWithWebHookAction(hookAction.id, true, rule); + const { id } = await createRule(supertest, log, ruleToCreate); + await waitForRuleSuccessOrStatus(supertest, log, id); + await waitForSignalsToBePresent(supertest, log, 4, [id]); + + await retry.try(async () => { + const stats = await getStats(supertest, log); + const expected: DetectionMetrics = { + ...getInitialDetectionMetrics(), + detection_rules: { + ...getInitialDetectionMetrics().detection_rules, + detection_rule_usage: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, + eql: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.eql, + enabled: 1, + alerts: 4, + notifications_enabled: 1, + }, + custom_total: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, + enabled: 1, + alerts: 4, + notifications_enabled: 1, + }, + }, + }, + }; + expect(stats).to.eql(expected); + }); + }); + + it('should show "legacy_notifications_disabled" to be "1" for rule that has at least "1" legacy action(s) and the alert is "disabled"/"in-active"', async () => { + const rule = getEqlRuleForSignalTesting(['telemetry'], 'rule-1', false); + const { id } = await createRule(supertest, log, rule); + const hookAction = await createNewAction(supertest, log); + await createLegacyRuleAction(supertest, id, hookAction.id); + + await retry.try(async () => { + const stats = await getStats(supertest, log); + const expected: DetectionMetrics = { + ...getInitialDetectionMetrics(), + detection_rules: { + ...getInitialDetectionMetrics().detection_rules, + detection_rule_usage: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, + eql: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.eql, + disabled: 1, + legacy_notifications_disabled: 1, + }, + custom_total: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, + disabled: 1, + legacy_notifications_disabled: 1, + }, + }, + }, + }; + expect(stats).to.eql(expected); + }); + }); + + it('should show "legacy_notifications_enabled" to be "1" for rule that has at least "1" legacy action(s) and the alert is "enabled"/"active"', async () => { + const rule = getEqlRuleForSignalTesting(['telemetry']); + const { id } = await createRule(supertest, log, rule); + const hookAction = await createNewAction(supertest, log); + await createLegacyRuleAction(supertest, id, hookAction.id); + await waitForRuleSuccessOrStatus(supertest, log, id); + await waitForSignalsToBePresent(supertest, log, 4, [id]); + + await retry.try(async () => { + const stats = await getStats(supertest, log); + const expected: DetectionMetrics = { + ...getInitialDetectionMetrics(), + detection_rules: { + ...getInitialDetectionMetrics().detection_rules, + detection_rule_usage: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, + eql: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.eql, + alerts: 4, + enabled: 1, + legacy_notifications_enabled: 1, + }, + custom_total: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, + alerts: 4, + enabled: 1, + legacy_notifications_enabled: 1, + }, + }, + }, + }; + expect(stats).to.eql(expected); + }); + }); + }); + + describe('"threshold" rule type', () => { + it('should show "notifications_enabled", "notifications_disabled" "legacy_notifications_enabled", "legacy_notifications_disabled", all to be "0" for "disabled"/"in-active" rule that does not have any actions', async () => { + const rule: ThresholdCreateSchema = { + ...getThresholdRuleForSignalTesting(['telemetry'], 'rule-1', false), + threshold: { + field: 'keyword', + value: 1, + }, + }; + await createRule(supertest, log, rule); + await retry.try(async () => { + const stats = await getStats(supertest, log); + const expected: DetectionMetrics = { + ...getInitialDetectionMetrics(), + detection_rules: { + ...getInitialDetectionMetrics().detection_rules, + detection_rule_usage: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, + threshold: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.threshold, + disabled: 1, + notifications_enabled: 0, + notifications_disabled: 0, + legacy_notifications_disabled: 0, + legacy_notifications_enabled: 0, + }, + custom_total: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, + disabled: 1, + notifications_enabled: 0, + notifications_disabled: 0, + legacy_notifications_disabled: 0, + legacy_notifications_enabled: 0, + }, + }, + }, + }; + expect(stats).to.eql(expected); + }); + }); + + it('should show "notifications_enabled", "notifications_disabled" "legacy_notifications_enabled", "legacy_notifications_disabled", all to be "0" for "enabled"/"active" rule that does not have any actions', async () => { + const rule: ThresholdCreateSchema = { + ...getThresholdRuleForSignalTesting(['telemetry']), + threshold: { + field: 'keyword', + value: 1, + }, + }; + const { id } = await createRule(supertest, log, rule); + await waitForRuleSuccessOrStatus(supertest, log, id); + await waitForSignalsToBePresent(supertest, log, 4, [id]); + await retry.try(async () => { + const stats = await getStats(supertest, log); + const expected: DetectionMetrics = { + ...getInitialDetectionMetrics(), + detection_rules: { + ...getInitialDetectionMetrics().detection_rules, + detection_rule_usage: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, + threshold: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.threshold, + enabled: 1, + alerts: 4, + notifications_enabled: 0, + notifications_disabled: 0, + legacy_notifications_disabled: 0, + legacy_notifications_enabled: 0, + }, + custom_total: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, + enabled: 1, + alerts: 4, + notifications_enabled: 0, + notifications_disabled: 0, + legacy_notifications_disabled: 0, + legacy_notifications_enabled: 0, + }, + }, + }, + }; + expect(stats).to.eql(expected); + }); + }); + + it('should show "notifications_disabled" to be "1" for rule that has at least "1" action(s) and the alert is "disabled"/"in-active"', async () => { + const rule: ThresholdCreateSchema = { + ...getThresholdRuleForSignalTesting(['telemetry'], 'rule-1', false), + threshold: { + field: 'keyword', + value: 1, + }, + }; + const hookAction = await createNewAction(supertest, log); + const ruleToCreate = getRuleWithWebHookAction(hookAction.id, false, rule); + await createRule(supertest, log, ruleToCreate); + + await retry.try(async () => { + const stats = await getStats(supertest, log); + const expected: DetectionMetrics = { + ...getInitialDetectionMetrics(), + detection_rules: { + ...getInitialDetectionMetrics().detection_rules, + detection_rule_usage: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, + threshold: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.threshold, + notifications_disabled: 1, + disabled: 1, + }, + custom_total: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, + notifications_disabled: 1, + disabled: 1, + }, + }, + }, + }; + expect(stats).to.eql(expected); + }); + }); + + it('should show "notifications_enabled" to be "1" for rule that has at least "1" action(s) and the alert is "enabled"/"active"', async () => { + const rule: ThresholdCreateSchema = { + ...getThresholdRuleForSignalTesting(['telemetry']), + threshold: { + field: 'keyword', + value: 1, + }, + }; + const hookAction = await createNewAction(supertest, log); + const ruleToCreate = getRuleWithWebHookAction(hookAction.id, true, rule); + const { id } = await createRule(supertest, log, ruleToCreate); + await waitForRuleSuccessOrStatus(supertest, log, id); + await waitForSignalsToBePresent(supertest, log, 4, [id]); + + await retry.try(async () => { + const stats = await getStats(supertest, log); + const expected: DetectionMetrics = { + ...getInitialDetectionMetrics(), + detection_rules: { + ...getInitialDetectionMetrics().detection_rules, + detection_rule_usage: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, + threshold: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.threshold, + enabled: 1, + alerts: 4, + notifications_enabled: 1, + }, + custom_total: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, + enabled: 1, + alerts: 4, + notifications_enabled: 1, + }, + }, + }, + }; + expect(stats).to.eql(expected); + }); + }); + + it('should show "legacy_notifications_disabled" to be "1" for rule that has at least "1" legacy action(s) and the alert is "disabled"/"in-active"', async () => { + const rule: ThresholdCreateSchema = { + ...getThresholdRuleForSignalTesting(['telemetry'], 'rule-1', false), + threshold: { + field: 'keyword', + value: 1, + }, + }; + const { id } = await createRule(supertest, log, rule); + const hookAction = await createNewAction(supertest, log); + await createLegacyRuleAction(supertest, id, hookAction.id); + + await retry.try(async () => { + const stats = await getStats(supertest, log); + const expected: DetectionMetrics = { + ...getInitialDetectionMetrics(), + detection_rules: { + ...getInitialDetectionMetrics().detection_rules, + detection_rule_usage: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, + threshold: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.threshold, + disabled: 1, + legacy_notifications_disabled: 1, + }, + custom_total: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, + disabled: 1, + legacy_notifications_disabled: 1, + }, + }, + }, + }; + expect(stats).to.eql(expected); + }); + }); + + it('should show "legacy_notifications_enabled" to be "1" for rule that has at least "1" legacy action(s) and the alert is "enabled"/"active"', async () => { + const rule: ThresholdCreateSchema = { + ...getThresholdRuleForSignalTesting(['telemetry']), + threshold: { + field: 'keyword', + value: 1, + }, + }; const { id } = await createRule(supertest, log, rule); + const hookAction = await createNewAction(supertest, log); + await createLegacyRuleAction(supertest, id, hookAction.id); await waitForRuleSuccessOrStatus(supertest, log, id); await waitForSignalsToBePresent(supertest, log, 4, [id]); + + await retry.try(async () => { + const stats = await getStats(supertest, log); + const expected: DetectionMetrics = { + ...getInitialDetectionMetrics(), + detection_rules: { + ...getInitialDetectionMetrics().detection_rules, + detection_rule_usage: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, + threshold: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.threshold, + alerts: 4, + enabled: 1, + legacy_notifications_enabled: 1, + }, + custom_total: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, + alerts: 4, + enabled: 1, + legacy_notifications_enabled: 1, + }, + }, + }, + }; + expect(stats).to.eql(expected); + }); + }); + }); + + // Note: We don't actually find signals with these tests as we don't have a good way of signal finding with ML rules. + describe('"ml" rule type', () => { + it('should show "notifications_enabled", "notifications_disabled" "legacy_notifications_enabled", "legacy_notifications_disabled", all to be "0" for "disabled"/"in-active" rule that does not have any actions', async () => { + const rule = getSimpleMlRule(); + await createRule(supertest, log, rule); + await retry.try(async () => { + const stats = await getStats(supertest, log); + const expected: DetectionMetrics = { + ...getInitialDetectionMetrics(), + detection_rules: { + ...getInitialDetectionMetrics().detection_rules, + detection_rule_usage: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, + machine_learning: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage + .machine_learning, + disabled: 1, + notifications_enabled: 0, + notifications_disabled: 0, + legacy_notifications_disabled: 0, + legacy_notifications_enabled: 0, + }, + custom_total: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, + disabled: 1, + notifications_enabled: 0, + notifications_disabled: 0, + legacy_notifications_disabled: 0, + legacy_notifications_enabled: 0, + }, + }, + }, + }; + expect(stats).to.eql(expected); + }); + }); + + it('should show "notifications_enabled", "notifications_disabled" "legacy_notifications_enabled", "legacy_notifications_disabled", all to be "0" for "enabled"/"active" rule that does not have any actions', async () => { + const rule = getSimpleMlRule('rule-1', true); + await createRule(supertest, log, rule); + await retry.try(async () => { + const stats = await getStats(supertest, log); + const expected: DetectionMetrics = { + ...getInitialDetectionMetrics(), + detection_rules: { + ...getInitialDetectionMetrics().detection_rules, + detection_rule_usage: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, + machine_learning: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage + .machine_learning, + enabled: 1, + notifications_enabled: 0, + notifications_disabled: 0, + legacy_notifications_disabled: 0, + legacy_notifications_enabled: 0, + }, + custom_total: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, + enabled: 1, + notifications_enabled: 0, + notifications_disabled: 0, + legacy_notifications_disabled: 0, + legacy_notifications_enabled: 0, + }, + }, + }, + }; + expect(stats).to.eql(expected); + }); + }); + + it('should show "notifications_disabled" to be "1" for rule that has at least "1" action(s) and the alert is "disabled"/"in-active"', async () => { + const rule = getSimpleMlRule(); + const hookAction = await createNewAction(supertest, log); + const ruleToCreate = getRuleWithWebHookAction(hookAction.id, false, rule); + await createRule(supertest, log, ruleToCreate); + + await retry.try(async () => { + const stats = await getStats(supertest, log); + const expected: DetectionMetrics = { + ...getInitialDetectionMetrics(), + detection_rules: { + ...getInitialDetectionMetrics().detection_rules, + detection_rule_usage: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, + machine_learning: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage + .machine_learning, + notifications_disabled: 1, + disabled: 1, + }, + custom_total: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, + notifications_disabled: 1, + disabled: 1, + }, + }, + }, + }; + expect(stats).to.eql(expected); + }); + }); + + it('should show "notifications_enabled" to be "1" for rule that has at least "1" action(s) and the alert is "enabled"/"active"', async () => { + const rule = getSimpleMlRule('rule-1', true); + const hookAction = await createNewAction(supertest, log); + const ruleToCreate = getRuleWithWebHookAction(hookAction.id, true, rule); + await createRule(supertest, log, ruleToCreate); + await retry.try(async () => { const stats = await getStats(supertest, log); const expected: DetectionMetrics = { @@ -77,15 +839,16 @@ export default ({ getService }: FtrProviderContext) => { ...getInitialDetectionMetrics().detection_rules, detection_rule_usage: { ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, - query: { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.query, + machine_learning: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage + .machine_learning, enabled: 1, - alerts: 4, + notifications_enabled: 1, }, custom_total: { ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, enabled: 1, - alerts: 4, + notifications_enabled: 1, }, }, }, @@ -94,9 +857,12 @@ export default ({ getService }: FtrProviderContext) => { }); }); - it('should show stats for in-active rule', async () => { - const rule: QueryCreateSchema = getRuleForSignalTesting(['telemetry'], 'rule-1', false); - await createRule(supertest, log, rule); + it('should show "legacy_notifications_disabled" to be "1" for rule that has at least "1" legacy action(s) and the alert is "disabled"/"in-active"', async () => { + const rule = getSimpleMlRule(); + const { id } = await createRule(supertest, log, rule); + const hookAction = await createNewAction(supertest, log); + await createLegacyRuleAction(supertest, id, hookAction.id); + await retry.try(async () => { const stats = await getStats(supertest, log); const expected: DetectionMetrics = { @@ -105,13 +871,16 @@ export default ({ getService }: FtrProviderContext) => { ...getInitialDetectionMetrics().detection_rules, detection_rule_usage: { ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, - query: { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.query, + machine_learning: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage + .machine_learning, disabled: 1, + legacy_notifications_disabled: 1, }, custom_total: { ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, disabled: 1, + legacy_notifications_disabled: 1, }, }, }, @@ -119,14 +888,13 @@ export default ({ getService }: FtrProviderContext) => { expect(stats).to.eql(expected); }); }); - }); - describe('"eql" rule type', () => { - it('should show stats for active rule', async () => { - const rule: EqlCreateSchema = getEqlRuleForSignalTesting(['telemetry']); + it('should show "legacy_notifications_enabled" to be "1" for rule that has at least "1" legacy action(s) and the alert is "enabled"/"active"', async () => { + const rule = getSimpleMlRule('rule-1', true); const { id } = await createRule(supertest, log, rule); - await waitForRuleSuccessOrStatus(supertest, log, id); - await waitForSignalsToBePresent(supertest, log, 4, [id]); + const hookAction = await createNewAction(supertest, log); + await createLegacyRuleAction(supertest, id, hookAction.id); + await retry.try(async () => { const stats = await getStats(supertest, log); const expected: DetectionMetrics = { @@ -135,15 +903,16 @@ export default ({ getService }: FtrProviderContext) => { ...getInitialDetectionMetrics().detection_rules, detection_rule_usage: { ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, - eql: { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.query, + machine_learning: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage + .machine_learning, enabled: 1, - alerts: 4, + legacy_notifications_enabled: 1, }, custom_total: { ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, enabled: 1, - alerts: 4, + legacy_notifications_enabled: 1, }, }, }, @@ -151,9 +920,11 @@ export default ({ getService }: FtrProviderContext) => { expect(stats).to.eql(expected); }); }); + }); - it('should show stats for in-active rule', async () => { - const rule: EqlCreateSchema = getEqlRuleForSignalTesting(['telemetry'], 'rule-1', false); + describe('"indicator_match/threat_match" rule type', () => { + it('should show "notifications_enabled", "notifications_disabled" "legacy_notifications_enabled", "legacy_notifications_disabled", all to be "0" for "disabled"/"in-active" rule that does not have any actions', async () => { + const rule = getSimpleThreatMatch(); await createRule(supertest, log, rule); await retry.try(async () => { const stats = await getStats(supertest, log); @@ -163,13 +934,21 @@ export default ({ getService }: FtrProviderContext) => { ...getInitialDetectionMetrics().detection_rules, detection_rule_usage: { ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, - eql: { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.query, + threat_match: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.threat_match, disabled: 1, + notifications_enabled: 0, + notifications_disabled: 0, + legacy_notifications_disabled: 0, + legacy_notifications_enabled: 0, }, custom_total: { ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, disabled: 1, + notifications_enabled: 0, + notifications_disabled: 0, + legacy_notifications_disabled: 0, + legacy_notifications_enabled: 0, }, }, }, @@ -177,16 +956,23 @@ export default ({ getService }: FtrProviderContext) => { expect(stats).to.eql(expected); }); }); - }); - describe('"threshold" rule type', () => { - it('should show stats for active rule', async () => { - const rule: ThresholdCreateSchema = { - ...getThresholdRuleForSignalTesting(['telemetry']), - threshold: { - field: 'keyword', - value: 1, - }, + it('should show "notifications_enabled", "notifications_disabled" "legacy_notifications_enabled", "legacy_notifications_disabled", all to be "0" for "enabled"/"active" rule that does not have any actions', async () => { + const rule: ThreatMatchCreateSchema = { + ...getSimpleThreatMatch('rule-1', true), + index: ['telemetry'], + threat_index: ['telemetry'], + threat_mapping: [ + { + entries: [ + { + field: 'keyword', + value: 'keyword', + type: 'mapping', + }, + ], + }, + ], }; const { id } = await createRule(supertest, log, rule); await waitForRuleSuccessOrStatus(supertest, log, id); @@ -199,15 +985,23 @@ export default ({ getService }: FtrProviderContext) => { ...getInitialDetectionMetrics().detection_rules, detection_rule_usage: { ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, - threshold: { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.query, + threat_match: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.threat_match, enabled: 1, alerts: 4, + notifications_enabled: 0, + notifications_disabled: 0, + legacy_notifications_disabled: 0, + legacy_notifications_enabled: 0, }, custom_total: { ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, enabled: 1, alerts: 4, + notifications_enabled: 0, + notifications_disabled: 0, + legacy_notifications_disabled: 0, + legacy_notifications_enabled: 0, }, }, }, @@ -216,15 +1010,12 @@ export default ({ getService }: FtrProviderContext) => { }); }); - it('should show stats for in-active rule', async () => { - const rule: ThresholdCreateSchema = { - ...getThresholdRuleForSignalTesting(['telemetry'], 'rule-1', false), - threshold: { - field: 'keyword', - value: 1, - }, - }; - await createRule(supertest, log, rule); + it('should show "notifications_disabled" to be "1" for rule that has at least "1" action(s) and the alert is "disabled"/"in-active"', async () => { + const rule = getSimpleThreatMatch(); + const hookAction = await createNewAction(supertest, log); + const ruleToCreate = getRuleWithWebHookAction(hookAction.id, false, rule); + await createRule(supertest, log, ruleToCreate); + await retry.try(async () => { const stats = await getStats(supertest, log); const expected: DetectionMetrics = { @@ -233,12 +1024,14 @@ export default ({ getService }: FtrProviderContext) => { ...getInitialDetectionMetrics().detection_rules, detection_rule_usage: { ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, - threshold: { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.query, + threat_match: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.threat_match, + notifications_disabled: 1, disabled: 1, }, custom_total: { ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, + notifications_disabled: 1, disabled: 1, }, }, @@ -247,13 +1040,30 @@ export default ({ getService }: FtrProviderContext) => { expect(stats).to.eql(expected); }); }); - }); - describe('"ml" rule type', () => { - // Note: We don't actually find signals with this test as we don't have a good way of signal finding with ML rules. - it('should show stats for active rule', async () => { - const rule = getSimpleMlRule('rule-1', true); - await createRule(supertest, log, rule); + it('should show "notifications_enabled" to be "1" for rule that has at least "1" action(s) and the alert is "enabled"/"active"', async () => { + const rule: ThreatMatchCreateSchema = { + ...getSimpleThreatMatch('rule-1', true), + index: ['telemetry'], + threat_index: ['telemetry'], + threat_mapping: [ + { + entries: [ + { + field: 'keyword', + value: 'keyword', + type: 'mapping', + }, + ], + }, + ], + }; + const hookAction = await createNewAction(supertest, log); + const ruleToCreate = getRuleWithWebHookAction(hookAction.id, true, rule); + const { id } = await createRule(supertest, log, ruleToCreate); + await waitForRuleSuccessOrStatus(supertest, log, id); + await waitForSignalsToBePresent(supertest, log, 4, [id]); + await retry.try(async () => { const stats = await getStats(supertest, log); const expected: DetectionMetrics = { @@ -262,13 +1072,17 @@ export default ({ getService }: FtrProviderContext) => { ...getInitialDetectionMetrics().detection_rules, detection_rule_usage: { ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, - machine_learning: { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.query, + threat_match: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.threat_match, enabled: 1, + alerts: 4, + notifications_enabled: 1, }, custom_total: { ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, enabled: 1, + alerts: 4, + notifications_enabled: 1, }, }, }, @@ -277,9 +1091,12 @@ export default ({ getService }: FtrProviderContext) => { }); }); - it('should show stats for in-active rule', async () => { - const rule = getSimpleMlRule(); - await createRule(supertest, log, rule); + it('should show "legacy_notifications_disabled" to be "1" for rule that has at least "1" legacy action(s) and the alert is "disabled"/"in-active"', async () => { + const rule = getSimpleThreatMatch(); + const { id } = await createRule(supertest, log, rule); + const hookAction = await createNewAction(supertest, log); + await createLegacyRuleAction(supertest, id, hookAction.id); + await retry.try(async () => { const stats = await getStats(supertest, log); const expected: DetectionMetrics = { @@ -288,13 +1105,15 @@ export default ({ getService }: FtrProviderContext) => { ...getInitialDetectionMetrics().detection_rules, detection_rule_usage: { ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, - machine_learning: { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.query, + threat_match: { + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.threat_match, disabled: 1, + legacy_notifications_disabled: 1, }, custom_total: { ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, disabled: 1, + legacy_notifications_disabled: 1, }, }, }, @@ -302,10 +1121,8 @@ export default ({ getService }: FtrProviderContext) => { expect(stats).to.eql(expected); }); }); - }); - describe('"indicator_match/threat_match" rule type', () => { - it('should show stats for active rule', async () => { + it('should show "legacy_notifications_enabled" to be "1" for rule that has at least "1" legacy action(s) and the alert is "enabled"/"active"', async () => { const rule: ThreatMatchCreateSchema = { ...getSimpleThreatMatch('rule-1', true), index: ['telemetry'], @@ -323,8 +1140,11 @@ export default ({ getService }: FtrProviderContext) => { ], }; const { id } = await createRule(supertest, log, rule); + const hookAction = await createNewAction(supertest, log); + await createLegacyRuleAction(supertest, id, hookAction.id); await waitForRuleSuccessOrStatus(supertest, log, id); await waitForSignalsToBePresent(supertest, log, 4, [id]); + await retry.try(async () => { const stats = await getStats(supertest, log); const expected: DetectionMetrics = { @@ -334,40 +1154,16 @@ export default ({ getService }: FtrProviderContext) => { detection_rule_usage: { ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, threat_match: { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.query, - enabled: 1, + ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.threat_match, alerts: 4, - }, - custom_total: { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, enabled: 1, - alerts: 4, - }, - }, - }, - }; - expect(stats).to.eql(expected); - }); - }); - - it('should show stats for in-active rule', async () => { - const rule = getSimpleThreatMatch(); - await createRule(supertest, log, rule); - await retry.try(async () => { - const stats = await getStats(supertest, log); - const expected: DetectionMetrics = { - ...getInitialDetectionMetrics(), - detection_rules: { - ...getInitialDetectionMetrics().detection_rules, - detection_rule_usage: { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage, - threat_match: { - ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.query, - disabled: 1, + legacy_notifications_enabled: 1, }, custom_total: { ...getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total, - disabled: 1, + alerts: 4, + enabled: 1, + legacy_notifications_enabled: 1, }, }, }, @@ -377,7 +1173,7 @@ export default ({ getService }: FtrProviderContext) => { }); }); - describe('"pre-packaged" rules', async () => { + describe('"pre-packaged"/"immutable" rules', async () => { it('should show stats for totals for in-active pre-packaged rules', async () => { await installPrePackagedRules(supertest, log); await retry.try(async () => { @@ -385,12 +1181,33 @@ export default ({ getService }: FtrProviderContext) => { expect(stats.detection_rules.detection_rule_usage.elastic_total.enabled).above(0); expect(stats.detection_rules.detection_rule_usage.elastic_total.disabled).above(0); expect(stats.detection_rules.detection_rule_usage.elastic_total.enabled).above(0); - expect(stats.detection_rules.detection_rule_usage.custom_total.enabled).equal(0); + expect( + stats.detection_rules.detection_rule_usage.elastic_total.legacy_notifications_enabled + ).to.eql(0); + expect( + stats.detection_rules.detection_rule_usage.elastic_total.legacy_notifications_disabled + ).to.eql(0); + expect( + stats.detection_rules.detection_rule_usage.elastic_total.notifications_enabled + ).to.eql(0); + expect( + stats.detection_rules.detection_rule_usage.elastic_total.notifications_disabled + ).to.eql(0); expect(stats.detection_rules.detection_rule_detail.length).above(0); + expect(stats.detection_rules.detection_rule_usage.custom_total).to.eql({ + enabled: 0, + disabled: 0, + alerts: 0, + cases: 0, + legacy_notifications_enabled: 0, + legacy_notifications_disabled: 0, + notifications_enabled: 0, + notifications_disabled: 0, + }); }); }); - it('should show stats for the detection_rule_details for pre-packaged rules', async () => { + it('should show stats for the detection_rule_details for a specific pre-packaged rule', async () => { await installPrePackagedRules(supertest, log); await retry.try(async () => { const stats = await getStats(supertest, log); @@ -402,7 +1219,7 @@ export default ({ getService }: FtrProviderContext) => { (rule) => rule.rule_id === '9a1a2dae-0b5f-4c3d-8305-a268d404c306' ); if (foundRule == null) { - throw new Error('Found rule should not be null'); + throw new Error('Found rule should not be null. Please change this end to end test.'); } const { created_on: createdOn, @@ -418,7 +1235,227 @@ export default ({ getService }: FtrProviderContext) => { elastic_rule: true, alert_count_daily: 0, cases_count_total: 0, + has_notification: false, + has_legacy_notification: false, + }); + }); + }); + + it('should show "notifications_disabled" to be "1" for rule that has at least "1" action(s) and the alert is "disabled"/"in-active"', async () => { + await installPrePackagedRules(supertest, log); + // Rule id of "9a1a2dae-0b5f-4c3d-8305-a268d404c306" is from the file: + // x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/elastic_endpoint_security.json + const immutableRule = await getRule(supertest, log, '9a1a2dae-0b5f-4c3d-8305-a268d404c306'); + const hookAction = await createNewAction(supertest, log); + const newRuleToUpdate = getSimpleRule(immutableRule.rule_id); + const ruleToUpdate = getRuleWithWebHookAction(hookAction.id, false, newRuleToUpdate); + await updateRule(supertest, log, ruleToUpdate); + + await retry.try(async () => { + const stats = await getStats(supertest, log); + + // We have to search by "rule_name" since the "rule_id" it is storing is the Saved Object ID and not the rule_id + const foundRule = stats.detection_rules.detection_rule_detail.find( + (rule) => rule.rule_id === '9a1a2dae-0b5f-4c3d-8305-a268d404c306' + ); + if (foundRule == null) { + throw new Error('Found rule should not be null. Please change this end to end test.'); + } + const { + created_on: createdOn, + updated_on: updatedOn, + rule_id: ruleId, + ...omittedFields + } = foundRule; + expect(omittedFields).to.eql({ + rule_name: 'Simple Rule Query', + rule_type: 'query', + rule_version: 3, + enabled: false, + elastic_rule: true, + alert_count_daily: 0, + cases_count_total: 0, + has_notification: true, + has_legacy_notification: false, + }); + expect( + stats.detection_rules.detection_rule_usage.elastic_total.notifications_disabled + ).to.eql(1); + expect( + stats.detection_rules.detection_rule_usage.elastic_total.legacy_notifications_enabled + ).to.eql(0); + expect( + stats.detection_rules.detection_rule_usage.elastic_total.legacy_notifications_disabled + ).to.eql(0); + expect( + stats.detection_rules.detection_rule_usage.elastic_total.notifications_enabled + ).to.eql(0); + expect(stats.detection_rules.detection_rule_usage.custom_total).to.eql( + getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total + ); + }); + }); + + it('should show "notifications_enabled" to be "1" for rule that has at least "1" action(s) and the alert is "enabled"/"active"', async () => { + await installPrePackagedRules(supertest, log); + // Rule id of "9a1a2dae-0b5f-4c3d-8305-a268d404c306" is from the file: + // x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/elastic_endpoint_security.json + const immutableRule = await getRule(supertest, log, '9a1a2dae-0b5f-4c3d-8305-a268d404c306'); + const hookAction = await createNewAction(supertest, log); + const newRuleToUpdate = getSimpleRule(immutableRule.rule_id); + const ruleToUpdate = getRuleWithWebHookAction(hookAction.id, true, newRuleToUpdate); + await updateRule(supertest, log, ruleToUpdate); + + await retry.try(async () => { + const stats = await getStats(supertest, log); + + // We have to search by "rule_name" since the "rule_id" it is storing is the Saved Object ID and not the rule_id + const foundRule = stats.detection_rules.detection_rule_detail.find( + (rule) => rule.rule_id === '9a1a2dae-0b5f-4c3d-8305-a268d404c306' + ); + if (foundRule == null) { + throw new Error('Found rule should not be null. Please change this end to end test.'); + } + const { + created_on: createdOn, + updated_on: updatedOn, + rule_id: ruleId, + ...omittedFields + } = foundRule; + expect(omittedFields).to.eql({ + rule_name: 'Simple Rule Query', + rule_type: 'query', + rule_version: 3, + enabled: true, + elastic_rule: true, + alert_count_daily: 0, + cases_count_total: 0, + has_notification: true, + has_legacy_notification: false, + }); + expect( + stats.detection_rules.detection_rule_usage.elastic_total.notifications_disabled + ).to.eql(0); + expect( + stats.detection_rules.detection_rule_usage.elastic_total.legacy_notifications_enabled + ).to.eql(0); + expect( + stats.detection_rules.detection_rule_usage.elastic_total.legacy_notifications_disabled + ).to.eql(0); + expect( + stats.detection_rules.detection_rule_usage.elastic_total.notifications_enabled + ).to.eql(1); + expect(stats.detection_rules.detection_rule_usage.custom_total).to.eql( + getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total + ); + }); + }); + + it('should show "legacy_notifications_disabled" to be "1" for rule that has at least "1" action(s) and the alert is "disabled"/"in-active"', async () => { + await installPrePackagedRules(supertest, log); + // Rule id of "9a1a2dae-0b5f-4c3d-8305-a268d404c306" is from the file: + // x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/elastic_endpoint_security.json + const immutableRule = await getRule(supertest, log, '9a1a2dae-0b5f-4c3d-8305-a268d404c306'); + const hookAction = await createNewAction(supertest, log); + const newRuleToUpdate = getSimpleRule(immutableRule.rule_id, false); + await updateRule(supertest, log, newRuleToUpdate); + await createLegacyRuleAction(supertest, immutableRule.id, hookAction.id); + + await retry.try(async () => { + const stats = await getStats(supertest, log); + // We have to search by "rule_name" since the "rule_id" it is storing is the Saved Object ID and not the rule_id + const foundRule = stats.detection_rules.detection_rule_detail.find( + (rule) => rule.rule_id === '9a1a2dae-0b5f-4c3d-8305-a268d404c306' + ); + if (foundRule == null) { + throw new Error('Found rule should not be null. Please change this end to end test.'); + } + const { + created_on: createdOn, + updated_on: updatedOn, + rule_id: ruleId, + ...omittedFields + } = foundRule; + expect(omittedFields).to.eql({ + rule_name: 'Simple Rule Query', + rule_type: 'query', + rule_version: 3, + enabled: false, + elastic_rule: true, + alert_count_daily: 0, + cases_count_total: 0, + has_notification: false, + has_legacy_notification: true, + }); + expect( + stats.detection_rules.detection_rule_usage.elastic_total.notifications_disabled + ).to.eql(0); + expect( + stats.detection_rules.detection_rule_usage.elastic_total.legacy_notifications_enabled + ).to.eql(0); + expect( + stats.detection_rules.detection_rule_usage.elastic_total.legacy_notifications_disabled + ).to.eql(1); + expect( + stats.detection_rules.detection_rule_usage.elastic_total.notifications_enabled + ).to.eql(0); + expect(stats.detection_rules.detection_rule_usage.custom_total).to.eql( + getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total + ); + }); + }); + + it('should show "legacy_notifications_enabled" to be "1" for rule that has at least "1" action(s) and the alert is "enabled"/"active"', async () => { + await installPrePackagedRules(supertest, log); + // Rule id of "9a1a2dae-0b5f-4c3d-8305-a268d404c306" is from the file: + // x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/elastic_endpoint_security.json + const immutableRule = await getRule(supertest, log, '9a1a2dae-0b5f-4c3d-8305-a268d404c306'); + const hookAction = await createNewAction(supertest, log); + const newRuleToUpdate = getSimpleRule(immutableRule.rule_id, true); + await updateRule(supertest, log, newRuleToUpdate); + await createLegacyRuleAction(supertest, immutableRule.id, hookAction.id); + + await retry.try(async () => { + const stats = await getStats(supertest, log); + // We have to search by "rule_name" since the "rule_id" it is storing is the Saved Object ID and not the rule_id + const foundRule = stats.detection_rules.detection_rule_detail.find( + (rule) => rule.rule_id === '9a1a2dae-0b5f-4c3d-8305-a268d404c306' + ); + if (foundRule == null) { + throw new Error('Found rule should not be null. Please change this end to end test.'); + } + const { + created_on: createdOn, + updated_on: updatedOn, + rule_id: ruleId, + ...omittedFields + } = foundRule; + expect(omittedFields).to.eql({ + rule_name: 'Simple Rule Query', + rule_type: 'query', + rule_version: 3, + enabled: true, + elastic_rule: true, + alert_count_daily: 0, + cases_count_total: 0, + has_notification: false, + has_legacy_notification: true, }); + expect( + stats.detection_rules.detection_rule_usage.elastic_total.notifications_disabled + ).to.eql(0); + expect( + stats.detection_rules.detection_rule_usage.elastic_total.legacy_notifications_enabled + ).to.eql(1); + expect( + stats.detection_rules.detection_rule_usage.elastic_total.legacy_notifications_disabled + ).to.eql(0); + expect( + stats.detection_rules.detection_rule_usage.elastic_total.notifications_enabled + ).to.eql(0); + expect(stats.detection_rules.detection_rule_usage.custom_total).to.eql( + getInitialDetectionMetrics().detection_rules.detection_rule_usage.custom_total + ); }); }); }); diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/telemetry/index.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/telemetry/index.ts index 21676d614bb206..cf9db6373033af 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/telemetry/index.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/telemetry/index.ts @@ -13,7 +13,6 @@ export default ({ loadTestFile }: FtrProviderContext): void => { describe('', function () { this.tags('ciGroup11'); loadTestFile(require.resolve('./detection_rules')); - loadTestFile(require.resolve('./legacy_notifications')); }); }); }; diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/telemetry/legacy_notifications.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/telemetry/legacy_notifications.ts deleted file mode 100644 index aa406519e24439..00000000000000 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/telemetry/legacy_notifications.ts +++ /dev/null @@ -1,75 +0,0 @@ -/* - * 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 '../../../common/ftr_provider_context'; -import { - createRule, - createSignalsIndex, - deleteAllAlerts, - deleteSignalsIndex, - getSimpleRule, - getStats, - getWebHookAction, -} from '../../../utils'; - -// eslint-disable-next-line import/no-default-export -export default ({ getService }: FtrProviderContext) => { - const supertest = getService('supertest'); - const log = getService('log'); - const retry = getService('retry'); - - describe('legacy notification telemetry', async () => { - beforeEach(async () => { - await createSignalsIndex(supertest, log); - }); - - afterEach(async () => { - await deleteSignalsIndex(supertest, log); - await deleteAllAlerts(supertest, log); - }); - - it('should have 1 legacy notification when there is a rule on the default', async () => { - // create an connector/action - const { body: hookAction } = await supertest - .post('/api/actions/action') - .set('kbn-xsrf', 'true') - .send(getWebHookAction()) - .expect(200); - - // create a rule without actions - const createRuleBody = await createRule(supertest, log, getSimpleRule('rule-1')); - - // attach the legacy notification - await supertest - .post(`/internal/api/detection/legacy/notifications?alert_id=${createRuleBody.id}`) - .set('kbn-xsrf', 'true') - .send({ - name: 'Legacy notification with one action', - interval: '1h', - actions: [ - { - id: hookAction.id, - group: 'default', - params: { - message: - 'Hourly\nRule {{context.rule.name}} generated {{state.signals_count}} alerts', - }, - actionTypeId: hookAction.actionTypeId, - }, - ], - }) - .expect(200); - - await retry.try(async () => { - const stats = await getStats(supertest, log); - // NOTE: We have to do "above 0" until this bug is fixed: https://github.com/elastic/kibana/issues/122456 because other tests are accumulating non-cleaned up legacy actions/notifications and this number isn't reliable at the moment - expect(stats.detection_rules.detection_rule_usage.legacy_notifications.total).to.above(0); - }); - }); - }); -}; From ec38f00bb192d35e12d4bda280ff9d80f7b3e377 Mon Sep 17 00:00:00 2001 From: Miriam <31922082+MiriamAparicio@users.noreply.github.com> Date: Wed, 19 Jan 2022 18:03:06 +0000 Subject: [PATCH 053/108] [APM] Show rows per page option tables pagination (#122658) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add rows per page on tables * Set page options and default size at shared ManagedTable component * Fixed TransactionsTable, the rows option wasn’t working, use ManagedTable * Fix i18n * Make hidePerPageOptions false by default * fix snapshot * Improvements after PR review --- .../agent_configurations/List/index.tsx | 1 - .../custom_link/custom_link_table.tsx | 1 - .../error_group_list/index.tsx | 1 - .../service_inventory/service_list/index.tsx | 1 - .../app/service_node_overview/index.tsx | 2 - .../components/app/service_overview/index.tsx | 2 + .../index.tsx | 3 + .../app/trace_overview/trace_list.tsx | 1 - .../shared/dependencies_table/index.tsx | 4 +- .../__snapshots__/managed_table.test.tsx.snap | 14 ++++- .../components/shared/managed_table/index.tsx | 8 ++- .../shared/transactions_table/get_columns.tsx | 10 +--- .../shared/transactions_table/index.tsx | 57 +++++-------------- .../translations/translations/ja-JP.json | 1 - .../translations/translations/zh-CN.json | 1 - 15 files changed, 43 insertions(+), 64 deletions(-) diff --git a/x-pack/plugins/apm/public/components/app/Settings/agent_configurations/List/index.tsx b/x-pack/plugins/apm/public/components/app/Settings/agent_configurations/List/index.tsx index 15efd28756b0b6..fc9250973fc307 100644 --- a/x-pack/plugins/apm/public/components/app/Settings/agent_configurations/List/index.tsx +++ b/x-pack/plugins/apm/public/components/app/Settings/agent_configurations/List/index.tsx @@ -245,7 +245,6 @@ export function AgentConfigurationList({ items={configurations} initialSortField="service.name" initialSortDirection="asc" - initialPageSize={20} /> ); diff --git a/x-pack/plugins/apm/public/components/app/Settings/custom_link/custom_link_table.tsx b/x-pack/plugins/apm/public/components/app/Settings/custom_link/custom_link_table.tsx index 5ce98f8b10884c..d2603538d84bfa 100644 --- a/x-pack/plugins/apm/public/components/app/Settings/custom_link/custom_link_table.tsx +++ b/x-pack/plugins/apm/public/components/app/Settings/custom_link/custom_link_table.tsx @@ -119,7 +119,6 @@ export function CustomLinkTable({ items = [], onCustomLinkSelected }: Props) { } items={filteredItems} columns={columns} - initialPageSize={10} initialSortField="@timestamp" initialSortDirection="desc" /> diff --git a/x-pack/plugins/apm/public/components/app/error_group_overview/error_group_list/index.tsx b/x-pack/plugins/apm/public/components/app/error_group_overview/error_group_list/index.tsx index 65681a398d8e65..adeb3b17504447 100644 --- a/x-pack/plugins/apm/public/components/app/error_group_overview/error_group_list/index.tsx +++ b/x-pack/plugins/apm/public/components/app/error_group_overview/error_group_list/index.tsx @@ -233,7 +233,6 @@ function ErrorGroupList({ })} items={mainStatistics} columns={columns} - initialPageSize={25} initialSortField="occurrences" initialSortDirection="desc" sortItems={false} diff --git a/x-pack/plugins/apm/public/components/app/service_inventory/service_list/index.tsx b/x-pack/plugins/apm/public/components/app/service_inventory/service_list/index.tsx index 2d83f1f46bd388..4617daac2ddcf9 100644 --- a/x-pack/plugins/apm/public/components/app/service_inventory/service_list/index.tsx +++ b/x-pack/plugins/apm/public/components/app/service_inventory/service_list/index.tsx @@ -315,7 +315,6 @@ export function ServiceList({ noItemsMessage={noItemsMessage} initialSortField={initialSortField} initialSortDirection="desc" - initialPageSize={50} sortFn={(itemsToSort, sortField, sortDirection) => { // For healthStatus, sort items by healthStatus first, then by TPM return sortField === 'healthStatus' diff --git a/x-pack/plugins/apm/public/components/app/service_node_overview/index.tsx b/x-pack/plugins/apm/public/components/app/service_node_overview/index.tsx index 0436c27cdd6b7b..379632d33a8083 100644 --- a/x-pack/plugins/apm/public/components/app/service_node_overview/index.tsx +++ b/x-pack/plugins/apm/public/components/app/service_node_overview/index.tsx @@ -25,7 +25,6 @@ import { truncate, unit } from '../../../utils/style'; import { ServiceNodeMetricOverviewLink } from '../../shared/links/apm/service_node_metric_overview_link'; import { ITableColumn, ManagedTable } from '../../shared/managed_table'; -const INITIAL_PAGE_SIZE = 25; const INITIAL_SORT_FIELD = 'cpu'; const INITIAL_SORT_DIRECTION = 'desc'; @@ -170,7 +169,6 @@ function ServiceNodeOverview() { })} items={items} columns={columns} - initialPageSize={INITIAL_PAGE_SIZE} initialSortField={INITIAL_SORT_FIELD} initialSortDirection={INITIAL_SORT_DIRECTION} /> diff --git a/x-pack/plugins/apm/public/components/app/service_overview/index.tsx b/x-pack/plugins/apm/public/components/app/service_overview/index.tsx index 9e5508a5810df7..2c30027770f435 100644 --- a/x-pack/plugins/apm/public/components/app/service_overview/index.tsx +++ b/x-pack/plugins/apm/public/components/app/service_overview/index.tsx @@ -118,6 +118,7 @@ export function ServiceOverview() { isSingleColumn={isSingleColumn} start={start} end={end} + hidePerPageOptions={true} /> @@ -164,6 +165,7 @@ export function ServiceOverview() { {i18n.translate( diff --git a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_dependencies_table/index.tsx b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_dependencies_table/index.tsx index cbf60b7b59e4d8..255dfbdeb427a9 100644 --- a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_dependencies_table/index.tsx +++ b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_dependencies_table/index.tsx @@ -24,12 +24,14 @@ interface ServiceOverviewDependenciesTableProps { fixedHeight?: boolean; isSingleColumn?: boolean; link?: ReactNode; + hidePerPageOptions?: boolean; } export function ServiceOverviewDependenciesTable({ fixedHeight, isSingleColumn = true, link, + hidePerPageOptions = false, }: ServiceOverviewDependenciesTableProps) { const { urlParams: { comparisonEnabled, comparisonType, latencyAggregationType }, @@ -139,6 +141,7 @@ export function ServiceOverviewDependenciesTable({ )} status={status} link={link} + hidePerPageOptions={hidePerPageOptions} /> ); } diff --git a/x-pack/plugins/apm/public/components/app/trace_overview/trace_list.tsx b/x-pack/plugins/apm/public/components/app/trace_overview/trace_list.tsx index e5f3c7bcbee4e7..fe09a4784239e2 100644 --- a/x-pack/plugins/apm/public/components/app/trace_overview/trace_list.tsx +++ b/x-pack/plugins/apm/public/components/app/trace_overview/trace_list.tsx @@ -169,7 +169,6 @@ export function TraceList({ items = [], isLoading, isFailure }: Props) { initialSortField="impact" initialSortDirection="desc" noItemsMessage={noItemsMessage} - initialPageSize={25} /> ); } diff --git a/x-pack/plugins/apm/public/components/shared/dependencies_table/index.tsx b/x-pack/plugins/apm/public/components/shared/dependencies_table/index.tsx index 7c2bc722ac1e6b..844957defe67db 100644 --- a/x-pack/plugins/apm/public/components/shared/dependencies_table/index.tsx +++ b/x-pack/plugins/apm/public/components/shared/dependencies_table/index.tsx @@ -45,6 +45,7 @@ interface Props { nameColumnTitle: React.ReactNode; status: FETCH_STATUS; compact?: boolean; + hidePerPageOptions?: boolean; } export function DependenciesTable(props: Props) { @@ -57,6 +58,7 @@ export function DependenciesTable(props: Props) { nameColumnTitle, status, compact = true, + hidePerPageOptions = false, } = props; // SparkPlots should be hidden if we're in two-column view and size XL (1200px) @@ -210,8 +212,8 @@ export function DependenciesTable(props: Props) { noItemsMessage={noItemsMessage} initialSortField="impactValue" initialSortDirection="desc" - initialPageSize={5} pagination={true} + hidePerPageOptions={hidePerPageOptions} /> diff --git a/x-pack/plugins/apm/public/components/shared/managed_table/__snapshots__/managed_table.test.tsx.snap b/x-pack/plugins/apm/public/components/shared/managed_table/__snapshots__/managed_table.test.tsx.snap index 15613af4daf98a..3559ee4afbb82c 100644 --- a/x-pack/plugins/apm/public/components/shared/managed_table/__snapshots__/managed_table.test.tsx.snap +++ b/x-pack/plugins/apm/public/components/shared/managed_table/__snapshots__/managed_table.test.tsx.snap @@ -44,9 +44,14 @@ exports[`ManagedTable should render a page-full of items, with defaults 1`] = ` onChange={[Function]} pagination={ Object { - "hidePerPageOptions": true, + "hidePerPageOptions": false, "pageIndex": 0, - "pageSize": 10, + "pageSize": 25, + "pageSizeOptions": Array [ + 10, + 25, + 50, + ], "totalItemCount": 3, } } @@ -102,6 +107,11 @@ exports[`ManagedTable should render when specifying initial values 1`] = ` "hidePerPageOptions": false, "pageIndex": 1, "pageSize": 2, + "pageSizeOptions": Array [ + 10, + 25, + 50, + ], "totalItemCount": 3, } } diff --git a/x-pack/plugins/apm/public/components/shared/managed_table/index.tsx b/x-pack/plugins/apm/public/components/shared/managed_table/index.tsx index 16ab8cb1d92021..37d55887cd182b 100644 --- a/x-pack/plugins/apm/public/components/shared/managed_table/index.tsx +++ b/x-pack/plugins/apm/public/components/shared/managed_table/index.tsx @@ -47,6 +47,9 @@ interface Props { tableLayout?: 'auto' | 'fixed'; } +const PAGE_SIZE_OPTIONS = [10, 25, 50]; +const INITIAL_PAGE_SIZE = 25; + function defaultSortFn( items: T[], sortField: string, @@ -61,10 +64,10 @@ function UnoptimizedManagedTable(props: Props) { items, columns, initialPageIndex = 0, - initialPageSize = 10, + initialPageSize = INITIAL_PAGE_SIZE, initialSortField = props.columns[0]?.field || '', initialSortDirection = 'asc', - hidePerPageOptions = true, + hidePerPageOptions = false, noItemsMessage, sortItems = true, sortFn = defaultSortFn, @@ -128,6 +131,7 @@ function UnoptimizedManagedTable(props: Props) { totalItemCount: items.length, pageIndex: page, pageSize, + pageSizeOptions: PAGE_SIZE_OPTIONS, }; }, [hidePerPageOptions, items, page, pageSize, pagination]); diff --git a/x-pack/plugins/apm/public/components/shared/transactions_table/get_columns.tsx b/x-pack/plugins/apm/public/components/shared/transactions_table/get_columns.tsx index b6e02b1b08c3cb..49d5e95344ea43 100644 --- a/x-pack/plugins/apm/public/components/shared/transactions_table/get_columns.tsx +++ b/x-pack/plugins/apm/public/components/shared/transactions_table/get_columns.tsx @@ -5,12 +5,7 @@ * 2.0. */ -import { - EuiBasicTableColumn, - EuiFlexGroup, - EuiFlexItem, - RIGHT_ALIGNMENT, -} from '@elastic/eui'; +import { EuiFlexGroup, EuiFlexItem, RIGHT_ALIGNMENT } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import React from 'react'; import { ValuesType } from 'utility-types'; @@ -25,6 +20,7 @@ import { APIReturnType } from '../../../services/rest/createCallApmApi'; import { ImpactBar } from '../impact_bar'; import { TransactionDetailLink } from '../links/apm/transaction_detail_link'; import { ListMetric } from '../list_metric'; +import { ITableColumn } from '../managed_table'; import { TruncateWithTooltip } from '../truncate_with_tooltip'; import { getLatencyColumnLabel } from './get_latency_column_label'; @@ -51,7 +47,7 @@ export function getColumns({ comparisonEnabled?: boolean; shouldShowSparkPlots?: boolean; comparisonType?: TimeRangeComparisonType; -}): Array> { +}): Array> { return [ { field: 'name', diff --git a/x-pack/plugins/apm/public/components/shared/transactions_table/index.tsx b/x-pack/plugins/apm/public/components/shared/transactions_table/index.tsx index f943cf4da4b059..a98eda2d3b9616 100644 --- a/x-pack/plugins/apm/public/components/shared/transactions_table/index.tsx +++ b/x-pack/plugins/apm/public/components/shared/transactions_table/index.tsx @@ -5,12 +5,7 @@ * 2.0. */ -import { - EuiBasicTable, - EuiFlexGroup, - EuiFlexItem, - EuiTitle, -} from '@elastic/eui'; +import { EuiFlexGroup, EuiFlexItem, EuiTitle } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { orderBy } from 'lodash'; import React, { useState } from 'react'; @@ -28,6 +23,7 @@ import { OverviewTableContainer } from '../overview_table_container'; import { getColumns } from './get_columns'; import { ElasticDocsLink } from '../links/elastic_docs_link'; import { useBreakpoints } from '../../../hooks/use_breakpoints'; +import { ManagedTable } from '../managed_table'; type ApiResponse = APIReturnType<'GET /internal/apm/services/{serviceName}/transactions/groups/main_statistics'>; @@ -60,6 +56,7 @@ interface Props { hideViewTransactionsLink?: boolean; isSingleColumn?: boolean; numberOfTransactionsPerPage?: number; + hidePerPageOptions?: boolean; showAggregationAccurateCallout?: boolean; environment: string; fixedHeight?: boolean; @@ -73,13 +70,14 @@ export function TransactionsTable({ hideViewTransactionsLink = false, isSingleColumn = true, numberOfTransactionsPerPage = 5, + hidePerPageOptions = false, showAggregationAccurateCallout = false, environment, kuery, start, end, }: Props) { - const [tableOptions, setTableOptions] = useState<{ + const [tableOptions] = useState<{ pageIndex: number; sort: { direction: SortDirection; @@ -228,13 +226,6 @@ export function TransactionsTable({ const isLoading = status === FETCH_STATUS.LOADING; const isNotInitiated = status === FETCH_STATUS.NOT_INITIATED; - const pagination = { - pageIndex, - pageSize: numberOfTransactionsPerPage, - totalItemCount: transactionGroupsTotalItems, - hidePerPageOptions: true, - }; - return ( @@ -309,7 +300,14 @@ export function TransactionsTable({ transactionGroupsTotalItems === 0 && isNotInitiated } > - { - setTableOptions({ - pageIndex: newTableOptions.page?.index ?? 0, - sort: newTableOptions.sort - ? { - field: newTableOptions.sort.field as SortField, - direction: newTableOptions.sort.direction, - } - : DEFAULT_SORT, - }); - }} + hidePerPageOptions={hidePerPageOptions} /> diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 9a3bdd0ad0df57..42fd880311a589 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -6231,7 +6231,6 @@ "xpack.apm.transactionsTable.cardinalityWarning.body": "一意のトランザクション名の数が構成された値{bucketSize}を超えています。エージェントを再構成し、類似したトランザクションをグループ化するか、{codeBlock}の値を増やしてください。", "xpack.apm.transactionsTable.cardinalityWarning.docsLink": "詳細はドキュメントをご覧ください", "xpack.apm.transactionsTable.cardinalityWarning.title": "このビューには、報告されたトランザクションのサブセットが表示されます。", - "xpack.apm.transactionsTable.errorMessage": "取得できませんでした", "xpack.apm.transactionsTable.linkText": "トランザクションを表示", "xpack.apm.transactionsTable.loading": "読み込み中...", "xpack.apm.transactionsTable.noResults": "トランザクショングループが見つかりません", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index eaf7f9f33edadf..2fe7805f64259a 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -6275,7 +6275,6 @@ "xpack.apm.transactionsTable.cardinalityWarning.body": "唯一事务名称的数目超过 {bucketSize} 的已配置值。尝试重新配置您的代理以对类似的事务分组或增大 {codeBlock} 的值", "xpack.apm.transactionsTable.cardinalityWarning.docsLink": "在文档中了解详情", "xpack.apm.transactionsTable.cardinalityWarning.title": "此视图显示已报告事务的子集。", - "xpack.apm.transactionsTable.errorMessage": "无法提取", "xpack.apm.transactionsTable.linkText": "查看事务", "xpack.apm.transactionsTable.loading": "正在加载……", "xpack.apm.transactionsTable.noResults": "未找到事务组", From 8dc224432154d703af50f68c4b33904883a286a3 Mon Sep 17 00:00:00 2001 From: Miriam <31922082+MiriamAparicio@users.noreply.github.com> Date: Wed, 19 Jan 2022 18:14:10 +0000 Subject: [PATCH 054/108] Create flag for the infrastructure view (#123159) * Create flag for the infrastructure view * added keys to schema and types * update telemetry schema * Change in copy, import key to the apm-services-template * fix import --- .../server/collectors/management/schema.ts | 4 ++++ .../server/collectors/management/types.ts | 1 + src/plugins/telemetry/schema/oss_plugins.json | 6 ++++++ .../templates/apm_service_template/index.tsx | 5 ++++- x-pack/plugins/observability/common/index.ts | 1 + .../observability/common/ui_settings_keys.ts | 1 + x-pack/plugins/observability/public/index.ts | 7 +++++-- x-pack/plugins/observability/server/ui_settings.ts | 14 +++++++++++++- 8 files changed, 35 insertions(+), 4 deletions(-) diff --git a/src/plugins/kibana_usage_collection/server/collectors/management/schema.ts b/src/plugins/kibana_usage_collection/server/collectors/management/schema.ts index c2a4f18218dd47..27e44cba1094f0 100644 --- a/src/plugins/kibana_usage_collection/server/collectors/management/schema.ts +++ b/src/plugins/kibana_usage_collection/server/collectors/management/schema.ts @@ -428,6 +428,10 @@ export const stackManagementSchema: MakeSchemaFrom = { type: 'boolean', _meta: { description: 'Non-default value of setting.' }, }, + 'observability:enableInfrastructureView': { + type: 'boolean', + _meta: { description: 'Non-default value of setting.' }, + }, 'banners:placement': { type: 'keyword', _meta: { description: 'Non-default value of setting.' }, diff --git a/src/plugins/kibana_usage_collection/server/collectors/management/types.ts b/src/plugins/kibana_usage_collection/server/collectors/management/types.ts index 69ed647f0845a0..8776bad89f8a60 100644 --- a/src/plugins/kibana_usage_collection/server/collectors/management/types.ts +++ b/src/plugins/kibana_usage_collection/server/collectors/management/types.ts @@ -39,6 +39,7 @@ export interface UsageStats { 'observability:enableInspectEsQueries': boolean; 'observability:maxSuggestions': number; 'observability:enableComparisonByDefault': boolean; + 'observability:enableInfrastructureView': boolean; 'visualize:enableLabs': boolean; 'visualization:heatmap:maxBuckets': number; 'visualization:colorMapping': string; diff --git a/src/plugins/telemetry/schema/oss_plugins.json b/src/plugins/telemetry/schema/oss_plugins.json index 4641d271b3e4f6..9c2c71898dee72 100644 --- a/src/plugins/telemetry/schema/oss_plugins.json +++ b/src/plugins/telemetry/schema/oss_plugins.json @@ -7790,6 +7790,12 @@ "description": "Non-default value of setting." } }, + "observability:enableInfrastructureView": { + "type": "boolean", + "_meta": { + "description": "Non-default value of setting." + } + }, "banners:placement": { "type": "keyword", "_meta": { diff --git a/x-pack/plugins/apm/public/components/routing/templates/apm_service_template/index.tsx b/x-pack/plugins/apm/public/components/routing/templates/apm_service_template/index.tsx index 962fbb4eb6be6d..93c222164f0260 100644 --- a/x-pack/plugins/apm/public/components/routing/templates/apm_service_template/index.tsx +++ b/x-pack/plugins/apm/public/components/routing/templates/apm_service_template/index.tsx @@ -15,6 +15,7 @@ import { import { i18n } from '@kbn/i18n'; import { omit } from 'lodash'; import React from 'react'; +import { enableInfrastructureView } from '../../../../../../observability/public'; import { isIosAgentName, isJavaAgentName, @@ -159,7 +160,8 @@ export function isJVMsTabHidden({ function useTabs({ selectedTab }: { selectedTab: Tab['key'] }) { const { agentName, runtimeName } = useApmServiceContext(); - const { config } = useApmPluginContext(); + const { config, core } = useApmPluginContext(); + const showInfraTab = core.uiSettings.get(enableInfrastructureView); const router = useApmRouter(); @@ -250,6 +252,7 @@ function useTabs({ selectedTab }: { selectedTab: Tab['key'] }) { label: i18n.translate('xpack.apm.home.infraTabLabel', { defaultMessage: 'Infrastructure', }), + hidden: !showInfraTab, }, { key: 'service-map', diff --git a/x-pack/plugins/observability/common/index.ts b/x-pack/plugins/observability/common/index.ts index 03860fd3cd1227..4f303390e1e1b2 100644 --- a/x-pack/plugins/observability/common/index.ts +++ b/x-pack/plugins/observability/common/index.ts @@ -10,6 +10,7 @@ export { enableInspectEsQueries, maxSuggestions, enableComparisonByDefault, + enableInfrastructureView, } from './ui_settings_keys'; export const casesFeatureId = 'observabilityCases'; diff --git a/x-pack/plugins/observability/common/ui_settings_keys.ts b/x-pack/plugins/observability/common/ui_settings_keys.ts index 4d34e216a017c0..ea8a2f20ea4e78 100644 --- a/x-pack/plugins/observability/common/ui_settings_keys.ts +++ b/x-pack/plugins/observability/common/ui_settings_keys.ts @@ -8,3 +8,4 @@ export const enableInspectEsQueries = 'observability:enableInspectEsQueries'; export const maxSuggestions = 'observability:maxSuggestions'; export const enableComparisonByDefault = 'observability:enableComparisonByDefault'; +export const enableInfrastructureView = 'observability:enableInfrastructureView'; diff --git a/x-pack/plugins/observability/public/index.ts b/x-pack/plugins/observability/public/index.ts index e502cf7fb37e0c..d855d0178192ed 100644 --- a/x-pack/plugins/observability/public/index.ts +++ b/x-pack/plugins/observability/public/index.ts @@ -23,7 +23,11 @@ export type { ObservabilityPublicPluginsSetup, ObservabilityPublicPluginsStart, }; -export { enableInspectEsQueries } from '../common/ui_settings_keys'; +export { + enableInspectEsQueries, + enableComparisonByDefault, + enableInfrastructureView, +} from '../common/ui_settings_keys'; export { uptimeOverviewLocatorID } from '../common'; export interface ConfigSchema { @@ -94,7 +98,6 @@ export type { AddInspectorRequest } from './context/inspector/inspector_context' export { InspectorContextProvider } from './context/inspector/inspector_context'; export { useInspectorContext } from './context/inspector/use_inspector_context'; -export { enableComparisonByDefault } from '../common/ui_settings_keys'; export type { SeriesConfig, ConfigProps } from './components/shared/exploratory_view/types'; export { ReportTypes, diff --git a/x-pack/plugins/observability/server/ui_settings.ts b/x-pack/plugins/observability/server/ui_settings.ts index ad0aa31542e8c7..8d37398b8a07b0 100644 --- a/x-pack/plugins/observability/server/ui_settings.ts +++ b/x-pack/plugins/observability/server/ui_settings.ts @@ -13,6 +13,7 @@ import { enableComparisonByDefault, enableInspectEsQueries, maxSuggestions, + enableInfrastructureView, } from '../common/ui_settings_keys'; /** @@ -48,7 +49,18 @@ export const uiSettings: Record> = { }), value: true, description: i18n.translate('xpack.observability.enableComparisonByDefaultDescription', { - defaultMessage: 'Enable the comparison feature on APM UI', + defaultMessage: 'Enable the comparison feature in APM app', + }), + schema: schema.boolean(), + }, + [enableInfrastructureView]: { + category: [observabilityFeatureId], + name: i18n.translate('xpack.observability.enableInfrastructureView', { + defaultMessage: 'Infrastructure feature', + }), + value: true, + description: i18n.translate('xpack.observability.enableInfrastructureViewDescription', { + defaultMessage: 'Enable the Infrastruture view feature in APM app', }), schema: schema.boolean(), }, From d7dbf159194d752622bf6bad1395f68b6e881be0 Mon Sep 17 00:00:00 2001 From: Nicolas Chaulet Date: Wed, 19 Jan 2022 13:20:32 -0500 Subject: [PATCH 055/108] [Fleet] Validate package policy on create or update APIs (#123261) --- .../fleet/server/services/package_policy.ts | 53 +++++++------ .../log/agent/stream/stream.yml.hbs | 1 + .../0.1.0/data_stream/log/fields/fields.yml | 16 ++++ .../0.1.0/data_stream/log/manifest.yml | 15 ++++ .../0.1.0/docs/README.md | 5 ++ .../0.1.0/img/logo.svg | 7 ++ .../img/screenshots/metricbeat_dashboard.png | Bin 0 -> 94863 bytes .../0.1.0/manifest.yml | 41 ++++++++++ .../apis/package_policy/create.ts | 75 ++++++++++++++++++ .../apis/package_policy/upgrade.ts | 8 +- 10 files changed, 197 insertions(+), 24 deletions(-) create mode 100644 x-pack/test/fleet_api_integration/apis/fixtures/test_packages/with_required_variables/0.1.0/data_stream/log/agent/stream/stream.yml.hbs create mode 100644 x-pack/test/fleet_api_integration/apis/fixtures/test_packages/with_required_variables/0.1.0/data_stream/log/fields/fields.yml create mode 100644 x-pack/test/fleet_api_integration/apis/fixtures/test_packages/with_required_variables/0.1.0/data_stream/log/manifest.yml create mode 100644 x-pack/test/fleet_api_integration/apis/fixtures/test_packages/with_required_variables/0.1.0/docs/README.md create mode 100644 x-pack/test/fleet_api_integration/apis/fixtures/test_packages/with_required_variables/0.1.0/img/logo.svg create mode 100644 x-pack/test/fleet_api_integration/apis/fixtures/test_packages/with_required_variables/0.1.0/img/screenshots/metricbeat_dashboard.png create mode 100644 x-pack/test/fleet_api_integration/apis/fixtures/test_packages/with_required_variables/0.1.0/manifest.yml diff --git a/x-pack/plugins/fleet/server/services/package_policy.ts b/x-pack/plugins/fleet/server/services/package_policy.ts index 5591c165bd7063..1ad4ff1adbdd09 100644 --- a/x-pack/plugins/fleet/server/services/package_policy.ts +++ b/x-pack/plugins/fleet/server/services/package_policy.ts @@ -157,8 +157,10 @@ class PackagePolicyService { ); } } + validatePackagePolicyOrThrow(packagePolicy, pkgInfo); const registryPkgInfo = await Registry.fetchInfo(pkgInfo.name, pkgInfo.version); + inputs = await this._compilePackagePolicyInputs( registryPkgInfo, pkgInfo, @@ -392,6 +394,8 @@ class PackagePolicyService { pkgVersion: packagePolicy.package.version, }); + validatePackagePolicyOrThrow(packagePolicy, pkgInfo); + const registryPkgInfo = await Registry.fetchInfo(pkgInfo.name, pkgInfo.version); inputs = await this._compilePackagePolicyInputs( registryPkgInfo, @@ -865,6 +869,31 @@ class PackagePolicyService { } } +function validatePackagePolicyOrThrow(packagePolicy: NewPackagePolicy, pkgInfo: PackageInfo) { + const validationResults = validatePackagePolicy(packagePolicy, pkgInfo, safeLoad); + if (validationHasErrors(validationResults)) { + const responseFormattedValidationErrors = Object.entries(getFlattenedObject(validationResults)) + .map(([key, value]) => ({ + key, + message: value, + })) + .filter(({ message }) => !!message); + + if (responseFormattedValidationErrors.length) { + throw new PackagePolicyValidationError( + i18n.translate('xpack.fleet.packagePolicyInvalidError', { + defaultMessage: 'Package policy is invalid: {errors}', + values: { + errors: responseFormattedValidationErrors + .map(({ key, message }) => `${key}: ${message}`) + .join('\n'), + }, + }) + ); + } + } +} + function assignStreamIdToInput(packagePolicyId: string, input: NewPackagePolicyInput) { return { ...input, @@ -1314,29 +1343,7 @@ export function preconfigurePackageInputs( inputs, }; - const validationResults = validatePackagePolicy(resultingPackagePolicy, packageInfo, safeLoad); - - if (validationHasErrors(validationResults)) { - const responseFormattedValidationErrors = Object.entries(getFlattenedObject(validationResults)) - .map(([key, value]) => ({ - key, - message: value, - })) - .filter(({ message }) => !!message); - - if (responseFormattedValidationErrors.length) { - throw new PackagePolicyValidationError( - i18n.translate('xpack.fleet.packagePolicyInvalidError', { - defaultMessage: 'Package policy is invalid: {errors}', - values: { - errors: responseFormattedValidationErrors - .map(({ key, message }) => `${key}: ${message}`) - .join('\n'), - }, - }) - ); - } - } + validatePackagePolicyOrThrow(resultingPackagePolicy, packageInfo); return resultingPackagePolicy; } diff --git a/x-pack/test/fleet_api_integration/apis/fixtures/test_packages/with_required_variables/0.1.0/data_stream/log/agent/stream/stream.yml.hbs b/x-pack/test/fleet_api_integration/apis/fixtures/test_packages/with_required_variables/0.1.0/data_stream/log/agent/stream/stream.yml.hbs new file mode 100644 index 00000000000000..2870385f21f959 --- /dev/null +++ b/x-pack/test/fleet_api_integration/apis/fixtures/test_packages/with_required_variables/0.1.0/data_stream/log/agent/stream/stream.yml.hbs @@ -0,0 +1 @@ +config.version: "2" diff --git a/x-pack/test/fleet_api_integration/apis/fixtures/test_packages/with_required_variables/0.1.0/data_stream/log/fields/fields.yml b/x-pack/test/fleet_api_integration/apis/fixtures/test_packages/with_required_variables/0.1.0/data_stream/log/fields/fields.yml new file mode 100644 index 00000000000000..6e003ed0ad1476 --- /dev/null +++ b/x-pack/test/fleet_api_integration/apis/fixtures/test_packages/with_required_variables/0.1.0/data_stream/log/fields/fields.yml @@ -0,0 +1,16 @@ +- name: data_stream.type + type: constant_keyword + description: > + Data stream type. +- name: data_stream.dataset + type: constant_keyword + description: > + Data stream dataset. +- name: data_stream.namespace + type: constant_keyword + description: > + Data stream namespace. +- name: '@timestamp' + type: date + description: > + Event timestamp. diff --git a/x-pack/test/fleet_api_integration/apis/fixtures/test_packages/with_required_variables/0.1.0/data_stream/log/manifest.yml b/x-pack/test/fleet_api_integration/apis/fixtures/test_packages/with_required_variables/0.1.0/data_stream/log/manifest.yml new file mode 100644 index 00000000000000..0b1ae9c6cb9959 --- /dev/null +++ b/x-pack/test/fleet_api_integration/apis/fixtures/test_packages/with_required_variables/0.1.0/data_stream/log/manifest.yml @@ -0,0 +1,15 @@ +title: Test stream +type: logs +streams: + - input: test_input + vars: + - name: test_var_required + type: string + title: Test Var + required: true + show_user: true + - name: test_var + type: string + title: Test Var + required: false + show_user: true diff --git a/x-pack/test/fleet_api_integration/apis/fixtures/test_packages/with_required_variables/0.1.0/docs/README.md b/x-pack/test/fleet_api_integration/apis/fixtures/test_packages/with_required_variables/0.1.0/docs/README.md new file mode 100644 index 00000000000000..d6cfcce90527cb --- /dev/null +++ b/x-pack/test/fleet_api_integration/apis/fixtures/test_packages/with_required_variables/0.1.0/docs/README.md @@ -0,0 +1,5 @@ +# filetest + +This package contains randomly collected files from other packages to be used in API integration tests. + +It also serves as an example how to serve a package from the fixtures directory with the package registry docker container. For this, also see the `x-pack/test/fleet_api_integration/config.ts` how the `test_packages` directory is mounted into the docker container, and `x-pack/test/fleet_api_integration/apis/fixtures/package_registry_config.yml` how to pass the directory to the registry. diff --git a/x-pack/test/fleet_api_integration/apis/fixtures/test_packages/with_required_variables/0.1.0/img/logo.svg b/x-pack/test/fleet_api_integration/apis/fixtures/test_packages/with_required_variables/0.1.0/img/logo.svg new file mode 100644 index 00000000000000..15b49bcf28aec2 --- /dev/null +++ b/x-pack/test/fleet_api_integration/apis/fixtures/test_packages/with_required_variables/0.1.0/img/logo.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/x-pack/test/fleet_api_integration/apis/fixtures/test_packages/with_required_variables/0.1.0/img/screenshots/metricbeat_dashboard.png b/x-pack/test/fleet_api_integration/apis/fixtures/test_packages/with_required_variables/0.1.0/img/screenshots/metricbeat_dashboard.png new file mode 100644 index 0000000000000000000000000000000000000000..76d414b86c4ab447ba7334e7a4797ae7e137a4f4 GIT binary patch literal 94863 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

pKP@oJqhb%^lSm%Gaw$mvo9c$gO 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 SqSbLwN5Rw8&t;ucLK6TtSdwJ` literal 0 HcmV?d00001 diff --git a/x-pack/test/fleet_api_integration/apis/fixtures/test_packages/with_required_variables/0.1.0/manifest.yml b/x-pack/test/fleet_api_integration/apis/fixtures/test_packages/with_required_variables/0.1.0/manifest.yml new file mode 100644 index 00000000000000..f1ed5a8a5a78ba --- /dev/null +++ b/x-pack/test/fleet_api_integration/apis/fixtures/test_packages/with_required_variables/0.1.0/manifest.yml @@ -0,0 +1,41 @@ +format_version: 1.0.0 +name: with_required_variables +title: Package with variables +description: This is a package. +version: 0.1.0 +categories: [] +# Options are experimental, beta, ga +release: beta +# The package type. The options for now are [integration, solution], more type might be added in the future. +# The default type is integration and will be set if empty. +type: integration +license: basic +# This package can be removed +removable: true + +requirement: + elasticsearch: + versions: ">7.7.0" + kibana: + versions: ">7.7.0" + +screenshots: +- src: "/img/screenshots/metricbeat_dashboard.png" + title: "metricbeat dashboard" + size: "1855x949" + type: "image/png" +icons: + - src: "/img/logo.svg" + size: "16x16" + type: "image/svg+xml" + + +policy_templates: + - name: with_required_variables + title: Package Policy Upgrade + description: Test Package for Upgrading Package Policies + inputs: + - type: test_input + title: Test Input + description: Test Input + enabled: true \ No newline at end of file diff --git a/x-pack/test/fleet_api_integration/apis/package_policy/create.ts b/x-pack/test/fleet_api_integration/apis/package_policy/create.ts index 1815ab91b53165..75d5c58d8e3759 100644 --- a/x-pack/test/fleet_api_integration/apis/package_policy/create.ts +++ b/x-pack/test/fleet_api_integration/apis/package_policy/create.ts @@ -324,5 +324,80 @@ export default function (providerContext: FtrProviderContext) { }) .expect(400); }); + + it('should return a 400 with required variables not provided', async function () { + const { body } = await supertest + .post(`/api/fleet/package_policies`) + .set('kbn-xsrf', 'xxxx') + .send({ + name: 'pacakge-policy-required-variables-test-456', + description: '', + namespace: 'default', + policy_id: agentPolicyId, + enabled: true, + output_id: '', + inputs: [ + { + enabled: true, + streams: [ + { + data_stream: { + dataset: 'with_required_variables.log', + type: 'logs', + }, + enabled: true, + vars: {}, + }, + ], + type: 'test_input', + }, + ], + package: { + name: 'with_required_variables', + version: '0.1.0', + }, + }) + .expect(400); + expect(body.message).contain('Package policy is invalid'); + }); + + it('should work with required variables provided', async function () { + await supertest + .post(`/api/fleet/package_policies`) + .set('kbn-xsrf', 'xxxx') + .send({ + name: 'pacakge-policy-required-variables-test-123', + description: '', + namespace: 'default', + policy_id: agentPolicyId, + enabled: true, + output_id: '', + inputs: [ + { + enabled: true, + streams: [ + { + data_stream: { + dataset: 'with_required_variables.log', + type: 'logs', + }, + enabled: true, + vars: { + test_var_required: { + value: 'I am required', + }, + }, + }, + ], + type: 'test_input', + }, + ], + package: { + name: 'with_required_variables', + version: '0.1.0', + }, + }) + .expect(200); + }); }); } diff --git a/x-pack/test/fleet_api_integration/apis/package_policy/upgrade.ts b/x-pack/test/fleet_api_integration/apis/package_policy/upgrade.ts index 727a779178bb35..0ccbb913f0d10c 100644 --- a/x-pack/test/fleet_api_integration/apis/package_policy/upgrade.ts +++ b/x-pack/test/fleet_api_integration/apis/package_policy/upgrade.ts @@ -841,6 +841,7 @@ export default function (providerContext: FtrProviderContext) { policy_template: 'package_policy_upgrade', type: 'test_input_new_2', enabled: true, + vars: {}, streams: [ { id: 'test-package_policy_upgrade-xxxx', @@ -850,6 +851,12 @@ export default function (providerContext: FtrProviderContext) { dataset: 'package_policy_upgrade.test_stream_new_2', }, vars: { + test_input_new_2_var_1: { + value: 'Test input value 1', + }, + test_input_new_2_var_2: { + value: 'Test input value 2', + }, test_var_new_2_var_1: { value: 'Test value 1', }, @@ -867,7 +874,6 @@ export default function (providerContext: FtrProviderContext) { version: '0.5.0-restructure-inputs', }, }); - packagePolicyId = packagePolicyResponse.item.id; }); From bdb3ce465f5d56da97e2a8342fc1e8528e92109d Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Wed, 19 Jan 2022 11:50:25 -0700 Subject: [PATCH 056/108] [maps] fetch geometry from fields API (#122431) * [maps] fetch geometry from fields API * tslint, eslint * fix elasticsearch_geo_utils unit test * more clean up of unit test * i18n * clean up * eslint * update functional test expects * eslint * remove unused turfCircle import Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- package.json | 1 - .../elasticsearch_geo_utils.test.js | 148 +++++++++++------- .../elasticsearch_geo_utils.ts | 145 ++++------------- .../es_search_source/es_search_source.tsx | 18 ++- .../translations/translations/ja-JP.json | 2 - .../translations/translations/zh-CN.json | 2 - .../test/functional/apps/maps/mvt_scaling.js | 2 +- yarn.lock | 36 +---- 8 files changed, 146 insertions(+), 208 deletions(-) diff --git a/package.json b/package.json index 07b75529823065..429d1ea67e73f2 100644 --- a/package.json +++ b/package.json @@ -411,7 +411,6 @@ "venn.js": "0.2.20", "vinyl": "^2.2.0", "vt-pbf": "^3.1.1", - "wellknown": "^0.5.0", "whatwg-fetch": "^3.0.0", "xml2js": "^0.4.22", "yauzl": "^2.10.0" diff --git a/x-pack/plugins/maps/common/elasticsearch_util/elasticsearch_geo_utils.test.js b/x-pack/plugins/maps/common/elasticsearch_util/elasticsearch_geo_utils.test.js index d4fcab060b01c0..096f5370ca3b97 100644 --- a/x-pack/plugins/maps/common/elasticsearch_util/elasticsearch_geo_utils.test.js +++ b/x-pack/plugins/maps/common/elasticsearch_util/elasticsearch_geo_utils.test.js @@ -42,14 +42,24 @@ describe('hitsToGeoJson', () => { _id: 'doc1', _index: 'index1', fields: { - [geoFieldName]: '20,100', + [geoFieldName]: [ + { + type: 'Point', + coordinates: [100, 20], + }, + ], }, }, { _id: 'doc2', _index: 'index1', - _source: { - [geoFieldName]: '30,110', + fields: { + [geoFieldName]: [ + { + type: 'Point', + coordinates: [110, 30], + }, + ], }, }, ]; @@ -73,12 +83,17 @@ describe('hitsToGeoJson', () => { it('Should handle documents where geoField is not populated', () => { const hits = [ { - _source: { - [geoFieldName]: '20,100', + fields: { + [geoFieldName]: [ + { + type: 'Point', + coordinates: [100, 20], + }, + ], }, }, { - _source: {}, + fields: {}, }, ]; const geojson = hitsToGeoJson(hits, flattenHitMock, geoFieldName, 'geo_point', []); @@ -90,10 +105,15 @@ describe('hitsToGeoJson', () => { const hits = [ { _source: { - [geoFieldName]: '20,100', myField: 8, }, fields: { + [geoFieldName]: [ + { + type: 'Point', + coordinates: [100, 20], + }, + ], myScriptedField: 10, }, }, @@ -109,8 +129,17 @@ describe('hitsToGeoJson', () => { { _id: 'doc1', _index: 'index1', - _source: { - [geoFieldName]: ['20,100', '30,110'], + fields: { + [geoFieldName]: [ + { + type: 'Point', + coordinates: [100, 20], + }, + { + type: 'Point', + coordinates: [110, 30], + }, + ], myField: 8, }, }, @@ -151,15 +180,15 @@ describe('hitsToGeoJson', () => { { _id: 'doc1', _index: 'index1', - _source: { + fields: { [geoFieldName]: { type: 'GeometryCollection', geometries: [ { - type: 'geometrycollection', //explicitly test coercion to proper GeoJson type value + type: 'geometrycollection', geometries: [ { - type: 'point', //explicitly test coercion to proper GeoJson type value + type: 'Point', coordinates: [0, 0], }, ], @@ -216,8 +245,11 @@ describe('hitsToGeoJson', () => { { _id: 'doc1', _index: 'index1', - _source: { - [geoFieldName]: '20,100', + fields: { + [geoFieldName]: { + type: 'Point', + coordinates: [100, 20], + }, myDateField: '1587156257081', }, }, @@ -234,16 +266,21 @@ describe('hitsToGeoJson', () => { const geoFieldName = 'my.location'; const indexPatternFlattenHit = (hit) => { return { - [geoFieldName]: _.get(hit._source, geoFieldName), + [geoFieldName]: _.get(hit.fields, geoFieldName), }; }; it('Should handle geoField being an object', () => { const hits = [ { - _source: { + fields: { my: { - location: '20,100', + location: [ + { + type: 'Point', + coordinates: [100, 20], + }, + ], }, }, }, @@ -258,8 +295,13 @@ describe('hitsToGeoJson', () => { it('Should handle geoField containing dot in the name', () => { const hits = [ { - _source: { - ['my.location']: '20,100', + fields: { + ['my.location']: [ + { + type: 'Point', + coordinates: [100, 20], + }, + ], }, }, ]; @@ -273,15 +315,25 @@ describe('hitsToGeoJson', () => { it('Should not modify results of flattenHit', () => { const geoFieldName = 'location'; const cachedProperities = { - [geoFieldName]: '20,100', + [geoFieldName]: [ + { + type: 'Point', + coordinates: [100, 20], + }, + ], }; const cachedFlattenHit = () => { return cachedProperities; }; const hits = [ { - _source: { - [geoFieldName]: '20,100', + fields: { + [geoFieldName]: [ + { + type: 'Point', + coordinates: [100, 20], + }, + ], }, }, ]; @@ -296,8 +348,11 @@ describe('geoPointToGeometry', () => { const lat = 41.12; const lon = -71.34; - it('Should convert single docvalue_field', () => { - const value = `${lat},${lon}`; + it('Should convert value', () => { + const value = { + type: 'Point', + coordinates: [lon, lat], + }; const points = []; geoPointToGeometry(value, points); expect(points.length).toBe(1); @@ -305,10 +360,19 @@ describe('geoPointToGeometry', () => { expect(points[0].coordinates).toEqual([lon, lat]); }); - it('Should convert multiple docvalue_fields', () => { + it('Should convert array of values', () => { const lat2 = 30; const lon2 = -60; - const value = [`${lat},${lon}`, `${lat2},${lon2}`]; + const value = [ + { + type: 'Point', + coordinates: [lon, lat], + }, + { + type: 'Point', + coordinates: [lon2, lat2], + }, + ]; const points = []; geoPointToGeometry(value, points); expect(points.length).toBe(2); @@ -318,13 +382,13 @@ describe('geoPointToGeometry', () => { }); describe('geoShapeToGeometry', () => { - it('Should convert value stored as geojson', () => { + it('Should convert value', () => { const coordinates = [ [-77.03653, 38.897676], [-77.009051, 38.889939], ]; const value = { - type: 'linestring', + type: 'LineString', coordinates: coordinates, }; const shapes = []; @@ -340,7 +404,7 @@ describe('geoShapeToGeometry', () => { [101.0, 0.0], ]; const value = { - type: 'envelope', + type: 'Envelope', coordinates: coordinates, }; const shapes = []; @@ -366,11 +430,11 @@ describe('geoShapeToGeometry', () => { const pointCoordinates = [125.6, 10.1]; const value = [ { - type: 'linestring', + type: 'LineString', coordinates: linestringCoordinates, }, { - type: 'point', + type: 'Point', coordinates: pointCoordinates, }, ]; @@ -382,28 +446,6 @@ describe('geoShapeToGeometry', () => { expect(shapes[1].type).toBe('Point'); expect(shapes[1].coordinates).toEqual(pointCoordinates); }); - - it('Should convert wkt shapes to geojson', () => { - const pointWkt = 'POINT (32 40)'; - const linestringWkt = 'LINESTRING (50 60, 70 80)'; - - const shapes = []; - geoShapeToGeometry(pointWkt, shapes); - geoShapeToGeometry(linestringWkt, shapes); - - expect(shapes.length).toBe(2); - expect(shapes[0]).toEqual({ - coordinates: [32, 40], - type: 'Point', - }); - expect(shapes[1]).toEqual({ - coordinates: [ - [50, 60], - [70, 80], - ], - type: 'LineString', - }); - }); }); describe('roundCoordinates', () => { diff --git a/x-pack/plugins/maps/common/elasticsearch_util/elasticsearch_geo_utils.ts b/x-pack/plugins/maps/common/elasticsearch_util/elasticsearch_geo_utils.ts index 98782e7447b348..3e494976787447 100644 --- a/x-pack/plugins/maps/common/elasticsearch_util/elasticsearch_geo_utils.ts +++ b/x-pack/plugins/maps/common/elasticsearch_util/elasticsearch_geo_utils.ts @@ -7,10 +7,6 @@ import _ from 'lodash'; import { i18n } from '@kbn/i18n'; -// @ts-expect-error -import { parse } from 'wellknown'; -// @ts-expect-error -import turfCircle from '@turf/circle'; import { Feature, FeatureCollection, Geometry, Polygon, Point, Position } from 'geojson'; import { BBox } from '@turf/helpers'; import { @@ -89,12 +85,12 @@ export function hitsToGeoJson( ensureGeoField(geoFieldType); if (geoFieldType === ES_GEO_FIELD_TYPE.GEO_POINT) { geoPointToGeometry( - properties[geoFieldName] as string | string[] | undefined, + properties[geoFieldName] as Point | Point[] | undefined, tmpGeometriesAccumulator ); } else { geoShapeToGeometry( - properties[geoFieldName] as string | string[] | ESGeometry | ESGeometry[] | undefined, + properties[geoFieldName] as ESGeometry | ESGeometry[] | undefined, tmpGeometriesAccumulator ); } @@ -131,12 +127,9 @@ export function hitsToGeoJson( }; } -// Parse geo_point docvalue_field -// Either -// 1) Array of latLon strings -// 2) latLon string +// Parse geo_point fields API response export function geoPointToGeometry( - value: string[] | string | undefined, + value: Point[] | Point | undefined, accumulator: Geometry[] ): void { if (!value) { @@ -150,99 +143,12 @@ export function geoPointToGeometry( return; } - const commaSplit = value.split(','); - const lat = parseFloat(commaSplit[0]); - const lon = parseFloat(commaSplit[1]); - accumulator.push({ - type: GEO_JSON_TYPE.POINT, - coordinates: [lon, lat], - } as Point); -} - -export function convertESShapeToGeojsonGeometry(value: ESGeometry): Geometry { - const geoJson = { - type: value.type, - coordinates: value.coordinates, - }; - - // https://www.elastic.co/guide/en/elasticsearch/reference/current/geo-shape.html#input-structure - // For some unknown compatibility nightmarish reason, Elasticsearch types are not capitalized the same as geojson types - // For example: 'LineString' geojson type is 'linestring' in elasticsearch - // Convert feature types to geojson spec values - // Sometimes, the type in ES is capitalized correctly. Sometimes it is not. It depends on how the doc was ingested - // The below is the correction in-place. - switch (value.type) { - case 'point': - geoJson.type = GEO_JSON_TYPE.POINT; - break; - case 'linestring': - geoJson.type = GEO_JSON_TYPE.LINE_STRING; - break; - case 'polygon': - geoJson.type = GEO_JSON_TYPE.POLYGON; - break; - case 'multipoint': - geoJson.type = GEO_JSON_TYPE.MULTI_POINT; - break; - case 'multilinestring': - geoJson.type = GEO_JSON_TYPE.MULTI_LINE_STRING; - break; - case 'multipolygon': - geoJson.type = GEO_JSON_TYPE.MULTI_POLYGON; - break; - case 'geometrycollection': - case GEO_JSON_TYPE.GEOMETRY_COLLECTION: - // PEBKAC - geometry-collections need to be unrolled to their individual geometries first. - const invalidGeometrycollectionError = i18n.translate( - 'xpack.maps.es_geo_utils.convert.invalidGeometryCollectionErrorMessage', - { - defaultMessage: `Should not pass GeometryCollection to convertESShapeToGeojsonGeometry`, - } - ); - throw new Error(invalidGeometrycollectionError); - case 'envelope': - const envelopeCoords = geoJson.coordinates as Position[]; - // format defined here https://www.elastic.co/guide/en/elasticsearch/reference/current/geo-shape.html#_envelope - const polygon = formatEnvelopeAsPolygon({ - minLon: envelopeCoords[0][0], - maxLon: envelopeCoords[1][0], - minLat: envelopeCoords[1][1], - maxLat: envelopeCoords[0][1], - }); - geoJson.type = polygon.type; - geoJson.coordinates = polygon.coordinates; - break; - case 'circle': - const errorMessage = i18n.translate( - 'xpack.maps.es_geo_utils.convert.unsupportedGeometryTypeErrorMessage', - { - defaultMessage: `Unable to convert {geometryType} geometry to geojson, not supported`, - values: { - geometryType: geoJson.type, - }, - } - ); - throw new Error(errorMessage); - } - return geoJson as unknown as Geometry; -} - -function convertWKTStringToGeojson(value: string): Geometry { - try { - return parse(value); - } catch (e) { - const errorMessage = i18n.translate('xpack.maps.es_geo_utils.wkt.invalidWKTErrorMessage', { - defaultMessage: `Unable to convert {wkt} to geojson. Valid WKT expected.`, - values: { - wkt: value, - }, - }); - throw new Error(errorMessage); - } + accumulator.push(value as Point); } +// Parse geo_shape fields API response export function geoShapeToGeometry( - value: string | ESGeometry | string[] | ESGeometry[] | undefined, + value: ESGeometry | ESGeometry[] | undefined, accumulator: Geometry[] ): void { if (!value) { @@ -257,21 +163,38 @@ export function geoShapeToGeometry( return; } - if (typeof value === 'string') { - const geoJson = convertWKTStringToGeojson(value); - accumulator.push(geoJson); - } else if ( - // Needs to deal with possible inconsistencies in capitalization - value.type === GEO_JSON_TYPE.GEOMETRY_COLLECTION || - value.type === 'geometrycollection' - ) { + if (value.type.toLowerCase() === GEO_JSON_TYPE.GEOMETRY_COLLECTION.toLowerCase()) { const geometryCollection = value as unknown as { geometries: ESGeometry[] }; for (let i = 0; i < geometryCollection.geometries.length; i++) { geoShapeToGeometry(geometryCollection.geometries[i], accumulator); } + return; + } + + // fields API does not return true geojson yet, circle and envelope still exist which are not part of geojson spec + if (value.type.toLowerCase() === 'envelope') { + const envelopeCoords = value.coordinates as Position[]; + // format defined here https://www.elastic.co/guide/en/elasticsearch/reference/current/geo-shape.html#_envelope + const polygon = formatEnvelopeAsPolygon({ + minLon: envelopeCoords[0][0], + maxLon: envelopeCoords[1][0], + minLat: envelopeCoords[1][1], + maxLat: envelopeCoords[0][1], + }); + accumulator.push(polygon); + } else if (value.type.toLowerCase() === 'circle') { + const errorMessage = i18n.translate( + 'xpack.maps.es_geo_utils.convert.unsupportedGeometryTypeErrorMessage', + { + defaultMessage: `Unable to convert {geometryType} geometry to geojson, not supported`, + values: { + geometryType: value.type, + }, + } + ); + throw new Error(errorMessage); } else { - const geoJson = convertESShapeToGeojsonGeometry(value); - accumulator.push(geoJson); + accumulator.push(value as Geometry); } } diff --git a/x-pack/plugins/maps/public/classes/sources/es_search_source/es_search_source.tsx b/x-pack/plugins/maps/public/classes/sources/es_search_source/es_search_source.tsx index 687418edd25b5b..1b7c9e1cd6aa0c 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_search_source/es_search_source.tsx +++ b/x-pack/plugins/maps/public/classes/sources/es_search_source/es_search_source.tsx @@ -281,21 +281,26 @@ export class ESSearchSource extends AbstractESSource implements IMvtVectorSource const indexPattern: IndexPattern = await this.getIndexPattern(); + const fieldNames = searchFilters.fieldNames.filter( + (fieldName) => fieldName !== this._descriptor.geoField + ); const { docValueFields, sourceOnlyFields, scriptFields } = getDocValueAndSourceFields( indexPattern, - searchFilters.fieldNames, + fieldNames, 'epoch_millis' ); const topHits: { size: number; script_fields: Record; docvalue_fields: Array; + fields: string[]; _source?: boolean | { includes: string[] }; sort?: Array>; } = { size: topHitsSize, script_fields: scriptFields, docvalue_fields: docValueFields, + fields: [this._descriptor.geoField], }; if (this._hasSort()) { @@ -389,9 +394,12 @@ export class ESSearchSource extends AbstractESSource implements IMvtVectorSource ) { const indexPattern = await this.getIndexPattern(); + const fieldNames = searchFilters.fieldNames.filter( + (fieldName) => fieldName !== this._descriptor.geoField + ); const { docValueFields, sourceOnlyFields } = getDocValueAndSourceFields( indexPattern, - searchFilters.fieldNames, + fieldNames, 'epoch_millis' ); @@ -418,6 +426,7 @@ export class ESSearchSource extends AbstractESSource implements IMvtVectorSource } else { searchSource.setField('source', sourceOnlyFields); } + searchSource.setField('fields', [this._descriptor.geoField]); if (this._hasSort()) { searchSource.setField('sort', this._buildEsSort()); } @@ -800,9 +809,12 @@ export class ESSearchSource extends AbstractESSource implements IMvtVectorSource const indexPattern = await this.getIndexPattern(); const indexSettings = await loadIndexSettings(indexPattern.title); + const fieldNames = searchFilters.fieldNames.filter( + (fieldName) => fieldName !== this._descriptor.geoField + ); const { docValueFields, sourceOnlyFields } = getDocValueAndSourceFields( indexPattern, - searchFilters.fieldNames, + fieldNames, 'epoch_millis' ); diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 42fd880311a589..bbc5309e476dda 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -14910,12 +14910,10 @@ "xpack.maps.embeddableDisplayName": "マップ", "xpack.maps.emsFileSelect.selectPlaceholder": "EMSレイヤーを選択", "xpack.maps.emsSource.tooltipsTitle": "ツールチップフィールド", - "xpack.maps.es_geo_utils.convert.invalidGeometryCollectionErrorMessage": "GeometryCollectionを convertESShapeToGeojsonGeometryに渡さないでください", "xpack.maps.es_geo_utils.convert.unsupportedGeometryTypeErrorMessage": "{geometryType} ジオメトリから Geojson に変換できません。サポートされていません", "xpack.maps.es_geo_utils.distanceFilterAlias": "{pointLabel}の{distanceKm} km以内", "xpack.maps.es_geo_utils.unsupportedFieldTypeErrorMessage": "サポートされていないフィールドタイプ、期待値:{expectedTypes}、提供された値:{fieldType}", "xpack.maps.es_geo_utils.unsupportedGeometryTypeErrorMessage": "サポートされていないジオメトリタイプ、期待値:{expectedTypes}、提供された値:{geometryType}", - "xpack.maps.es_geo_utils.wkt.invalidWKTErrorMessage": "{wkt} を Geojson に変換できません。有効な WKT が必要です。", "xpack.maps.esGeoLine.areEntitiesTrimmedMsg": "結果は ~{totalEntities} 中最初の {entityCount} トラックに制限されます。", "xpack.maps.esGeoLine.tracksCountMsg": "{entityCount} 個のトラックが見つかりました。", "xpack.maps.esGeoLine.tracksTrimmedMsg": "{entityCount} 中 {numTrimmedTracks} 個のトラックが不完全です。", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 2fe7805f64259a..ebfc41d0821b01 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -15105,12 +15105,10 @@ "xpack.maps.embeddableDisplayName": "地图", "xpack.maps.emsFileSelect.selectPlaceholder": "选择 EMS 图层", "xpack.maps.emsSource.tooltipsTitle": "工具提示字段", - "xpack.maps.es_geo_utils.convert.invalidGeometryCollectionErrorMessage": "不应将 GeometryCollection 传递给 convertESShapeToGeojsonGeometry", "xpack.maps.es_geo_utils.convert.unsupportedGeometryTypeErrorMessage": "无法将 {geometryType} 几何图形转换成 geojson,不支持", "xpack.maps.es_geo_utils.distanceFilterAlias": "{pointLabel} {distanceKm}km 内", "xpack.maps.es_geo_utils.unsupportedFieldTypeErrorMessage": "字段类型不受支持,应为 {expectedTypes},而提供的是 {fieldType}", "xpack.maps.es_geo_utils.unsupportedGeometryTypeErrorMessage": "几何类型不受支持,应为 {expectedTypes},而提供的是 {geometryType}", - "xpack.maps.es_geo_utils.wkt.invalidWKTErrorMessage": "无法将 {wkt} 转换成 geojson。需要有效的 WKT。", "xpack.maps.esGeoLine.areEntitiesTrimmedMsg": "结果限制为 ~{totalEntities} 条轨迹中的前 {entityCount} 条。", "xpack.maps.esGeoLine.tracksCountMsg": "找到 {entityCount} 条轨迹。", "xpack.maps.esGeoLine.tracksTrimmedMsg": "{entityCount} 条轨迹中有 {numTrimmedTracks} 条不完整。", diff --git a/x-pack/test/functional/apps/maps/mvt_scaling.js b/x-pack/test/functional/apps/maps/mvt_scaling.js index 3e0e8924a6417e..2be9606d11dea5 100644 --- a/x-pack/test/functional/apps/maps/mvt_scaling.js +++ b/x-pack/test/functional/apps/maps/mvt_scaling.js @@ -52,7 +52,7 @@ export default function ({ getPageObjects, getService }) { geometryFieldName: 'geometry', index: 'geo_shapes*', requestBody: - '(_source:!(geometry),docvalue_fields:!(prop1),query:(bool:(filter:!(),must:!(),must_not:!(),should:!())),runtime_mappings:(),script_fields:(),size:10001,stored_fields:!(geometry,prop1))', + '(_source:!f,docvalue_fields:!(prop1),query:(bool:(filter:!(),must:!(),must_not:!(),should:!())),runtime_mappings:(),script_fields:(),size:10001,stored_fields:!(geometry,prop1))', }); }); diff --git a/yarn.lock b/yarn.lock index b73679a1945c3d..369c5edf179d2f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10311,15 +10311,6 @@ concat-stream@1.6.2, concat-stream@^1.4.7, concat-stream@^1.5.0, concat-stream@^ readable-stream "^2.2.2" typedarray "^0.0.6" -concat-stream@~1.5.0: - version "1.5.2" - resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.5.2.tgz#708978624d856af41a5a741defdd261da752c266" - integrity sha1-cIl4Yk2FavQaWnQd790mHadSwmY= - dependencies: - inherits "~2.0.1" - readable-stream "~2.0.0" - typedarray "~0.0.5" - concat-stream@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-2.0.0.tgz#414cf5af790a48c60ab9be4527d56d5e41133cb1" @@ -22651,11 +22642,6 @@ process-nextick-args@^2.0.0, process-nextick-args@~2.0.0: resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== -process-nextick-args@~1.0.6: - version "1.0.7" - resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" - integrity sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M= - process-on-spawn@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/process-on-spawn/-/process-on-spawn-1.0.0.tgz#95b05a23073d30a17acfdc92a440efd2baefdc93" @@ -24032,18 +24018,6 @@ readable-stream@~1.1.9: isarray "0.0.1" string_decoder "~0.10.x" -readable-stream@~2.0.0: - version "2.0.6" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e" - integrity sha1-j5A0HmilPMySh4jaz80Rs265t44= - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "~1.0.0" - process-nextick-args "~1.0.6" - string_decoder "~0.10.x" - util-deprecate "~1.0.1" - readdir-glob@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/readdir-glob/-/readdir-glob-1.1.1.tgz#f0e10bb7bf7bfa7e0add8baffdc54c3f7dbee6c4" @@ -27877,7 +27851,7 @@ typedarray-to-buffer@^3.1.5: dependencies: is-typedarray "^1.0.0" -typedarray@^0.0.6, typedarray@~0.0.5: +typedarray@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= @@ -29518,14 +29492,6 @@ websocket-extensions@>=0.1.1: resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.4.tgz#7f8473bc839dfd87608adb95d7eb075211578a42" integrity sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg== -wellknown@^0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/wellknown/-/wellknown-0.5.0.tgz#09ae9871fa826cf0a6ec1537ef00c379d78d7101" - integrity sha1-Ca6YcfqCbPCm7BU37wDDedeNcQE= - dependencies: - concat-stream "~1.5.0" - minimist "~1.2.0" - wgs84@0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/wgs84/-/wgs84-0.0.0.tgz#34fdc555917b6e57cf2a282ed043710c049cdc76" From 2050262b51001442f83a1bffdc57c6e1e856d133 Mon Sep 17 00:00:00 2001 From: Stacey Gammon Date: Wed, 19 Jan 2022 14:04:37 -0500 Subject: [PATCH 057/108] remove reference to deprecated kibana.index setting (#123379) --- docs/developer/advanced/running-elasticsearch.asciidoc | 7 ------- 1 file changed, 7 deletions(-) diff --git a/docs/developer/advanced/running-elasticsearch.asciidoc b/docs/developer/advanced/running-elasticsearch.asciidoc index 36f9ee420d41db..c04c53f66cf191 100644 --- a/docs/developer/advanced/running-elasticsearch.asciidoc +++ b/docs/developer/advanced/running-elasticsearch.asciidoc @@ -71,13 +71,6 @@ elasticsearch.password: {{ password }} elasticsearch.ssl.verificationMode: none ---- -If many other users will be interacting with your remote cluster, you'll want to add the following to avoid causing conflicts: - -[source,bash] ----- -kibana.index: '.{YourGitHubHandle}-kibana' ----- - ==== Running remote clusters Setup remote clusters for cross cluster search (CCS) and cross cluster replication (CCR). From 70c2b8b98e8fe453ebb8c8a24893b7480f3789a8 Mon Sep 17 00:00:00 2001 From: Brian Seeders Date: Wed, 19 Jan 2022 15:40:07 -0500 Subject: [PATCH 058/108] Move bazel remote cache token to a space that more employees have access to (#123402) --- packages/kbn-pm/dist/index.js | 2 +- packages/kbn-pm/src/utils/bazel/setup_remote_cache.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/kbn-pm/dist/index.js b/packages/kbn-pm/dist/index.js index bf51f1a97e8dd2..3896c67454b902 100644 --- a/packages/kbn-pm/dist/index.js +++ b/packages/kbn-pm/dist/index.js @@ -59012,7 +59012,7 @@ async function setupRemoteCache(repoRootPath) { try { const { stdout - } = await Object(_child_process__WEBPACK_IMPORTED_MODULE_3__["spawn"])('vault', ['read', '-field=readonly-key', 'secret/kibana-issues/dev/bazel-remote-cache'], { + } = await Object(_child_process__WEBPACK_IMPORTED_MODULE_3__["spawn"])('vault', ['read', '-field=readonly-key', 'secret/ui-team/kibana-bazel-remote-cache'], { stdio: 'pipe' }); apiKey = stdout.trim(); diff --git a/packages/kbn-pm/src/utils/bazel/setup_remote_cache.ts b/packages/kbn-pm/src/utils/bazel/setup_remote_cache.ts index fb510cfa81ffd0..0e740e674b7d81 100644 --- a/packages/kbn-pm/src/utils/bazel/setup_remote_cache.ts +++ b/packages/kbn-pm/src/utils/bazel/setup_remote_cache.ts @@ -60,7 +60,7 @@ export async function setupRemoteCache(repoRootPath: string) { try { const { stdout } = await spawn( 'vault', - ['read', '-field=readonly-key', 'secret/kibana-issues/dev/bazel-remote-cache'], + ['read', '-field=readonly-key', 'secret/ui-team/kibana-bazel-remote-cache'], { stdio: 'pipe', } From 158a9a53a33957c9bf31fe832a9ce4c2daee08ae Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Wed, 19 Jan 2022 14:09:31 -0800 Subject: [PATCH 059/108] [Actions] Fixed ad-hoc actions tasks remain as "running" when they timeout by adding cancellation support (#120853) * [Actions] Fixed ad-hoc actions tasks remain as "running" when they timeout by adding cancellation support * fixed test * fixed tests * fixed test * removed test data * fixed typechecks * fixed typechecks * fixed typechecks * fixed tests * fixed typechecks * fixed tests * fixed typechecks * fixed test * fixed tests * fixed tests * changed unit tests * fixed tests * fixed jest tests * fixed typechecks Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../actions/server/constants/event_log.ts | 1 + .../server/lib/action_executor.mock.ts | 1 + .../server/lib/action_executor.test.ts | 30 ++++ .../actions/server/lib/action_executor.ts | 150 ++++++++++++++---- ...ate_action_event_log_record_object.test.ts | 128 +++++++++++++++ .../create_action_event_log_record_object.ts | 53 +++++++ .../server/lib/task_runner_factory.test.ts | 34 +++- .../actions/server/lib/task_runner_factory.ts | 84 +++++++--- .../task_running/ephemeral_task_runner.ts | 1 + .../server/task_running/task_runner.ts | 1 + 10 files changed, 423 insertions(+), 60 deletions(-) create mode 100644 x-pack/plugins/actions/server/lib/create_action_event_log_record_object.test.ts create mode 100644 x-pack/plugins/actions/server/lib/create_action_event_log_record_object.ts diff --git a/x-pack/plugins/actions/server/constants/event_log.ts b/x-pack/plugins/actions/server/constants/event_log.ts index 9163a0d105ce8a..9dba72462f317f 100644 --- a/x-pack/plugins/actions/server/constants/event_log.ts +++ b/x-pack/plugins/actions/server/constants/event_log.ts @@ -10,4 +10,5 @@ export const EVENT_LOG_ACTIONS = { execute: 'execute', executeStart: 'execute-start', executeViaHttp: 'execute-via-http', + executeTimeout: 'execute-timeout', }; diff --git a/x-pack/plugins/actions/server/lib/action_executor.mock.ts b/x-pack/plugins/actions/server/lib/action_executor.mock.ts index 6abfec1116c3ad..54df74b2fbd3d0 100644 --- a/x-pack/plugins/actions/server/lib/action_executor.mock.ts +++ b/x-pack/plugins/actions/server/lib/action_executor.mock.ts @@ -11,6 +11,7 @@ const createActionExecutorMock = () => { const mocked: jest.Mocked = { initialize: jest.fn(), execute: jest.fn().mockResolvedValue({ status: 'ok', actionId: '' }), + logCancellation: jest.fn(), }; return mocked; }; diff --git a/x-pack/plugins/actions/server/lib/action_executor.test.ts b/x-pack/plugins/actions/server/lib/action_executor.test.ts index 30d4ed92e03f8e..1d678c244c1b09 100644 --- a/x-pack/plugins/actions/server/lib/action_executor.test.ts +++ b/x-pack/plugins/actions/server/lib/action_executor.test.ts @@ -115,6 +115,7 @@ test('successfully executes', async () => { Object { "event": Object { "action": "execute-start", + "kind": "action", }, "kibana": Object { "saved_objects": Array [ @@ -134,6 +135,7 @@ test('successfully executes', async () => { Object { "event": Object { "action": "execute", + "kind": "action", "outcome": "success", }, "kibana": Object { @@ -511,6 +513,34 @@ test('logs a warning when alert executor returns invalid status', async () => { ); }); +test('writes to event log for execute timeout', async () => { + setupActionExecutorMock(); + + await actionExecutor.logCancellation({ + actionId: 'action1', + relatedSavedObjects: [], + request: {} as KibanaRequest, + }); + expect(eventLogger.logEvent).toHaveBeenCalledTimes(1); + expect(eventLogger.logEvent.mock.calls[0][0]).toMatchObject({ + event: { + action: 'execute-timeout', + }, + kibana: { + saved_objects: [ + { + rel: 'primary', + type: 'action', + id: 'action1', + type_id: 'test', + namespace: 'some-namespace', + }, + ], + }, + message: `action: test:action1: 'action-1' execution cancelled due to timeout - exceeded default timeout of "5m"`, + }); +}); + test('writes to event log for execute and execute start', async () => { const executorMock = setupActionExecutorMock(); executorMock.mockResolvedValue({ diff --git a/x-pack/plugins/actions/server/lib/action_executor.ts b/x-pack/plugins/actions/server/lib/action_executor.ts index 9458180fdd2200..9737630628823f 100644 --- a/x-pack/plugins/actions/server/lib/action_executor.ts +++ b/x-pack/plugins/actions/server/lib/action_executor.ts @@ -19,16 +19,17 @@ import { ActionTypeExecutorResult, ActionTypeRegistryContract, GetServicesFunction, - RawAction, PreConfiguredAction, + RawAction, } from '../types'; import { EncryptedSavedObjectsClient } from '../../../encrypted_saved_objects/server'; import { SpacesServiceStart } from '../../../spaces/server'; import { EVENT_LOG_ACTIONS } from '../constants/event_log'; -import { IEvent, IEventLogger, SAVED_OBJECT_REL_PRIMARY } from '../../../event_log/server'; +import { IEventLogger, SAVED_OBJECT_REL_PRIMARY } from '../../../event_log/server'; import { ActionsClient } from '../actions_client'; import { ActionExecutionSource } from './action_execution_source'; import { RelatedSavedObjects } from './related_saved_objects'; +import { createActionEventLogRecordObject } from './create_action_event_log_record_object'; // 1,000,000 nanoseconds in 1 millisecond const Millis2Nanos = 1000 * 1000; @@ -68,6 +69,7 @@ export class ActionExecutor { private isInitialized = false; private actionExecutorContext?: ActionExecutorContext; private readonly isESOCanEncrypt: boolean; + private actionInfo: ActionInfo | undefined; constructor({ isESOCanEncrypt }: { isESOCanEncrypt: boolean }) { this.isESOCanEncrypt = isESOCanEncrypt; @@ -124,7 +126,7 @@ export class ActionExecutor { const spaceId = spaces && spaces.getSpaceId(request); const namespace = spaceId && spaceId !== 'default' ? { namespace: spaceId } : {}; - const { actionTypeId, name, config, secrets } = await getActionInfo( + const actionInfo = await getActionInfoInternal( await getActionsClientWithRequest(request, source), encryptedSavedObjectsClient, preconfiguredActions, @@ -132,6 +134,12 @@ export class ActionExecutor { namespace.namespace ); + const { actionTypeId, name, config, secrets } = actionInfo; + + if (!this.actionInfo || this.actionInfo.actionId !== actionId) { + this.actionInfo = actionInfo; + } + if (span) { span.name = `execute_action ${actionTypeId}`; span.addLabels({ @@ -169,26 +177,25 @@ export class ActionExecutor { ? { task: { scheduled: taskInfo.scheduled.toISOString(), - schedule_delay: Millis2Nanos * (Date.now() - taskInfo.scheduled.getTime()), + scheduleDelay: Millis2Nanos * (Date.now() - taskInfo.scheduled.getTime()), }, } : {}; - const event: IEvent = { - event: { action: EVENT_LOG_ACTIONS.execute }, - kibana: { - ...task, - saved_objects: [ - { - rel: SAVED_OBJECT_REL_PRIMARY, - type: 'action', - id: actionId, - type_id: actionTypeId, - ...namespace, - }, - ], - }, - }; + const event = createActionEventLogRecordObject({ + actionId, + action: EVENT_LOG_ACTIONS.execute, + ...namespace, + ...task, + savedObjects: [ + { + type: 'action', + id: actionId, + typeId: actionTypeId, + relation: SAVED_OBJECT_REL_PRIMARY, + }, + ], + }); for (const relatedSavedObject of relatedSavedObjects || []) { event.kibana?.saved_objects?.push({ @@ -210,6 +217,7 @@ export class ActionExecutor { }, message: `action started: ${actionLabel}`, }); + eventLogger.logEvent(startEvent); let rawResult: ActionTypeExecutorResult; @@ -269,22 +277,77 @@ export class ActionExecutor { } ); } -} -function actionErrorToMessage(result: ActionTypeExecutorResult): string { - let message = result.message || 'unknown error running action'; - - if (result.serviceMessage) { - message = `${message}: ${result.serviceMessage}`; - } - - if (result.retry instanceof Date) { - message = `${message}; retry at ${result.retry.toISOString()}`; - } else if (result.retry) { - message = `${message}; retry: ${JSON.stringify(result.retry)}`; + public async logCancellation({ + actionId, + request, + relatedSavedObjects, + source, + taskInfo, + }: { + actionId: string; + request: KibanaRequest; + taskInfo?: TaskInfo; + relatedSavedObjects: RelatedSavedObjects; + source?: ActionExecutionSource; + }) { + const { + spaces, + encryptedSavedObjectsClient, + preconfiguredActions, + eventLogger, + getActionsClientWithRequest, + } = this.actionExecutorContext!; + + const spaceId = spaces && spaces.getSpaceId(request); + const namespace = spaceId && spaceId !== 'default' ? { namespace: spaceId } : {}; + if (!this.actionInfo || this.actionInfo.actionId !== actionId) { + this.actionInfo = await getActionInfoInternal( + await getActionsClientWithRequest(request, source), + encryptedSavedObjectsClient, + preconfiguredActions, + actionId, + namespace.namespace + ); + } + const task = taskInfo + ? { + task: { + scheduled: taskInfo.scheduled.toISOString(), + scheduleDelay: Millis2Nanos * (Date.now() - taskInfo.scheduled.getTime()), + }, + } + : {}; + // Write event log entry + const event = createActionEventLogRecordObject({ + actionId, + action: EVENT_LOG_ACTIONS.executeTimeout, + message: `action: ${this.actionInfo.actionTypeId}:${actionId}: '${ + this.actionInfo.name ?? '' + }' execution cancelled due to timeout - exceeded default timeout of "5m"`, + ...namespace, + ...task, + savedObjects: [ + { + type: 'action', + id: actionId, + typeId: this.actionInfo.actionTypeId, + relation: SAVED_OBJECT_REL_PRIMARY, + }, + ], + }); + + for (const relatedSavedObject of (relatedSavedObjects || []) as RelatedSavedObjects) { + event.kibana?.saved_objects?.push({ + rel: SAVED_OBJECT_REL_PRIMARY, + type: relatedSavedObject.type, + id: relatedSavedObject.id, + type_id: relatedSavedObject.typeId, + namespace: relatedSavedObject.namespace, + }); + } + eventLogger.logEvent(event); } - - return message; } interface ActionInfo { @@ -292,9 +355,10 @@ interface ActionInfo { name: string; config: unknown; secrets: unknown; + actionId: string; } -async function getActionInfo( +async function getActionInfoInternal( actionsClient: PublicMethodsOf, encryptedSavedObjectsClient: EncryptedSavedObjectsClient, preconfiguredActions: PreConfiguredAction[], @@ -311,6 +375,7 @@ async function getActionInfo( name: pcAction.name, config: pcAction.config, secrets: pcAction.secrets, + actionId, }; } @@ -329,5 +394,22 @@ async function getActionInfo( name, config, secrets, + actionId, }; } + +function actionErrorToMessage(result: ActionTypeExecutorResult): string { + let message = result.message || 'unknown error running action'; + + if (result.serviceMessage) { + message = `${message}: ${result.serviceMessage}`; + } + + if (result.retry instanceof Date) { + message = `${message}; retry at ${result.retry.toISOString()}`; + } else if (result.retry) { + message = `${message}; retry: ${JSON.stringify(result.retry)}`; + } + + return message; +} diff --git a/x-pack/plugins/actions/server/lib/create_action_event_log_record_object.test.ts b/x-pack/plugins/actions/server/lib/create_action_event_log_record_object.test.ts new file mode 100644 index 00000000000000..ee58f8a01488ce --- /dev/null +++ b/x-pack/plugins/actions/server/lib/create_action_event_log_record_object.test.ts @@ -0,0 +1,128 @@ +/* + * 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 { createActionEventLogRecordObject } from './create_action_event_log_record_object'; + +describe('createActionEventLogRecordObject', () => { + test('created action event "execute-start"', async () => { + expect( + createActionEventLogRecordObject({ + actionId: '1', + action: 'execute-start', + timestamp: '1970-01-01T00:00:00.000Z', + task: { + scheduled: '1970-01-01T00:00:00.000Z', + scheduleDelay: 0, + }, + savedObjects: [ + { + id: '1', + type: 'action', + typeId: 'test', + relation: 'primary', + }, + ], + }) + ).toStrictEqual({ + '@timestamp': '1970-01-01T00:00:00.000Z', + event: { + action: 'execute-start', + kind: 'action', + }, + kibana: { + saved_objects: [ + { + id: '1', + rel: 'primary', + type: 'action', + type_id: 'test', + }, + ], + task: { + schedule_delay: 0, + scheduled: '1970-01-01T00:00:00.000Z', + }, + }, + }); + }); + + test('created action event "execute"', async () => { + expect( + createActionEventLogRecordObject({ + actionId: '1', + name: 'test name', + action: 'execute', + message: 'action execution start', + namespace: 'default', + savedObjects: [ + { + id: '2', + type: 'action', + typeId: '.email', + relation: 'primary', + }, + ], + }) + ).toStrictEqual({ + event: { + action: 'execute', + kind: 'action', + }, + kibana: { + saved_objects: [ + { + id: '2', + namespace: 'default', + rel: 'primary', + type: 'action', + type_id: '.email', + }, + ], + }, + message: 'action execution start', + }); + }); + + test('created action event "execute-timeout"', async () => { + expect( + createActionEventLogRecordObject({ + actionId: '1', + action: 'execute-timeout', + task: { + scheduled: '1970-01-01T00:00:00.000Z', + }, + savedObjects: [ + { + id: '1', + type: 'action', + typeId: 'test', + relation: 'primary', + }, + ], + }) + ).toStrictEqual({ + event: { + action: 'execute-timeout', + kind: 'action', + }, + kibana: { + saved_objects: [ + { + id: '1', + rel: 'primary', + type: 'action', + type_id: 'test', + }, + ], + task: { + schedule_delay: undefined, + scheduled: '1970-01-01T00:00:00.000Z', + }, + }, + }); + }); +}); diff --git a/x-pack/plugins/actions/server/lib/create_action_event_log_record_object.ts b/x-pack/plugins/actions/server/lib/create_action_event_log_record_object.ts new file mode 100644 index 00000000000000..1a1c5e9e6b3aaa --- /dev/null +++ b/x-pack/plugins/actions/server/lib/create_action_event_log_record_object.ts @@ -0,0 +1,53 @@ +/* + * 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 { IEvent } from '../../../event_log/server'; + +export type Event = Exclude; + +interface CreateActionEventLogRecordParams { + actionId: string; + action: string; + name?: string; + message?: string; + namespace?: string; + timestamp?: string; + task?: { + scheduled?: string; + scheduleDelay?: number; + }; + savedObjects: Array<{ + type: string; + id: string; + typeId: string; + relation?: string; + }>; +} + +export function createActionEventLogRecordObject(params: CreateActionEventLogRecordParams): Event { + const { action, message, task, namespace } = params; + + const event: Event = { + ...(params.timestamp ? { '@timestamp': params.timestamp } : {}), + event: { + action, + kind: 'action', + }, + kibana: { + saved_objects: params.savedObjects.map((so) => ({ + ...(so.relation ? { rel: so.relation } : {}), + type: so.type, + id: so.id, + type_id: so.typeId, + ...(namespace ? { namespace } : {}), + })), + ...(task ? { task: { scheduled: task.scheduled, schedule_delay: task.scheduleDelay } } : {}), + }, + ...(message ? { message } : {}), + }; + return event; +} diff --git a/x-pack/plugins/actions/server/lib/task_runner_factory.test.ts b/x-pack/plugins/actions/server/lib/task_runner_factory.test.ts index ec0aa48ef291e4..0ea6b5316fb82a 100644 --- a/x-pack/plugins/actions/server/lib/task_runner_factory.test.ts +++ b/x-pack/plugins/actions/server/lib/task_runner_factory.test.ts @@ -22,6 +22,7 @@ const spaceIdToNamespace = jest.fn(); const actionTypeRegistry = actionTypeRegistryMock.create(); const mockedEncryptedSavedObjectsClient = encryptedSavedObjectsMock.createClient(); const mockedActionExecutor = actionExecutorMock.create(); +const eventLogger = eventLoggerMock.create(); let fakeTimer: sinon.SinonFakeTimers; let taskRunnerFactory: TaskRunnerFactory; @@ -62,7 +63,7 @@ const actionExecutorInitializerParams = { actionTypeRegistry, getActionsClientWithRequest: jest.fn(async () => actionsClientMock.create()), encryptedSavedObjectsClient: mockedEncryptedSavedObjectsClient, - eventLogger: eventLoggerMock.create(), + eventLogger, preconfiguredActions: [], }; const taskRunnerFactoryInitializerParams = { @@ -236,6 +237,37 @@ test('cleans up action_task_params object', async () => { expect(services.savedObjectsClient.delete).toHaveBeenCalledWith('action_task_params', '3'); }); +test('task runner should implement CancellableTask cancel method with logging warning message', async () => { + mockedEncryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValueOnce({ + id: '3', + type: 'action_task_params', + attributes: { + actionId: '2', + params: { baz: true }, + apiKey: Buffer.from('123:abc').toString('base64'), + }, + references: [ + { + id: '2', + name: 'actionRef', + type: 'action', + }, + ], + }); + const taskRunner = taskRunnerFactory.create({ + taskInstance: mockedTaskInstance, + }); + + await taskRunner.cancel(); + expect(mockedActionExecutor.logCancellation.mock.calls[0][0].actionId).toBe('2'); + + expect(mockedActionExecutor.logCancellation.mock.calls.length).toBe(1); + + expect(taskRunnerFactoryInitializerParams.logger.debug).toHaveBeenCalledWith( + `Cancelling action task for action with id 2 - execution error due to timeout.` + ); +}); + test('runs successfully when cleanup fails and logs the error', async () => { const taskRunner = taskRunnerFactory.create({ taskInstance: mockedTaskInstance, diff --git a/x-pack/plugins/actions/server/lib/task_runner_factory.ts b/x-pack/plugins/actions/server/lib/task_runner_factory.ts index 4f6b9ac2e8b7d7..f3fdf627e08fff 100644 --- a/x-pack/plugins/actions/server/lib/task_runner_factory.ts +++ b/x-pack/plugins/actions/server/lib/task_runner_factory.ts @@ -93,31 +93,10 @@ export class TaskRunnerFactory { encryptedSavedObjectsClient, spaceIdToNamespace ); - - const requestHeaders: Record = {}; - if (apiKey) { - requestHeaders.authorization = `ApiKey ${apiKey}`; - } - const path = addSpaceIdToPath('/', spaceId); - // Since we're using API keys and accessing elasticsearch can only be done - // via a request, we're faking one with the proper authorization headers. - const fakeRequest = KibanaRequest.from({ - headers: requestHeaders, - path: '/', - route: { settings: {} }, - url: { - href: '/', - }, - raw: { - req: { - url: '/', - }, - }, - } as unknown as Request); - - basePathService.set(fakeRequest, path); + const request = getFakeRequest(apiKey); + basePathService.set(request, path); // Throwing an executor error means we will attempt to retry the task // TM will treat a task as a failure if `attempts >= maxAttempts` @@ -132,7 +111,7 @@ export class TaskRunnerFactory { params, actionId: actionId as string, isEphemeral: !isPersistedActionTask(actionTaskExecutorParams), - request: fakeRequest, + request, ...getSourceFromReferences(references), taskInfo, relatedSavedObjects: validatedRelatedSavedObjects(logger, relatedSavedObjects), @@ -181,7 +160,7 @@ export class TaskRunnerFactory { // We would idealy secure every operation but in order to support clean up of legacy alerts // we allow this operation in an unsecured manner // Once support for legacy alert RBAC is dropped, this can be secured - await getUnsecuredSavedObjectsClient(fakeRequest).delete( + await getUnsecuredSavedObjectsClient(request).delete( ACTION_TASK_PARAMS_SAVED_OBJECT_TYPE, actionTaskExecutorParams.actionTaskParamsId ); @@ -193,10 +172,65 @@ export class TaskRunnerFactory { } } }, + cancel: async () => { + // Write event log entry + const actionTaskExecutorParams = taskInstance.params as ActionTaskExecutorParams; + const { spaceId } = actionTaskExecutorParams; + + const { + attributes: { actionId, apiKey, relatedSavedObjects }, + references, + } = await getActionTaskParams( + actionTaskExecutorParams, + encryptedSavedObjectsClient, + spaceIdToNamespace + ); + + const request = getFakeRequest(apiKey); + const path = addSpaceIdToPath('/', spaceId); + basePathService.set(request, path); + + await actionExecutor.logCancellation({ + actionId, + request, + relatedSavedObjects: (relatedSavedObjects || []) as RelatedSavedObjects, + ...getSourceFromReferences(references), + }); + + logger.debug( + `Cancelling action task for action with id ${actionId} - execution error due to timeout.` + ); + return { state: {} }; + }, }; } } +function getFakeRequest(apiKey?: string) { + const requestHeaders: Record = {}; + if (apiKey) { + requestHeaders.authorization = `ApiKey ${apiKey}`; + } + + // Since we're using API keys and accessing elasticsearch can only be done + // via a request, we're faking one with the proper authorization headers. + const fakeRequest = KibanaRequest.from({ + headers: requestHeaders, + path: '/', + route: { settings: {} }, + url: { + href: '/', + }, + raw: { + req: { + url: '/', + }, + }, + } as unknown as Request); + + return fakeRequest; +} + async function getActionTaskParams( executorParams: ActionTaskExecutorParams, encryptedSavedObjectsClient: EncryptedSavedObjectsClient, diff --git a/x-pack/plugins/task_manager/server/task_running/ephemeral_task_runner.ts b/x-pack/plugins/task_manager/server/task_running/ephemeral_task_runner.ts index 0085329cd66e61..a9d1d8b6f2f168 100644 --- a/x-pack/plugins/task_manager/server/task_running/ephemeral_task_runner.ts +++ b/x-pack/plugins/task_manager/server/task_running/ephemeral_task_runner.ts @@ -304,6 +304,7 @@ export class EphemeralTaskManagerRunner implements TaskRunner { public async cancel() { const { task } = this; if (task?.cancel) { + // it will cause the task state of "running" to be cleared this.task = undefined; return task.cancel(); } diff --git a/x-pack/plugins/task_manager/server/task_running/task_runner.ts b/x-pack/plugins/task_manager/server/task_running/task_runner.ts index e21e418c904615..48927435c4bdf9 100644 --- a/x-pack/plugins/task_manager/server/task_running/task_runner.ts +++ b/x-pack/plugins/task_manager/server/task_running/task_runner.ts @@ -431,6 +431,7 @@ export class TaskManagerRunner implements TaskRunner { public async cancel() { const { task } = this; if (task?.cancel) { + // it will cause the task state of "running" to be cleared this.task = undefined; return task.cancel(); } From 12e63dd46912c63ca027c3d0d6c778bf4c4750c5 Mon Sep 17 00:00:00 2001 From: Spencer Date: Wed, 19 Jan 2022 15:46:32 -0700 Subject: [PATCH 060/108] [ftr] support filtering tests by es version (#123289) Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../src/serializers/recursive_serializer.ts | 19 +++++- packages/kbn-es-archiver/src/cli.ts | 4 +- packages/kbn-test/BUILD.bazel | 2 + .../src/functional_test_runner/cli.ts | 10 ++- .../functional_test_runner.ts | 47 +++++++++++-- .../src/functional_test_runner/index.ts | 2 +- .../lib/config/read_config_file.test.js | 23 ++++--- .../lib/config/read_config_file.ts | 20 ++++-- .../functional_test_runner/lib/es_version.ts | 55 +++++++++++++++ .../src/functional_test_runner/lib/index.ts | 1 + .../lib/mocha/decorate_mocha_ui.js | 3 + ..._by_tags.test.js => filter_suites.test.js} | 33 ++++++++- ...ter_suites_by_tags.js => filter_suites.ts} | 68 ++++++++++++++++--- .../lib/mocha/setup_mocha.js | 17 +++-- .../functional_test_runner/public_types.ts | 10 +-- .../run_tests/__snapshots__/args.test.js.snap | 13 ++++ .../functional_tests/cli/run_tests/args.js | 2 + .../cli/run_tests/args.test.js | 13 +++- .../src/functional_tests/lib/run_ftr.ts | 64 ++++++++++------- .../kbn-test/src/functional_tests/tasks.ts | 8 ++- packages/kbn-test/src/kbn_archiver_cli.ts | 4 +- .../kbn-test/types/ftr_globals/mocha.d.ts | 6 ++ 22 files changed, 349 insertions(+), 75 deletions(-) create mode 100644 packages/kbn-test/src/functional_test_runner/lib/es_version.ts rename packages/kbn-test/src/functional_test_runner/lib/mocha/{filter_suites_by_tags.test.js => filter_suites.test.js} (86%) rename packages/kbn-test/src/functional_test_runner/lib/mocha/{filter_suites_by_tags.js => filter_suites.ts} (55%) diff --git a/packages/kbn-dev-utils/src/serializers/recursive_serializer.ts b/packages/kbn-dev-utils/src/serializers/recursive_serializer.ts index 6e6572addbc833..15d3f033a85a12 100644 --- a/packages/kbn-dev-utils/src/serializers/recursive_serializer.ts +++ b/packages/kbn-dev-utils/src/serializers/recursive_serializer.ts @@ -6,11 +6,26 @@ * Side Public License, v 1. */ -export function createRecursiveSerializer(test: (v: any) => boolean, print: (v: any) => string) { +class RawPrint { + static fromString(s: string) { + return new RawPrint(s); + } + constructor(public readonly v: string) {} +} + +export function createRecursiveSerializer( + test: (v: any) => boolean, + print: (v: any, printRaw: (v: string) => RawPrint) => string | RawPrint +) { return { test: (v: any) => test(v), serialize: (v: any, ...rest: any[]) => { - const replacement = print(v); + const replacement = print(v, RawPrint.fromString); + + if (replacement instanceof RawPrint) { + return replacement.v; + } + const printer = rest.pop()!; return printer(replacement, ...rest); }, diff --git a/packages/kbn-es-archiver/src/cli.ts b/packages/kbn-es-archiver/src/cli.ts index e54b4d5fbdb52c..fbb5784afe5ac9 100644 --- a/packages/kbn-es-archiver/src/cli.ts +++ b/packages/kbn-es-archiver/src/cli.ts @@ -18,7 +18,7 @@ import readline from 'readline'; import Fs from 'fs'; import { RunWithCommands, createFlagError, CA_CERT_PATH } from '@kbn/dev-utils'; -import { readConfigFile, KbnClient } from '@kbn/test'; +import { readConfigFile, KbnClient, EsVersion } from '@kbn/test'; import { Client, HttpConnection } from '@elastic/elasticsearch'; import { EsArchiver } from './es_archiver'; @@ -45,7 +45,7 @@ export function runCli() { if (typeof configPath !== 'string') { throw createFlagError('--config must be a string'); } - const config = await readConfigFile(log, Path.resolve(configPath)); + const config = await readConfigFile(log, EsVersion.getDefault(), Path.resolve(configPath)); statsMeta.set('ftrConfigPath', configPath); let esUrl = flags['es-url']; diff --git a/packages/kbn-test/BUILD.bazel b/packages/kbn-test/BUILD.bazel index 1ff9677615f5ab..69addd9e3c4c7c 100644 --- a/packages/kbn-test/BUILD.bazel +++ b/packages/kbn-test/BUILD.bazel @@ -69,6 +69,7 @@ RUNTIME_DEPS = [ "@npm//react-router-dom", "@npm//redux", "@npm//rxjs", + "@npm//semver", "@npm//strip-ansi", "@npm//xmlbuilder", "@npm//xml2js", @@ -108,6 +109,7 @@ TYPES_DEPS = [ "@npm//@types/react-dom", "@npm//@types/react-redux", "@npm//@types/react-router-dom", + "@npm//@types/semver", "@npm//@types/xml2js", ] diff --git a/packages/kbn-test/src/functional_test_runner/cli.ts b/packages/kbn-test/src/functional_test_runner/cli.ts index d9938bebea5bb0..e013085e1b39a3 100644 --- a/packages/kbn-test/src/functional_test_runner/cli.ts +++ b/packages/kbn-test/src/functional_test_runner/cli.ts @@ -35,6 +35,11 @@ export function runFtrCli() { const reportTime = getTimeReporter(toolingLog, 'scripts/functional_test_runner'); run( async ({ flags, log }) => { + const esVersion = flags['es-version'] || undefined; // convert "" to undefined + if (esVersion !== undefined && typeof esVersion !== 'string') { + throw createFlagError('expected --es-version to be a string'); + } + const functionalTestRunner = new FunctionalTestRunner( log, makeAbsolutePath(flags.config as string), @@ -57,7 +62,8 @@ export function runFtrCli() { }, updateBaselines: flags.updateBaselines || flags.u, updateSnapshots: flags.updateSnapshots || flags.u, - } + }, + esVersion ); if (flags.throttle) { @@ -131,6 +137,7 @@ export function runFtrCli() { 'include-tag', 'exclude-tag', 'kibana-install-dir', + 'es-version', ], boolean: [ 'bail', @@ -150,6 +157,7 @@ export function runFtrCli() { --bail stop tests after the first failure --grep pattern used to select which tests to run --invert invert grep to exclude tests + --es-version the elasticsearch version, formatted as "x.y.z" --include=file a test file to be included, pass multiple times for multiple files --exclude=file a test file to be excluded, pass multiple times for multiple files --include-tag=tag a tag to be included, pass multiple times for multiple tags. Only diff --git a/packages/kbn-test/src/functional_test_runner/functional_test_runner.ts b/packages/kbn-test/src/functional_test_runner/functional_test_runner.ts index 4130cd8d138b87..ea55a2672d670f 100644 --- a/packages/kbn-test/src/functional_test_runner/functional_test_runner.ts +++ b/packages/kbn-test/src/functional_test_runner/functional_test_runner.ts @@ -6,6 +6,7 @@ * Side Public License, v 1. */ +import type { Client as EsClient } from '@elastic/elasticsearch'; import { ToolingLog } from '@kbn/dev-utils'; import { Suite, Test } from './fake_mocha_types'; @@ -21,6 +22,7 @@ import { DockerServersService, Config, SuiteTracker, + EsVersion, } from './lib'; export class FunctionalTestRunner { @@ -28,10 +30,12 @@ export class FunctionalTestRunner { public readonly failureMetadata = new FailureMetadata(this.lifecycle); private closed = false; + private readonly esVersion: EsVersion; constructor( private readonly log: ToolingLog, private readonly configFile: string, - private readonly configOverrides: any + private readonly configOverrides: any, + esVersion?: string | EsVersion ) { for (const [key, value] of Object.entries(this.lifecycle)) { if (value instanceof LifecyclePhase) { @@ -39,6 +43,12 @@ export class FunctionalTestRunner { value.after$.subscribe(() => log.verbose('starting %j lifecycle phase', key)); } } + this.esVersion = + esVersion === undefined + ? EsVersion.getDefault() + : esVersion instanceof EsVersion + ? esVersion + : new EsVersion(esVersion); } async run() { @@ -51,6 +61,27 @@ export class FunctionalTestRunner { ...readProviderSpec('PageObject', config.get('pageObjects')), ]); + // validate es version + if (providers.hasService('es')) { + const es = (await providers.getService('es')) as unknown as EsClient; + let esInfo; + try { + esInfo = await es.info(); + } catch (error) { + throw new Error( + `attempted to use the "es" service to fetch Elasticsearch version info but the request failed: ${error.stack}` + ); + } + + if (!this.esVersion.eql(esInfo.version.number)) { + throw new Error( + `ES reports a version number "${ + esInfo.version.number + }" which doesn't match supplied es version "${this.esVersion.toString()}"` + ); + } + } + await providers.loadAll(); const customTestRunner = config.get('testRunner'); @@ -61,7 +92,7 @@ export class FunctionalTestRunner { return (await providers.invokeProviderFn(customTestRunner)) || 0; } - const mocha = await setupMocha(this.lifecycle, this.log, config, providers); + const mocha = await setupMocha(this.lifecycle, this.log, config, providers, this.esVersion); await this.lifecycle.beforeTests.trigger(mocha.suite); this.log.info('Starting tests'); @@ -107,14 +138,14 @@ export class FunctionalTestRunner { ...readStubbedProviderSpec('PageObject', config.get('pageObjects'), []), ]); - const mocha = await setupMocha(this.lifecycle, this.log, config, providers); + const mocha = await setupMocha(this.lifecycle, this.log, config, providers, this.esVersion); const countTests = (suite: Suite): number => suite.suites.reduce((sum, s) => sum + countTests(s), suite.tests.length); return { testCount: countTests(mocha.suite), - excludedTests: mocha.excludedTests.map((t: Test) => t.fullTitle()), + testsExcludedByTag: mocha.testsExcludedByTag.map((t: Test) => t.fullTitle()), }; }); } @@ -125,7 +156,12 @@ export class FunctionalTestRunner { let runErrorOccurred = false; try { - const config = await readConfigFile(this.log, this.configFile, this.configOverrides); + const config = await readConfigFile( + this.log, + this.esVersion, + this.configFile, + this.configOverrides + ); this.log.info('Config loaded'); if ( @@ -148,6 +184,7 @@ export class FunctionalTestRunner { failureMetadata: () => this.failureMetadata, config: () => config, dockerServers: () => dockerServers, + esVersion: () => this.esVersion, }); return await handler(config, coreProviders); diff --git a/packages/kbn-test/src/functional_test_runner/index.ts b/packages/kbn-test/src/functional_test_runner/index.ts index 268c6b2bd9a670..1718b5f7a4bc57 100644 --- a/packages/kbn-test/src/functional_test_runner/index.ts +++ b/packages/kbn-test/src/functional_test_runner/index.ts @@ -7,7 +7,7 @@ */ export { FunctionalTestRunner } from './functional_test_runner'; -export { readConfigFile, Config } from './lib'; +export { readConfigFile, Config, EsVersion } from './lib'; export { runFtrCli } from './cli'; export * from './lib/docker_servers'; export * from './public_types'; diff --git a/packages/kbn-test/src/functional_test_runner/lib/config/read_config_file.test.js b/packages/kbn-test/src/functional_test_runner/lib/config/read_config_file.test.js index 60c307b58aee69..27434ce5a09ca0 100644 --- a/packages/kbn-test/src/functional_test_runner/lib/config/read_config_file.test.js +++ b/packages/kbn-test/src/functional_test_runner/lib/config/read_config_file.test.js @@ -9,34 +9,41 @@ import { ToolingLog } from '@kbn/dev-utils'; import { readConfigFile } from './read_config_file'; import { Config } from './config'; +import { EsVersion } from '../es_version'; const log = new ToolingLog(); +const esVersion = new EsVersion('8.0.0'); describe('readConfigFile()', () => { it('reads config from a file, returns an instance of Config class', async () => { - const config = await readConfigFile(log, require.resolve('./__fixtures__/config.1')); + const config = await readConfigFile(log, esVersion, require.resolve('./__fixtures__/config.1')); expect(config instanceof Config).toBeTruthy(); expect(config.get('testFiles')).toEqual(['config.1']); }); it('merges setting overrides into log', async () => { - const config = await readConfigFile(log, require.resolve('./__fixtures__/config.1'), { - screenshots: { - directory: 'foo.bar', - }, - }); + const config = await readConfigFile( + log, + esVersion, + require.resolve('./__fixtures__/config.1'), + { + screenshots: { + directory: 'foo.bar', + }, + } + ); expect(config.get('screenshots.directory')).toBe('foo.bar'); }); it('supports loading config files from within config files', async () => { - const config = await readConfigFile(log, require.resolve('./__fixtures__/config.2')); + const config = await readConfigFile(log, esVersion, require.resolve('./__fixtures__/config.2')); expect(config.get('testFiles')).toEqual(['config.1', 'config.2']); }); it('throws if settings are invalid', async () => { try { - await readConfigFile(log, require.resolve('./__fixtures__/config.invalid')); + await readConfigFile(log, esVersion, require.resolve('./__fixtures__/config.invalid')); throw new Error('expected readConfigFile() to fail'); } catch (err) { expect(err.message).toMatch(/"foo"/); diff --git a/packages/kbn-test/src/functional_test_runner/lib/config/read_config_file.ts b/packages/kbn-test/src/functional_test_runner/lib/config/read_config_file.ts index 374edea7a8db77..fd836f338edf02 100644 --- a/packages/kbn-test/src/functional_test_runner/lib/config/read_config_file.ts +++ b/packages/kbn-test/src/functional_test_runner/lib/config/read_config_file.ts @@ -10,10 +10,16 @@ import { ToolingLog } from '@kbn/dev-utils'; import { defaultsDeep } from 'lodash'; import { Config } from './config'; +import { EsVersion } from '../es_version'; const cache = new WeakMap(); -async function getSettingsFromFile(log: ToolingLog, path: string, settingOverrides: any) { +async function getSettingsFromFile( + log: ToolingLog, + esVersion: EsVersion, + path: string, + settingOverrides: any +) { const configModule = require(path); // eslint-disable-line @typescript-eslint/no-var-requires const configProvider = configModule.__esModule ? configModule.default : configModule; @@ -23,9 +29,10 @@ async function getSettingsFromFile(log: ToolingLog, path: string, settingOverrid configProvider, configProvider({ log, + esVersion, async readConfigFile(p: string, o: any) { return new Config({ - settings: await getSettingsFromFile(log, p, o), + settings: await getSettingsFromFile(log, esVersion, p, o), primary: false, path: p, }); @@ -43,9 +50,14 @@ async function getSettingsFromFile(log: ToolingLog, path: string, settingOverrid return settingsWithDefaults; } -export async function readConfigFile(log: ToolingLog, path: string, settingOverrides: any = {}) { +export async function readConfigFile( + log: ToolingLog, + esVersion: EsVersion, + path: string, + settingOverrides: any = {} +) { return new Config({ - settings: await getSettingsFromFile(log, path, settingOverrides), + settings: await getSettingsFromFile(log, esVersion, path, settingOverrides), primary: true, path, }); diff --git a/packages/kbn-test/src/functional_test_runner/lib/es_version.ts b/packages/kbn-test/src/functional_test_runner/lib/es_version.ts new file mode 100644 index 00000000000000..8b3acde47a4dc8 --- /dev/null +++ b/packages/kbn-test/src/functional_test_runner/lib/es_version.ts @@ -0,0 +1,55 @@ +/* + * 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. + */ + +import semver from 'semver'; +import { kibanaPackageJson } from '@kbn/utils'; + +export class EsVersion { + static getDefault() { + // example: https://storage.googleapis.com/kibana-ci-es-snapshots-daily/8.0.0/manifest-latest-verified.json + const manifestUrl = process.env.ES_SNAPSHOT_MANIFEST; + if (manifestUrl) { + const match = manifestUrl.match(/\d+\.\d+\.\d+/); + if (!match) { + throw new Error('unable to extract es version from ES_SNAPSHOT_MANIFEST_URL'); + } + return new EsVersion(match[0]); + } + + return new EsVersion(process.env.TEST_ES_BRANCH || kibanaPackageJson.version); + } + + public readonly parsed: semver.SemVer; + + constructor(version: string) { + const parsed = semver.coerce(version); + if (!parsed) { + throw new Error(`unable to parse es version [${version}]`); + } + this.parsed = parsed; + } + + toString() { + return this.parsed.version; + } + + /** + * Determine if the ES version matches a semver range, like >=7 or ^8.1.0 + */ + matchRange(range: string) { + return semver.satisfies(this.parsed, range); + } + + /** + * Determine if the ES version matches a specific version, ignores things like -SNAPSHOT + */ + eql(version: string) { + const other = semver.coerce(version); + return other && semver.compareLoose(this.parsed, other) === 0; + } +} diff --git a/packages/kbn-test/src/functional_test_runner/lib/index.ts b/packages/kbn-test/src/functional_test_runner/lib/index.ts index 1cb1e58a265d57..98b5fec0597e4e 100644 --- a/packages/kbn-test/src/functional_test_runner/lib/index.ts +++ b/packages/kbn-test/src/functional_test_runner/lib/index.ts @@ -17,3 +17,4 @@ export * from './docker_servers'; export { SuiteTracker } from './suite_tracker'; export type { Provider } from './providers'; +export * from './es_version'; diff --git a/packages/kbn-test/src/functional_test_runner/lib/mocha/decorate_mocha_ui.js b/packages/kbn-test/src/functional_test_runner/lib/mocha/decorate_mocha_ui.js index 7610ca91286949..e12ffdc8cd616a 100644 --- a/packages/kbn-test/src/functional_test_runner/lib/mocha/decorate_mocha_ui.js +++ b/packages/kbn-test/src/functional_test_runner/lib/mocha/decorate_mocha_ui.js @@ -84,6 +84,9 @@ export function decorateMochaUi(log, lifecycle, context, { isDockerGroup, rootTa this._tags = [...this._tags, ...tagsToAdd]; }; + this.onlyEsVersion = (semver) => { + this._esVersionRequirement = semver; + }; provider.call(this); diff --git a/packages/kbn-test/src/functional_test_runner/lib/mocha/filter_suites_by_tags.test.js b/packages/kbn-test/src/functional_test_runner/lib/mocha/filter_suites.test.js similarity index 86% rename from packages/kbn-test/src/functional_test_runner/lib/mocha/filter_suites_by_tags.test.js rename to packages/kbn-test/src/functional_test_runner/lib/mocha/filter_suites.test.js index 10030a1c05632b..191503af123d01 100644 --- a/packages/kbn-test/src/functional_test_runner/lib/mocha/filter_suites_by_tags.test.js +++ b/packages/kbn-test/src/functional_test_runner/lib/mocha/filter_suites.test.js @@ -12,9 +12,10 @@ import Mocha from 'mocha'; import { create as createSuite } from 'mocha/lib/suite'; import Test from 'mocha/lib/test'; -import { filterSuitesByTags } from './filter_suites_by_tags'; +import { filterSuites } from './filter_suites'; +import { EsVersion } from '../es_version'; -function setup({ include, exclude }) { +function setup({ include, exclude, esVersion }) { return new Promise((resolve) => { const history = []; @@ -55,6 +56,7 @@ function setup({ include, exclude }) { const level1b = createSuite(level1, 'level 1b'); level1b._tags = ['level1b']; + level1b._esVersionRequirement = '<=8'; level1b.addTest(new Test('test 1b', () => {})); const level2 = createSuite(mocha.suite, 'level 2'); @@ -62,7 +64,7 @@ function setup({ include, exclude }) { level2a._tags = ['level2a']; level2a.addTest(new Test('test 2a', () => {})); - filterSuitesByTags({ + filterSuites({ log: { info(...args) { history.push(`info: ${format(...args)}`); @@ -71,6 +73,7 @@ function setup({ include, exclude }) { mocha, include, exclude, + esVersion, }); mocha.run(); @@ -208,3 +211,27 @@ it('does nothing if everything excluded', async () => { ] `); }); + +it(`excludes tests which don't meet the esVersionRequirement`, async () => { + const { history } = await setup({ + include: [], + exclude: [], + esVersion: new EsVersion('9.0.0'), + }); + + expect(history).toMatchInlineSnapshot(` + Array [ + "info: Only running suites which are compatible with ES version 9.0.0", + "suite: ", + "suite: level 1", + "suite: level 1 level 1a", + "hook: \\"before each\\" hook: rootBeforeEach for \\"test 1a\\"", + "hook: level 1 \\"before each\\" hook: level1BeforeEach for \\"test 1a\\"", + "test: level 1 level 1a test 1a", + "suite: level 2", + "suite: level 2 level 2a", + "hook: \\"before each\\" hook: rootBeforeEach for \\"test 2a\\"", + "test: level 2 level 2a test 2a", + ] + `); +}); diff --git a/packages/kbn-test/src/functional_test_runner/lib/mocha/filter_suites_by_tags.js b/packages/kbn-test/src/functional_test_runner/lib/mocha/filter_suites.ts similarity index 55% rename from packages/kbn-test/src/functional_test_runner/lib/mocha/filter_suites_by_tags.js rename to packages/kbn-test/src/functional_test_runner/lib/mocha/filter_suites.ts index 9724956e121f34..90bb3a894bc6c3 100644 --- a/packages/kbn-test/src/functional_test_runner/lib/mocha/filter_suites_by_tags.js +++ b/packages/kbn-test/src/functional_test_runner/lib/mocha/filter_suites.ts @@ -6,6 +6,24 @@ * Side Public License, v 1. */ +import { ToolingLog } from '@kbn/dev-utils'; +import { Suite, Test } from '../../fake_mocha_types'; +import { EsVersion } from '../es_version'; + +interface SuiteInternal extends Suite { + _tags?: string[]; + _esVersionRequirement?: string; + suites: SuiteInternal[]; +} + +interface Options { + log: ToolingLog; + mocha: any; + include: string[]; + exclude: string[]; + esVersion?: EsVersion; +} + /** * Given a mocha instance that has already loaded all of its suites, filter out * the suites based on the include/exclude tags. If there are include tags then @@ -16,23 +34,50 @@ * @param options.include an array of tags that suites must be tagged with to be run * @param options.exclude an array of tags that will be used to exclude suites from the run */ -export function filterSuitesByTags({ log, mocha, include, exclude }) { - mocha.excludedTests = []; +export function filterSuites({ log, mocha, include, exclude, esVersion }: Options) { + mocha.testsExcludedByTag = []; + mocha.testsExcludedByEsVersion = []; + // collect all the tests from some suite, including it's children - const collectTests = (suite) => + const collectTests = (suite: SuiteInternal): Test[] => suite.suites.reduce((acc, s) => acc.concat(collectTests(s)), suite.tests); + if (esVersion) { + // traverse the test graph and exclude any tests which don't meet their esVersionRequirement + log.info('Only running suites which are compatible with ES version', esVersion.toString()); + (function recurse(parentSuite: SuiteInternal) { + const children = parentSuite.suites; + parentSuite.suites = []; + + const meetsEsVersionRequirement = (suite: SuiteInternal) => + !suite._esVersionRequirement || esVersion.matchRange(suite._esVersionRequirement); + + for (const child of children) { + if (meetsEsVersionRequirement(child)) { + parentSuite.suites.push(child); + recurse(child); + } else { + mocha.testsExcludedByEsVersion = mocha.testsExcludedByEsVersion.concat( + collectTests(child) + ); + } + } + })(mocha.suite); + } + // if include tags were provided, filter the tree once to // only include branches that are included at some point if (include.length) { log.info('Only running suites (and their sub-suites) if they include the tag(s):', include); - const isIncluded = (suite) => + const isIncludedByTags = (suite: SuiteInternal) => !suite._tags ? false : suite._tags.some((t) => include.includes(t)); - const isChildIncluded = (suite) => + + const isIncluded = (suite: SuiteInternal) => isIncludedByTags(suite); + const isChildIncluded = (suite: SuiteInternal): boolean => suite.suites.some((s) => isIncluded(s) || isChildIncluded(s)); - (function recurse(parentSuite) { + (function recurse(parentSuite: SuiteInternal) { const children = parentSuite.suites; parentSuite.suites = []; @@ -47,13 +92,13 @@ export function filterSuitesByTags({ log, mocha, include, exclude }) { // itself, so strip out its tests and recurse to filter // out child suites which are not included if (isChildIncluded(child)) { - mocha.excludedTests = mocha.excludedTests.concat(child.tests); + mocha.testsExcludedByTag = mocha.testsExcludedByTag.concat(child.tests); child.tests = []; parentSuite.suites.push(child); recurse(child); continue; } else { - mocha.excludedTests = mocha.excludedTests.concat(collectTests(child)); + mocha.testsExcludedByTag = mocha.testsExcludedByTag.concat(collectTests(child)); } } })(mocha.suite); @@ -64,9 +109,10 @@ export function filterSuitesByTags({ log, mocha, include, exclude }) { if (exclude.length) { log.info('Filtering out any suites that include the tag(s):', exclude); - const isNotExcluded = (suite) => !suite._tags || !suite._tags.some((t) => exclude.includes(t)); + const isNotExcluded = (suite: SuiteInternal) => + !suite._tags || !suite._tags.some((t) => exclude.includes(t)); - (function recurse(parentSuite) { + (function recurse(parentSuite: SuiteInternal) { const children = parentSuite.suites; parentSuite.suites = []; @@ -77,7 +123,7 @@ export function filterSuitesByTags({ log, mocha, include, exclude }) { parentSuite.suites.push(child); recurse(child); } else { - mocha.excludedTests = mocha.excludedTests.concat(collectTests(child)); + mocha.testsExcludedByTag = mocha.testsExcludedByTag.concat(collectTests(child)); } } })(mocha.suite); diff --git a/packages/kbn-test/src/functional_test_runner/lib/mocha/setup_mocha.js b/packages/kbn-test/src/functional_test_runner/lib/mocha/setup_mocha.js index 65b7c09242fdd4..8d88410cb2c1da 100644 --- a/packages/kbn-test/src/functional_test_runner/lib/mocha/setup_mocha.js +++ b/packages/kbn-test/src/functional_test_runner/lib/mocha/setup_mocha.js @@ -11,7 +11,7 @@ import { relative } from 'path'; import { REPO_ROOT } from '@kbn/utils'; import { loadTestFiles } from './load_test_files'; -import { filterSuitesByTags } from './filter_suites_by_tags'; +import { filterSuites } from './filter_suites'; import { MochaReporterProvider } from './reporter'; import { validateCiGroupTags } from './validate_ci_group_tags'; @@ -22,9 +22,10 @@ import { validateCiGroupTags } from './validate_ci_group_tags'; * @param {ToolingLog} log * @param {Config} config * @param {ProviderCollection} providers + * @param {EsVersion} esVersion * @return {Promise} */ -export async function setupMocha(lifecycle, log, config, providers) { +export async function setupMocha(lifecycle, log, config, providers, esVersion) { // configure mocha const mocha = new Mocha({ ...config.get('mochaOpts'), @@ -50,18 +51,26 @@ export async function setupMocha(lifecycle, log, config, providers) { // valiate that there aren't any tests in multiple ciGroups validateCiGroupTags(log, mocha); + filterSuites({ + log, + mocha, + include: [], + exclude: [], + esVersion, + }); + // Each suite has a tag that is the path relative to the root of the repo // So we just need to take input paths, make them relative to the root, and use them as tags // Also, this is a separate filterSuitesByTags() call so that the test suites will be filtered first by // files, then by tags. This way, you can target tags (like smoke) in a specific file. - filterSuitesByTags({ + filterSuites({ log, mocha, include: config.get('suiteFiles.include').map((file) => relative(REPO_ROOT, file)), exclude: config.get('suiteFiles.exclude').map((file) => relative(REPO_ROOT, file)), }); - filterSuitesByTags({ + filterSuites({ log, mocha, include: config.get('suiteTags.include').map((tag) => tag.replace(/-\d+$/, '')), diff --git a/packages/kbn-test/src/functional_test_runner/public_types.ts b/packages/kbn-test/src/functional_test_runner/public_types.ts index d1a0f7998b0a98..6cb6d5adf4b191 100644 --- a/packages/kbn-test/src/functional_test_runner/public_types.ts +++ b/packages/kbn-test/src/functional_test_runner/public_types.ts @@ -6,10 +6,10 @@ * Side Public License, v 1. */ -import { ToolingLog } from '@kbn/dev-utils'; +import type { ToolingLog } from '@kbn/dev-utils'; -import { Config, Lifecycle, FailureMetadata, DockerServersService } from './lib'; -import { Test, Suite } from './fake_mocha_types'; +import type { Config, Lifecycle, FailureMetadata, DockerServersService, EsVersion } from './lib'; +import type { Test, Suite } from './fake_mocha_types'; export { Lifecycle, Config, FailureMetadata }; @@ -57,7 +57,7 @@ export interface GenericFtrProviderContext< * @param serviceName */ hasService( - serviceName: 'config' | 'log' | 'lifecycle' | 'failureMetadata' | 'dockerServers' + serviceName: 'config' | 'log' | 'lifecycle' | 'failureMetadata' | 'dockerServers' | 'esVersion' ): true; hasService(serviceName: K): serviceName is K; hasService(serviceName: string): serviceName is Extract; @@ -72,6 +72,7 @@ export interface GenericFtrProviderContext< getService(serviceName: 'lifecycle'): Lifecycle; getService(serviceName: 'dockerServers'): DockerServersService; getService(serviceName: 'failureMetadata'): FailureMetadata; + getService(serviceName: 'esVersion'): EsVersion; getService(serviceName: T): ServiceMap[T]; /** @@ -100,6 +101,7 @@ export class GenericFtrService; } diff --git a/packages/kbn-test/src/functional_tests/cli/run_tests/__snapshots__/args.test.js.snap b/packages/kbn-test/src/functional_tests/cli/run_tests/__snapshots__/args.test.js.snap index ad2f82de87b82d..fb00908e0c7548 100644 --- a/packages/kbn-test/src/functional_tests/cli/run_tests/__snapshots__/args.test.js.snap +++ b/packages/kbn-test/src/functional_tests/cli/run_tests/__snapshots__/args.test.js.snap @@ -37,6 +37,7 @@ Object { ], "createLogger": [Function], "esFrom": "snapshot", + "esVersion": "999.999.999", "extraKbnOpts": undefined, "suiteFiles": Object { "exclude": Array [], @@ -58,6 +59,7 @@ Object { ], "createLogger": [Function], "esFrom": "snapshot", + "esVersion": "999.999.999", "extraKbnOpts": undefined, "suiteFiles": Object { "exclude": Array [], @@ -80,6 +82,7 @@ Object { "createLogger": [Function], "debug": true, "esFrom": "snapshot", + "esVersion": "999.999.999", "extraKbnOpts": undefined, "suiteFiles": Object { "exclude": Array [], @@ -101,6 +104,7 @@ Object { ], "createLogger": [Function], "esFrom": "snapshot", + "esVersion": "999.999.999", "extraKbnOpts": undefined, "suiteFiles": Object { "exclude": Array [], @@ -124,6 +128,7 @@ Object { ], "createLogger": [Function], "esFrom": "snapshot", + "esVersion": "999.999.999", "extraKbnOpts": Object { "server.foo": "bar", }, @@ -146,6 +151,7 @@ Object { ], "createLogger": [Function], "esFrom": "snapshot", + "esVersion": "999.999.999", "extraKbnOpts": undefined, "quiet": true, "suiteFiles": Object { @@ -167,6 +173,7 @@ Object { ], "createLogger": [Function], "esFrom": "snapshot", + "esVersion": "999.999.999", "extraKbnOpts": undefined, "silent": true, "suiteFiles": Object { @@ -188,6 +195,7 @@ Object { ], "createLogger": [Function], "esFrom": "source", + "esVersion": "999.999.999", "extraKbnOpts": undefined, "suiteFiles": Object { "exclude": Array [], @@ -208,6 +216,7 @@ Object { ], "createLogger": [Function], "esFrom": "source", + "esVersion": "999.999.999", "extraKbnOpts": undefined, "suiteFiles": Object { "exclude": Array [], @@ -228,6 +237,7 @@ Object { ], "createLogger": [Function], "esFrom": "snapshot", + "esVersion": "999.999.999", "extraKbnOpts": undefined, "installDir": "foo", "suiteFiles": Object { @@ -249,6 +259,7 @@ Object { ], "createLogger": [Function], "esFrom": "snapshot", + "esVersion": "999.999.999", "extraKbnOpts": undefined, "grep": "management", "suiteFiles": Object { @@ -270,6 +281,7 @@ Object { ], "createLogger": [Function], "esFrom": "snapshot", + "esVersion": "999.999.999", "extraKbnOpts": undefined, "suiteFiles": Object { "exclude": Array [], @@ -291,6 +303,7 @@ Object { ], "createLogger": [Function], "esFrom": "snapshot", + "esVersion": "999.999.999", "extraKbnOpts": undefined, "suiteFiles": Object { "exclude": Array [], diff --git a/packages/kbn-test/src/functional_tests/cli/run_tests/args.js b/packages/kbn-test/src/functional_tests/cli/run_tests/args.js index 901ff6394649de..497a9b9c6c5339 100644 --- a/packages/kbn-test/src/functional_tests/cli/run_tests/args.js +++ b/packages/kbn-test/src/functional_tests/cli/run_tests/args.js @@ -10,6 +10,7 @@ import { resolve } from 'path'; import dedent from 'dedent'; import { ToolingLog, pickLevelFromFlags } from '@kbn/dev-utils'; +import { EsVersion } from '../../../functional_test_runner'; const options = { help: { desc: 'Display this menu and exit.' }, @@ -147,6 +148,7 @@ export function processOptions(userOptions, defaultConfigPaths) { configs: configs.map((c) => resolve(c)), createLogger, extraKbnOpts: userOptions._, + esVersion: EsVersion.getDefault(), }; } diff --git a/packages/kbn-test/src/functional_tests/cli/run_tests/args.test.js b/packages/kbn-test/src/functional_tests/cli/run_tests/args.test.js index 7786aee5af5526..72ba541466960d 100644 --- a/packages/kbn-test/src/functional_tests/cli/run_tests/args.test.js +++ b/packages/kbn-test/src/functional_tests/cli/run_tests/args.test.js @@ -6,9 +6,20 @@ * Side Public License, v 1. */ -import { displayHelp, processOptions } from './args'; import { createAbsolutePathSerializer } from '@kbn/dev-utils'; +import { displayHelp, processOptions } from './args'; + +jest.mock('../../../functional_test_runner/lib/es_version', () => { + return { + EsVersion: class { + static getDefault() { + return '999.999.999'; + } + }, + }; +}); + expect.addSnapshotSerializer(createAbsolutePathSerializer(process.cwd())); const INITIAL_TEST_ES_FROM = process.env.TEST_ES_FROM; diff --git a/packages/kbn-test/src/functional_tests/lib/run_ftr.ts b/packages/kbn-test/src/functional_tests/lib/run_ftr.ts index f9e109928ddc0b..77d6cd8e357a5a 100644 --- a/packages/kbn-test/src/functional_tests/lib/run_ftr.ts +++ b/packages/kbn-test/src/functional_tests/lib/run_ftr.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ import type { ToolingLog } from '@kbn/dev-utils'; -import { FunctionalTestRunner, readConfigFile } from '../../functional_test_runner'; +import { FunctionalTestRunner, readConfigFile, EsVersion } from '../../functional_test_runner'; import { CliError } from './run_cli'; export interface CreateFtrOptions { @@ -26,6 +26,7 @@ export interface CreateFtrOptions { exclude?: string[]; }; updateSnapshots?: boolean; + esVersion: EsVersion; } export interface CreateFtrParams { @@ -34,31 +35,46 @@ export interface CreateFtrParams { } async function createFtr({ configPath, - options: { installDir, log, bail, grep, updateBaselines, suiteFiles, suiteTags, updateSnapshots }, + options: { + installDir, + log, + bail, + grep, + updateBaselines, + suiteFiles, + suiteTags, + updateSnapshots, + esVersion, + }, }: CreateFtrParams) { - const config = await readConfigFile(log, configPath); + const config = await readConfigFile(log, esVersion, configPath); return { config, - ftr: new FunctionalTestRunner(log, configPath, { - mochaOpts: { - bail: !!bail, - grep, + ftr: new FunctionalTestRunner( + log, + configPath, + { + mochaOpts: { + bail: !!bail, + grep, + }, + kbnTestServer: { + installDir, + }, + updateBaselines, + updateSnapshots, + suiteFiles: { + include: [...(suiteFiles?.include || []), ...config.get('suiteFiles.include')], + exclude: [...(suiteFiles?.exclude || []), ...config.get('suiteFiles.exclude')], + }, + suiteTags: { + include: [...(suiteTags?.include || []), ...config.get('suiteTags.include')], + exclude: [...(suiteTags?.exclude || []), ...config.get('suiteTags.exclude')], + }, }, - kbnTestServer: { - installDir, - }, - updateBaselines, - updateSnapshots, - suiteFiles: { - include: [...(suiteFiles?.include || []), ...config.get('suiteFiles.include')], - exclude: [...(suiteFiles?.exclude || []), ...config.get('suiteFiles.exclude')], - }, - suiteTags: { - include: [...(suiteTags?.include || []), ...config.get('suiteTags.include')], - exclude: [...(suiteTags?.exclude || []), ...config.get('suiteTags.exclude')], - }, - }), + esVersion + ), }; } @@ -71,15 +87,15 @@ export async function assertNoneExcluded({ configPath, options }: CreateFtrParam } const stats = await ftr.getTestStats(); - if (stats.excludedTests.length > 0) { + if (stats.testsExcludedByTag.length > 0) { throw new CliError(` - ${stats.excludedTests.length} tests in the ${configPath} config + ${stats.testsExcludedByTag.length} tests in the ${configPath} config are excluded when filtering by the tags run on CI. Make sure that all suites are tagged with one of the following tags: ${JSON.stringify(options.suiteTags)} - - ${stats.excludedTests.join('\n - ')} + - ${stats.testsExcludedByTag.join('\n - ')} `); } } diff --git a/packages/kbn-test/src/functional_tests/tasks.ts b/packages/kbn-test/src/functional_tests/tasks.ts index cace061be64a9c..5906193ca145c7 100644 --- a/packages/kbn-test/src/functional_tests/tasks.ts +++ b/packages/kbn-test/src/functional_tests/tasks.ts @@ -23,7 +23,7 @@ import { CreateFtrOptions, } from './lib'; -import { readConfigFile } from '../functional_test_runner/lib'; +import { readConfigFile, EsVersion } from '../functional_test_runner/lib'; const makeSuccessMessage = (options: StartServerOptions) => { const installDirFlag = options.installDir ? ` --kibana-install-dir=${options.installDir}` : ''; @@ -55,6 +55,7 @@ interface RunTestsParams extends CreateFtrOptions { configs: string[]; /** run from source instead of snapshot */ esFrom?: string; + esVersion: EsVersion; createLogger: () => ToolingLog; extraKbnOpts: string[]; assertNoneExcluded: boolean; @@ -105,7 +106,7 @@ export async function runTests(options: RunTestsParams) { log.write(`--- [${progress}] Running ${relative(REPO_ROOT, configPath)}`); await withProcRunner(log, async (procs) => { - const config = await readConfigFile(log, configPath); + const config = await readConfigFile(log, options.esVersion, configPath); let es; try { @@ -145,6 +146,7 @@ interface StartServerOptions { createLogger: () => ToolingLog; extraKbnOpts: string[]; useDefaultConfig?: boolean; + esVersion: EsVersion; } export async function startServers({ ...options }: StartServerOptions) { @@ -162,7 +164,7 @@ export async function startServers({ ...options }: StartServerOptions) { }; await withProcRunner(log, async (procs) => { - const config = await readConfigFile(log, options.config); + const config = await readConfigFile(log, options.esVersion, options.config); const es = await runElasticsearch({ config, options: opts }); await runKibanaServer({ diff --git a/packages/kbn-test/src/kbn_archiver_cli.ts b/packages/kbn-test/src/kbn_archiver_cli.ts index 80e35efaec976f..f7f17900efcfff 100644 --- a/packages/kbn-test/src/kbn_archiver_cli.ts +++ b/packages/kbn-test/src/kbn_archiver_cli.ts @@ -12,7 +12,7 @@ import Url from 'url'; import { RunWithCommands, createFlagError, Flags } from '@kbn/dev-utils'; import { KbnClient } from './kbn_client'; -import { readConfigFile } from './functional_test_runner'; +import { readConfigFile, EsVersion } from './functional_test_runner'; function getSinglePositionalArg(flags: Flags) { const positional = flags._; @@ -57,7 +57,7 @@ export function runKbnArchiverCli() { throw createFlagError('expected --config to be a string'); } - config = await readConfigFile(log, Path.resolve(flags.config)); + config = await readConfigFile(log, EsVersion.getDefault(), Path.resolve(flags.config)); statsMeta.set('ftrConfigPath', flags.config); } diff --git a/packages/kbn-test/types/ftr_globals/mocha.d.ts b/packages/kbn-test/types/ftr_globals/mocha.d.ts index ac9e33d4b9dcc7..d5895b40f12453 100644 --- a/packages/kbn-test/types/ftr_globals/mocha.d.ts +++ b/packages/kbn-test/types/ftr_globals/mocha.d.ts @@ -14,5 +14,11 @@ declare module 'mocha' { * Assign tags to the test suite to determine in which CI job it should be run. */ tags(tags: string[] | string): void; + /** + * Define the ES versions for which this test requires, any version which doesn't meet this range will + * cause these tests to be skipped + * @param semver any valid semver range, like ">=8" + */ + onlyEsVersion(semver: string): void; } } From aaefbd22aac753b8f48026ed6c1e4418bcbf7c8f Mon Sep 17 00:00:00 2001 From: Dominique Clarke Date: Wed, 19 Jan 2022 18:43:16 -0500 Subject: [PATCH 061/108] [Uptime] Monitor management - fix breadcrumbs (#123240) * uptime - monitor management - fix breadcrumbs * add synthetics breadcrumbs tests * fix types * update i18n --- x-pack/plugins/uptime/common/constants/ui.ts | 2 +- .../journeys/monitor_management.journey.ts | 60 ++++++++++++++++++ .../e2e/page_objects/monitor_management.tsx | 4 ++ .../common/header/action_menu_content.tsx | 8 ++- .../action_bar/action_bar.tsx | 6 +- .../monitor_list/actions.tsx | 1 + .../pages/monitor_management/add_monitor.tsx | 3 + .../pages/monitor_management/edit_monitor.tsx | 2 + .../monitor_management/monitor_management.tsx | 2 + .../use_monitor_management_breadcrumbs.tsx | 63 +++++++++++++++++++ x-pack/plugins/uptime/public/routes.tsx | 4 +- 11 files changed, 147 insertions(+), 8 deletions(-) create mode 100644 x-pack/plugins/uptime/public/pages/monitor_management/use_monitor_management_breadcrumbs.tsx diff --git a/x-pack/plugins/uptime/common/constants/ui.ts b/x-pack/plugins/uptime/common/constants/ui.ts index 7a9cd4943bc579..155c6ea80242fc 100644 --- a/x-pack/plugins/uptime/common/constants/ui.ts +++ b/x-pack/plugins/uptime/common/constants/ui.ts @@ -11,7 +11,7 @@ export const MONITOR_ADD_ROUTE = '/add-monitor'; export const MONITOR_EDIT_ROUTE = '/edit-monitor/:monitorId'; -export const MONITOR_MANAGEMENT = '/manage-monitors'; +export const MONITOR_MANAGEMENT_ROUTE = '/manage-monitors'; export const OVERVIEW_ROUTE = '/'; diff --git a/x-pack/plugins/uptime/e2e/journeys/monitor_management.journey.ts b/x-pack/plugins/uptime/e2e/journeys/monitor_management.journey.ts index efc47c44765c8c..e5b0cd352ac5bf 100644 --- a/x-pack/plugins/uptime/e2e/journeys/monitor_management.journey.ts +++ b/x-pack/plugins/uptime/e2e/journeys/monitor_management.journey.ts @@ -134,3 +134,63 @@ journey('Monitor Management', async ({ page, params }: { page: Page; params: any await deleteMonitor(); }); }); + +journey('Monitor Management breadcrumbs', async ({ page, params }: { page: Page; params: any }) => { + const uptime = monitorManagementPageProvider({ page, kibanaUrl: params.kibanaUrl }); + const basicMonitorDetails = { + name: 'Sample monitor', + location: 'US Central', + schedule: '@every 3m', + apmServiceName: 'service', + }; + + before(async () => { + await uptime.waitForLoadingToFinish(); + }); + + step('Go to monitor-management', async () => { + await uptime.navigateToMonitorManagement(); + }); + + step('login to Kibana', async () => { + await uptime.loginToKibana(); + }); + + step('Check breadcrumb', async () => { + const lastBreadcrumb = await (await uptime.findByTestSubj('"breadcrumb last"')).textContent(); + expect(lastBreadcrumb).toEqual('Monitor management'); + }); + + step('check breadcrumbs', async () => { + await uptime.clickAddMonitor(); + const breadcrumbs = await page.$$('[data-test-subj="breadcrumb"]'); + expect(await breadcrumbs[1].textContent()).toEqual('Monitor management'); + const lastBreadcrumb = await (await uptime.findByTestSubj('"breadcrumb last"')).textContent(); + expect(lastBreadcrumb).toEqual('Add monitor'); + }); + + step('create monitor http monitor', async () => { + const monitorDetails = { + ...basicMonitorDetails, + url: 'https://elastic.co', + locations: [basicMonitorDetails.location], + }; + await uptime.createBasicHTTPMonitorDetails(monitorDetails); + const isSuccessful = await uptime.confirmAndSave(); + expect(isSuccessful).toBeTruthy(); + }); + + step('edit http monitor and check breadcrumb', async () => { + await uptime.editMonitor(); + const breadcrumbs = await page.$$('[data-test-subj=breadcrumb]'); + expect(await breadcrumbs[1].textContent()).toEqual('Monitor management'); + const lastBreadcrumb = await (await uptime.findByTestSubj('"breadcrumb last"')).textContent(); + expect(lastBreadcrumb).toEqual('Edit monitor'); + }); + + step('delete monitor', async () => { + await uptime.navigateToMonitorManagement(); + const isSuccessful = await uptime.deleteMonitor(); + expect(isSuccessful).toBeTruthy(); + }); +}); diff --git a/x-pack/plugins/uptime/e2e/page_objects/monitor_management.tsx b/x-pack/plugins/uptime/e2e/page_objects/monitor_management.tsx index 51f476a7a17429..e12b7fdf40bc37 100644 --- a/x-pack/plugins/uptime/e2e/page_objects/monitor_management.tsx +++ b/x-pack/plugins/uptime/e2e/page_objects/monitor_management.tsx @@ -44,6 +44,10 @@ export function monitorManagementPageProvider({ return await this.findByTestSubj('uptimeDeleteMonitorSuccess'); }, + async editMonitor() { + await this.clickByTestSubj('monitorManagementEditMonitor'); + }, + async findMonitorConfiguration(monitorConfig: Record) { const values = Object.values(monitorConfig); diff --git a/x-pack/plugins/uptime/public/components/common/header/action_menu_content.tsx b/x-pack/plugins/uptime/public/components/common/header/action_menu_content.tsx index 0600a629ad3e2b..985b1ae9146f24 100644 --- a/x-pack/plugins/uptime/public/components/common/header/action_menu_content.tsx +++ b/x-pack/plugins/uptime/public/components/common/header/action_menu_content.tsx @@ -16,7 +16,11 @@ import { useKibana } from '../../../../../../../src/plugins/kibana_react/public' import { useUptimeSettingsContext } from '../../../contexts/uptime_settings_context'; import { useGetUrlParams } from '../../../hooks'; import { ToggleAlertFlyoutButton } from '../../overview/alerts/alerts_containers'; -import { MONITOR_MANAGEMENT, MONITOR_ROUTE, SETTINGS_ROUTE } from '../../../../common/constants'; +import { + MONITOR_MANAGEMENT_ROUTE, + MONITOR_ROUTE, + SETTINGS_ROUTE, +} from '../../../../common/constants'; import { stringifyUrlParams } from '../../../lib/helper/stringify_url_params'; import { InspectorHeaderLink } from './inspector_header_link'; import { monitorStatusSelector } from '../../../state/selectors'; @@ -81,7 +85,7 @@ export function ActionMenuContent({ config }: { config: UptimeConfig }): React.R color="text" data-test-subj="management-page-link" href={history.createHref({ - pathname: MONITOR_MANAGEMENT, + pathname: MONITOR_MANAGEMENT_ROUTE, })} > { }, [data, status, notifications.toasts, isSaving, isValid, monitorId]); return status === FETCH_STATUS.SUCCESS ? ( - + ) : ( {!isValid && hasBeenSubmitted && VALIDATION_ERROR_LABEL} @@ -92,7 +92,7 @@ export const ActionBar = ({ monitor, isValid, onSave }: Props) => { color="ghost" size="s" iconType="cross" - href={`${basePath}/app/uptime/${MONITOR_MANAGEMENT}`} + href={`${basePath}/app/uptime/${MONITOR_MANAGEMENT_ROUTE}`} > {DISCARD_LABEL} diff --git a/x-pack/plugins/uptime/public/components/monitor_management/monitor_list/actions.tsx b/x-pack/plugins/uptime/public/components/monitor_management/monitor_list/actions.tsx index c3ef3610f8c7e3..d86117df555ad3 100644 --- a/x-pack/plugins/uptime/public/components/monitor_management/monitor_list/actions.tsx +++ b/x-pack/plugins/uptime/public/components/monitor_management/monitor_list/actions.tsx @@ -61,6 +61,7 @@ export const Actions = ({ id, setRefresh }: Props) => { iconType="pencil" href={`${basePath}/app/uptime/edit-monitor/${Buffer.from(id, 'utf8').toString('base64')}`} aria-label={EDIT_MONITOR_LABEL} + data-test-subj="monitorManagementEditMonitor" /> diff --git a/x-pack/plugins/uptime/public/pages/monitor_management/add_monitor.tsx b/x-pack/plugins/uptime/public/pages/monitor_management/add_monitor.tsx index 749a109dffda2b..cc474b06546439 100644 --- a/x-pack/plugins/uptime/public/pages/monitor_management/add_monitor.tsx +++ b/x-pack/plugins/uptime/public/pages/monitor_management/add_monitor.tsx @@ -13,6 +13,7 @@ import { SyntheticsProviders } from '../../components/fleet_package/contexts'; import { Loader } from '../../components/monitor_management/loader/loader'; import { MonitorConfig } from '../../components/monitor_management/monitor_config/monitor_config'; import { useLocations } from '../../components/monitor_management/hooks/use_locations'; +import { useMonitorManagementBreadcrumbs } from './use_monitor_management_breadcrumbs'; export const AddMonitorPage: React.FC = () => { useTrackPageview({ app: 'uptime', path: 'add-monitor' }); @@ -20,6 +21,8 @@ export const AddMonitorPage: React.FC = () => { const { error, loading } = useLocations(); + useMonitorManagementBreadcrumbs({ isAddMonitor: true }); + return ( { useTrackPageview({ app: 'uptime', path: 'edit-monitor' }); useTrackPageview({ app: 'uptime', path: 'edit-monitor', delay: 15000 }); + useMonitorManagementBreadcrumbs({ isEditMonitor: true }); const { monitorId } = useParams<{ monitorId: string }>(); const { data, status } = useFetcher>(() => { diff --git a/x-pack/plugins/uptime/public/pages/monitor_management/monitor_management.tsx b/x-pack/plugins/uptime/public/pages/monitor_management/monitor_management.tsx index 0619f4d4bed1cf..cb43dc9c90d7d0 100644 --- a/x-pack/plugins/uptime/public/pages/monitor_management/monitor_management.tsx +++ b/x-pack/plugins/uptime/public/pages/monitor_management/monitor_management.tsx @@ -11,6 +11,7 @@ import { useTrackPageview } from '../../../../observability/public'; import { getMonitors } from '../../state/actions'; import { monitorManagementListSelector } from '../../state/selectors'; import { MonitorManagementList } from '../../components/monitor_management/monitor_list/monitor_list'; +import { useMonitorManagementBreadcrumbs } from './use_monitor_management_breadcrumbs'; export const MonitorManagementPage: React.FC = () => { const [refresh, setRefresh] = useState(true); @@ -18,6 +19,7 @@ export const MonitorManagementPage: React.FC = () => { const [pageSize, setPageSize] = useState(10); // saved objects page index is base 1 useTrackPageview({ app: 'uptime', path: 'manage-monitors' }); useTrackPageview({ app: 'uptime', path: 'manage-monitors', delay: 15000 }); + useMonitorManagementBreadcrumbs(); const dispatch = useDispatch(); const monitorList = useSelector(monitorManagementListSelector); diff --git a/x-pack/plugins/uptime/public/pages/monitor_management/use_monitor_management_breadcrumbs.tsx b/x-pack/plugins/uptime/public/pages/monitor_management/use_monitor_management_breadcrumbs.tsx new file mode 100644 index 00000000000000..e5784591a00fc4 --- /dev/null +++ b/x-pack/plugins/uptime/public/pages/monitor_management/use_monitor_management_breadcrumbs.tsx @@ -0,0 +1,63 @@ +/* + * 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 { i18n } from '@kbn/i18n'; +import { useKibana } from '../../../../../../src/plugins/kibana_react/public'; +import { useBreadcrumbs } from '../../hooks/use_breadcrumbs'; +import { MONITOR_MANAGEMENT_ROUTE } from '../../../common/constants'; +import { PLUGIN } from '../../../common/constants/plugin'; + +export const useMonitorManagementBreadcrumbs = ({ + isAddMonitor, + isEditMonitor, + monitorId, +}: { + isAddMonitor?: boolean; + isEditMonitor?: boolean; + monitorId?: string; +} = {}) => { + const kibana = useKibana(); + const appPath = kibana.services.application?.getUrlForApp(PLUGIN.ID) ?? ''; + + useBreadcrumbs([ + { + text: MONITOR_MANAGEMENT_CRUMB, + href: isAddMonitor || isEditMonitor ? `${appPath}/${MONITOR_MANAGEMENT_ROUTE}` : undefined, + }, + ...(isAddMonitor + ? [ + { + text: ADD_MONITOR_CRUMB, + }, + ] + : []), + ...(isEditMonitor + ? [ + { + text: EDIT_MONITOR_CRUMB, + }, + ] + : []), + ]); +}; + +export const MONITOR_MANAGEMENT_CRUMB = i18n.translate( + 'xpack.uptime.monitorManagement.monitorManagementCrumb', + { + defaultMessage: 'Monitor management', + } +); + +export const ADD_MONITOR_CRUMB = i18n.translate('xpack.uptime.monitorManagement.addMonitorCrumb', { + defaultMessage: 'Add monitor', +}); + +export const EDIT_MONITOR_CRUMB = i18n.translate( + 'xpack.uptime.monitorManagement.editMonitorCrumb', + { + defaultMessage: 'Edit monitor', + } +); diff --git a/x-pack/plugins/uptime/public/routes.tsx b/x-pack/plugins/uptime/public/routes.tsx index d462d35a15f566..bcb942250c6f13 100644 --- a/x-pack/plugins/uptime/public/routes.tsx +++ b/x-pack/plugins/uptime/public/routes.tsx @@ -16,7 +16,7 @@ import { MONITOR_ROUTE, MONITOR_ADD_ROUTE, MONITOR_EDIT_ROUTE, - MONITOR_MANAGEMENT, + MONITOR_MANAGEMENT_ROUTE, OVERVIEW_ROUTE, SETTINGS_ROUTE, STEP_DETAIL_ROUTE, @@ -231,7 +231,7 @@ const getRoutes = (config: UptimeConfig): RouteProps[] => { defaultMessage: 'Manage Monitors | {baseTitle}', values: { baseTitle }, }), - path: MONITOR_MANAGEMENT, + path: MONITOR_MANAGEMENT_ROUTE, component: MonitorManagementPage, dataTestSubj: 'uptimeMonitorManagementListPage', telemetryId: UptimePage.MonitorManagement, From b5c8464162dc56407b14e97153ea9ad626915d44 Mon Sep 17 00:00:00 2001 From: Pablo Machado Date: Wed, 19 Jan 2022 21:57:52 -0300 Subject: [PATCH 062/108] Host Risk score tab on Host details page (#122586) * Create host risk tab * Create host score over time chart * Create Top risk score contributors table * Fix Host risk score over time chart * Add Dashboard and information buttons to host details page * Update Top risk score contributors table to follow timerange filter * Improve unit tests * Hide risk tab from Hots detaisl when feature flag is disabled * Add cypress test to host details risk tab * Delete filterQuery option from Hostrisk SearchStrategy --- .../security_solution/common/constants.ts | 3 +- .../hosts/risk_score/index.ts | 12 +- .../hosts/host_details_risk_tab.spec.ts | 40 ++++ ...sk_column.ts => hosts_risk_column.spec.ts} | 0 .../cypress/screens/hosts/host_risk.ts | 16 ++ .../cypress/tasks/host_risk.ts | 17 ++ .../security_solution/cypress/tasks/login.ts | 4 +- .../cti_details/host_risk_summary.test.tsx | 2 + .../navigation/tab_navigation/index.test.tsx | 3 +- .../common/containers/hosts_risk/types.ts | 13 ++ .../hosts_risk/use_hosts_risk_score.ts | 41 +++- .../use_hosts_risk_score_complete.ts | 4 + .../public/common/mock/global_state.ts | 2 + .../host_risk_information/index.test.tsx | 22 +- .../host_risk_information/index.tsx | 53 +++-- .../host_risk_information/translations.ts | 7 + .../host_score_over_time/index.test.tsx | 51 +++++ .../components/host_score_over_time/index.tsx | 202 ++++++++++++++++++ .../host_score_over_time/translations.ts | 33 +++ .../kpi_hosts/risky_hosts/index.tsx | 7 +- .../index.test.tsx | 72 +++++++ .../top_host_score_contributors/index.tsx | 125 +++++++++++ .../translations.ts | 29 +++ .../hosts/pages/details/details_tabs.tsx | 4 + .../public/hosts/pages/details/index.tsx | 9 +- .../hosts/pages/details/nav_tabs.test.tsx | 15 +- .../public/hosts/pages/details/nav_tabs.tsx | 23 +- .../public/hosts/pages/details/utils.ts | 1 + .../public/hosts/pages/index.tsx | 1 + .../pages/navigation/host_risk_tab_body.tsx | 60 ++++++ .../public/hosts/pages/navigation/index.ts | 1 + .../public/hosts/pages/translations.ts | 14 ++ .../public/hosts/store/helpers.test.ts | 4 + .../public/hosts/store/model.ts | 2 + .../public/hosts/store/reducer.ts | 2 + .../overview_risky_host_links/index.tsx | 6 +- .../risky_hosts_enabled_module.test.tsx | 1 + .../risky_hosts_panel_view.tsx | 4 +- .../query.hosts_kpi_risky_hosts.dsl.ts | 3 - .../hosts/risk_score/query.hosts_risk.dsl.ts | 14 +- .../es_archives/risky_hosts/data.json | 25 +++ .../es_archives/risky_hosts/mappings.json | 58 +++++ 42 files changed, 953 insertions(+), 52 deletions(-) create mode 100644 x-pack/plugins/security_solution/cypress/integration/hosts/host_details_risk_tab.spec.ts rename x-pack/plugins/security_solution/cypress/integration/hosts/{hosts_risk_column.ts => hosts_risk_column.spec.ts} (100%) create mode 100644 x-pack/plugins/security_solution/cypress/screens/hosts/host_risk.ts create mode 100644 x-pack/plugins/security_solution/cypress/tasks/host_risk.ts create mode 100644 x-pack/plugins/security_solution/public/common/containers/hosts_risk/types.ts create mode 100644 x-pack/plugins/security_solution/public/hosts/components/host_score_over_time/index.test.tsx create mode 100644 x-pack/plugins/security_solution/public/hosts/components/host_score_over_time/index.tsx create mode 100644 x-pack/plugins/security_solution/public/hosts/components/host_score_over_time/translations.ts create mode 100644 x-pack/plugins/security_solution/public/hosts/components/top_host_score_contributors/index.test.tsx create mode 100644 x-pack/plugins/security_solution/public/hosts/components/top_host_score_contributors/index.tsx create mode 100644 x-pack/plugins/security_solution/public/hosts/components/top_host_score_contributors/translations.ts create mode 100644 x-pack/plugins/security_solution/public/hosts/pages/navigation/host_risk_tab_body.tsx diff --git a/x-pack/plugins/security_solution/common/constants.ts b/x-pack/plugins/security_solution/common/constants.ts index 9a9236d573fc4e..7514edea6247ff 100644 --- a/x-pack/plugins/security_solution/common/constants.ts +++ b/x-pack/plugins/security_solution/common/constants.ts @@ -99,6 +99,7 @@ export enum SecurityPageName { hosts = 'hosts', hostsAnomalies = 'hosts-anomalies', hostsExternalAlerts = 'hosts-external_alerts', + hostsRisk = 'hosts-risk', investigate = 'investigate', network = 'network', networkAnomalies = 'network-anomalies', @@ -359,7 +360,7 @@ export const showAllOthersBucket: string[] = [ */ export const ELASTIC_NAME = 'estc' as const; -export const RISKY_HOSTS_INDEX_PREFIX = 'ml_host_risk_score_latest_' as const; +export const RISKY_HOSTS_INDEX_PREFIX = 'ml_host_risk_score_' as const; export const TRANSFORM_STATES = { ABORTING: 'aborting', diff --git a/x-pack/plugins/security_solution/common/search_strategy/security_solution/hosts/risk_score/index.ts b/x-pack/plugins/security_solution/common/search_strategy/security_solution/hosts/risk_score/index.ts index 4273c08c638f3f..1c0d20161823ba 100644 --- a/x-pack/plugins/security_solution/common/search_strategy/security_solution/hosts/risk_score/index.ts +++ b/x-pack/plugins/security_solution/common/search_strategy/security_solution/hosts/risk_score/index.ts @@ -11,13 +11,16 @@ import type { IEsSearchResponse, } from '../../../../../../../../src/plugins/data/common'; import { RISKY_HOSTS_INDEX_PREFIX } from '../../../../constants'; -import { Inspect, Maybe, TimerangeInput } from '../../../common'; +import { Direction, Inspect, Maybe, TimerangeInput } from '../../../common'; export interface HostsRiskScoreRequestOptions extends IEsSearchRequest { defaultIndex: string[]; factoryQueryType?: FactoryQueryTypes; hostNames?: string[]; timerange?: TimerangeInput; + onlyLatest?: boolean; + limit?: number; + sortOrder?: Direction.asc | Direction.desc; } export interface HostsRiskScoreStrategyResponse extends IEsSearchResponse { @@ -25,6 +28,7 @@ export interface HostsRiskScoreStrategyResponse extends IEsSearchResponse { } export interface HostsRiskScore { + '@timestamp': string; host: { name: string; }; @@ -37,9 +41,9 @@ export interface HostsRiskScore { export interface RuleRisk { rule_name: string; - rule_risk: string; + rule_risk: number; } -export const getHostRiskIndex = (spaceId: string): string => { - return `${RISKY_HOSTS_INDEX_PREFIX}${spaceId}`; +export const getHostRiskIndex = (spaceId: string, onlyLatest: boolean = true): string => { + return `${RISKY_HOSTS_INDEX_PREFIX}${onlyLatest ? 'latest_' : ''}${spaceId}`; }; diff --git a/x-pack/plugins/security_solution/cypress/integration/hosts/host_details_risk_tab.spec.ts b/x-pack/plugins/security_solution/cypress/integration/hosts/host_details_risk_tab.spec.ts new file mode 100644 index 00000000000000..8f17d69a0d35be --- /dev/null +++ b/x-pack/plugins/security_solution/cypress/integration/hosts/host_details_risk_tab.spec.ts @@ -0,0 +1,40 @@ +/* + * 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 { loginAndWaitForHostDetailsPage } from '../../tasks/login'; + +import { cleanKibana } from '../../tasks/common'; +import { esArchiverLoad, esArchiverUnload } from '../../tasks/es_archiver'; +import { + navigateToHostRiskDetailTab, + openRiskFlyout, + waitForTableToLoad, +} from '../../tasks/host_risk'; +import { RULE_NAME, RISK_FLYOUT } from '../../screens/hosts/host_risk'; + +describe('risk tab', () => { + before(() => { + cleanKibana(); + esArchiverLoad('risky_hosts'); + loginAndWaitForHostDetailsPage('siem-kibana'); + navigateToHostRiskDetailTab(); + waitForTableToLoad(); + }); + + after(() => { + esArchiverUnload('risky_hosts'); + }); + + it('renders risk tab', () => { + cy.get(RULE_NAME).eq(3).should('have.text', 'Unusual Linux Username'); + }); + + it('shows risk information overlay when button is clicked', () => { + openRiskFlyout(); + cy.get(RISK_FLYOUT).should('have.text', 'How is host risk calculated?'); + }); +}); diff --git a/x-pack/plugins/security_solution/cypress/integration/hosts/hosts_risk_column.ts b/x-pack/plugins/security_solution/cypress/integration/hosts/hosts_risk_column.spec.ts similarity index 100% rename from x-pack/plugins/security_solution/cypress/integration/hosts/hosts_risk_column.ts rename to x-pack/plugins/security_solution/cypress/integration/hosts/hosts_risk_column.spec.ts diff --git a/x-pack/plugins/security_solution/cypress/screens/hosts/host_risk.ts b/x-pack/plugins/security_solution/cypress/screens/hosts/host_risk.ts new file mode 100644 index 00000000000000..00bd39b911fb81 --- /dev/null +++ b/x-pack/plugins/security_solution/cypress/screens/hosts/host_risk.ts @@ -0,0 +1,16 @@ +/* + * 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 const RULE_NAME = '[data-test-subj="topHostScoreContributors"] .euiTableCellContent__text'; + +export const RISK_FLYOUT = '[data-test-subj="open-risk-information-flyout"] .euiFlyoutHeader'; + +export const RISK_DETAILS_NAV = '[data-test-subj="navigation-hostRisk"]'; + +export const RISK_FLYOUT_TRIGGER = '[data-test-subj="open-risk-information-flyout-trigger"]'; + +export const LOADING_TABLE = '.euiBasicTable-loading'; diff --git a/x-pack/plugins/security_solution/cypress/tasks/host_risk.ts b/x-pack/plugins/security_solution/cypress/tasks/host_risk.ts new file mode 100644 index 00000000000000..7a357e8a5c7fb2 --- /dev/null +++ b/x-pack/plugins/security_solution/cypress/tasks/host_risk.ts @@ -0,0 +1,17 @@ +/* + * 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 { LOADING_TABLE, RISK_DETAILS_NAV, RISK_FLYOUT_TRIGGER } from '../screens/hosts/host_risk'; + +export const navigateToHostRiskDetailTab = () => cy.get(RISK_DETAILS_NAV).click(); + +export const openRiskFlyout = () => cy.get(RISK_FLYOUT_TRIGGER).click(); + +export const waitForTableToLoad = () => { + cy.get(LOADING_TABLE).should('exist'); + cy.get(LOADING_TABLE).should('not.exist'); +}; diff --git a/x-pack/plugins/security_solution/cypress/tasks/login.ts b/x-pack/plugins/security_solution/cypress/tasks/login.ts index 0610333352ce85..ad6ad0486e5185 100644 --- a/x-pack/plugins/security_solution/cypress/tasks/login.ts +++ b/x-pack/plugins/security_solution/cypress/tasks/login.ts @@ -334,8 +334,8 @@ export const loginAndWaitForTimeline = (timelineId: string, role?: ROLES) => { cy.get(TIMELINE_FLYOUT_BODY).should('be.visible'); }; -export const loginAndWaitForHostDetailsPage = () => { - loginAndWaitForPage(hostDetailsUrl('suricata-iowa')); +export const loginAndWaitForHostDetailsPage = (hostName = 'suricata-iowa') => { + loginAndWaitForPage(hostDetailsUrl(hostName)); cy.get('[data-test-subj="loading-spinner"]', { timeout: 12000 }).should('not.exist'); }; diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/cti_details/host_risk_summary.test.tsx b/x-pack/plugins/security_solution/public/common/components/event_details/cti_details/host_risk_summary.test.tsx index 9d60fbc496d8db..945317036e7bcb 100644 --- a/x-pack/plugins/security_solution/public/common/components/event_details/cti_details/host_risk_summary.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/event_details/cti_details/host_risk_summary.test.tsx @@ -20,6 +20,7 @@ describe('HostRiskSummary', () => { isModuleEnabled: true, result: [ { + '@timestamp': '1641902481', host: { name: 'test-host-name', }, @@ -63,6 +64,7 @@ describe('HostRiskSummary', () => { isModuleEnabled: false, result: [ { + '@timestamp': '1641902530', host: { name: 'test-host-name', }, diff --git a/x-pack/plugins/security_solution/public/common/components/navigation/tab_navigation/index.test.tsx b/x-pack/plugins/security_solution/public/common/components/navigation/tab_navigation/index.test.tsx index b123a26257683b..d2a17e87cffcfa 100644 --- a/x-pack/plugins/security_solution/public/common/components/navigation/tab_navigation/index.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/navigation/tab_navigation/index.test.tsx @@ -51,13 +51,14 @@ const hostName = 'siem-window'; describe('Table Navigation', () => { const mockHasMlUserPermissions = true; + const mockRiskyHostEnabled = true; const mockProps: TabNavigationProps & RouteSpyState = { pageName: 'hosts', pathName: '/hosts', detailName: undefined, search: '', tabName: HostsTableType.authentications, - navTabs: navTabsHostDetails(hostName, mockHasMlUserPermissions), + navTabs: navTabsHostDetails(hostName, mockHasMlUserPermissions, mockRiskyHostEnabled), [CONSTANTS.timerange]: { global: { [CONSTANTS.timerange]: { diff --git a/x-pack/plugins/security_solution/public/common/containers/hosts_risk/types.ts b/x-pack/plugins/security_solution/public/common/containers/hosts_risk/types.ts new file mode 100644 index 00000000000000..4a231b38ce6126 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/containers/hosts_risk/types.ts @@ -0,0 +1,13 @@ +/* + * 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 const enum HostRiskScoreQueryId { + DEFAULT = 'HostRiskScore', + HOST_RISK_SCORE_OVER_TIME = 'HostRiskScoreOverTimeQuery', + TOP_HOST_SCORE_CONTRIBUTORS = 'TopHostScoreContributorsQuery', + OVERVIEW_RISKY_HOSTS = 'OverviewRiskyHosts', +} diff --git a/x-pack/plugins/security_solution/public/common/containers/hosts_risk/use_hosts_risk_score.ts b/x-pack/plugins/security_solution/public/common/containers/hosts_risk/use_hosts_risk_score.ts index debdacb570ad05..3c47c4d02b358c 100644 --- a/x-pack/plugins/security_solution/public/common/containers/hosts_risk/use_hosts_risk_score.ts +++ b/x-pack/plugins/security_solution/public/common/containers/hosts_risk/use_hosts_risk_score.ts @@ -8,17 +8,16 @@ import { i18n } from '@kbn/i18n'; import { useCallback, useEffect, useState } from 'react'; import { useDispatch } from 'react-redux'; - import { useAppToasts } from '../../hooks/use_app_toasts'; import { useKibana } from '../../lib/kibana'; import { inputsActions } from '../../store/actions'; import { isIndexNotFoundError } from '../../utils/exceptions'; -import { getHostRiskIndex, HostsRiskScore } from '../../../../common/search_strategy'; +import { Direction, getHostRiskIndex, HostsRiskScore } from '../../../../common/search_strategy'; import { useHostsRiskScoreComplete } from './use_hosts_risk_score_complete'; import { useIsExperimentalFeatureEnabled } from '../../hooks/use_experimental_features'; +import { HostRiskScoreQueryId } from './types'; -export const QUERY_ID = 'host_risk_score'; const noop = () => {}; const isRecord = (item: unknown): item is Record => @@ -37,12 +36,23 @@ export interface HostRisk { result?: HostsRiskScore[]; } +/** + * @param queryId Provide this parameter when using query inspector to identify the query. + */ export const useHostsRiskScore = ({ timerange, hostName, + onlyLatest = true, + queryId = HostRiskScoreQueryId.DEFAULT, + sortOrder, + limit, }: { timerange?: { to: string; from: string }; hostName?: string; + onlyLatest?: boolean; + queryId?: HostRiskScoreQueryId; + limit?: number; + sortOrder?: Direction; }): HostRisk | null => { const riskyHostsFeatureEnabled = useIsExperimentalFeatureEnabled('riskyHostsEnabled'); const [isModuleEnabled, setIsModuleEnabled] = useState(undefined); @@ -56,8 +66,8 @@ export const useHostsRiskScore = ({ const { error, result, start, loading: isHostsRiskScoreLoading } = useHostsRiskScoreComplete(); const deleteQuery = useCallback(() => { - dispatch(inputsActions.deleteOneQuery({ inputId: 'global', id: QUERY_ID })); - }, [dispatch]); + dispatch(inputsActions.deleteOneQuery({ inputId: 'global', id: queryId })); + }, [dispatch, queryId]); useEffect(() => { if (!isHostsRiskScoreLoading && result) { @@ -66,7 +76,7 @@ export const useHostsRiskScore = ({ dispatch( inputsActions.setQuery({ inputId: 'global', - id: QUERY_ID, + id: queryId, inspect: { dsl: result.inspect?.dsl ?? [], response: [JSON.stringify(result.rawResponse, null, 2)], @@ -77,7 +87,7 @@ export const useHostsRiskScore = ({ ); } return deleteQuery; - }, [deleteQuery, dispatch, isHostsRiskScoreLoading, result, setIsModuleEnabled]); + }, [deleteQuery, dispatch, isHostsRiskScoreLoading, result, setIsModuleEnabled, queryId]); useEffect(() => { if (error) { @@ -105,11 +115,24 @@ export const useHostsRiskScore = ({ ? { to: timerange.to, from: timerange.from, interval: '' } : undefined, hostNames: hostName ? [hostName] : undefined, - defaultIndex: [getHostRiskIndex(space.id)], + defaultIndex: [getHostRiskIndex(space.id, onlyLatest)], + onlyLatest, + sortOrder, + limit, }); }); } - }, [start, data, timerange, hostName, riskyHostsFeatureEnabled, spaces]); + }, [ + start, + data, + timerange, + hostName, + onlyLatest, + riskyHostsFeatureEnabled, + spaces, + sortOrder, + limit, + ]); if ((!hostName && !timerange) || !riskyHostsFeatureEnabled) { return null; diff --git a/x-pack/plugins/security_solution/public/common/containers/hosts_risk/use_hosts_risk_score_complete.ts b/x-pack/plugins/security_solution/public/common/containers/hosts_risk/use_hosts_risk_score_complete.ts index 6faaa3c8f08dbf..2531d533d830bf 100644 --- a/x-pack/plugins/security_solution/public/common/containers/hosts_risk/use_hosts_risk_score_complete.ts +++ b/x-pack/plugins/security_solution/public/common/containers/hosts_risk/use_hosts_risk_score_complete.ts @@ -30,6 +30,8 @@ export const getHostsRiskScore = ({ timerange, hostNames, signal, + limit, + sortOrder, }: GetHostsRiskScoreProps): Observable => data.search.search( { @@ -37,6 +39,8 @@ export const getHostsRiskScore = ({ factoryQueryType: HostsQueries.hostsRiskScore, timerange, hostNames, + limit, + sortOrder, }, { strategy: 'securitySolutionSearchStrategy', diff --git a/x-pack/plugins/security_solution/public/common/mock/global_state.ts b/x-pack/plugins/security_solution/public/common/mock/global_state.ts index 2d804392580d0a..cf7d9f1dae23e6 100644 --- a/x-pack/plugins/security_solution/public/common/mock/global_state.ts +++ b/x-pack/plugins/security_solution/public/common/mock/global_state.ts @@ -83,6 +83,7 @@ export const mockGlobalState: State = { uncommonProcesses: { activePage: 0, limit: 10 }, anomalies: null, externalAlerts: { activePage: 0, limit: 10 }, + hostRisk: null, }, }, details: { @@ -98,6 +99,7 @@ export const mockGlobalState: State = { uncommonProcesses: { activePage: 0, limit: 10 }, anomalies: null, externalAlerts: { activePage: 0, limit: 10 }, + hostRisk: null, }, }, }, diff --git a/x-pack/plugins/security_solution/public/hosts/components/host_risk_information/index.test.tsx b/x-pack/plugins/security_solution/public/hosts/components/host_risk_information/index.test.tsx index 09d0375cf7dffb..7f5e512978ee9c 100644 --- a/x-pack/plugins/security_solution/public/hosts/components/host_risk_information/index.test.tsx +++ b/x-pack/plugins/security_solution/public/hosts/components/host_risk_information/index.test.tsx @@ -7,25 +7,35 @@ import { render, fireEvent } from '@testing-library/react'; import React from 'react'; -import { HostRiskInformation } from '.'; +import { HostRiskInformationButtonIcon, HostRiskInformationButtonEmpty } from '.'; import { TestProviders } from '../../../common/mock'; describe('Host Risk Flyout', () => { - it('renders', () => { - const { queryByTestId } = render(); + describe('HostRiskInformationButtonIcon', () => { + it('renders', () => { + const { queryByTestId } = render(); - expect(queryByTestId('open-risk-information-flyout')).toBeInTheDocument(); + expect(queryByTestId('open-risk-information-flyout-trigger')).toBeInTheDocument(); + }); + }); + + describe('HostRiskInformationButtonEmpty', () => { + it('renders', () => { + const { queryByTestId } = render(); + + expect(queryByTestId('open-risk-information-flyout-trigger')).toBeInTheDocument(); + }); }); it('opens and displays table with 5 rows', () => { const NUMBER_OF_ROWS = 1 + 5; // 1 header row + 5 severity rows const { getByTestId, queryByTestId, queryAllByRole } = render( - + ); - fireEvent.click(getByTestId('open-risk-information-flyout')); + fireEvent.click(getByTestId('open-risk-information-flyout-trigger')); expect(queryByTestId('risk-information-table')).toBeInTheDocument(); expect(queryAllByRole('row')).toHaveLength(NUMBER_OF_ROWS); diff --git a/x-pack/plugins/security_solution/public/hosts/components/host_risk_information/index.tsx b/x-pack/plugins/security_solution/public/hosts/components/host_risk_information/index.tsx index b4632466672e28..00230b0a4d2786 100644 --- a/x-pack/plugins/security_solution/public/hosts/components/host_risk_information/index.tsx +++ b/x-pack/plugins/security_solution/public/hosts/components/host_risk_information/index.tsx @@ -21,10 +21,11 @@ import { EuiButton, EuiSpacer, EuiBasicTableColumn, + EuiButtonEmpty, } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; -import React, { useState, useCallback } from 'react'; +import React, { useState, useCallback, memo } from 'react'; import { HostRiskSeverity } from '../../../../common/search_strategy'; import { RISKY_HOSTS_DOC_LINK } from '../../../overview/components/overview_risky_host_links/risky_hosts_disabled_module'; import { HostRiskScore } from '../common/host_risk_score'; @@ -61,16 +62,8 @@ const tableItems: TableItem[] = [ export const HOST_RISK_INFO_BUTTON_CLASS = 'HostRiskInformation__button'; -export const HostRiskInformation = () => { - const [isFlyoutVisible, setIsFlyoutVisible] = useState(false); - - const handleOnClose = useCallback(() => { - setIsFlyoutVisible(false); - }, []); - - const handleOnOpen = useCallback(() => { - setIsFlyoutVisible(true); - }, []); +export const HostRiskInformationButtonIcon = memo(() => { + const [isFlyoutVisible, handleOnOpen, handleOnClose] = useOnOpenCloseHandler(); return ( <> @@ -81,11 +74,39 @@ export const HostRiskInformation = () => { aria-label={i18n.INFORMATION_ARIA_LABEL} onClick={handleOnOpen} className={HOST_RISK_INFO_BUTTON_CLASS} - data-test-subj="open-risk-information-flyout" + data-test-subj="open-risk-information-flyout-trigger" /> {isFlyoutVisible && } ); +}); +HostRiskInformationButtonIcon.displayName = 'HostRiskInformationButtonIcon'; + +export const HostRiskInformationButtonEmpty = memo(() => { + const [isFlyoutVisible, handleOnOpen, handleOnClose] = useOnOpenCloseHandler(); + + return ( + <> + + {i18n.INFO_BUTTON_TEXT} + + {isFlyoutVisible && } + + ); +}); +HostRiskInformationButtonEmpty.displayName = 'HostRiskInformationButtonEmpty'; + +const useOnOpenCloseHandler = (): [boolean, () => void, () => void] => { + const [isOpen, setIsOpen] = useState(false); + + const handleOnClose = useCallback(() => { + setIsOpen(false); + }, []); + + const handleOnOpen = useCallback(() => { + setIsOpen(true); + }, []); + return [isOpen, handleOnOpen, handleOnClose]; }; const HostRiskInformationFlyout = ({ handleOnClose }: { handleOnClose: () => void }) => { @@ -94,7 +115,13 @@ const HostRiskInformationFlyout = ({ handleOnClose }: { handleOnClose: () => voi }); return ( - +

{i18n.TITLE}

diff --git a/x-pack/plugins/security_solution/public/hosts/components/host_risk_information/translations.ts b/x-pack/plugins/security_solution/public/hosts/components/host_risk_information/translations.ts index 244c7b458b2060..1e031a84ae8a50 100644 --- a/x-pack/plugins/security_solution/public/hosts/components/host_risk_information/translations.ts +++ b/x-pack/plugins/security_solution/public/hosts/components/host_risk_information/translations.ts @@ -68,3 +68,10 @@ export const CLOSE_BUTTON_LTEXT = i18n.translate( defaultMessage: 'Close', } ); + +export const INFO_BUTTON_TEXT = i18n.translate( + 'xpack.securitySolution.hosts.hostRiskInformation.buttonLabel', + { + defaultMessage: 'How is risk score calculated?', + } +); diff --git a/x-pack/plugins/security_solution/public/hosts/components/host_score_over_time/index.test.tsx b/x-pack/plugins/security_solution/public/hosts/components/host_score_over_time/index.test.tsx new file mode 100644 index 00000000000000..9a7dfcc967fbb4 --- /dev/null +++ b/x-pack/plugins/security_solution/public/hosts/components/host_score_over_time/index.test.tsx @@ -0,0 +1,51 @@ +/* + * 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 { render } from '@testing-library/react'; +import React from 'react'; +import { HostRiskScoreOverTime } from '.'; +import { TestProviders } from '../../../common/mock'; +import { useHostsRiskScore } from '../../../common/containers/hosts_risk/use_hosts_risk_score'; + +jest.mock('../../../common/containers/hosts_risk/use_hosts_risk_score'); +const useHostsRiskScoreMock = useHostsRiskScore as jest.Mock; + +describe('Host Risk Flyout', () => { + it('renders', () => { + const { queryByTestId } = render( + + + + ); + + expect(queryByTestId('hostRiskScoreOverTime')).toBeInTheDocument(); + }); + + it('renders loader when HostsRiskScore is laoding', () => { + useHostsRiskScoreMock.mockReturnValueOnce({ + loading: true, + isModuleEnabled: true, + result: [], + }); + + const { queryByTestId } = render( + + + + ); + + expect(queryByTestId('HostRiskScoreOverTime-loading')).toBeInTheDocument(); + }); +}); diff --git a/x-pack/plugins/security_solution/public/hosts/components/host_score_over_time/index.tsx b/x-pack/plugins/security_solution/public/hosts/components/host_score_over_time/index.tsx new file mode 100644 index 00000000000000..eb34f9100101b3 --- /dev/null +++ b/x-pack/plugins/security_solution/public/hosts/components/host_score_over_time/index.tsx @@ -0,0 +1,202 @@ +/* + * 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 React, { useMemo, useCallback } from 'react'; +import { + Chart, + LineSeries, + ScaleType, + Settings, + Axis, + Position, + AnnotationDomainType, + LineAnnotation, + TooltipValue, +} from '@elastic/charts'; +import { euiThemeVars } from '@kbn/ui-shared-deps-src/theme'; +import { EuiFlexGroup, EuiFlexItem, EuiLoadingChart, EuiText, EuiPanel } from '@elastic/eui'; +import styled from 'styled-components'; +import { chartDefaultSettings, useTheme } from '../../../common/components/charts/common'; +import { useTimeZone } from '../../../common/lib/kibana'; +import { histogramDateTimeFormatter } from '../../../common/components/utils'; +import { HeaderSection } from '../../../common/components/header_section'; +import { InspectButton, InspectButtonContainer } from '../../../common/components/inspect'; +import * as i18n from './translations'; +import { useHostsRiskScore } from '../../../common/containers/hosts_risk/use_hosts_risk_score'; +import { PreferenceFormattedDate } from '../../../common/components/formatted_date'; +import { HostRiskScoreQueryId } from '../../../common/containers/hosts_risk/types'; + +export interface HostRiskScoreOverTimeProps { + hostName: string; + from: string; + to: string; +} + +const RISKY_TRESHOULD = 70; +const DEFAULT_CHART_HEIGH = 250; + +const StyledEuiText = styled(EuiText)` + font-size: 9px; + font-weight: ${({ theme }) => theme.eui.euiFontWeightSemiBold}; + margin-right: ${({ theme }) => theme.eui.paddingSizes.xs}; +`; + +const LoadingChart = styled(EuiLoadingChart)` + display: block; + text-align: center; +`; + +const HostRiskScoreOverTimeComponent: React.FC = ({ + hostName, + from, + to, +}) => { + const timeZone = useTimeZone(); + + const memoizedDataTimeFormatter = useMemo( + () => histogramDateTimeFormatter([from, to]), + [from, to] + ); + const scoreFormatter = useCallback((d: number) => Math.round(d).toString(), []); + const headerFormatter = useCallback( + (tooltip: TooltipValue) => , + [] + ); + + const timerange = useMemo( + () => ({ + from, + to, + }), + [from, to] + ); + const theme = useTheme(); + + const hostRisk = useHostsRiskScore({ + hostName, + onlyLatest: false, + timerange, + queryId: HostRiskScoreQueryId.HOST_RISK_SCORE_OVER_TIME, + }); + + const data = useMemo( + () => + hostRisk?.result + ?.map((result) => ({ + x: result['@timestamp'], + y: result.risk_stats.risk_score, + })) + .reverse() ?? [], + [hostRisk] + ); + + return ( + + + + + + + + + + + + + + +
+ {hostRisk?.loading ? ( + + ) : ( + + + + + + + {i18n.RISKY} + + } + /> + + )} +
+
+
+
+
+ ); +}; + +HostRiskScoreOverTimeComponent.displayName = 'HostRiskScoreOverTimeComponent'; +export const HostRiskScoreOverTime = React.memo(HostRiskScoreOverTimeComponent); +HostRiskScoreOverTime.displayName = 'HostRiskScoreOverTime'; diff --git a/x-pack/plugins/security_solution/public/hosts/components/host_score_over_time/translations.ts b/x-pack/plugins/security_solution/public/hosts/components/host_score_over_time/translations.ts new file mode 100644 index 00000000000000..5e1b4ca7410a83 --- /dev/null +++ b/x-pack/plugins/security_solution/public/hosts/components/host_score_over_time/translations.ts @@ -0,0 +1,33 @@ +/* + * 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 { i18n } from '@kbn/i18n'; + +export const HOST_RISK_SCORE_OVER_TIME = i18n.translate( + 'xpack.securitySolution.hosts.hostScoreOverTime.title', + { + defaultMessage: 'Host risk score over time', + } +); + +export const HOST_RISK_THRESHOLD = i18n.translate( + 'xpack.securitySolution.hosts.hostScoreOverTime.riskyThresholdHeader', + { + defaultMessage: 'Risky threshold', + } +); + +export const RISKY = i18n.translate('xpack.securitySolution.hosts.hostScoreOverTime.riskyLabel', { + defaultMessage: 'Risky', +}); + +export const RISK_SCORE = i18n.translate( + 'xpack.securitySolution.hosts.hostScoreOverTime.riskScore', + { + defaultMessage: 'Risk score', + } +); diff --git a/x-pack/plugins/security_solution/public/hosts/components/kpi_hosts/risky_hosts/index.tsx b/x-pack/plugins/security_solution/public/hosts/components/kpi_hosts/risky_hosts/index.tsx index f882e12d211d39..9e7e01c64a4325 100644 --- a/x-pack/plugins/security_solution/public/hosts/components/kpi_hosts/risky_hosts/index.tsx +++ b/x-pack/plugins/security_solution/public/hosts/components/kpi_hosts/risky_hosts/index.tsx @@ -33,7 +33,10 @@ import { import { useInspectQuery } from '../../../../common/hooks/use_inspect_query'; import { useErrorToast } from '../../../../common/hooks/use_error_toast'; import { HostRiskScore } from '../../common/host_risk_score'; -import { HostRiskInformation, HOST_RISK_INFO_BUTTON_CLASS } from '../../host_risk_information'; +import { + HostRiskInformationButtonIcon, + HOST_RISK_INFO_BUTTON_CLASS, +} from '../../host_risk_information'; import { HoverVisibilityContainer } from '../../../../common/components/hover_visibility_container'; const QUERY_ID = 'hostsKpiRiskyHostsQuery'; @@ -80,7 +83,7 @@ const RiskyHostsComponent: React.FC<{ - + {data?.inspect && ( diff --git a/x-pack/plugins/security_solution/public/hosts/components/top_host_score_contributors/index.test.tsx b/x-pack/plugins/security_solution/public/hosts/components/top_host_score_contributors/index.test.tsx new file mode 100644 index 00000000000000..6315897fac1d2f --- /dev/null +++ b/x-pack/plugins/security_solution/public/hosts/components/top_host_score_contributors/index.test.tsx @@ -0,0 +1,72 @@ +/* + * 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 { render } from '@testing-library/react'; +import React from 'react'; +import { TopHostScoreContributors } from '.'; +import { TestProviders } from '../../../common/mock'; +import { useHostsRiskScore } from '../../../common/containers/hosts_risk/use_hosts_risk_score'; + +jest.mock('../../../common/containers/hosts_risk/use_hosts_risk_score'); +const useHostsRiskScoreMock = useHostsRiskScore as jest.Mock; + +describe('Host Risk Flyout', () => { + it('renders', () => { + const { queryByTestId } = render( + + + + ); + + expect(queryByTestId('topHostScoreContributors')).toBeInTheDocument(); + }); + + it('renders sorted items', () => { + useHostsRiskScoreMock.mockReturnValueOnce({ + loading: true, + isModuleEnabled: true, + result: [ + { + risk_stats: { + rule_risks: [ + { + rule_name: 'third', + rule_risk: '10', + }, + { + rule_name: 'first', + rule_risk: '99', + }, + { + rule_name: 'second', + rule_risk: '55', + }, + ], + }, + }, + ], + }); + + const { queryAllByRole } = render( + + + + ); + + expect(queryAllByRole('row')[1]).toHaveTextContent('first'); + expect(queryAllByRole('row')[2]).toHaveTextContent('second'); + expect(queryAllByRole('row')[3]).toHaveTextContent('third'); + }); +}); diff --git a/x-pack/plugins/security_solution/public/hosts/components/top_host_score_contributors/index.tsx b/x-pack/plugins/security_solution/public/hosts/components/top_host_score_contributors/index.tsx new file mode 100644 index 00000000000000..84892da3b6e3cb --- /dev/null +++ b/x-pack/plugins/security_solution/public/hosts/components/top_host_score_contributors/index.tsx @@ -0,0 +1,125 @@ +/* + * 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 React, { useMemo } from 'react'; + +import { + EuiFlexGroup, + EuiFlexItem, + EuiPanel, + EuiInMemoryTable, + EuiTableFieldDataColumnType, +} from '@elastic/eui'; + +import { HeaderSection } from '../../../common/components/header_section'; +import { InspectButton, InspectButtonContainer } from '../../../common/components/inspect'; +import * as i18n from './translations'; +import { useHostsRiskScore } from '../../../common/containers/hosts_risk/use_hosts_risk_score'; +import { Direction } from '../../../../../timelines/common'; +import { HostRiskScoreQueryId } from '../../../common/containers/hosts_risk/types'; + +export interface TopHostScoreContributorsProps { + hostName: string; + from: string; + to: string; +} + +interface TableItem { + rank: number; + name: string; +} + +const columns: Array> = [ + { + name: i18n.RANK_TITLE, + field: 'rank', + width: '45px', + align: 'right', + }, + { + name: i18n.RULE_NAME_TITLE, + field: 'name', + sortable: true, + truncateText: true, + }, +]; + +const PAGE_SIZE = 5; + +const TopHostScoreContributorsComponent: React.FC = ({ + hostName, + from, + to, +}) => { + const timerange = useMemo( + () => ({ + from, + to, + }), + [from, to] + ); + + const hostRisk = useHostsRiskScore({ + hostName, + timerange, + onlyLatest: false, + queryId: HostRiskScoreQueryId.TOP_HOST_SCORE_CONTRIBUTORS, + limit: 1, + sortOrder: Direction.desc, + }); + + const result = hostRisk?.result; + + const items = useMemo(() => { + const rules = result && result.length > 0 ? result[0].risk_stats.rule_risks : []; + return rules + .sort((a, b) => b.rule_risk - a.rule_risk) + .map(({ rule_name: name }, i) => ({ rank: i + 1, name })); + }, [result]); + + const pagination = useMemo( + () => ({ + hidePerPageOptions: true, + pageSize: PAGE_SIZE, + totalItemCount: items.length, + }), + [items.length] + ); + + return ( + + + + + + + + + + + + + + + + + + + + ); +}; + +export const TopHostScoreContributors = React.memo(TopHostScoreContributorsComponent); +TopHostScoreContributors.displayName = 'TopHostScoreContributors'; diff --git a/x-pack/plugins/security_solution/public/hosts/components/top_host_score_contributors/translations.ts b/x-pack/plugins/security_solution/public/hosts/components/top_host_score_contributors/translations.ts new file mode 100644 index 00000000000000..02017bf33d2da0 --- /dev/null +++ b/x-pack/plugins/security_solution/public/hosts/components/top_host_score_contributors/translations.ts @@ -0,0 +1,29 @@ +/* + * 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 { i18n } from '@kbn/i18n'; + +export const TOP_RISK_SCORE_CONTRIBUTORS = i18n.translate( + 'xpack.securitySolution.hosts.topRiskScoreContributors.title', + { + defaultMessage: 'Top risk score contributors', + } +); + +export const RANK_TITLE = i18n.translate( + 'xpack.securitySolution.hosts.topRiskScoreContributors.rankColumnTitle', + { + defaultMessage: 'Rank', + } +); + +export const RULE_NAME_TITLE = i18n.translate( + 'xpack.securitySolution.hosts.topRiskScoreContributors.ruleNameColumnTitle', + { + defaultMessage: 'Rule name', + } +); diff --git a/x-pack/plugins/security_solution/public/hosts/pages/details/details_tabs.tsx b/x-pack/plugins/security_solution/public/hosts/pages/details/details_tabs.tsx index dc537f2f6ffe35..891db470161d42 100644 --- a/x-pack/plugins/security_solution/public/hosts/pages/details/details_tabs.tsx +++ b/x-pack/plugins/security_solution/public/hosts/pages/details/details_tabs.tsx @@ -25,6 +25,7 @@ import { UncommonProcessQueryTabBody, EventsQueryTabBody, HostAlertsQueryTabBody, + HostRiskTabBody, } from '../navigation'; export const HostDetailsTabs = React.memo( @@ -102,6 +103,9 @@ export const HostDetailsTabs = React.memo( + + + ); } diff --git a/x-pack/plugins/security_solution/public/hosts/pages/details/index.tsx b/x-pack/plugins/security_solution/public/hosts/pages/details/index.tsx index 2f89efa56b4d06..40ba3990ee9a7e 100644 --- a/x-pack/plugins/security_solution/public/hosts/pages/details/index.tsx +++ b/x-pack/plugins/security_solution/public/hosts/pages/details/index.tsx @@ -53,6 +53,7 @@ import { ID, useHostDetails } from '../../containers/hosts/details'; import { manageQuery } from '../../../common/components/page/manage_query'; import { useInvalidFilterQuery } from '../../../common/hooks/use_invalid_filter_query'; import { useSourcererDataView } from '../../../common/containers/sourcerer'; +import { useIsExperimentalFeatureEnabled } from '../../../common/hooks/use_experimental_features'; const HostOverviewManage = manageQuery(HostOverview); @@ -119,6 +120,8 @@ const HostDetailsComponent: React.FC = ({ detailName, hostDeta dispatch(setHostDetailsTablesActivePageToZero()); }, [dispatch, detailName]); + const riskyHostsFeatureEnabled = useIsExperimentalFeatureEnabled('riskyHostsEnabled'); + return ( <> {indicesExist ? ( @@ -195,7 +198,11 @@ const HostDetailsComponent: React.FC = ({ detailName, hostDeta diff --git a/x-pack/plugins/security_solution/public/hosts/pages/details/nav_tabs.test.tsx b/x-pack/plugins/security_solution/public/hosts/pages/details/nav_tabs.test.tsx index 872afc4e82440d..90f3c223c5501f 100644 --- a/x-pack/plugins/security_solution/public/hosts/pages/details/nav_tabs.test.tsx +++ b/x-pack/plugins/security_solution/public/hosts/pages/details/nav_tabs.test.tsx @@ -11,18 +11,29 @@ import { navTabsHostDetails } from './nav_tabs'; describe('navTabsHostDetails', () => { const mockHostName = 'mockHostName'; test('it should skip anomalies tab if without mlUserPermission', () => { - const tabs = navTabsHostDetails(mockHostName, false); + const tabs = navTabsHostDetails(mockHostName, false, false); expect(tabs).toHaveProperty(HostsTableType.authentications); expect(tabs).toHaveProperty(HostsTableType.uncommonProcesses); expect(tabs).not.toHaveProperty(HostsTableType.anomalies); expect(tabs).toHaveProperty(HostsTableType.events); + expect(tabs).not.toHaveProperty(HostsTableType.risk); }); test('it should display anomalies tab if with mlUserPermission', () => { - const tabs = navTabsHostDetails(mockHostName, true); + const tabs = navTabsHostDetails(mockHostName, true, false); expect(tabs).toHaveProperty(HostsTableType.authentications); expect(tabs).toHaveProperty(HostsTableType.uncommonProcesses); expect(tabs).toHaveProperty(HostsTableType.anomalies); expect(tabs).toHaveProperty(HostsTableType.events); + expect(tabs).not.toHaveProperty(HostsTableType.risk); + }); + + test('it should display risky hosts tab if when risky hosts is enabled', () => { + const tabs = navTabsHostDetails(mockHostName, false, true); + expect(tabs).toHaveProperty(HostsTableType.authentications); + expect(tabs).toHaveProperty(HostsTableType.uncommonProcesses); + expect(tabs).not.toHaveProperty(HostsTableType.anomalies); + expect(tabs).toHaveProperty(HostsTableType.events); + expect(tabs).toHaveProperty(HostsTableType.risk); }); }); diff --git a/x-pack/plugins/security_solution/public/hosts/pages/details/nav_tabs.tsx b/x-pack/plugins/security_solution/public/hosts/pages/details/nav_tabs.tsx index 02f8fa740c024b..c58fbde09aef1d 100644 --- a/x-pack/plugins/security_solution/public/hosts/pages/details/nav_tabs.tsx +++ b/x-pack/plugins/security_solution/public/hosts/pages/details/nav_tabs.tsx @@ -16,8 +16,11 @@ const getTabsOnHostDetailsUrl = (hostName: string, tabName: HostsTableType) => export const navTabsHostDetails = ( hostName: string, - hasMlUserPermissions: boolean + hasMlUserPermissions: boolean, + isRiskyHostsEnabled: boolean ): HostDetailsNavTab => { + const hiddenTabs = []; + const hostDetailsNavTabs = { [HostsTableType.authentications]: { id: HostsTableType.authentications, @@ -49,9 +52,21 @@ export const navTabsHostDetails = ( href: getTabsOnHostDetailsUrl(hostName, HostsTableType.alerts), disabled: false, }, + [HostsTableType.risk]: { + id: HostsTableType.risk, + name: i18n.NAVIGATION_HOST_RISK_TITLE, + href: getTabsOnHostDetailsUrl(hostName, HostsTableType.risk), + disabled: false, + }, }; - return hasMlUserPermissions - ? hostDetailsNavTabs - : omit(HostsTableType.anomalies, hostDetailsNavTabs); + if (!hasMlUserPermissions) { + hiddenTabs.push(HostsTableType.anomalies); + } + + if (!isRiskyHostsEnabled) { + hiddenTabs.push(HostsTableType.risk); + } + + return omit(hiddenTabs, hostDetailsNavTabs); }; diff --git a/x-pack/plugins/security_solution/public/hosts/pages/details/utils.ts b/x-pack/plugins/security_solution/public/hosts/pages/details/utils.ts index 3a584f7fefb500..19975b6ad7abb7 100644 --- a/x-pack/plugins/security_solution/public/hosts/pages/details/utils.ts +++ b/x-pack/plugins/security_solution/public/hosts/pages/details/utils.ts @@ -27,6 +27,7 @@ const TabNameMappedToI18nKey: Record = { [HostsTableType.anomalies]: i18n.NAVIGATION_ANOMALIES_TITLE, [HostsTableType.events]: i18n.NAVIGATION_EVENTS_TITLE, [HostsTableType.alerts]: i18n.NAVIGATION_ALERTS_TITLE, + [HostsTableType.risk]: i18n.NAVIGATION_HOST_RISK_TITLE, }; export const getBreadcrumbs = ( diff --git a/x-pack/plugins/security_solution/public/hosts/pages/index.tsx b/x-pack/plugins/security_solution/public/hosts/pages/index.tsx index 23be8f09ce1405..64acbbc666312e 100644 --- a/x-pack/plugins/security_solution/public/hosts/pages/index.tsx +++ b/x-pack/plugins/security_solution/public/hosts/pages/index.tsx @@ -30,6 +30,7 @@ const getHostDetailsTabPath = () => `${HostsTableType.uncommonProcesses}|` + `${HostsTableType.anomalies}|` + `${HostsTableType.events}|` + + `${HostsTableType.risk}|` + `${HostsTableType.alerts})`; export const HostsContainer = React.memo(() => { diff --git a/x-pack/plugins/security_solution/public/hosts/pages/navigation/host_risk_tab_body.tsx b/x-pack/plugins/security_solution/public/hosts/pages/navigation/host_risk_tab_body.tsx new file mode 100644 index 00000000000000..6982047aa26ada --- /dev/null +++ b/x-pack/plugins/security_solution/public/hosts/pages/navigation/host_risk_tab_body.tsx @@ -0,0 +1,60 @@ +/* + * 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 { EuiButton, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import React from 'react'; +import styled from 'styled-components'; +import { HostRiskScoreOverTime } from '../../components/host_score_over_time'; +import { TopHostScoreContributors } from '../../components/top_host_score_contributors'; +import { HostsComponentsQueryProps } from './types'; +import * as i18n from '../translations'; +import { useRiskyHostsDashboardButtonHref } from '../../../overview/containers/overview_risky_host_links/use_risky_hosts_dashboard_button_href'; +import { HostRiskInformationButtonEmpty } from '../../components/host_risk_information'; + +const StyledEuiFlexGroup = styled(EuiFlexGroup)` + margin-top: ${({ theme }) => theme.eui.paddingSizes.l}; +`; + +const HostRiskTabBodyComponent: React.FC< + Pick & { hostName: string } +> = ({ hostName, startDate, endDate }) => { + const { buttonHref } = useRiskyHostsDashboardButtonHref(startDate, endDate); + + return ( + <> + + + + + + + + + + + + {i18n.VIEW_DASHBOARD_BUTTON} + + + + + + + + ); +}; + +HostRiskTabBodyComponent.displayName = 'HostRiskTabBodyComponent'; + +export const HostRiskTabBody = React.memo(HostRiskTabBodyComponent); + +HostRiskTabBody.displayName = 'HostRiskTabBody'; diff --git a/x-pack/plugins/security_solution/public/hosts/pages/navigation/index.ts b/x-pack/plugins/security_solution/public/hosts/pages/navigation/index.ts index 09adfece7b01ed..d5961cdc788e4d 100644 --- a/x-pack/plugins/security_solution/public/hosts/pages/navigation/index.ts +++ b/x-pack/plugins/security_solution/public/hosts/pages/navigation/index.ts @@ -10,3 +10,4 @@ export * from './events_query_tab_body'; export * from './hosts_query_tab_body'; export * from './uncommon_process_query_tab_body'; export * from './alerts_query_tab_body'; +export * from './host_risk_tab_body'; diff --git a/x-pack/plugins/security_solution/public/hosts/pages/translations.ts b/x-pack/plugins/security_solution/public/hosts/pages/translations.ts index 5563dc285ad5a8..337f18ef335034 100644 --- a/x-pack/plugins/security_solution/public/hosts/pages/translations.ts +++ b/x-pack/plugins/security_solution/public/hosts/pages/translations.ts @@ -57,6 +57,13 @@ export const NAVIGATION_ALERTS_TITLE = i18n.translate( } ); +export const NAVIGATION_HOST_RISK_TITLE = i18n.translate( + 'xpack.securitySolution.hosts.navigation.hostRisk', + { + defaultMessage: 'Host risk', + } +); + export const ERROR_FETCHING_AUTHENTICATIONS_DATA = i18n.translate( 'xpack.securitySolution.hosts.navigaton.matrixHistogram.errorFetchingAuthenticationsData', { @@ -76,3 +83,10 @@ export const EVENTS_UNIT = (totalCount: number) => values: { totalCount }, defaultMessage: `{totalCount, plural, =1 {event} other {events}}`, }); + +export const VIEW_DASHBOARD_BUTTON = i18n.translate( + 'xpack.securitySolution.hosts.navigaton.hostRisk.viewDashboardButtonLabel', + { + defaultMessage: 'View source dashboard', + } +); diff --git a/x-pack/plugins/security_solution/public/hosts/store/helpers.test.ts b/x-pack/plugins/security_solution/public/hosts/store/helpers.test.ts index 8c3a3e27ffb38b..0d7df790f8f317 100644 --- a/x-pack/plugins/security_solution/public/hosts/store/helpers.test.ts +++ b/x-pack/plugins/security_solution/public/hosts/store/helpers.test.ts @@ -36,6 +36,7 @@ export const mockHostsState: HostsModel = { activePage: 4, limit: DEFAULT_TABLE_LIMIT, }, + [HostsTableType.risk]: null, }, }, details: { @@ -63,6 +64,7 @@ export const mockHostsState: HostsModel = { activePage: 4, limit: DEFAULT_TABLE_LIMIT, }, + [HostsTableType.risk]: null, }, }, }; @@ -94,6 +96,7 @@ describe('Hosts redux store', () => { activePage: 0, limit: 10, }, + [HostsTableType.risk]: null, }); }); @@ -122,6 +125,7 @@ describe('Hosts redux store', () => { activePage: 0, limit: 10, }, + [HostsTableType.risk]: null, }); }); }); diff --git a/x-pack/plugins/security_solution/public/hosts/store/model.ts b/x-pack/plugins/security_solution/public/hosts/store/model.ts index ea168e965fa233..0a82d3961aa020 100644 --- a/x-pack/plugins/security_solution/public/hosts/store/model.ts +++ b/x-pack/plugins/security_solution/public/hosts/store/model.ts @@ -20,6 +20,7 @@ export enum HostsTableType { uncommonProcesses = 'uncommonProcesses', anomalies = 'anomalies', alerts = 'externalAlerts', + risk = 'hostRisk', } export interface BasicQueryPaginated { @@ -39,6 +40,7 @@ export interface Queries { [HostsTableType.uncommonProcesses]: BasicQueryPaginated; [HostsTableType.anomalies]: null | undefined; [HostsTableType.alerts]: BasicQueryPaginated; + [HostsTableType.risk]: null | undefined; } export interface GenericHostsModel { diff --git a/x-pack/plugins/security_solution/public/hosts/store/reducer.ts b/x-pack/plugins/security_solution/public/hosts/store/reducer.ts index eebf3ca1684a1d..171431144a746b 100644 --- a/x-pack/plugins/security_solution/public/hosts/store/reducer.ts +++ b/x-pack/plugins/security_solution/public/hosts/store/reducer.ts @@ -51,6 +51,7 @@ export const initialHostsState: HostsState = { activePage: DEFAULT_TABLE_ACTIVE_PAGE, limit: DEFAULT_TABLE_LIMIT, }, + [HostsTableType.risk]: null, }, }, details: { @@ -78,6 +79,7 @@ export const initialHostsState: HostsState = { activePage: DEFAULT_TABLE_ACTIVE_PAGE, limit: DEFAULT_TABLE_LIMIT, }, + [HostsTableType.risk]: null, }, }, }; diff --git a/x-pack/plugins/security_solution/public/overview/components/overview_risky_host_links/index.tsx b/x-pack/plugins/security_solution/public/overview/components/overview_risky_host_links/index.tsx index 64829aab7776d0..add96986d1d079 100644 --- a/x-pack/plugins/security_solution/public/overview/components/overview_risky_host_links/index.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/overview_risky_host_links/index.tsx @@ -10,12 +10,16 @@ import React from 'react'; import { RiskyHostsEnabledModule } from './risky_hosts_enabled_module'; import { RiskyHostsDisabledModule } from './risky_hosts_disabled_module'; import { useHostsRiskScore } from '../../../common/containers/hosts_risk/use_hosts_risk_score'; +import { HostRiskScoreQueryId } from '../../../common/containers/hosts_risk/types'; export interface RiskyHostLinksProps { timerange: { to: string; from: string }; } const RiskyHostLinksComponent: React.FC = ({ timerange }) => { - const hostRiskScore = useHostsRiskScore({ timerange }); + const hostRiskScore = useHostsRiskScore({ + timerange, + queryId: HostRiskScoreQueryId.OVERVIEW_RISKY_HOSTS, + }); switch (hostRiskScore?.isModuleEnabled) { case true: diff --git a/x-pack/plugins/security_solution/public/overview/components/overview_risky_host_links/risky_hosts_enabled_module.test.tsx b/x-pack/plugins/security_solution/public/overview/components/overview_risky_host_links/risky_hosts_enabled_module.test.tsx index 364b608c6086de..bc45faf1f05805 100644 --- a/x-pack/plugins/security_solution/public/overview/components/overview_risky_host_links/risky_hosts_enabled_module.test.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/overview_risky_host_links/risky_hosts_enabled_module.test.tsx @@ -57,6 +57,7 @@ describe('RiskyHostsEnabledModule', () => { isModuleEnabled: true, result: [ { + '@timestamp': '1641902481', host: { name: 'a', }, diff --git a/x-pack/plugins/security_solution/public/overview/components/overview_risky_host_links/risky_hosts_panel_view.tsx b/x-pack/plugins/security_solution/public/overview/components/overview_risky_host_links/risky_hosts_panel_view.tsx index 8a42cedc3be461..f508da6c1c9911 100644 --- a/x-pack/plugins/security_solution/public/overview/components/overview_risky_host_links/risky_hosts_panel_view.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/overview_risky_host_links/risky_hosts_panel_view.tsx @@ -14,8 +14,8 @@ import { LinkPanelViewProps } from '../link_panel/types'; import { Link } from '../link_panel/link'; import * as i18n from './translations'; import { VIEW_DASHBOARD } from '../overview_cti_links/translations'; -import { QUERY_ID as RiskyHostsQueryId } from '../../../common/containers/hosts_risk/use_hosts_risk_score'; import { NavigateToHost } from './navigate_to_host'; +import { HostRiskScoreQueryId } from '../../../common/containers/hosts_risk/types'; const columns: Array> = [ { @@ -94,7 +94,7 @@ export const RiskyHostsPanelView: React.FC = ({ dataTestSubj: 'risky-hosts-dashboard-links', defaultSortField: 'count', defaultSortOrder: 'desc', - inspectQueryId: isInspectEnabled ? RiskyHostsQueryId : undefined, + inspectQueryId: isInspectEnabled ? HostRiskScoreQueryId.OVERVIEW_RISKY_HOSTS : undefined, listItems, panelTitle: i18n.PANEL_TITLE, splitPanel: splitPanelElement, diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/kpi/risky_hosts/query.hosts_kpi_risky_hosts.dsl.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/kpi/risky_hosts/query.hosts_kpi_risky_hosts.dsl.ts index 201d73c4ebb185..7c00b7c0f8193b 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/kpi/risky_hosts/query.hosts_kpi_risky_hosts.dsl.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/kpi/risky_hosts/query.hosts_kpi_risky_hosts.dsl.ts @@ -6,15 +6,12 @@ */ import type { HostsKpiRiskyHostsRequestOptions } from '../../../../../../../common/search_strategy/security_solution/hosts/kpi/risky_hosts'; -import { createQueryFilterClauses } from '../../../../../../utils/build_query'; export const buildHostsKpiRiskyHostsQuery = ({ - filterQuery, timerange: { from, to }, defaultIndex, }: HostsKpiRiskyHostsRequestOptions) => { const filter = [ - ...createQueryFilterClauses(filterQuery), { range: { '@timestamp': { diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/risk_score/query.hosts_risk.dsl.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/risk_score/query.hosts_risk.dsl.ts index 182ad7892204f8..dc3d1e4b5d587c 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/risk_score/query.hosts_risk.dsl.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/risk_score/query.hosts_risk.dsl.ts @@ -5,12 +5,16 @@ * 2.0. */ -import { HostsRiskScoreRequestOptions } from '../../../../../../common/search_strategy'; +import { Direction, HostsRiskScoreRequestOptions } from '../../../../../../common/search_strategy'; + +const QUERY_SIZE = 10; export const buildHostsRiskScoreQuery = ({ timerange, hostNames, defaultIndex, + limit = QUERY_SIZE, + sortOrder = Direction.desc, }: HostsRiskScoreRequestOptions) => { const filter = []; @@ -35,12 +39,20 @@ export const buildHostsRiskScoreQuery = ({ allow_no_indices: false, ignore_unavailable: true, track_total_hits: false, + size: limit, body: { query: { bool: { filter, }, }, + sort: [ + { + '@timestamp': { + order: sortOrder, + }, + }, + ], }, }; diff --git a/x-pack/test/security_solution_cypress/es_archives/risky_hosts/data.json b/x-pack/test/security_solution_cypress/es_archives/risky_hosts/data.json index f9972f21eeb642..cde819a836b0a3 100644 --- a/x-pack/test/security_solution_cypress/es_archives/risky_hosts/data.json +++ b/x-pack/test/security_solution_cypress/es_archives/risky_hosts/data.json @@ -22,3 +22,28 @@ } } } + +{ + "type":"doc", + "value":{ + "id":"a4cf452c1e0375c3d4412cb550bd1783358468a3b3b777da4829d72c7d6fb74f", + "index":"ml_host_risk_score_default", + "source":{ + "@timestamp":"2021-03-10T14:51:05.766Z", + "risk_stats": { + "risk_score": 21, + "rule_risks": [ + { + "rule_name": "Unusual Linux Username", + "rule_risk": 42 + } + ] + }, + "host":{ + "name":"siem-kibana" + }, + "ingest_timestamp":"2021-03-09T18:02:08.319296053Z", + "risk":"Low" + } + } +} diff --git a/x-pack/test/security_solution_cypress/es_archives/risky_hosts/mappings.json b/x-pack/test/security_solution_cypress/es_archives/risky_hosts/mappings.json index 97d3288bf07b69..02ceb5b5ebcccc 100644 --- a/x-pack/test/security_solution_cypress/es_archives/risky_hosts/mappings.json +++ b/x-pack/test/security_solution_cypress/es_archives/risky_hosts/mappings.json @@ -54,3 +54,61 @@ } } } + + +{ + "type": "index", + "value": { + "index": "ml_host_risk_score_default", + "mappings": { + "properties": { + "@timestamp": { + "type": "date" + }, + "host": { + "properties": { + "name": { + "type": "keyword" + } + } + }, + "ingest_timestamp": { + "type": "date" + }, + "risk": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "risk_stats": { + "properties": { + "risk_score": { + "type": "long" + } + } + } + } + }, + "settings": { + "index": { + "lifecycle": { + "name": "ml_host_risk_score_latest_default", + "rollover_alias": "ml_host_risk_score_latest_default" + }, + "mapping": { + "total_fields": { + "limit": "10000" + } + }, + "max_docvalue_fields_search": "200", + "number_of_replicas": "1", + "number_of_shards": "1", + "refresh_interval": "5s" + } + } + } +} From d6917fcb8be5bbb13196d7d8cae0923f636ae7df Mon Sep 17 00:00:00 2001 From: Garrett Spong Date: Wed, 19 Jan 2022 19:30:21 -0700 Subject: [PATCH 063/108] Fixes broken cypress test after ECS update to Rule Registry (#123429) ## Summary New ECS FieldMap was generated in https://github.com/elastic/kibana/pull/123012, however since it only contained changes to `Rule Registry` code the `Security Solution` Cypress tests were not run, and thus did not catch this field change. See https://github.com/elastic/kibana/pull/122661#discussion_r784412959 for details. Confirmed w/ @madirey that expected value is indeed `5` now that `host.geo.continent_code` has been [added](https://github.com/elastic/kibana/pull/123012/files#diff-a1647ccb73ef26c8c8b6aefd87084504b146af72fcb088ccacad93fcaad15b69R1524-R1528). Some failing PR's from `main`: https://github.com/elastic/kibana/pull/123357 https://github.com/elastic/kibana/pull/121644 https://github.com/elastic/kibana/pull/123352 ### Checklist Delete any items that are not applicable to this PR. - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios --- .../cypress/integration/timelines/fields_browser.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/cypress/integration/timelines/fields_browser.spec.ts b/x-pack/plugins/security_solution/cypress/integration/timelines/fields_browser.spec.ts index df194136c6bb2c..be726f0323d48c 100644 --- a/x-pack/plugins/security_solution/cypress/integration/timelines/fields_browser.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/timelines/fields_browser.spec.ts @@ -109,7 +109,7 @@ describe('Fields Browser', () => { filterFieldsBrowser(filterInput); - cy.get(FIELDS_BROWSER_SELECTED_CATEGORY_COUNT).should('have.text', '4'); + cy.get(FIELDS_BROWSER_SELECTED_CATEGORY_COUNT).should('have.text', '5'); }); }); From df163c63f65633b82e80cf3ce8ced71c81775773 Mon Sep 17 00:00:00 2001 From: vladpro25 <91911546+vladpro25@users.noreply.github.com> Date: Thu, 20 Jan 2022 06:11:50 +0200 Subject: [PATCH 064/108] [Kibana][Dev Console][Autocomplete] Autocomplete missing comma on correct location (#121611) * Fix autocomplete missing comma on the correct location * Add a test case Co-authored-by: Muhammad Ibragimov Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../models/sense_editor/integration.test.js | 4 +- .../public/lib/autocomplete/autocomplete.ts | 13 ++++- test/functional/apps/console/_console.ts | 20 ++++++++ test/functional/page_objects/console_page.ts | 48 +++++++++++++++++-- 4 files changed, 77 insertions(+), 8 deletions(-) diff --git a/src/plugins/console/public/application/models/sense_editor/integration.test.js b/src/plugins/console/public/application/models/sense_editor/integration.test.js index f7e8bd1314ab58..a342c3429d03db 100644 --- a/src/plugins/console/public/application/models/sense_editor/integration.test.js +++ b/src/plugins/console/public/application/models/sense_editor/integration.test.js @@ -361,7 +361,7 @@ describe('Integration', () => { cursor: { lineNumber: 7, column: 1 }, initialValue: '', addTemplate: true, - prefixToAdd: ', ', + prefixToAdd: '', suffixToAdd: '', rangeToReplace: { start: { lineNumber: 7, column: 1 }, @@ -374,7 +374,7 @@ describe('Integration', () => { cursor: { lineNumber: 6, column: 15 }, initialValue: '', addTemplate: true, - prefixToAdd: ', ', + prefixToAdd: '', suffixToAdd: '', rangeToReplace: { start: { lineNumber: 6, column: 15 }, diff --git a/src/plugins/console/public/lib/autocomplete/autocomplete.ts b/src/plugins/console/public/lib/autocomplete/autocomplete.ts index a85e53d44d1a32..43fdde3f023490 100644 --- a/src/plugins/console/public/lib/autocomplete/autocomplete.ts +++ b/src/plugins/console/public/lib/autocomplete/autocomplete.ts @@ -762,7 +762,18 @@ export default function ({ break; default: if (nonEmptyToken && nonEmptyToken.type.indexOf('url') < 0) { - context.prefixToAdd = ', '; + const { position, value } = nonEmptyToken; + + // We can not rely on prefixToAdd here, because it adds a comma at the beginning of the new token + // Since we have access to the position of the previous token here, this could be a good place to insert a comma manually + context.prefixToAdd = ''; + editor.insert( + { + column: position.column + value.length, + lineNumber: position.lineNumber, + }, + ', ' + ); } } diff --git a/test/functional/apps/console/_console.ts b/test/functional/apps/console/_console.ts index 72e0b0a0123c6d..3f873850ff1931 100644 --- a/test/functional/apps/console/_console.ts +++ b/test/functional/apps/console/_console.ts @@ -85,12 +85,32 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { // Ensure that the text area can be interacted with await PageObjects.console.dismissTutorial(); expect(await PageObjects.console.hasAutocompleter()).to.be(false); + await PageObjects.console.enterRequest(); await PageObjects.console.promptAutocomplete(); await retry.waitFor('autocomplete to be visible', () => PageObjects.console.hasAutocompleter() ); }); + it('should add comma after previous non empty line on autocomplete', async () => { + const LINE_NUMBER = 2; + + await PageObjects.console.dismissTutorial(); + await PageObjects.console.clearTextArea(); + await PageObjects.console.enterText(`{\n\t"query": {\n\t\t"match": {}`); + await PageObjects.console.pressEnter(); + await PageObjects.console.pressEnter(); + await PageObjects.console.pressEnter(); + await PageObjects.console.promptAutocomplete(); + + await retry.try(async () => { + const textOfPreviousNonEmptyLine = await PageObjects.console.getVisibleTextAt(LINE_NUMBER); + log.debug(textOfPreviousNonEmptyLine); + const lastChar = textOfPreviousNonEmptyLine.charAt(textOfPreviousNonEmptyLine.length - 1); + expect(lastChar).to.be.equal(','); + }); + }); + describe('with a data URI in the load_from query', () => { it('loads the data from the URI', async () => { await PageObjects.common.navigateToApp('console', { diff --git a/test/functional/page_objects/console_page.ts b/test/functional/page_objects/console_page.ts index 77c87f6066e854..f8a64c0032bb23 100644 --- a/test/functional/page_objects/console_page.ts +++ b/test/functional/page_objects/console_page.ts @@ -84,13 +84,8 @@ export class ConsolePageObject extends FtrService { } public async promptAutocomplete() { - // This focusses the cursor on the bottom of the text area - const editor = await this.getEditor(); - const content = await editor.findByCssSelector('.ace_content'); - await content.click(); const textArea = await this.testSubjects.find('console-textarea'); // There should be autocomplete for this on all license levels - await textArea.pressKeys('\nGET s'); await textArea.pressKeys([Key.CONTROL, Key.SPACE]); } @@ -101,4 +96,47 @@ export class ConsolePageObject extends FtrService { return false; } } + + public async enterRequest(request: string = '\nGET _search') { + const textArea = await this.getEditorTextArea(); + await textArea.pressKeys(request); + await textArea.pressKeys(Key.ENTER); + } + + public async enterText(text: string) { + const textArea = await this.getEditorTextArea(); + await textArea.pressKeys(text); + } + + private async getEditorTextArea() { + // This focusses the cursor on the bottom of the text area + const editor = await this.getEditor(); + const content = await editor.findByCssSelector('.ace_content'); + await content.click(); + return await this.testSubjects.find('console-textarea'); + } + + public async getVisibleTextAt(lineIndex: number) { + const editor = await this.getEditor(); + const lines = await editor.findAllByClassName('ace_line_group'); + + if (lines.length < lineIndex) { + throw new Error(`No line with index: ${lineIndex}`); + } + + const line = lines[lineIndex]; + const text = await line.getVisibleText(); + + return text.trim(); + } + + public async pressEnter() { + const textArea = await this.testSubjects.find('console-textarea'); + await textArea.pressKeys(Key.ENTER); + } + + public async clearTextArea() { + const textArea = await this.getEditorTextArea(); + await textArea.clearValueWithKeyboard(); + } } From 91825b9a4d42516e68a5d2b4efa76c805e081cc6 Mon Sep 17 00:00:00 2001 From: Frank Hassanabad Date: Wed, 19 Jan 2022 23:25:32 -0700 Subject: [PATCH 065/108] Fixes comments from earlier PR (#123392) ## Summary Adds comments to earlier PR: https://github.com/elastic/kibana/pull/123332 In the tests for documentation. --- .../tests/telemetry/detection_rules.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/telemetry/detection_rules.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/telemetry/detection_rules.ts index 561c8bc3564766..f4228ed31f2796 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/telemetry/detection_rules.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/telemetry/detection_rules.ts @@ -1241,7 +1241,7 @@ export default ({ getService }: FtrProviderContext) => { }); }); - it('should show "notifications_disabled" to be "1" for rule that has at least "1" action(s) and the alert is "disabled"/"in-active"', async () => { + it('should show "notifications_disabled" to be "1", "has_notification" to be "true, "has_legacy_notification" to be "false" for rule that has at least "1" action(s) and the alert is "disabled"/"in-active"', async () => { await installPrePackagedRules(supertest, log); // Rule id of "9a1a2dae-0b5f-4c3d-8305-a268d404c306" is from the file: // x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/elastic_endpoint_security.json @@ -1296,7 +1296,7 @@ export default ({ getService }: FtrProviderContext) => { }); }); - it('should show "notifications_enabled" to be "1" for rule that has at least "1" action(s) and the alert is "enabled"/"active"', async () => { + it('should show "notifications_enabled" to be "1", "has_notification" to be "true, "has_legacy_notification" to be "false" for rule that has at least "1" action(s) and the alert is "enabled"/"active"', async () => { await installPrePackagedRules(supertest, log); // Rule id of "9a1a2dae-0b5f-4c3d-8305-a268d404c306" is from the file: // x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/elastic_endpoint_security.json @@ -1351,7 +1351,7 @@ export default ({ getService }: FtrProviderContext) => { }); }); - it('should show "legacy_notifications_disabled" to be "1" for rule that has at least "1" action(s) and the alert is "disabled"/"in-active"', async () => { + it('should show "legacy_notifications_disabled" to be "1", "has_notification" to be "false, "has_legacy_notification" to be "true" for rule that has at least "1" action(s) and the alert is "disabled"/"in-active"', async () => { await installPrePackagedRules(supertest, log); // Rule id of "9a1a2dae-0b5f-4c3d-8305-a268d404c306" is from the file: // x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/elastic_endpoint_security.json @@ -1405,7 +1405,7 @@ export default ({ getService }: FtrProviderContext) => { }); }); - it('should show "legacy_notifications_enabled" to be "1" for rule that has at least "1" action(s) and the alert is "enabled"/"active"', async () => { + it('should show "legacy_notifications_enabled" to be "1", "has_notification" to be "false, "has_legacy_notification" to be "true" for rule that has at least "1" action(s) and the alert is "enabled"/"active"', async () => { await installPrePackagedRules(supertest, log); // Rule id of "9a1a2dae-0b5f-4c3d-8305-a268d404c306" is from the file: // x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules/elastic_endpoint_security.json From d9709d018da685796f4ece6bd662c5bd5c3932a1 Mon Sep 17 00:00:00 2001 From: Maja Grubic Date: Thu, 20 Jan 2022 08:47:04 +0100 Subject: [PATCH 066/108] [Discover] Introduce storybook (#122538) * [Discover] Add error state if chart loading fails * Reorder stuff around * Remove file * Fix error message a bit * Update src/plugins/discover/public/application/main/components/chart/histogram.tsx Co-authored-by: Andrea Del Rio * Add error handling * Add a unit test * [Discover] Add storybook * Add VisualizeButtonInner * Merge master * Fix package.json * Add Discover webpack to tsconfig.json * Remove unnecessary file * Fix storybook path * Fix yarn.lock * Revert yarn.lock to main * Add buckets to details; fix css Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Andrea Del Rio --- src/dev/storybook/aliases.ts | 1 + .../discover/.storybook/discover.webpack.ts | 14 +++ src/plugins/discover/.storybook/main.js | 10 ++ .../discover_field_details.stories.tsx | 93 +++++++++++++++++++ .../discover_field_visualize.stories.tsx | 29 ++++++ .../components/sidebar/__stories__/fields.ts | 51 ++++++++++ .../sidebar/discover_field_visualize.tsx | 21 ++--- .../discover_field_visualize_inner.tsx | 38 ++++++++ .../__stories__/field_name.stories.tsx | 47 ++++++++++ src/plugins/discover/tsconfig.json | 2 +- 10 files changed, 290 insertions(+), 16 deletions(-) create mode 100644 src/plugins/discover/.storybook/discover.webpack.ts create mode 100644 src/plugins/discover/.storybook/main.js create mode 100644 src/plugins/discover/public/application/main/components/sidebar/__stories__/discover_field_details.stories.tsx create mode 100644 src/plugins/discover/public/application/main/components/sidebar/__stories__/discover_field_visualize.stories.tsx create mode 100644 src/plugins/discover/public/application/main/components/sidebar/__stories__/fields.ts create mode 100644 src/plugins/discover/public/application/main/components/sidebar/discover_field_visualize_inner.tsx create mode 100644 src/plugins/discover/public/components/field_name/__stories__/field_name.stories.tsx diff --git a/src/dev/storybook/aliases.ts b/src/dev/storybook/aliases.ts index 54a48685275e6a..896ed6b0bb5367 100644 --- a/src/dev/storybook/aliases.ts +++ b/src/dev/storybook/aliases.ts @@ -17,6 +17,7 @@ export const storybookAliases = { dashboard_enhanced: 'x-pack/plugins/dashboard_enhanced/.storybook', dashboard: 'src/plugins/dashboard/.storybook', data_enhanced: 'x-pack/plugins/data_enhanced/.storybook', + discover: 'src/plugins/discover/.storybook', embeddable: 'src/plugins/embeddable/.storybook', expression_error: 'src/plugins/expression_error/.storybook', expression_image: 'src/plugins/expression_image/.storybook', diff --git a/src/plugins/discover/.storybook/discover.webpack.ts b/src/plugins/discover/.storybook/discover.webpack.ts new file mode 100644 index 00000000000000..7b978a4e7110ef --- /dev/null +++ b/src/plugins/discover/.storybook/discover.webpack.ts @@ -0,0 +1,14 @@ +/* + * 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. + */ +import { defaultConfig } from '@kbn/storybook'; + +export const discoverStorybookConfig = { + ...defaultConfig, + stories: ['../**/*.stories.tsx'], + addons: [...(defaultConfig.addons || []), './addon/target/register'], +}; diff --git a/src/plugins/discover/.storybook/main.js b/src/plugins/discover/.storybook/main.js new file mode 100644 index 00000000000000..85ea71a7f08f76 --- /dev/null +++ b/src/plugins/discover/.storybook/main.js @@ -0,0 +1,10 @@ +/* + * 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. + */ +import { discoverStorybookConfig } from './discover.webpack'; + +module.exports = discoverStorybookConfig; diff --git a/src/plugins/discover/public/application/main/components/sidebar/__stories__/discover_field_details.stories.tsx b/src/plugins/discover/public/application/main/components/sidebar/__stories__/discover_field_details.stories.tsx new file mode 100644 index 00000000000000..cecf02c0166762 --- /dev/null +++ b/src/plugins/discover/public/application/main/components/sidebar/__stories__/discover_field_details.stories.tsx @@ -0,0 +1,93 @@ +/* + * 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. + */ + +import { storiesOf } from '@storybook/react'; +import React from 'react'; +import { KBN_FIELD_TYPES } from '@kbn/field-types'; +import { DiscoverFieldDetails } from '../discover_field_details'; +import { DataView, IndexPatternField } from '../../../../../../../data_views/common'; +import { fieldSpecMap } from './fields'; +import { numericField as field } from './fields'; +import { Bucket } from '../types'; + +const buckets = [ + { count: 1, display: 'Stewart', percent: 50.0, value: 'Stewart' }, + { count: 1, display: 'Perry', percent: 50.0, value: 'Perry' }, +] as Bucket[]; +const details = { buckets, error: '', exists: 1, total: 2, columns: [] }; + +const fieldFormatInstanceType = {}; +const defaultMap = { + [KBN_FIELD_TYPES.NUMBER]: { id: KBN_FIELD_TYPES.NUMBER, params: {} }, +}; + +const fieldFormat = { + getByFieldType: (fieldType: KBN_FIELD_TYPES) => { + return [fieldFormatInstanceType]; + }, + getDefaultConfig: () => { + return defaultMap.number; + }, + defaultMap, +}; + +const scriptedField = new IndexPatternField({ + name: 'machine.os', + type: 'string', + esTypes: ['long'], + count: 10, + scripted: true, + searchable: true, + aggregatable: true, + readFromDocValues: true, +}); + +const dataView = new DataView({ + spec: { + id: 'logstash-*', + fields: fieldSpecMap, + title: 'logstash-*', + timeFieldName: '@timestamp', + }, + metaFields: ['_id', '_type', '_source'], + shortDotsEnable: false, + // @ts-expect-error + fieldFormats: fieldFormat, +}); + +storiesOf('components/sidebar/DiscoverFieldDetails', module) + .add('default', () => ( +
+ { + alert('On add filter clicked'); + }} + /> +
+ )) + .add('scripted', () => ( +
+ {}} + /> +
+ )) + .add('error', () => ( + {}} + /> + )); diff --git a/src/plugins/discover/public/application/main/components/sidebar/__stories__/discover_field_visualize.stories.tsx b/src/plugins/discover/public/application/main/components/sidebar/__stories__/discover_field_visualize.stories.tsx new file mode 100644 index 00000000000000..397ada8da109de --- /dev/null +++ b/src/plugins/discover/public/application/main/components/sidebar/__stories__/discover_field_visualize.stories.tsx @@ -0,0 +1,29 @@ +/* + * 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. + */ + +import { storiesOf } from '@storybook/react'; +import React from 'react'; +import { DiscoverFieldVisualizeInner } from '../discover_field_visualize_inner'; +import { numericField as field } from './fields'; + +const visualizeInfo = { + href: 'http://localhost:9001/', + field, +}; + +const handleVisualizeLinkClick = () => { + alert('Clicked'); +}; + +storiesOf('components/sidebar/DiscoverFieldVisualizeInner', module).add('default', () => ( + +)); diff --git a/src/plugins/discover/public/application/main/components/sidebar/__stories__/fields.ts b/src/plugins/discover/public/application/main/components/sidebar/__stories__/fields.ts new file mode 100644 index 00000000000000..950ea5b328e6f8 --- /dev/null +++ b/src/plugins/discover/public/application/main/components/sidebar/__stories__/fields.ts @@ -0,0 +1,51 @@ +/* + * 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. + */ + +import { FieldSpec, IndexPatternField } from '../../../../../../../data_views/common'; + +export const fieldSpecMap: Record = { + 'machine.os': { + name: 'machine.os', + esTypes: ['text'], + type: 'string', + aggregatable: false, + searchable: false, + }, + 'machine.os.raw': { + name: 'machine.os.raw', + type: 'string', + esTypes: ['keyword'], + aggregatable: true, + searchable: true, + }, + 'not.filterable': { + name: 'not.filterable', + type: 'string', + esTypes: ['text'], + aggregatable: true, + searchable: false, + }, + bytes: { + name: 'bytes', + type: 'number', + esTypes: ['long'], + aggregatable: true, + searchable: true, + }, +}; + +export const numericField = new IndexPatternField({ + name: 'bytes', + type: 'number', + esTypes: ['long'], + count: 10, + scripted: false, + searchable: true, + aggregatable: true, + readFromDocValues: true, +}); diff --git a/src/plugins/discover/public/application/main/components/sidebar/discover_field_visualize.tsx b/src/plugins/discover/public/application/main/components/sidebar/discover_field_visualize.tsx index b0e10afde9c561..fb845828d62abb 100644 --- a/src/plugins/discover/public/application/main/components/sidebar/discover_field_visualize.tsx +++ b/src/plugins/discover/public/application/main/components/sidebar/discover_field_visualize.tsx @@ -7,14 +7,13 @@ */ import React, { useEffect, useState } from 'react'; -import { EuiButton } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n-react'; import { METRIC_TYPE, UiCounterMetricType } from '@kbn/analytics'; import type { DataView, DataViewField } from 'src/plugins/data/common'; import { triggerVisualizeActions, VisualizeInformation } from './lib/visualize_trigger_utils'; import type { FieldDetails } from './types'; import { getVisualizeInformation } from './lib/visualize_trigger_utils'; +import { DiscoverFieldVisualizeInner } from './discover_field_visualize_inner'; interface Props { field: DataViewField; @@ -46,19 +45,11 @@ export const DiscoverFieldVisualize: React.FC = React.memo( }; return ( - // eslint-disable-next-line @elastic/eui/href-or-on-click - - - + ); } ); diff --git a/src/plugins/discover/public/application/main/components/sidebar/discover_field_visualize_inner.tsx b/src/plugins/discover/public/application/main/components/sidebar/discover_field_visualize_inner.tsx new file mode 100644 index 00000000000000..f4c7205f25026f --- /dev/null +++ b/src/plugins/discover/public/application/main/components/sidebar/discover_field_visualize_inner.tsx @@ -0,0 +1,38 @@ +/* + * 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. + */ + +import React from 'react'; +import { EuiButton } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { IndexPatternField } from '../../../../../../data_views/common'; +import { VisualizeInformation } from './lib/visualize_trigger_utils'; + +interface DiscoverFieldVisualizeInnerProps { + field: IndexPatternField; + visualizeInfo: VisualizeInformation; + handleVisualizeLinkClick: (event: React.MouseEvent) => void; +} + +export const DiscoverFieldVisualizeInner = (props: DiscoverFieldVisualizeInnerProps) => { + const { field, visualizeInfo, handleVisualizeLinkClick } = props; + return ( + // eslint-disable-next-line @elastic/eui/href-or-on-click + + + + ); +}; diff --git a/src/plugins/discover/public/components/field_name/__stories__/field_name.stories.tsx b/src/plugins/discover/public/components/field_name/__stories__/field_name.stories.tsx new file mode 100644 index 00000000000000..91ef279405b619 --- /dev/null +++ b/src/plugins/discover/public/components/field_name/__stories__/field_name.stories.tsx @@ -0,0 +1,47 @@ +/* + * 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. + */ + +import { storiesOf } from '@storybook/react'; +import React from 'react'; +import { EuiFlexGroup } from '@elastic/eui'; +import { FieldName } from '../field_name'; +import { IndexPatternField } from '../../../../../data_views/common'; + +const field = new IndexPatternField({ + name: 'bytes', + type: 'number', + esTypes: ['long'], + count: 10, + scripted: false, + searchable: true, + aggregatable: true, + readFromDocValues: true, +}); + +const renderFieldName = (fldName: {} | null | undefined) => { + return ( + + {fldName} + + ); +}; + +storiesOf('components/FieldName/FieldNameStories', module) + .add('default', () => renderFieldName()) + .add('with field type', () => + renderFieldName() + ) + .add('with field mapping', () => + renderFieldName( + + ) + ); diff --git a/src/plugins/discover/tsconfig.json b/src/plugins/discover/tsconfig.json index 961d265ab7ff90..4ff6f0598d7d8b 100644 --- a/src/plugins/discover/tsconfig.json +++ b/src/plugins/discover/tsconfig.json @@ -6,7 +6,7 @@ "declaration": true, "declarationMap": true }, - "include": ["common/**/*", "public/**/*", "server/**/*", "../../../typings/**/*"], + "include": ["common/**/*", "public/**/*", "server/**/*", "../../../typings/**/*", ".storybook/**/*"], "references": [ { "path": "../../core/tsconfig.json" }, { "path": "../charts/tsconfig.json" }, From 5238ba835a2606bc254f2966c605062d1436adf9 Mon Sep 17 00:00:00 2001 From: Matthias Wilhelm Date: Thu, 20 Jan 2022 09:01:56 +0100 Subject: [PATCH 067/108] [Discover] Fix unmapped field document explorer rendering (#123174) --- .../get_render_cell_value.test.tsx | 60 +++++++++++++++++++ .../discover_grid/get_render_cell_value.tsx | 9 ++- 2 files changed, 67 insertions(+), 2 deletions(-) diff --git a/src/plugins/discover/public/components/discover_grid/get_render_cell_value.test.tsx b/src/plugins/discover/public/components/discover_grid/get_render_cell_value.test.tsx index a102622402d026..4479e051b1f264 100644 --- a/src/plugins/discover/public/components/discover_grid/get_render_cell_value.test.tsx +++ b/src/plugins/discover/public/components/discover_grid/get_render_cell_value.test.tsx @@ -600,4 +600,64 @@ describe('Discover grid cell rendering', function () { ); expect(component.html()).toMatchInlineSnapshot(`"-"`); }); + + it('renders unmapped fields correctly', () => { + (indexPatternMock.getFieldByName as jest.Mock).mockReturnValueOnce(undefined); + const rowsFieldsUnmapped: ElasticSearchHit[] = [ + { + _id: '1', + _index: 'test', + _score: 1, + _source: undefined, + fields: { unmapped: ['.gz'] }, + highlight: { + extension: ['@kibana-highlighted-field.gz@/kibana-highlighted-field'], + }, + }, + ]; + const DiscoverGridCellValue = getRenderCellValueFn( + indexPatternMock, + rowsFieldsUnmapped, + rowsFieldsUnmapped.map(flatten), + true, + ['unmapped'], + 100 + ); + const component = shallow( + + ); + expect(component).toMatchInlineSnapshot(` + + .gz + + `); + + const componentWithDetails = shallow( + + ); + expect(componentWithDetails).toMatchInlineSnapshot(` + + `); + }); }); diff --git a/src/plugins/discover/public/components/discover_grid/get_render_cell_value.tsx b/src/plugins/discover/public/components/discover_grid/get_render_cell_value.tsx index 2a573bdb2415ef..e56c3ef2b699b1 100644 --- a/src/plugins/discover/public/components/discover_grid/get_render_cell_value.tsx +++ b/src/plugins/discover/public/components/discover_grid/get_render_cell_value.tsx @@ -169,10 +169,15 @@ export const getRenderCellValueFn = if (!field?.type && rowFlattened && typeof rowFlattened[columnId] === 'object') { if (isDetails) { // nicely formatted JSON for the expanded view - return {JSON.stringify(rowFlattened[columnId], null, 2)}; + return ( + } + width={defaultMonacoEditorWidth} + /> + ); } - return {JSON.stringify(rowFlattened[columnId])}; + return <>{formatFieldValue(rowFlattened[columnId], row, indexPattern, field)}; } return ( From b3455bb8ef84502110ebd470eaedaea18b780351 Mon Sep 17 00:00:00 2001 From: Christos Nasikas Date: Thu, 20 Jan 2022 11:02:58 +0200 Subject: [PATCH 068/108] [Cases] Show "removed comment" user action in the UI (#123352) Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../user_actions/comment/comment.test.tsx | 17 +++++++++++++ .../user_actions/comment/comment.tsx | 24 ++++++++++++++++++- 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/cases/public/components/user_actions/comment/comment.test.tsx b/x-pack/plugins/cases/public/components/user_actions/comment/comment.test.tsx index ca45191dd4cb16..df3374c848e56c 100644 --- a/x-pack/plugins/cases/public/components/user_actions/comment/comment.test.tsx +++ b/x-pack/plugins/cases/public/components/user_actions/comment/comment.test.tsx @@ -49,6 +49,23 @@ describe('createCommentUserActionBuilder', () => { expect(screen.getByText('edited comment')).toBeInTheDocument(); }); + it('renders correctly when deleting a comment', async () => { + const userAction = getUserAction('comment', Actions.delete); + const builder = createCommentUserActionBuilder({ + ...builderArgs, + userAction, + }); + + const createdUserAction = builder.build(); + render( + + + + ); + + expect(screen.getByText('removed comment')).toBeInTheDocument(); + }); + it('renders correctly a user comment', async () => { const userAction = getUserAction('comment', Actions.create, { commentId: basicCase.comments[0].id, diff --git a/x-pack/plugins/cases/public/components/user_actions/comment/comment.tsx b/x-pack/plugins/cases/public/components/user_actions/comment/comment.tsx index 79df2aaca99785..9c0b5397207489 100644 --- a/x-pack/plugins/cases/public/components/user_actions/comment/comment.tsx +++ b/x-pack/plugins/cases/public/components/user_actions/comment/comment.tsx @@ -17,6 +17,24 @@ import { createAlertAttachmentUserActionBuilder } from './alert'; import { createActionAttachmentUserActionBuilder } from './actions'; const getUpdateLabelTitle = () => `${i18n.EDITED_FIELD} ${i18n.COMMENT.toLowerCase()}`; +const getDeleteLabelTitle = () => `${i18n.REMOVED_FIELD} ${i18n.COMMENT.toLowerCase()}`; + +const getDeleteCommentUserAction = ({ + userAction, + handleOutlineComment, +}: { + userAction: UserActionResponse; +} & Pick): EuiCommentProps[] => { + const label = getDeleteLabelTitle(); + const commonBuilder = createCommonUpdateUserActionBuilder({ + userAction, + handleOutlineComment, + label, + icon: 'cross', + }); + + return commonBuilder.build(); +}; const getCreateCommentUserAction = ({ userAction, @@ -101,8 +119,12 @@ export const createCommentUserActionBuilder: UserActionBuilder = ({ }) => ({ build: () => { const commentUserAction = userAction as UserActionResponse; - const comment = caseData.comments.find((c) => c.id === commentUserAction.commentId); + if (commentUserAction.action === Actions.delete) { + return getDeleteCommentUserAction({ userAction: commentUserAction, handleOutlineComment }); + } + + const comment = caseData.comments.find((c) => c.id === commentUserAction.commentId); if (comment == null) { return []; } From 829fdae9fa7f7933ec01a98e195bb3e0a629c456 Mon Sep 17 00:00:00 2001 From: Christos Nasikas Date: Thu, 20 Jan 2022 11:45:03 +0200 Subject: [PATCH 069/108] [Cases] Total connectors metric (#123060) Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../client/metrics/actions/actions.test.ts | 4 +- .../server/client/metrics/connectors.test.ts | 50 ++++++ .../cases/server/client/metrics/connectors.ts | 31 +++- x-pack/plugins/cases/server/services/mocks.ts | 1 + .../services/user_actions/index.test.ts | 160 ++++++++++++++++++ .../server/services/user_actions/index.ts | 78 +++++++++ .../security_and_spaces/tests/common/index.ts | 1 + .../metrics/get_case_metrics_connectors.ts | 138 +++++++++++++++ 8 files changed, 458 insertions(+), 5 deletions(-) create mode 100644 x-pack/plugins/cases/server/client/metrics/connectors.test.ts create mode 100644 x-pack/test/cases_api_integration/security_and_spaces/tests/common/metrics/get_case_metrics_connectors.ts diff --git a/x-pack/plugins/cases/server/client/metrics/actions/actions.test.ts b/x-pack/plugins/cases/server/client/metrics/actions/actions.test.ts index f8336424be17d4..239277259539e4 100644 --- a/x-pack/plugins/cases/server/client/metrics/actions/actions.test.ts +++ b/x-pack/plugins/cases/server/client/metrics/actions/actions.test.ts @@ -5,13 +5,13 @@ * 2.0. */ +import { CaseResponse } from '../../../../common/api'; import { createCasesClientMock } from '../../mocks'; import { CasesClientArgs } from '../../types'; import { loggingSystemMock } from '../../../../../../../src/core/server/mocks'; import { createAttachmentServiceMock } from '../../../services/mocks'; import { Actions } from './actions'; -import { ICaseResponse } from '../../typedoc_interfaces'; const clientMock = createCasesClientMock(); const attachmentService = createAttachmentServiceMock(); @@ -30,7 +30,7 @@ const constructorOptions = { caseId: 'test-id', casesClient: clientMock, clientA describe('Actions', () => { beforeAll(() => { getAuthorizationFilter.mockResolvedValue({}); - clientMock.cases.get.mockResolvedValue({ id: '' } as unknown as ICaseResponse); + clientMock.cases.get.mockResolvedValue({ id: '' } as unknown as CaseResponse); }); beforeEach(() => { diff --git a/x-pack/plugins/cases/server/client/metrics/connectors.test.ts b/x-pack/plugins/cases/server/client/metrics/connectors.test.ts new file mode 100644 index 00000000000000..0b15b94525b029 --- /dev/null +++ b/x-pack/plugins/cases/server/client/metrics/connectors.test.ts @@ -0,0 +1,50 @@ +/* + * 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 { createCasesClientMock } from '../mocks'; +import { CasesClientArgs } from '../types'; +import { loggingSystemMock } from '../../../../../../src/core/server/mocks'; +import { createUserActionServiceMock } from '../../services/mocks'; +import { Connectors } from './connectors'; + +describe('Connectors', () => { + const clientMock = createCasesClientMock(); + const logger = loggingSystemMock.createLogger(); + const userActionService = createUserActionServiceMock(); + const getAuthorizationFilter = jest.fn().mockResolvedValue({}); + + const clientArgs = { + logger, + userActionService, + authorization: { getAuthorizationFilter }, + } as unknown as CasesClientArgs; + + const constructorOptions = { caseId: 'test-id', casesClient: clientMock, clientArgs }; + + beforeAll(() => {}); + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('returns zero as total if the are no connectors', async () => { + userActionService.getUniqueConnectors.mockResolvedValue([]); + const handler = new Connectors(constructorOptions); + expect(await handler.compute()).toEqual({ connectors: { total: 0 } }); + }); + + it('returns the correct number of connectors', async () => { + userActionService.getUniqueConnectors.mockResolvedValue([ + { id: '865b6040-7533-11ec-8bcc-a9fc6f9d63b2' }, + { id: '915c2600-7533-11ec-8bcc-a9fc6f9d63b2' }, + { id: 'b2635b10-63e1-11ec-90af-6fe7d490ff66' }, + ]); + + const handler = new Connectors(constructorOptions); + expect(await handler.compute()).toEqual({ connectors: { total: 3 } }); + }); +}); diff --git a/x-pack/plugins/cases/server/client/metrics/connectors.ts b/x-pack/plugins/cases/server/client/metrics/connectors.ts index 137bcdd61cdec9..3dd29b8b6dda7a 100644 --- a/x-pack/plugins/cases/server/client/metrics/connectors.ts +++ b/x-pack/plugins/cases/server/client/metrics/connectors.ts @@ -6,6 +6,8 @@ */ import { CaseMetricsResponse } from '../../../common/api'; +import { Operations } from '../../authorization'; +import { createCaseError } from '../../common/error'; import { BaseHandler } from './base_handler'; import { BaseHandlerCommonOptions } from './types'; @@ -15,8 +17,31 @@ export class Connectors extends BaseHandler { } public async compute(): Promise { - return { - connectors: { total: 0 }, - }; + const { unsecuredSavedObjectsClient, authorization, userActionService, logger } = + this.options.clientArgs; + + const { caseId } = this.options; + + const { filter: authorizationFilter } = await authorization.getAuthorizationFilter( + Operations.getUserActionMetrics + ); + + const uniqueConnectors = await userActionService.getUniqueConnectors({ + unsecuredSavedObjectsClient, + caseId, + filter: authorizationFilter, + }); + + try { + return { + connectors: { total: uniqueConnectors.length }, + }; + } catch (error) { + throw createCaseError({ + message: `Failed to retrieve total connectors metrics for case id: ${caseId}: ${error}`, + error, + logger, + }); + } } } diff --git a/x-pack/plugins/cases/server/services/mocks.ts b/x-pack/plugins/cases/server/services/mocks.ts index 751b7ef8882f19..169e3bd5dc8e08 100644 --- a/x-pack/plugins/cases/server/services/mocks.ts +++ b/x-pack/plugins/cases/server/services/mocks.ts @@ -93,6 +93,7 @@ export const createUserActionServiceMock = (): CaseUserActionServiceMock => { getAll: jest.fn(), bulkCreate: jest.fn(), findStatusChanges: jest.fn(), + getUniqueConnectors: jest.fn(), }; // the cast here is required because jest.Mocked tries to include private members and would throw an error diff --git a/x-pack/plugins/cases/server/services/user_actions/index.test.ts b/x-pack/plugins/cases/server/services/user_actions/index.test.ts index 8b42523f5ece2c..2ccfaf54dd9feb 100644 --- a/x-pack/plugins/cases/server/services/user_actions/index.test.ts +++ b/x-pack/plugins/cases/server/services/user_actions/index.test.ts @@ -924,5 +924,165 @@ describe('CaseUserActionService', () => { ); }); }); + + describe('getUniqueConnectors', () => { + const findResponse = createUserActionFindSO(createConnectorUserAction()); + const aggregationResponse = { + aggregations: { + references: { + doc_count: 8, + connectors: { + doc_count: 4, + ids: { + doc_count_error_upper_bound: 0, + sum_other_doc_count: 0, + buckets: [ + { + key: '865b6040-7533-11ec-8bcc-a9fc6f9d63b2', + doc_count: 2, + docs: {}, + }, + { + key: '915c2600-7533-11ec-8bcc-a9fc6f9d63b2', + doc_count: 1, + docs: {}, + }, + { + key: 'b2635b10-63e1-11ec-90af-6fe7d490ff66', + doc_count: 1, + docs: {}, + }, + ], + }, + }, + }, + }, + }; + + beforeAll(() => { + unsecuredSavedObjectsClient.find.mockResolvedValue( + findResponse as unknown as Promise + ); + }); + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('it returns an empty array if the response is not valid', async () => { + const res = await service.getUniqueConnectors({ + unsecuredSavedObjectsClient, + caseId: '123', + }); + + expect(res).toEqual([]); + }); + + it('it returns the connectors', async () => { + unsecuredSavedObjectsClient.find.mockResolvedValue({ + ...findResponse, + ...aggregationResponse, + } as unknown as Promise); + + const res = await service.getUniqueConnectors({ + unsecuredSavedObjectsClient, + caseId: '123', + }); + + expect(res).toEqual([ + { id: '865b6040-7533-11ec-8bcc-a9fc6f9d63b2' }, + { id: '915c2600-7533-11ec-8bcc-a9fc6f9d63b2' }, + { id: 'b2635b10-63e1-11ec-90af-6fe7d490ff66' }, + ]); + }); + + it('it returns the unique connectors', async () => { + await service.getUniqueConnectors({ + unsecuredSavedObjectsClient, + caseId: '123', + }); + + expect(unsecuredSavedObjectsClient.find.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + Object { + "aggs": Object { + "references": Object { + "aggregations": Object { + "connectors": Object { + "aggregations": Object { + "ids": Object { + "terms": Object { + "field": "cases-user-actions.references.id", + "size": 100, + }, + }, + }, + "filter": Object { + "term": Object { + "cases-user-actions.references.type": "action", + }, + }, + }, + }, + "nested": Object { + "path": "cases-user-actions.references", + }, + }, + }, + "filter": Object { + "arguments": Array [ + Object { + "arguments": Array [ + Object { + "type": "literal", + "value": "cases-user-actions.attributes.type", + }, + Object { + "type": "literal", + "value": "connector", + }, + Object { + "type": "literal", + "value": false, + }, + ], + "function": "is", + "type": "function", + }, + Object { + "arguments": Array [ + Object { + "type": "literal", + "value": "cases-user-actions.attributes.type", + }, + Object { + "type": "literal", + "value": "create_case", + }, + Object { + "type": "literal", + "value": false, + }, + ], + "function": "is", + "type": "function", + }, + ], + "function": "or", + "type": "function", + }, + "hasReference": Object { + "id": "123", + "type": "cases", + }, + "page": 1, + "perPage": 1, + "sortField": "created_at", + "type": "cases-user-actions", + }, + ] + `); + }); + }); }); }); diff --git a/x-pack/plugins/cases/server/services/user_actions/index.ts b/x-pack/plugins/cases/server/services/user_actions/index.ts index 9ff3da2f230e35..130fe476452788 100644 --- a/x-pack/plugins/cases/server/services/user_actions/index.ts +++ b/x-pack/plugins/cases/server/services/user_actions/index.ts @@ -16,6 +16,7 @@ import { SavedObjectsUpdateResponse, } from 'kibana/server'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { KueryNode } from '@kbn/es-query'; import { isConnectorUserAction, @@ -434,6 +435,83 @@ export class CaseUserActionService { throw error; } } + + public async getUniqueConnectors({ + caseId, + filter, + unsecuredSavedObjectsClient, + }: { + caseId: string; + unsecuredSavedObjectsClient: SavedObjectsClientContract; + filter?: KueryNode; + }): Promise> { + try { + this.log.debug(`Attempting to count connectors for case id ${caseId}`); + const connectorsFilter = buildFilter({ + filters: [ActionTypes.connector, ActionTypes.create_case], + field: 'type', + operator: 'or', + type: CASE_USER_ACTION_SAVED_OBJECT, + }); + + const combinedFilter = combineFilters([connectorsFilter, filter]); + + const response = await unsecuredSavedObjectsClient.find< + CaseUserActionAttributesWithoutConnectorId, + { references: { connectors: { ids: { buckets: Array<{ key: string }> } } } } + >({ + type: CASE_USER_ACTION_SAVED_OBJECT, + hasReference: { type: CASE_SAVED_OBJECT, id: caseId }, + page: 1, + perPage: 1, + sortField: defaultSortField, + aggs: this.buildCountConnectorsAggs(), + filter: combinedFilter, + }); + + return ( + response.aggregations?.references?.connectors?.ids?.buckets?.map(({ key }) => ({ + id: key, + })) ?? [] + ); + } catch (error) { + this.log.error(`Error while counting connectors for case id ${caseId}: ${error}`); + throw error; + } + } + + private buildCountConnectorsAggs( + /** + * It is high unlikely for a user to have more than + * 100 connectors attached to a case + */ + size: number = 100 + ): Record { + return { + references: { + nested: { + path: `${CASE_USER_ACTION_SAVED_OBJECT}.references`, + }, + aggregations: { + connectors: { + filter: { + term: { + [`${CASE_USER_ACTION_SAVED_OBJECT}.references.type`]: 'action', + }, + }, + aggregations: { + ids: { + terms: { + field: `${CASE_USER_ACTION_SAVED_OBJECT}.references.id`, + size, + }, + }, + }, + }, + }, + }, + }; + } } export function transformFindResponseToExternalModel( diff --git a/x-pack/test/cases_api_integration/security_and_spaces/tests/common/index.ts b/x-pack/test/cases_api_integration/security_and_spaces/tests/common/index.ts index 66fbd96d8f62dc..74b9401904d8c7 100644 --- a/x-pack/test/cases_api_integration/security_and_spaces/tests/common/index.ts +++ b/x-pack/test/cases_api_integration/security_and_spaces/tests/common/index.ts @@ -42,6 +42,7 @@ export default ({ loadTestFile }: FtrProviderContext): void => { loadTestFile(require.resolve('./metrics/get_case_metrics')); loadTestFile(require.resolve('./metrics/get_case_metrics_alerts')); loadTestFile(require.resolve('./metrics/get_case_metrics_actions')); + loadTestFile(require.resolve('./metrics/get_case_metrics_connectors')); // NOTE: Migrations are not included because they can inadvertently remove the .kibana indices which removes the users and spaces // which causes errors in any tests after them that relies on those diff --git a/x-pack/test/cases_api_integration/security_and_spaces/tests/common/metrics/get_case_metrics_connectors.ts b/x-pack/test/cases_api_integration/security_and_spaces/tests/common/metrics/get_case_metrics_connectors.ts new file mode 100644 index 00000000000000..adfb22d3cf145f --- /dev/null +++ b/x-pack/test/cases_api_integration/security_and_spaces/tests/common/metrics/get_case_metrics_connectors.ts @@ -0,0 +1,138 @@ +/* + * 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 { getPostCaseRequest } from '../../../../common/lib/mock'; +import { ObjectRemover as ActionsRemover } from '../../../../../alerting_api_integration/common/lib'; + +import { FtrProviderContext } from '../../../../common/ftr_provider_context'; +import { + createCase, + deleteAllCaseItems, + getCaseMetrics, + updateCase, +} from '../../../../common/lib/utils'; +import { ConnectorTypes } from '../../../../../../plugins/cases/common/api'; + +// eslint-disable-next-line import/no-default-export +export default ({ getService }: FtrProviderContext): void => { + const supertest = getService('supertest'); + const es = getService('es'); + + describe('case connector metrics', () => { + const actionsRemover = new ActionsRemover(supertest); + const jiraConnector = { + id: 'jira', + name: 'Jira', + type: ConnectorTypes.jira as const, + fields: { issueType: 'Task', priority: 'High', parent: null }, + }; + + const snConnector = { + id: 'sn', + name: 'SN', + type: ConnectorTypes.serviceNowITSM as const, + fields: { + urgency: '2', + impact: '2', + severity: '2', + category: 'software', + subcategory: 'os', + }, + }; + + afterEach(async () => { + await deleteAllCaseItems(es); + await actionsRemover.removeAll(); + }); + + describe('total connectors', () => { + const expectConnectorsToBe = async (caseId: string, expectedConnectors: number) => { + const metrics = await getCaseMetrics({ + supertest, + caseId, + features: ['connectors'], + }); + + expect(metrics).to.eql({ + connectors: { + total: expectedConnectors, + }, + }); + }; + + it('returns zero total connectors for a case with no connectors attached', async () => { + const theCase = await createCase(supertest, getPostCaseRequest()); + await expectConnectorsToBe(theCase.id, 0); + }); + + it('takes into account the connector from the create_case user action', async () => { + const theCase = await createCase( + supertest, + getPostCaseRequest({ + connector: jiraConnector, + }) + ); + await expectConnectorsToBe(theCase.id, 1); + }); + + it('returns the correct total number of connectors', async () => { + const theCase = await createCase(supertest, getPostCaseRequest()); + + /** + * We update the case three times to create three user actions + * Each user action created is of type connector. + * Although we have three user actions the metric + * should return two total connectors + * as the third update changes the fields + * of the Jira connector and does not adds + * a new connector. + */ + let patchedCases = await updateCase({ + supertest, + params: { + cases: [ + { + id: theCase.id, + version: theCase.version, + connector: jiraConnector, + }, + ], + }, + }); + + patchedCases = await updateCase({ + supertest, + params: { + cases: [ + { + id: theCase.id, + version: patchedCases[0].version, + connector: snConnector, + }, + ], + }, + }); + + await updateCase({ + supertest, + params: { + cases: [ + { + id: theCase.id, + version: patchedCases[0].version, + connector: { ...jiraConnector, fields: { ...jiraConnector.fields, urgency: '1' } }, + }, + ], + }, + }); + + await expectConnectorsToBe(theCase.id, 2); + }); + }); + }); +}; From 0ccd8421224f582310ded472b3e7eae4087b82f8 Mon Sep 17 00:00:00 2001 From: Shahzad Date: Thu, 20 Jan 2022 11:17:58 +0100 Subject: [PATCH 070/108] [Uptime] Test now mode while adding/editing monitors (#122642) --- .../common/constants/client_defaults.ts | 2 + .../uptime/common/constants/rest_api.ts | 1 + .../monitor/ping_list/ping_list.tsx | 218 +--------------- .../monitor/ping_list/ping_list_table.tsx | 244 ++++++++++++++++++ .../action_bar/action_bar.tsx | 56 +++- .../action_bar/action_bar_portal.tsx | 12 +- .../monitor_config/monitor_config.tsx | 50 +++- .../browser/browser_test_results.test.tsx | 236 +++++++++++++++++ .../browser/browser_test_results.tsx | 89 +++++++ .../use_browser_run_once_monitors.test.tsx | 42 +++ .../browser/use_browser_run_once_monitors.ts | 108 ++++++++ .../simple/simple_test_results.test.tsx | 203 +++++++++++++++ .../simple/simple_test_results.tsx | 32 +++ .../simple/use_simple_run_once_monitors.ts | 74 ++++++ .../test_now_mode/test_now_mode.test.tsx | 32 +++ .../test_now_mode/test_now_mode.tsx | 90 +++++++ .../test_now_mode/test_result_header.test.tsx | 46 ++++ .../test_now_mode/test_result_header.tsx | 107 ++++++++ .../test_now_mode/test_run_results.tsx | 23 ++ .../test_now_mode/use_tick_tick.ts | 27 ++ .../overview/filter_group/filter_group.tsx | 10 +- .../synthetics/check_steps/step_duration.tsx | 4 +- .../synthetics/check_steps/step_image.tsx | 5 +- .../synthetics/check_steps/steps_list.tsx | 53 ++-- .../components/synthetics/status_badge.tsx | 2 +- .../synthetics/step_screenshot_display.tsx | 5 +- .../uptime/public/lib/helper/rtl_helpers.tsx | 42 ++- .../monitor_management/monitor_management.tsx | 2 +- x-pack/plugins/uptime/public/routes.tsx | 2 + .../public/state/api/monitor_management.ts | 12 + .../server/lib/requests/get_ping_histogram.ts | 2 + .../lib/requests/get_snapshot_counts.ts | 3 +- .../requests/search/find_potential_matches.ts | 3 + .../synthetics_service/formatters/browser.ts | 2 +- .../formatters/convert_to_data_stream.ts | 2 +- .../formatters/format_configs.test.ts | 3 +- .../synthetics_service/service_api_client.ts | 12 +- .../synthetics_service/synthetics_service.ts | 28 ++ .../plugins/uptime/server/rest_api/index.ts | 2 + .../synthetics_service/add_monitor.ts | 5 +- .../synthetics_service/run_once_monitor.ts | 50 ++++ 41 files changed, 1671 insertions(+), 270 deletions(-) create mode 100644 x-pack/plugins/uptime/public/components/monitor/ping_list/ping_list_table.tsx create mode 100644 x-pack/plugins/uptime/public/components/monitor_management/test_now_mode/browser/browser_test_results.test.tsx create mode 100644 x-pack/plugins/uptime/public/components/monitor_management/test_now_mode/browser/browser_test_results.tsx create mode 100644 x-pack/plugins/uptime/public/components/monitor_management/test_now_mode/browser/use_browser_run_once_monitors.test.tsx create mode 100644 x-pack/plugins/uptime/public/components/monitor_management/test_now_mode/browser/use_browser_run_once_monitors.ts create mode 100644 x-pack/plugins/uptime/public/components/monitor_management/test_now_mode/simple/simple_test_results.test.tsx create mode 100644 x-pack/plugins/uptime/public/components/monitor_management/test_now_mode/simple/simple_test_results.tsx create mode 100644 x-pack/plugins/uptime/public/components/monitor_management/test_now_mode/simple/use_simple_run_once_monitors.ts create mode 100644 x-pack/plugins/uptime/public/components/monitor_management/test_now_mode/test_now_mode.test.tsx create mode 100644 x-pack/plugins/uptime/public/components/monitor_management/test_now_mode/test_now_mode.tsx create mode 100644 x-pack/plugins/uptime/public/components/monitor_management/test_now_mode/test_result_header.test.tsx create mode 100644 x-pack/plugins/uptime/public/components/monitor_management/test_now_mode/test_result_header.tsx create mode 100644 x-pack/plugins/uptime/public/components/monitor_management/test_now_mode/test_run_results.tsx create mode 100644 x-pack/plugins/uptime/public/components/monitor_management/test_now_mode/use_tick_tick.ts create mode 100644 x-pack/plugins/uptime/server/rest_api/synthetics_service/run_once_monitor.ts diff --git a/x-pack/plugins/uptime/common/constants/client_defaults.ts b/x-pack/plugins/uptime/common/constants/client_defaults.ts index 42521a1166bde3..a8860dcca4a1a1 100644 --- a/x-pack/plugins/uptime/common/constants/client_defaults.ts +++ b/x-pack/plugins/uptime/common/constants/client_defaults.ts @@ -41,3 +41,5 @@ export const CLIENT_DEFAULTS = { SEARCH: '', STATUS_FILTER: '', }; + +export const EXCLUDE_RUN_ONCE_FILTER = { bool: { must_not: { exists: { field: 'run_once' } } } }; diff --git a/x-pack/plugins/uptime/common/constants/rest_api.ts b/x-pack/plugins/uptime/common/constants/rest_api.ts index f2359e4f1fb1ee..2c369579b01500 100644 --- a/x-pack/plugins/uptime/common/constants/rest_api.ts +++ b/x-pack/plugins/uptime/common/constants/rest_api.ts @@ -40,4 +40,5 @@ export enum API_URLS { INDEX_TEMPLATES = '/internal/uptime/service/index_templates', SERVICE_LOCATIONS = '/internal/uptime/service/locations', SYNTHETICS_MONITORS = '/internal/uptime/service/monitors', + RUN_ONCE_MONITOR = '/internal/uptime/service/monitors/run_once', } diff --git a/x-pack/plugins/uptime/public/components/monitor/ping_list/ping_list.tsx b/x-pack/plugins/uptime/public/components/monitor/ping_list/ping_list.tsx index 06c7ab7bff843c..27141aa436d675 100644 --- a/x-pack/plugins/uptime/public/components/monitor/ping_list/ping_list.tsx +++ b/x-pack/plugins/uptime/public/components/monitor/ping_list/ping_list.tsx @@ -5,31 +5,15 @@ * 2.0. */ -import { EuiBasicTable, EuiPanel, EuiSpacer } from '@elastic/eui'; +import { EuiPanel, EuiSpacer } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import React, { useCallback, useState, useEffect, MouseEvent } from 'react'; +import React, { useState } from 'react'; import styled from 'styled-components'; -import { useHistory } from 'react-router-dom'; -import moment from 'moment'; -import { useDispatch } from 'react-redux'; -import { Ping } from '../../../../common/runtime_types'; import { convertMicrosecondsToMilliseconds as microsToMillis } from '../../../lib/helper'; -import { LocationName } from './location_name'; import { Pagination } from '../../overview/monitor_list'; -import { pruneJourneyState } from '../../../state/actions/journey'; -import { PingStatusColumn } from './columns/ping_status'; -import * as I18LABELS from './translations'; -import { MONITOR_TYPES } from '../../../../common/constants'; -import { ResponseCodeColumn } from './columns/response_code'; -import { ERROR_LABEL, LOCATION_LABEL, RES_CODE_LABEL, TIMESTAMP_LABEL } from './translations'; -import { ExpandRowColumn } from './columns/expand_row'; -import { PingErrorCol } from './columns/ping_error'; -import { PingTimestamp } from './columns/ping_timestamp'; -import { FailedStep } from './columns/failed_step'; import { usePingsList } from './use_pings'; import { PingListHeader } from './ping_list_header'; -import { clearPings } from '../../../state/actions'; -import { getShortTimeStamp } from '../../overview/monitor_list/columns/monitor_status_column'; +import { PingListTable } from './ping_list_table'; export const SpanWithMargin = styled.span` margin-right: 16px; @@ -52,7 +36,7 @@ export const formatDuration = (durationMicros: number) => { } const seconds = (durationMicros / ONE_SECOND_AS_MICROS).toFixed(0); - // we format seconds with correct pulralization here and not for `ms` because it is much more likely users + // we format seconds with correct pluralization here and not for `ms` because it is much more likely users // will encounter times of exactly '1' second. if (seconds === '1') { return i18n.translate('xpack.uptime.pingist.durationSecondsColumnFormatting.singular', { @@ -70,178 +54,11 @@ export const PingList = () => { const [pageSize, setPageSize] = useState(DEFAULT_PAGE_SIZE); const [pageIndex, setPageIndex] = useState(0); - const dispatch = useDispatch(); - - const history = useHistory(); - - const pruneJourneysCallback = useCallback( - (checkGroups: string[]) => dispatch(pruneJourneyState(checkGroups)), - [dispatch] - ); - const { error, loading, pings, total, failedSteps } = usePingsList({ pageSize, pageIndex, }); - const [expandedRows, setExpandedRows] = useState>({}); - - const expandedIdsToRemove = JSON.stringify( - Object.keys(expandedRows).filter((e) => !pings.some(({ docId }) => docId === e)) - ); - - useEffect(() => { - return () => { - dispatch(clearPings()); - }; - }, [dispatch]); - - useEffect(() => { - const parsed = JSON.parse(expandedIdsToRemove); - if (parsed.length) { - parsed.forEach((docId: string) => { - delete expandedRows[docId]; - }); - setExpandedRows(expandedRows); - } - }, [expandedIdsToRemove, expandedRows]); - - const expandedCheckGroups = pings - .filter((p: Ping) => Object.keys(expandedRows).some((f) => p.docId === f)) - .map(({ monitor: { check_group: cg } }) => cg); - - const expandedCheckGroupsStr = JSON.stringify(expandedCheckGroups); - - useEffect(() => { - pruneJourneysCallback(JSON.parse(expandedCheckGroupsStr)); - }, [pruneJourneysCallback, expandedCheckGroupsStr]); - - const hasStatus = pings.reduce( - (hasHttpStatus: boolean, currentPing) => - hasHttpStatus || !!currentPing.http?.response?.status_code, - false - ); - - const monitorType = pings?.[0]?.monitor.type; - - const columns: any[] = [ - { - field: 'monitor.status', - name: I18LABELS.STATUS_LABEL, - render: (pingStatus: string, item: Ping) => ( - - ), - }, - { - align: 'left', - field: 'observer.geo.name', - name: LOCATION_LABEL, - render: (location: string) => , - }, - ...(monitorType === MONITOR_TYPES.BROWSER - ? [ - { - align: 'left', - field: 'timestamp', - name: TIMESTAMP_LABEL, - render: (timestamp: string, item: Ping) => ( - - ), - }, - ] - : []), - // ip column not needed for browser type - ...(monitorType !== MONITOR_TYPES.BROWSER - ? [ - { - align: 'right', - dataType: 'number', - field: 'monitor.ip', - name: i18n.translate('xpack.uptime.pingList.ipAddressColumnLabel', { - defaultMessage: 'IP', - }), - }, - ] - : []), - { - align: 'center', - field: 'monitor.duration.us', - name: i18n.translate('xpack.uptime.pingList.durationMsColumnLabel', { - defaultMessage: 'Duration', - }), - render: (duration: number) => formatDuration(duration), - }, - { - field: 'error.type', - name: ERROR_LABEL, - width: '30%', - render: (errorType: string, item: Ping) => , - }, - ...(monitorType === MONITOR_TYPES.BROWSER - ? [ - { - field: 'monitor.status', - align: 'left', - name: i18n.translate('xpack.uptime.pingList.columns.failedStep', { - defaultMessage: 'Failed step', - }), - render: (_timestamp: string, item: Ping) => ( - - ), - }, - ] - : []), - // Only add this column is there is any status present in list - ...(hasStatus - ? [ - { - field: 'http.response.status_code', - align: 'right', - name: {RES_CODE_LABEL}, - render: (statusCode: string) => , - }, - ] - : []), - ...(monitorType !== MONITOR_TYPES.BROWSER - ? [ - { - align: 'right', - width: '24px', - isExpander: true, - render: (item: Ping) => ( - - ), - }, - ] - : []), - ]; - - const getRowProps = (item: Ping) => { - if (monitorType !== MONITOR_TYPES.BROWSER) { - return {}; - } - const { monitor } = item; - return { - height: '85px', - 'data-test-subj': `row-${monitor.check_group}`, - onClick: (evt: MouseEvent) => { - const targetElem = evt.target as HTMLElement; - - // we dont want to capture image click event - if (targetElem.tagName !== 'IMG' && targetElem.tagName !== 'path') { - history.push(`/journey/${monitor.check_group}/steps`); - } - }, - }; - }; - const pagination: Pagination = { initialPageSize: DEFAULT_PAGE_SIZE, pageIndex, @@ -254,31 +71,16 @@ export const PingList = () => { - { setPageSize(criteria.page!.size); setPageIndex(criteria.page!.index); }} - tableLayout={'auto'} - rowProps={getRowProps} + error={error} + pings={pings} + loading={loading} + pagination={pagination} + failedSteps={failedSteps} /> ); diff --git a/x-pack/plugins/uptime/public/components/monitor/ping_list/ping_list_table.tsx b/x-pack/plugins/uptime/public/components/monitor/ping_list/ping_list_table.tsx new file mode 100644 index 00000000000000..84a2d6a5d6a315 --- /dev/null +++ b/x-pack/plugins/uptime/public/components/monitor/ping_list/ping_list_table.tsx @@ -0,0 +1,244 @@ +/* + * 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 React, { MouseEvent, useCallback, useEffect, useState } from 'react'; +import { EuiBasicTable } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import moment from 'moment'; +import { useHistory } from 'react-router-dom'; +import { useDispatch } from 'react-redux'; +import * as I18LABELS from './translations'; +import { FailedStepsApiResponse, Ping } from '../../../../common/runtime_types'; +import { PingStatusColumn } from './columns/ping_status'; +import { ERROR_LABEL, LOCATION_LABEL, RES_CODE_LABEL, TIMESTAMP_LABEL } from './translations'; +import { LocationName } from './location_name'; +import { MONITOR_TYPES } from '../../../../common/constants'; +import { PingTimestamp } from './columns/ping_timestamp'; +import { getShortTimeStamp } from '../../overview/monitor_list/columns/monitor_status_column'; +import { PingErrorCol } from './columns/ping_error'; +import { FailedStep } from './columns/failed_step'; +import { ResponseCodeColumn } from './columns/response_code'; +import { ExpandRowColumn } from './columns/expand_row'; +import { formatDuration, SpanWithMargin } from './ping_list'; +import { clearPings } from '../../../state/actions'; +import { pruneJourneyState } from '../../../state/actions/journey'; +import { Pagination } from '../../overview'; + +interface Props { + loading?: boolean; + pings: Ping[]; + error?: Error; + onChange?: (criteria: any) => void; + pagination?: Pagination; + failedSteps?: FailedStepsApiResponse; +} + +export function PingListTable({ loading, error, pings, pagination, onChange, failedSteps }: Props) { + const history = useHistory(); + + const [expandedRows, setExpandedRows] = useState>({}); + + const expandedIdsToRemove = JSON.stringify( + Object.keys(expandedRows).filter((e) => !pings.some(({ docId }) => docId === e)) + ); + + const dispatch = useDispatch(); + + const pruneJourneysCallback = useCallback( + (checkGroups: string[]) => dispatch(pruneJourneyState(checkGroups)), + [dispatch] + ); + + useEffect(() => { + return () => { + dispatch(clearPings()); + }; + }, [dispatch]); + + useEffect(() => { + const parsed = JSON.parse(expandedIdsToRemove); + if (parsed.length) { + parsed.forEach((docId: string) => { + delete expandedRows[docId]; + }); + setExpandedRows(expandedRows); + } + }, [expandedIdsToRemove, expandedRows]); + + const expandedCheckGroups = pings + .filter((p: Ping) => Object.keys(expandedRows).some((f) => p.docId === f)) + .map(({ monitor: { check_group: cg } }) => cg); + + const expandedCheckGroupsStr = JSON.stringify(expandedCheckGroups); + + useEffect(() => { + pruneJourneysCallback(JSON.parse(expandedCheckGroupsStr)); + }, [pruneJourneysCallback, expandedCheckGroupsStr]); + + const hasStatus = pings.reduce( + (hasHttpStatus: boolean, currentPing) => + hasHttpStatus || !!currentPing.http?.response?.status_code, + false + ); + + const hasError = pings.reduce( + (errorType: boolean, currentPing) => errorType || !!currentPing.error?.type, + false + ); + + const monitorType = pings?.[0]?.monitor.type; + + const columns: any[] = [ + { + field: 'monitor.status', + name: I18LABELS.STATUS_LABEL, + render: (pingStatus: string, item: Ping) => ( + + ), + }, + { + align: 'left', + field: 'observer.geo.name', + name: LOCATION_LABEL, + render: (location: string) => , + }, + ...(monitorType === MONITOR_TYPES.BROWSER + ? [ + { + align: 'left', + field: 'timestamp', + name: TIMESTAMP_LABEL, + render: (timestamp: string, item: Ping) => ( + + ), + }, + ] + : []), + // ip column not needed for browser type + ...(monitorType !== MONITOR_TYPES.BROWSER + ? [ + { + align: 'right', + dataType: 'number', + field: 'monitor.ip', + name: i18n.translate('xpack.uptime.pingList.ipAddressColumnLabel', { + defaultMessage: 'IP', + }), + }, + ] + : []), + { + align: 'center', + field: 'monitor.duration.us', + name: i18n.translate('xpack.uptime.pingList.durationMsColumnLabel', { + defaultMessage: 'Duration', + }), + render: (duration: number) => formatDuration(duration), + }, + ...(hasError + ? [ + { + field: 'error.type', + name: ERROR_LABEL, + width: '30%', + render: (errorType: string, item: Ping) => ( + + ), + }, + ] + : []), + ...(monitorType === MONITOR_TYPES.BROWSER + ? [ + { + field: 'monitor.status', + align: 'left', + name: i18n.translate('xpack.uptime.pingList.columns.failedStep', { + defaultMessage: 'Failed step', + }), + render: (_timestamp: string, item: Ping) => ( + + ), + }, + ] + : []), + // Only add this column is there is any status present in list + ...(hasStatus + ? [ + { + field: 'http.response.status_code', + align: 'right', + name: {RES_CODE_LABEL}, + render: (statusCode: string) => , + }, + ] + : []), + ...(monitorType !== MONITOR_TYPES.BROWSER + ? [ + { + align: 'right', + width: '24px', + isExpander: true, + render: (item: Ping) => ( + + ), + }, + ] + : []), + ]; + + const getRowProps = (item: Ping) => { + if (monitorType !== MONITOR_TYPES.BROWSER) { + return {}; + } + const { monitor } = item; + return { + height: '85px', + 'data-test-subj': `row-${monitor.check_group}`, + onClick: (evt: MouseEvent) => { + const targetElem = evt.target as HTMLElement; + + // we dont want to capture image click event + if (targetElem.tagName !== 'IMG' && targetElem.tagName !== 'path') { + history.push(`/journey/${monitor.check_group}/steps`); + } + }, + }; + }; + + return ( + + ); +} diff --git a/x-pack/plugins/uptime/public/components/monitor_management/action_bar/action_bar.tsx b/x-pack/plugins/uptime/public/components/monitor_management/action_bar/action_bar.tsx index 06cc2b6db41d8a..6321688d92c4cb 100644 --- a/x-pack/plugins/uptime/public/components/monitor_management/action_bar/action_bar.tsx +++ b/x-pack/plugins/uptime/public/components/monitor_management/action_bar/action_bar.tsx @@ -7,7 +7,14 @@ import React, { useCallback, useContext, useState, useEffect } from 'react'; import { useParams, Redirect } from 'react-router-dom'; -import { EuiFlexGroup, EuiFlexItem, EuiButton, EuiButtonEmpty } from '@elastic/eui'; +import { + EuiFlexGroup, + EuiFlexItem, + EuiButton, + EuiButtonEmpty, + EuiText, + EuiToolTip, +} from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FETCH_STATUS, useFetcher } from '../../../../../observability/public'; @@ -18,14 +25,18 @@ import { UptimeSettingsContext } from '../../../contexts'; import { setMonitor } from '../../../state/api'; import { SyntheticsMonitor } from '../../../../common/runtime_types'; +import { euiStyled } from '../../../../../../../src/plugins/kibana_react/common'; +import { TestRun } from '../test_now_mode/test_now_mode'; -interface Props { +export interface ActionBarProps { monitor: SyntheticsMonitor; isValid: boolean; + testRun?: TestRun; onSave?: () => void; + onTestNow?: () => void; } -export const ActionBar = ({ monitor, isValid, onSave }: Props) => { +export const ActionBar = ({ monitor, isValid, onSave, onTestNow, testRun }: ActionBarProps) => { const { monitorId } = useParams<{ monitorId: string }>(); const { basePath } = useContext(UptimeSettingsContext); @@ -84,9 +95,28 @@ export const ActionBar = ({ monitor, isValid, onSave }: Props) => { ) : ( - {!isValid && hasBeenSubmitted && VALIDATION_ERROR_LABEL} + + {!isValid && hasBeenSubmitted && VALIDATION_ERROR_LABEL} + + {onTestNow && ( + + + onTestNow()} + disabled={!isValid} + > + {testRun ? RE_RUN_TEST_LABEL : RUN_TEST_LABEL} + + + + )} + { {DISCARD_LABEL} + { ); }; +const WarningText = euiStyled(EuiText)` + box-shadow: -4px 0 ${(props) => props.theme.eui.euiColorWarning}; + padding-left: 8px; +`; + const DISCARD_LABEL = i18n.translate('xpack.uptime.monitorManagement.discardLabel', { defaultMessage: 'Discard', }); @@ -128,6 +164,14 @@ const UPDATE_MONITOR_LABEL = i18n.translate('xpack.uptime.monitorManagement.upda defaultMessage: 'Update monitor', }); +const RUN_TEST_LABEL = i18n.translate('xpack.uptime.monitorManagement.runTest', { + defaultMessage: 'Run test', +}); + +const RE_RUN_TEST_LABEL = i18n.translate('xpack.uptime.monitorManagement.reRunTest', { + defaultMessage: 'Re-run test', +}); + const VALIDATION_ERROR_LABEL = i18n.translate('xpack.uptime.monitorManagement.validationError', { defaultMessage: 'Your monitor has errors. Please fix them before saving.', }); @@ -153,3 +197,7 @@ const MONITOR_FAILURE_LABEL = i18n.translate( defaultMessage: 'Monitor was unable to be saved. Please try again later.', } ); + +const TEST_NOW_DESCRIPTION = i18n.translate('xpack.uptime.testRun.description', { + defaultMessage: 'Test your monitor and verify the results before saving', +}); diff --git a/x-pack/plugins/uptime/public/components/monitor_management/action_bar/action_bar_portal.tsx b/x-pack/plugins/uptime/public/components/monitor_management/action_bar/action_bar_portal.tsx index 097bd48e966b16..b6a80ec90893c1 100644 --- a/x-pack/plugins/uptime/public/components/monitor_management/action_bar/action_bar_portal.tsx +++ b/x-pack/plugins/uptime/public/components/monitor_management/action_bar/action_bar_portal.tsx @@ -9,17 +9,9 @@ import React from 'react'; import { InPortal } from 'react-reverse-portal'; import { ActionBarPortalNode } from '../../../pages/monitor_management/action_bar_portal_node'; -import { SyntheticsMonitor } from '../../../../common/runtime_types'; +import { ActionBar, ActionBarProps } from './action_bar'; -import { ActionBar } from './action_bar'; - -interface Props { - monitor: SyntheticsMonitor; - isValid: boolean; - onSave?: () => void; -} - -export const ActionBarPortal = (props: Props) => { +export const ActionBarPortal = (props: ActionBarProps) => { return ( diff --git a/x-pack/plugins/uptime/public/components/monitor_management/monitor_config/monitor_config.tsx b/x-pack/plugins/uptime/public/components/monitor_management/monitor_config/monitor_config.tsx index 7536a76b315a87..bcade36929805c 100644 --- a/x-pack/plugins/uptime/public/components/monitor_management/monitor_config/monitor_config.tsx +++ b/x-pack/plugins/uptime/public/components/monitor_management/monitor_config/monitor_config.tsx @@ -5,8 +5,10 @@ * 2.0. */ -import React from 'react'; +import React, { useState } from 'react'; +import { EuiResizableContainer } from '@elastic/eui'; +import { v4 as uuidv4 } from 'uuid'; import { defaultConfig, usePolicyConfigContext } from '../../fleet_package/contexts'; import { usePolicy } from '../../fleet_package/hooks/use_policy'; @@ -14,11 +16,11 @@ import { validate } from '../validation'; import { ActionBarPortal } from '../action_bar/action_bar_portal'; import { useFormatMonitor } from '../hooks/use_format_monitor'; import { MonitorFields } from './monitor_fields'; +import { TestNowMode, TestRun } from '../test_now_mode/test_now_mode'; +import { MonitorFields as MonitorFieldsType } from '../../../../common/runtime_types'; export const MonitorConfig = () => { const { monitorType } = usePolicyConfigContext(); - /* TODO - Use Effect to make sure the package/index templates are loaded. Wait for it to load before showing view - * then show error message if it fails */ /* raw policy config compatible with the UI. Save this to saved objects */ const policyConfig = usePolicy(); @@ -27,18 +29,54 @@ export const MonitorConfig = () => { This type of helper should ideally be moved to task manager where we are syncing the config. We can process validation (isValid) and formatting for heartbeat (formattedMonitor) separately We don't need to save the heartbeat compatible version in saved objects */ - const { isValid } = useFormatMonitor({ + const { isValid, config } = useFormatMonitor({ monitorType, validate, config: policyConfig[monitorType], defaultConfig: defaultConfig[monitorType], }); + const [testRun, setTestRun] = useState(); + + const onTestNow = () => { + if (config) { + setTestRun({ id: uuidv4(), monitor: config as MonitorFieldsType }); + } + }; + return ( <> - + + {(EuiResizablePanel, EuiResizableButton) => ( + <> + + + + + + + + {config && } + + + )} + - + ); }; diff --git a/x-pack/plugins/uptime/public/components/monitor_management/test_now_mode/browser/browser_test_results.test.tsx b/x-pack/plugins/uptime/public/components/monitor_management/test_now_mode/browser/browser_test_results.test.tsx new file mode 100644 index 00000000000000..727dfa4b9ec31a --- /dev/null +++ b/x-pack/plugins/uptime/public/components/monitor_management/test_now_mode/browser/browser_test_results.test.tsx @@ -0,0 +1,236 @@ +/* + * 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 React from 'react'; +import { screen } from '@testing-library/react'; +import { render } from '../../../../lib/helper/rtl_helpers'; +import { kibanaService } from '../../../../state/kibana_service'; +import * as runOnceHooks from './use_browser_run_once_monitors'; +import { BrowserTestRunResult } from './browser_test_results'; +import { fireEvent } from '@testing-library/dom'; + +describe('BrowserTestRunResult', function () { + it('should render properly', async function () { + render(); + expect(await screen.findByText('Test result')).toBeInTheDocument(); + expect(await screen.findByText('0 steps completed')).toBeInTheDocument(); + const dataApi = (kibanaService.core as any).data.search; + + expect(dataApi.search).toHaveBeenCalledTimes(1); + expect(dataApi.search).toHaveBeenLastCalledWith( + { + params: { + body: { + query: { + bool: { + filter: [ + { term: { config_id: 'test-id' } }, + { + terms: { + 'synthetics.type': ['heartbeat/summary', 'journey/start'], + }, + }, + ], + }, + }, + sort: [{ '@timestamp': 'desc' }], + }, + index: 'heartbeat-8*,heartbeat-7*,synthetics-*', + size: 10, + }, + }, + {} + ); + }); + + it('should displays results', async function () { + jest.spyOn(runOnceHooks, 'useBrowserRunOnceMonitors').mockReturnValue({ + data, + stepListData: { steps: [stepEndDoc._source] } as any, + loading: false, + journeyStarted: true, + summaryDoc: summaryDoc._source, + stepEnds: [stepEndDoc._source], + }); + + render(); + + expect(await screen.findByText('Test result')).toBeInTheDocument(); + + expect(await screen.findByText('COMPLETED')).toBeInTheDocument(); + expect(await screen.findByText('Took 22 seconds')).toBeInTheDocument(); + expect(await screen.findByText('1 step completed')).toBeInTheDocument(); + + fireEvent.click(await screen.findByTestId('expandResults')); + + expect(await screen.findByText('Go to https://www.elastic.co/')).toBeInTheDocument(); + expect(await screen.findByText('21.8 seconds')).toBeInTheDocument(); + }); +}); + +const journeyStartDoc = { + _index: '.ds-synthetics-browser-default-2022.01.11-000002', + _id: 'J1pLU34B6BrWThBwS4Fb', + _score: null, + _source: { + agent: { + name: 'job-78df368e085a796b-x9cbm', + id: 'df497635-644b-43ba-97a6-2f4dce1ea93b', + type: 'heartbeat', + ephemeral_id: 'e24d9e65-ae5f-4088-9a79-01dd504a1403', + version: '8.0.0', + }, + package: { name: '@elastic/synthetics', version: '1.0.0-beta.17' }, + os: { platform: 'linux' }, + synthetics: { + package_version: '1.0.0-beta.17', + journey: { name: 'inline', id: 'inline' }, + payload: { + source: + 'async ({ page, context, browser, params }) => {\n scriptFn.apply(null, [core_1.step, page, context, browser, params, expect_1.expect]);\n }', + params: {}, + }, + index: 0, + type: 'journey/start', + }, + monitor: { + name: 'Test Browser monitor - inline', + id: '3e11e70a-41b9-472c-a465-7c9b76b1a085-inline', + timespan: { lt: '2022-01-13T11:58:49.463Z', gte: '2022-01-13T11:55:49.463Z' }, + check_group: 'c01406bf-7467-11ec-9858-aa31996e0afe', + type: 'browser', + }, + '@timestamp': '2022-01-13T11:55:49.462Z', + ecs: { version: '8.0.0' }, + config_id: '3e11e70a-41b9-472c-a465-7c9b76b1a085', + data_stream: { namespace: 'default', type: 'synthetics', dataset: 'browser' }, + run_once: true, + event: { + agent_id_status: 'auth_metadata_missing', + ingested: '2022-01-13T11:55:50Z', + dataset: 'browser', + }, + }, + sort: [1642074949462], +}; + +const summaryDoc: any = { + _index: '.ds-synthetics-browser-default-2022.01.11-000002', + _id: 'Ix5LU34BPllLwAMpqlfi', + _score: null, + _source: { + summary: { up: 1, down: 0 }, + agent: { + name: 'job-78df368e085a796b-x9cbm', + id: 'df497635-644b-43ba-97a6-2f4dce1ea93b', + type: 'heartbeat', + ephemeral_id: 'e24d9e65-ae5f-4088-9a79-01dd504a1403', + version: '8.0.0', + }, + synthetics: { + journey: { name: 'inline', id: 'inline', tags: null }, + type: 'heartbeat/summary', + }, + monitor: { + duration: { us: 21754383 }, + name: 'Test Browser monitor - inline', + check_group: 'c01406bf-7467-11ec-9858-aa31996e0afe', + id: '3e11e70a-41b9-472c-a465-7c9b76b1a085-inline', + timespan: { lt: '2022-01-13T11:59:13.567Z', gte: '2022-01-13T11:56:13.567Z' }, + type: 'browser', + status: 'up', + }, + url: { + path: '/', + scheme: 'https', + port: 443, + domain: 'www.elastic.co', + full: 'https://www.elastic.co/', + }, + '@timestamp': '2022-01-13T11:56:11.217Z', + ecs: { version: '8.0.0' }, + config_id: '3e11e70a-41b9-472c-a465-7c9b76b1a085', + data_stream: { namespace: 'default', type: 'synthetics', dataset: 'browser' }, + run_once: true, + event: { + agent_id_status: 'auth_metadata_missing', + ingested: '2022-01-13T11:56:14Z', + dataset: 'browser', + }, + }, + sort: [1642074971217], +}; + +const stepEndDoc: any = { + _index: '.ds-synthetics-browser-default-2022.01.11-000002', + _id: 'M1pLU34B6BrWThBwoIGk', + _score: null, + _source: { + agent: { + name: 'job-78df368e085a796b-x9cbm', + id: 'df497635-644b-43ba-97a6-2f4dce1ea93b', + ephemeral_id: 'e24d9e65-ae5f-4088-9a79-01dd504a1403', + type: 'heartbeat', + version: '8.0.0', + }, + package: { name: '@elastic/synthetics', version: '1.0.0-beta.17' }, + os: { platform: 'linux' }, + synthetics: { + package_version: '1.0.0-beta.17', + journey: { name: 'inline', id: 'inline' }, + payload: { + source: "async () => {\n await page.goto('https://www.elastic.co/');\n}", + url: 'https://www.elastic.co/', + status: 'succeeded', + }, + index: 12, + step: { + duration: { us: 21751370 }, + name: 'Go to https://www.elastic.co/', + index: 1, + status: 'succeeded', + }, + type: 'step/end', + }, + monitor: { + name: 'Test Browser monitor - inline', + id: '3e11e70a-41b9-472c-a465-7c9b76b1a085-inline', + timespan: { lt: '2022-01-13T11:59:11.250Z', gte: '2022-01-13T11:56:11.250Z' }, + check_group: 'c01406bf-7467-11ec-9858-aa31996e0afe', + type: 'browser', + }, + url: { + path: '/', + scheme: 'https', + port: 443, + domain: 'www.elastic.co', + full: 'https://www.elastic.co/', + }, + '@timestamp': '2022-01-13T11:56:11.216Z', + ecs: { version: '8.0.0' }, + config_id: '3e11e70a-41b9-472c-a465-7c9b76b1a085', + data_stream: { namespace: 'default', type: 'synthetics', dataset: 'browser' }, + run_once: true, + event: { + agent_id_status: 'auth_metadata_missing', + ingested: '2022-01-13T11:56:12Z', + dataset: 'browser', + }, + }, + sort: [1642074971216], +}; + +const data: any = { + took: 4, + timed_out: false, + _shards: { total: 8, successful: 8, skipped: 2, failed: 0 }, + hits: { + total: 3, + max_score: null, + hits: [journeyStartDoc, stepEndDoc, summaryDoc], + }, +}; diff --git a/x-pack/plugins/uptime/public/components/monitor_management/test_now_mode/browser/browser_test_results.tsx b/x-pack/plugins/uptime/public/components/monitor_management/test_now_mode/browser/browser_test_results.tsx new file mode 100644 index 00000000000000..d5dd333f7f6c70 --- /dev/null +++ b/x-pack/plugins/uptime/public/components/monitor_management/test_now_mode/browser/browser_test_results.tsx @@ -0,0 +1,89 @@ +/* + * 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 * as React from 'react'; +import { EuiAccordion, EuiText } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import styled from 'styled-components'; +import { StepsList } from '../../../synthetics/check_steps/steps_list'; +import { JourneyStep } from '../../../../../common/runtime_types'; +import { useBrowserRunOnceMonitors } from './use_browser_run_once_monitors'; +import { TestResultHeader } from '../test_result_header'; + +interface Props { + monitorId: string; +} +export const BrowserTestRunResult = ({ monitorId }: Props) => { + const { data, loading, stepEnds, journeyStarted, summaryDoc, stepListData } = + useBrowserRunOnceMonitors({ + monitorId, + }); + + const hits = data?.hits.hits; + const doc = hits?.[0]?._source as JourneyStep; + + const buttonContent = ( +
+ + +

+ + {i18n.translate('xpack.uptime.monitorManagement.stepCompleted', { + defaultMessage: + '{stepCount, number} {stepCount, plural, one {step} other {steps}} completed', + values: { + stepCount: stepEnds.length, + }, + })} + +

+
+
+ ); + + return ( + + {summaryDoc && stepEnds.length === 0 && {FAILED_TO_RUN}} + {!summaryDoc && journeyStarted && stepEnds.length === 0 && {LOADING_STEPS}} + {stepEnds.length > 0 && stepListData?.steps && ( + + )} + + ); +}; + +const AccordionWrapper = styled(EuiAccordion)` + .euiAccordion__buttonContent { + width: 100%; + } +`; + +const FAILED_TO_RUN = i18n.translate('xpack.uptime.monitorManagement.failedRun', { + defaultMessage: 'Failed to run steps', +}); + +const LOADING_STEPS = i18n.translate('xpack.uptime.monitorManagement.loadingSteps', { + defaultMessage: 'Loading steps...', +}); diff --git a/x-pack/plugins/uptime/public/components/monitor_management/test_now_mode/browser/use_browser_run_once_monitors.test.tsx b/x-pack/plugins/uptime/public/components/monitor_management/test_now_mode/browser/use_browser_run_once_monitors.test.tsx new file mode 100644 index 00000000000000..3a126e6f69e999 --- /dev/null +++ b/x-pack/plugins/uptime/public/components/monitor_management/test_now_mode/browser/use_browser_run_once_monitors.test.tsx @@ -0,0 +1,42 @@ +/* + * 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 { renderHook } from '@testing-library/react-hooks'; +import { useBrowserRunOnceMonitors } from './use_browser_run_once_monitors'; +import * as resultHook from './use_browser_run_once_monitors'; +import { WrappedHelper } from '../../../../lib/helper/rtl_helpers'; + +describe('useBrowserRunOnceMonitors', function () { + it('should return results as expected', function () { + jest.spyOn(resultHook, 'useBrowserEsResults').mockReturnValue({ + loading: false, + data: { + took: 4, + timed_out: false, + _shards: { total: 8, successful: 8, skipped: 2, failed: 0 }, + hits: { + total: { value: 3, relation: 'eq' }, + max_score: null, + hits: [], + }, + }, + }); + + const { result } = renderHook(() => useBrowserRunOnceMonitors({ monitorId: 'test-id' }), { + wrapper: WrappedHelper, + }); + + expect(result.current).toEqual({ + data: undefined, + journeyStarted: false, + loading: true, + stepEnds: [], + stepListData: undefined, + summaryDoc: undefined, + }); + }); +}); diff --git a/x-pack/plugins/uptime/public/components/monitor_management/test_now_mode/browser/use_browser_run_once_monitors.ts b/x-pack/plugins/uptime/public/components/monitor_management/test_now_mode/browser/use_browser_run_once_monitors.ts new file mode 100644 index 00000000000000..41f2b1cbe11f81 --- /dev/null +++ b/x-pack/plugins/uptime/public/components/monitor_management/test_now_mode/browser/use_browser_run_once_monitors.ts @@ -0,0 +1,108 @@ +/* + * 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 { useSelector } from 'react-redux'; +import { useEffect, useState } from 'react'; +import { selectDynamicSettings } from '../../../../state/selectors'; +import { JourneyStep } from '../../../../../common/runtime_types'; +import { createEsParams, useEsSearch, useFetcher } from '../../../../../../observability/public'; +import { useTickTick } from '../use_tick_tick'; +import { fetchJourneySteps } from '../../../../state/api/journey'; +import { isStepEnd } from '../../../synthetics/check_steps/steps_list'; + +export const useBrowserEsResults = ({ + monitorId, + lastRefresh, +}: { + monitorId: string; + lastRefresh: number; +}) => { + const { settings } = useSelector(selectDynamicSettings); + + return useEsSearch( + createEsParams({ + index: settings?.heartbeatIndices, + body: { + sort: [ + { + '@timestamp': 'desc', + }, + ], + query: { + bool: { + filter: [ + { + term: { + config_id: monitorId, + }, + }, + { + terms: { + 'synthetics.type': ['heartbeat/summary', 'journey/start'], + }, + }, + ], + }, + }, + }, + size: 10, + }), + [monitorId, settings?.heartbeatIndices, lastRefresh], + { name: 'TestRunData' } + ); +}; + +export const useBrowserRunOnceMonitors = ({ monitorId }: { monitorId: string }) => { + const { refreshTimer, lastRefresh } = useTickTick(); + + const [checkGroupId, setCheckGroupId] = useState(''); + const [stepEnds, setStepEnds] = useState([]); + const [summary, setSummary] = useState(); + + const { data, loading } = useBrowserEsResults({ monitorId, lastRefresh }); + + const { data: stepListData } = useFetcher(() => { + if (checkGroupId) { + return fetchJourneySteps({ + checkGroup: checkGroupId, + }); + } + return Promise.resolve(null); + }, [lastRefresh]); + + useEffect(() => { + const hits = data?.hits.hits; + + if (hits && hits.length > 0) { + hits?.forEach((hit) => { + const doc = hit._source as JourneyStep; + if (doc.synthetics?.type === 'journey/start') { + setCheckGroupId(doc.monitor.check_group); + } + if (doc.synthetics?.type === 'heartbeat/summary') { + setSummary(doc); + clearInterval(refreshTimer); + } + }); + } + }, [data, refreshTimer]); + + useEffect(() => { + if (stepListData?.steps && stepListData?.steps.length > 0) { + setStepEnds(stepListData.steps.filter(isStepEnd)); + } + }, [stepListData]); + + return { + data, + stepEnds, + loading, + stepListData, + summaryDoc: summary, + journeyStarted: Boolean(checkGroupId), + }; +}; diff --git a/x-pack/plugins/uptime/public/components/monitor_management/test_now_mode/simple/simple_test_results.test.tsx b/x-pack/plugins/uptime/public/components/monitor_management/test_now_mode/simple/simple_test_results.test.tsx new file mode 100644 index 00000000000000..99ed9ac43db1b2 --- /dev/null +++ b/x-pack/plugins/uptime/public/components/monitor_management/test_now_mode/simple/simple_test_results.test.tsx @@ -0,0 +1,203 @@ +/* + * 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 React from 'react'; +import { screen } from '@testing-library/react'; +import { render } from '../../../../lib/helper/rtl_helpers'; +import { SimpleTestResults } from './simple_test_results'; +import { kibanaService } from '../../../../state/kibana_service'; +import * as runOnceHooks from './use_simple_run_once_monitors'; +import { Ping } from '../../../../../common/runtime_types'; + +describe('SimpleTestResults', function () { + it('should render properly', async function () { + render(); + expect(await screen.findByText('Test result')).toBeInTheDocument(); + const dataApi = (kibanaService.core as any).data.search; + + expect(dataApi.search).toHaveBeenCalledTimes(1); + expect(dataApi.search).toHaveBeenLastCalledWith( + { + params: { + body: { + query: { + bool: { + filter: [{ term: { config_id: 'test-id' } }, { exists: { field: 'summary' } }], + }, + }, + sort: [{ '@timestamp': 'desc' }], + }, + index: 'heartbeat-8*,heartbeat-7*,synthetics-*', + size: 10, + }, + }, + {} + ); + }); + + it('should displays results', async function () { + const doc = data.hits.hits[0]; + jest.spyOn(runOnceHooks, 'useSimpleRunOnceMonitors').mockReturnValue({ + data: data as any, + summaryDoc: { + ...(doc._source as unknown as Ping), + timestamp: (doc._source as unknown as Record)?.['@timestamp'], + docId: doc._id, + }, + loading: false, + }); + + render(); + + expect(await screen.findByText('Test result')).toBeInTheDocument(); + + expect(await screen.findByText('COMPLETED')).toBeInTheDocument(); + expect(await screen.findByText('191 ms')).toBeInTheDocument(); + expect(await screen.findByText('151.101.2.217')).toBeInTheDocument(); + expect(await screen.findByText('Checked Jan 12, 2022 11:54:27 AM')).toBeInTheDocument(); + expect(await screen.findByText('Took 191 ms')).toBeInTheDocument(); + + screen.debug(); + }); +}); + +const data = { + took: 201, + timed_out: false, + _shards: { total: 8, successful: 8, skipped: 0, failed: 0 }, + hits: { + total: 1, + max_score: null, + hits: [ + { + _index: '.ds-synthetics-http-default-2022.01.11-000002', + _id: '6h42T34BPllLwAMpWCjo', + _score: null, + _source: { + tcp: { rtt: { connect: { us: 11480 } } }, + summary: { up: 1, down: 0 }, + agent: { + name: 'job-2b730ffa8811ff-knvmz', + id: 'a3ed3007-4261-40a9-ad08-7a8384cce7f5', + type: 'heartbeat', + ephemeral_id: '7ffe97e3-15a3-4d76-960e-8f0488998e3c', + version: '8.0.0', + }, + resolve: { rtt: { us: 46753 }, ip: '151.101.2.217' }, + monitor: { + duration: { us: 191528 }, + ip: '151.101.2.217', + name: 'Elastic HTTP', + check_group: '4d7fd600-73c8-11ec-b035-2621090844ff', + id: 'e5a3a871-b5c3-49cf-a798-3860028e7a6b', + timespan: { lt: '2022-01-12T16:57:27.443Z', gte: '2022-01-12T16:54:27.443Z' }, + type: 'http', + status: 'up', + }, + url: { + scheme: 'https', + port: 443, + domain: 'www.elastic.co', + full: 'https://www.elastic.co', + }, + '@timestamp': '2022-01-12T16:54:27.252Z', + ecs: { version: '8.0.0' }, + config_id: 'e5a3a871-b5c3-49cf-a798-3860028e7a6b', + data_stream: { namespace: 'default', type: 'synthetics', dataset: 'http' }, + run_once: true, + http: { + rtt: { + response_header: { us: 61231 }, + total: { us: 144630 }, + write_request: { us: 93 }, + content: { us: 25234 }, + validate: { us: 86466 }, + }, + response: { + headers: { + 'X-Dns-Prefetch-Control': 'off', + Server: 'my-server', + 'Access-Control-Allow-Origin': '*', + 'X-Timer': 'S1642006467.362040,VS0,VE51', + 'Referrer-Policy': 'strict-origin-when-cross-origin', + 'X-Frame-Options': 'SAMEORIGIN', + 'Strict-Transport-Security': 'max-age=0', + Etag: '"29d46-xv8YFxCD32Ncbzip9bXU5q9QSvg"', + 'X-Served-By': 'cache-sea4462-SEA, cache-pwk4941-PWK', + 'Content-Security-Policy': + "frame-ancestors 'self' https://*.elastic.co https://elasticsandbox.docebosaas.com https://elastic.docebosaas.com https://www.gather.town;", + 'Set-Cookie': + 'euid=2b70f3d5-56bc-49f1-a64f-50d352914207; Expires=Tuesday, 19 January 2038 01:00:00 GMT; Path=/; Domain=.elastic.co;', + 'X-Change-Language': 'true', + 'Content-Length': '171334', + Age: '1591', + 'Content-Type': 'text/html; charset=utf-8', + 'X-Powered-By': 'Next.js', + 'X-Cache': 'HIT, MISS', + 'X-Content-Type-Options': 'nosniff', + 'X-Download-Options': 'noopen', + Date: 'Wed, 12 Jan 2022 16:54:27 GMT', + Via: '1.1 varnish, 1.1 varnish', + 'Accept-Ranges': 'bytes', + 'Cache-Control': 'max-age=86400', + 'X-Xss-Protection': '1; mode=block', + Vary: 'Accept-Language, X-Change-Language, Accept-Encoding', + 'Elastic-Vi': '2b70f3d5-56bc-49f1-a64f-50d352914207', + 'X-Cache-Hits': '425, 0', + }, + status_code: 200, + mime_type: 'text/html; charset=utf-8', + body: { + bytes: 171334, + hash: '29e5b1a1949dc4d253399874b161049030639d70c5164a5235e039bb4b95f9fd', + }, + }, + }, + tls: { + established: true, + cipher: 'ECDHE-RSA-AES-128-GCM-SHA256', + certificate_not_valid_before: '2021-11-26T19:42:12.000Z', + server: { + x509: { + not_after: '2022-12-28T19:42:11.000Z', + public_key_exponent: 65537, + not_before: '2021-11-26T19:42:12.000Z', + subject: { + distinguished_name: 'CN=www.elastic.co', + common_name: 'www.elastic.co', + }, + public_key_algorithm: 'RSA', + signature_algorithm: 'SHA256-RSA', + public_key_size: 2048, + serial_number: '2487880865947729006738430997169012636', + issuer: { + distinguished_name: + 'CN=GlobalSign Atlas R3 DV TLS CA H2 2021,O=GlobalSign nv-sa,C=BE', + common_name: 'GlobalSign Atlas R3 DV TLS CA H2 2021', + }, + }, + hash: { + sha1: '21099729d121d9707ca6c1b642032a97ea2dcb74', + sha256: '55715c58c7e0939aa9b8989df59082ce33c1b274678e7913fd0c269f33103b02', + }, + }, + rtt: { handshake: { us: 46409 } }, + version: '1.2', + certificate_not_valid_after: '2022-12-28T19:42:11.000Z', + version_protocol: 'tls', + }, + event: { + agent_id_status: 'auth_metadata_missing', + ingested: '2022-01-12T16:54:28Z', + dataset: 'http', + }, + }, + sort: [1642006467252], + }, + ], + }, +}; diff --git a/x-pack/plugins/uptime/public/components/monitor_management/test_now_mode/simple/simple_test_results.tsx b/x-pack/plugins/uptime/public/components/monitor_management/test_now_mode/simple/simple_test_results.tsx new file mode 100644 index 00000000000000..97097285d0bbc9 --- /dev/null +++ b/x-pack/plugins/uptime/public/components/monitor_management/test_now_mode/simple/simple_test_results.tsx @@ -0,0 +1,32 @@ +/* + * 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 React, { useEffect, useState } from 'react'; +import { useSimpleRunOnceMonitors } from './use_simple_run_once_monitors'; +import { Ping } from '../../../../../common/runtime_types'; +import { PingListTable } from '../../../monitor/ping_list/ping_list_table'; +import { TestResultHeader } from '../test_result_header'; + +interface Props { + monitorId: string; +} +export function SimpleTestResults({ monitorId }: Props) { + const [summaryDocs, setSummaryDocs] = useState([]); + const { summaryDoc, loading } = useSimpleRunOnceMonitors({ monitorId }); + + useEffect(() => { + if (summaryDoc) { + setSummaryDocs((prevState) => [summaryDoc, ...prevState]); + } + }, [summaryDoc]); + + return ( + <> + + {summaryDoc && } + + ); +} diff --git a/x-pack/plugins/uptime/public/components/monitor_management/test_now_mode/simple/use_simple_run_once_monitors.ts b/x-pack/plugins/uptime/public/components/monitor_management/test_now_mode/simple/use_simple_run_once_monitors.ts new file mode 100644 index 00000000000000..816f9b019c45a9 --- /dev/null +++ b/x-pack/plugins/uptime/public/components/monitor_management/test_now_mode/simple/use_simple_run_once_monitors.ts @@ -0,0 +1,74 @@ +/* + * 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 { useSelector } from 'react-redux'; +import { useMemo } from 'react'; +import { selectDynamicSettings } from '../../../../state/selectors'; +import { Ping } from '../../../../../common/runtime_types'; +import { createEsParams, useEsSearch } from '../../../../../../observability/public'; +import { useTickTick } from '../use_tick_tick'; + +export const useSimpleRunOnceMonitors = ({ monitorId }: { monitorId: string }) => { + const { refreshTimer, lastRefresh } = useTickTick(); + + const { settings } = useSelector(selectDynamicSettings); + + const { data, loading } = useEsSearch( + createEsParams({ + index: settings?.heartbeatIndices, + body: { + sort: [ + { + '@timestamp': 'desc', + }, + ], + query: { + bool: { + filter: [ + { + term: { + config_id: monitorId, + }, + }, + { + exists: { + field: 'summary', + }, + }, + ], + }, + }, + }, + size: 10, + }), + [monitorId, settings?.heartbeatIndices, lastRefresh], + { name: 'TestRunData' } + ); + + return useMemo(() => { + const doc = data?.hits.hits?.[0]; + + if (doc) { + clearInterval(refreshTimer); + return { + data, + loading, + summaryDoc: { + ...(doc._source as Ping), + timestamp: (doc._source as Record)?.['@timestamp'], + docId: doc._id, + }, + }; + } + + return { + data, + loading, + summaryDoc: null, + }; + }, [data, loading, refreshTimer]); +}; diff --git a/x-pack/plugins/uptime/public/components/monitor_management/test_now_mode/test_now_mode.test.tsx b/x-pack/plugins/uptime/public/components/monitor_management/test_now_mode/test_now_mode.test.tsx new file mode 100644 index 00000000000000..849f1215614d06 --- /dev/null +++ b/x-pack/plugins/uptime/public/components/monitor_management/test_now_mode/test_now_mode.test.tsx @@ -0,0 +1,32 @@ +/* + * 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 React from 'react'; +import { screen } from '@testing-library/react'; +import { render } from '../../../lib/helper/rtl_helpers'; +import { TestNowMode } from './test_now_mode'; +import { kibanaService } from '../../../state/kibana_service'; +import { MonitorFields } from '../../../../common/runtime_types'; + +describe('TestNowMode', function () { + it('should render properly', async function () { + render( + + ); + expect(await screen.findByText('Test result')).toBeInTheDocument(); + expect(await screen.findByText('PENDING')).toBeInTheDocument(); + + expect(await screen.findByText('0 steps completed')).toBeInTheDocument(); + + expect(kibanaService.core.http.post).toHaveBeenCalledTimes(1); + + expect(kibanaService.core.http.post).toHaveBeenLastCalledWith( + expect.stringContaining('/internal/uptime/service/monitors/run_once/'), + { body: '{"type":"browser"}', method: 'POST' } + ); + }); +}); diff --git a/x-pack/plugins/uptime/public/components/monitor_management/test_now_mode/test_now_mode.tsx b/x-pack/plugins/uptime/public/components/monitor_management/test_now_mode/test_now_mode.tsx new file mode 100644 index 00000000000000..43d4e0e6e9d2a7 --- /dev/null +++ b/x-pack/plugins/uptime/public/components/monitor_management/test_now_mode/test_now_mode.tsx @@ -0,0 +1,90 @@ +/* + * 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 React, { useEffect } from 'react'; +import { i18n } from '@kbn/i18n'; +import { + EuiCallOut, + EuiFlexGroup, + EuiFlexItem, + EuiLoadingSpinner, + EuiPanel, + EuiSpacer, +} from '@elastic/eui'; +import { TestRunResult } from './test_run_results'; +import { MonitorFields } from '../../../../common/runtime_types'; +import { useFetcher } from '../../../../../observability/public'; +import { runOnceMonitor } from '../../../state/api'; +import { kibanaService } from '../../../state/kibana_service'; + +export interface TestRun { + id: string; + monitor: MonitorFields; +} + +export function TestNowMode({ testRun }: { testRun?: TestRun }) { + const { data, loading: isPushing } = useFetcher(() => { + if (testRun) { + return runOnceMonitor({ + monitor: testRun.monitor, + id: testRun.id, + }); + } + return new Promise((resolve) => resolve(null)); + }, [testRun]); + + useEffect(() => { + const errors = (data as { errors: Array<{ error: Error }> })?.errors; + + if (errors?.length > 0) { + errors.forEach(({ error }) => { + kibanaService.toasts.addError(error, { title: PushErrorLabel }); + }); + } + }, [data]); + + const errors = (data as { errors?: Array<{ error: Error }> })?.errors; + + const hasErrors = errors && errors?.length > 0; + + if (!testRun) { + return null; + } + + return ( + + {isPushing && ( + + {PushingLabel} + + )} + + {hasErrors && !isPushing && } + + {testRun && !hasErrors && !isPushing && ( + + + + + + )} + + + ); +} + +const PushingLabel = i18n.translate('xpack.uptime.testRun.pushing.description', { + defaultMessage: 'Pushing the monitor to service...', +}); + +const PushError = i18n.translate('xpack.uptime.testRun.pushError', { + defaultMessage: 'Failed to push the monitor to service.', +}); + +const PushErrorLabel = i18n.translate('xpack.uptime.testRun.pushErrorLabel', { + defaultMessage: 'Push error', +}); diff --git a/x-pack/plugins/uptime/public/components/monitor_management/test_now_mode/test_result_header.test.tsx b/x-pack/plugins/uptime/public/components/monitor_management/test_now_mode/test_result_header.test.tsx new file mode 100644 index 00000000000000..07b2d59e0751f8 --- /dev/null +++ b/x-pack/plugins/uptime/public/components/monitor_management/test_now_mode/test_result_header.test.tsx @@ -0,0 +1,46 @@ +/* + * 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 React from 'react'; +import { screen } from '@testing-library/react'; +import { render } from '../../../lib/helper/rtl_helpers'; +import { TestResultHeader } from './test_result_header'; + +describe('TestResultHeader', function () { + it('should render properly', async function () { + render(); + expect(await screen.findByText('Test result')).toBeInTheDocument(); + expect(await screen.findByText('PENDING')).toBeInTheDocument(); + }); + + it('should render in progress state', async function () { + render(); + + expect(await screen.findByText('Test result')).toBeInTheDocument(); + expect(await screen.findByText('IN PROGRESS')).toBeInTheDocument(); + }); + + it('should render completed state', async function () { + render( + + ); + expect(await screen.findByText('Test result')).toBeInTheDocument(); + expect(await screen.findByText('COMPLETED')).toBeInTheDocument(); + expect(await screen.findByText('Took 1 ms')).toBeInTheDocument(); + }); +}); diff --git a/x-pack/plugins/uptime/public/components/monitor_management/test_now_mode/test_result_header.tsx b/x-pack/plugins/uptime/public/components/monitor_management/test_now_mode/test_result_header.tsx new file mode 100644 index 00000000000000..51b120c3c7e5ed --- /dev/null +++ b/x-pack/plugins/uptime/public/components/monitor_management/test_now_mode/test_result_header.tsx @@ -0,0 +1,107 @@ +/* + * 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 { + EuiBadge, + EuiFlexGroup, + EuiFlexItem, + EuiLink, + EuiLoadingSpinner, + EuiText, + EuiTitle, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import * as React from 'react'; +import { formatDuration } from '../../monitor/ping_list/ping_list'; +import { JourneyStep, Ping } from '../../../../common/runtime_types'; +import { useUptimeSettingsContext } from '../../../contexts/uptime_settings_context'; + +interface Props { + doc?: JourneyStep; + summaryDocs?: Ping[] | JourneyStep[] | null; + journeyStarted?: boolean; + title?: string; + isCompleted: boolean; +} + +export function TestResultHeader({ doc, title, summaryDocs, journeyStarted, isCompleted }: Props) { + const { basePath } = useUptimeSettingsContext(); + let duration = 0; + if (summaryDocs && summaryDocs.length > 0) { + summaryDocs.forEach((sDoc) => { + duration += sDoc.monitor.duration!.us; + }); + } + + return ( + + + +

{title ?? TEST_RESULT}

+
+
+ + {isCompleted ? ( + + + {COMPLETED_LABEL} + + + + {i18n.translate('xpack.uptime.monitorManagement.timeTaken', { + defaultMessage: 'Took {timeTaken}', + values: { timeTaken: formatDuration(duration) }, + })} + + + + ) : ( + + + + {journeyStarted ? IN_PROGRESS : PENDING_LABEL} + + + + + + + )} + + {doc && ( + + + {VIEW_DETAILS} + + + )} +
+ ); +} + +const PENDING_LABEL = i18n.translate('xpack.uptime.monitorManagement.pending', { + defaultMessage: 'PENDING', +}); + +const TEST_RESULT = i18n.translate('xpack.uptime.monitorManagement.testResult', { + defaultMessage: 'Test result', +}); + +const COMPLETED_LABEL = i18n.translate('xpack.uptime.monitorManagement.completed', { + defaultMessage: 'COMPLETED', +}); + +const IN_PROGRESS = i18n.translate('xpack.uptime.monitorManagement.inProgress', { + defaultMessage: 'IN PROGRESS', +}); + +const VIEW_DETAILS = i18n.translate('xpack.uptime.monitorManagement.viewTestRunDetails', { + defaultMessage: 'View test result details', +}); diff --git a/x-pack/plugins/uptime/public/components/monitor_management/test_now_mode/test_run_results.tsx b/x-pack/plugins/uptime/public/components/monitor_management/test_now_mode/test_run_results.tsx new file mode 100644 index 00000000000000..4b261815e99498 --- /dev/null +++ b/x-pack/plugins/uptime/public/components/monitor_management/test_now_mode/test_run_results.tsx @@ -0,0 +1,23 @@ +/* + * 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 * as React from 'react'; +import { SyntheticsMonitor } from '../../../../common/runtime_types'; +import { BrowserTestRunResult } from './browser/browser_test_results'; +import { SimpleTestResults } from './simple/simple_test_results'; + +interface Props { + monitorId: string; + monitor: SyntheticsMonitor; +} +export const TestRunResult = ({ monitorId, monitor }: Props) => { + return monitor.type === 'browser' ? ( + + ) : ( + + ); +}; diff --git a/x-pack/plugins/uptime/public/components/monitor_management/test_now_mode/use_tick_tick.ts b/x-pack/plugins/uptime/public/components/monitor_management/test_now_mode/use_tick_tick.ts new file mode 100644 index 00000000000000..ff9b9f3f6154d0 --- /dev/null +++ b/x-pack/plugins/uptime/public/components/monitor_management/test_now_mode/use_tick_tick.ts @@ -0,0 +1,27 @@ +/* + * 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 { useEffect, useState, useContext } from 'react'; +import { UptimeRefreshContext } from '../../../contexts'; + +export function useTickTick() { + const { refreshApp, lastRefresh } = useContext(UptimeRefreshContext); + + const [tickTick] = useState(() => + setInterval(() => { + refreshApp(); + }, 5 * 1000) + ); + + useEffect(() => { + return () => { + clearInterval(tickTick); + }; + }, [tickTick]); + + return { refreshTimer: tickTick, lastRefresh }; +} diff --git a/x-pack/plugins/uptime/public/components/overview/filter_group/filter_group.tsx b/x-pack/plugins/uptime/public/components/overview/filter_group/filter_group.tsx index 835cbb80601429..06c080cc659fcb 100644 --- a/x-pack/plugins/uptime/public/components/overview/filter_group/filter_group.tsx +++ b/x-pack/plugins/uptime/public/components/overview/filter_group/filter_group.tsx @@ -15,6 +15,7 @@ import { FieldValueSuggestions, useInspectorContext } from '../../../../../obser import { SelectedFilters } from './selected_filters'; import { useIndexPattern } from '../../../contexts/uptime_index_pattern_context'; import { useGetUrlParams } from '../../../hooks'; +import { EXCLUDE_RUN_ONCE_FILTER } from '../../../../common/constants/client_defaults'; const Container = styled(EuiFilterGroup)` margin-bottom: 10px; @@ -67,7 +68,14 @@ export const FilterGroup = () => { asCombobox={false} asFilterButton={true} forceOpen={false} - filters={[]} + filters={[ + { + exists: { + field: 'summary', + }, + }, + EXCLUDE_RUN_ONCE_FILTER, + ]} cardinalityField="monitor.id" time={{ from: dateRangeStart, to: dateRangeEnd }} inspector={{ diff --git a/x-pack/plugins/uptime/public/components/synthetics/check_steps/step_duration.tsx b/x-pack/plugins/uptime/public/components/synthetics/check_steps/step_duration.tsx index 6f995665d7ce53..a9697a8969f656 100644 --- a/x-pack/plugins/uptime/public/components/synthetics/check_steps/step_duration.tsx +++ b/x-pack/plugins/uptime/public/components/synthetics/check_steps/step_duration.tsx @@ -16,6 +16,7 @@ import { StepFieldTrend } from './step_field_trend'; import { microToSec } from '../../../lib/formatting'; interface Props { + compactView?: boolean; step: JourneyStep; durationPopoverOpenIndex: number | null; setDurationPopoverOpenIndex: (val: number | null) => void; @@ -25,6 +26,7 @@ export const StepDuration = ({ step, durationPopoverOpenIndex, setDurationPopoverOpenIndex, + compactView = false, }: Props) => { const component = useMemo( () => ( @@ -44,7 +46,7 @@ export const StepDuration = ({ const button = ( setDurationPopoverOpenIndex(step.synthetics.step?.index ?? null)} - iconType="visArea" + iconType={compactView ? undefined : 'visArea'} > {i18n.translate('xpack.uptime.synthetics.step.duration', { defaultMessage: '{value} seconds', diff --git a/x-pack/plugins/uptime/public/components/synthetics/check_steps/step_image.tsx b/x-pack/plugins/uptime/public/components/synthetics/check_steps/step_image.tsx index e39a83599380b3..d08614fb0b3586 100644 --- a/x-pack/plugins/uptime/public/components/synthetics/check_steps/step_image.tsx +++ b/x-pack/plugins/uptime/public/components/synthetics/check_steps/step_image.tsx @@ -12,9 +12,10 @@ import { PingTimestamp } from '../../monitor/ping_list/columns/ping_timestamp'; interface Props { step: JourneyStep; + compactView?: boolean; } -export const StepImage = ({ step }: Props) => { +export const StepImage = ({ step, compactView }: Props) => { return ( @@ -24,7 +25,7 @@ export const StepImage = ({ step }: Props) => { /> - {step.synthetics?.step?.name} + {step.synthetics?.step?.name} ); diff --git a/x-pack/plugins/uptime/public/components/synthetics/check_steps/steps_list.tsx b/x-pack/plugins/uptime/public/components/synthetics/check_steps/steps_list.tsx index da061215155813..d635d76fc3f894 100644 --- a/x-pack/plugins/uptime/public/components/synthetics/check_steps/steps_list.tsx +++ b/x-pack/plugins/uptime/public/components/synthetics/check_steps/steps_list.tsx @@ -26,6 +26,7 @@ import { VIEW_PERFORMANCE } from '../../monitor/synthetics/translations'; import { StepImage } from './step_image'; import { useExpandedRow } from './use_expanded_row'; import { StepDuration } from './step_duration'; +import { useUptimeSettingsContext } from '../../../contexts/uptime_settings_context'; export const SpanWithMargin = styled.span` margin-right: 16px; @@ -35,6 +36,7 @@ interface Props { data: JourneyStep[]; error?: Error; loading: boolean; + compactView?: boolean; } interface StepStatusCount { @@ -43,7 +45,7 @@ interface StepStatusCount { succeeded: number; } -function isStepEnd(step: JourneyStep) { +export function isStepEnd(step: JourneyStep) { return step.synthetics?.type === 'step/end'; } @@ -83,12 +85,13 @@ function reduceStepStatus(prev: StepStatusCount, cur: JourneyStep): StepStatusCo return prev; } -export const StepsList = ({ data, error, loading }: Props) => { +export const StepsList = ({ data, error, loading, compactView = false }: Props) => { const steps: JourneyStep[] = data.filter(isStepEnd); const { expandedRows, toggleExpand } = useExpandedRow({ steps, allSteps: data, loading }); const [durationPopoverOpenIndex, setDurationPopoverOpenIndex] = useState(null); + const { basePath } = useUptimeSettingsContext(); const columns: Array> = [ { @@ -116,7 +119,7 @@ export const StepsList = ({ data, error, loading }: Props) => { align: 'left', field: 'timestamp', name: STEP_NAME_LABEL, - render: (_timestamp: string, item) => , + render: (_timestamp: string, item) => , mobileOptions: { render: (item: JourneyStep) => ( @@ -137,6 +140,7 @@ export const StepsList = ({ data, error, loading }: Props) => { step={item} durationPopoverOpenIndex={durationPopoverOpenIndex} setDurationPopoverOpenIndex={setDurationPopoverOpenIndex} + compactView={compactView} /> ); }, @@ -151,17 +155,23 @@ export const StepsList = ({ data, error, loading }: Props) => { align: 'left', field: 'timestamp', name: '', - render: (_val: string, item) => ( - - {VIEW_PERFORMANCE} - - ), mobileOptions: { show: false }, + render: (_val: string, item) => + compactView ? ( + + ) : ( + + {VIEW_PERFORMANCE} + + ), }, - { width: '40px', align: RIGHT_ALIGNMENT, @@ -203,15 +213,18 @@ export const StepsList = ({ data, error, loading }: Props) => { return ( <> - -

- {statusMessage( - steps.reduce(reduceStepStatus, { failed: 0, skipped: 0, succeeded: 0 }), - loading - )} -

-
+ {!compactView && ( + +

+ {statusMessage( + steps.reduce(reduceStepStatus, { failed: 0, skipped: 0, succeeded: 0 }), + loading + )} +

+
+ )} = ({ status, stepNo, isMobile }) {!isMobile && ( - + {stepNo}. diff --git a/x-pack/plugins/uptime/public/components/synthetics/step_screenshot_display.tsx b/x-pack/plugins/uptime/public/components/synthetics/step_screenshot_display.tsx index 7fde4033c04093..7dfc86575205b2 100644 --- a/x-pack/plugins/uptime/public/components/synthetics/step_screenshot_display.tsx +++ b/x-pack/plugins/uptime/public/components/synthetics/step_screenshot_display.tsx @@ -22,7 +22,7 @@ import { isScreenshotRef as isAScreenshotRef, ScreenshotRefImageData, } from '../../../common/runtime_types'; -import { UptimeSettingsContext, UptimeThemeContext } from '../../contexts'; +import { UptimeRefreshContext, UptimeSettingsContext, UptimeThemeContext } from '../../contexts'; import { useFetcher } from '../../../../observability/public'; import { getJourneyScreenshot } from '../../state/api/journey'; import { useCompositeImage } from '../../hooks'; @@ -114,6 +114,7 @@ export const StepScreenshotDisplay: FC = ({ rootMargin: '0px', threshold: 1, }); + const { lastRefresh } = useContext(UptimeRefreshContext); const [hasIntersected, setHasIntersected] = useState(false); const isIntersecting = intersection?.isIntersecting; @@ -134,7 +135,7 @@ export const StepScreenshotDisplay: FC = ({ if (isScreenshotRef) { return getJourneyScreenshot(imgSrc); } - }, [basePath, checkGroup, imgSrc, stepIndex, isScreenshotRef]); + }, [basePath, checkGroup, imgSrc, stepIndex, isScreenshotRef, lastRefresh]); const refDimensions = useMemo(() => { if (isAScreenshotRef(screenshotRef)) { diff --git a/x-pack/plugins/uptime/public/lib/helper/rtl_helpers.tsx b/x-pack/plugins/uptime/public/lib/helper/rtl_helpers.tsx index 9374012d094ab7..b0c8f61477d286 100644 --- a/x-pack/plugins/uptime/public/lib/helper/rtl_helpers.tsx +++ b/x-pack/plugins/uptime/public/lib/helper/rtl_helpers.tsx @@ -37,6 +37,7 @@ import { ClientPluginsStart } from '../../apps/plugin'; import { triggersActionsUiMock } from '../../../../triggers_actions_ui/public/mocks'; import { dataPluginMock } from '../../../../../../src/plugins/data/public/mocks'; import { UptimeRefreshContextProvider, UptimeStartupPluginsContextProvider } from '../../contexts'; +import { kibanaService } from '../../state/kibana_service'; type DeepPartial = { [P in keyof T]?: DeepPartial; @@ -149,6 +150,8 @@ export function MockKibanaProvider({ }: MockKibanaProviderProps) { const coreOptions = merge({}, mockCore(), core); + kibanaService.core = coreOptions as any; + return ( @@ -208,6 +211,27 @@ export const MockRedux = ({ ); }; +export function WrappedHelper({ + children, + core, + kibanaProps, + state, + url, + useRealStore, + path, + history = createMemoryHistory(), +}: RenderRouterOptions & { children: ReactElement; useRealStore?: boolean }) { + const testState: AppState = merge({}, mockState, state); + + return ( + + + {children} + + + ); +} + /* Custom react testing library render */ export function render( ui: ReactElement, @@ -222,19 +246,23 @@ export function render( useRealStore, }: RenderRouterOptions & { useRealStore?: boolean } = {} ) { - const testState: AppState = merge({}, mockState, state); - if (url) { history = getHistoryFromUrl(url); } return { ...reactTestLibRender( - - - {ui} - - , + + {ui} + , renderOptions ), history, diff --git a/x-pack/plugins/uptime/public/pages/monitor_management/monitor_management.tsx b/x-pack/plugins/uptime/public/pages/monitor_management/monitor_management.tsx index cb43dc9c90d7d0..aa4a9ca995b1b4 100644 --- a/x-pack/plugins/uptime/public/pages/monitor_management/monitor_management.tsx +++ b/x-pack/plugins/uptime/public/pages/monitor_management/monitor_management.tsx @@ -26,7 +26,7 @@ export const MonitorManagementPage: React.FC = () => { useEffect(() => { if (refresh) { dispatch(getMonitors({ page: pageIndex, perPage: pageSize })); - setRefresh(false); // TODO: avoid extra re-rendering when `refresh` turn to false (pass down the handler instead) + setRefresh(false); } }, [dispatch, refresh, pageIndex, pageSize]); diff --git a/x-pack/plugins/uptime/public/routes.tsx b/x-pack/plugins/uptime/public/routes.tsx index bcb942250c6f13..aa7bf22593abe6 100644 --- a/x-pack/plugins/uptime/public/routes.tsx +++ b/x-pack/plugins/uptime/public/routes.tsx @@ -206,6 +206,7 @@ const getRoutes = (config: UptimeConfig): RouteProps[] => { ), }, bottomBar: , + bottomBarProps: { paddingSize: 'm' as const }, }, { title: i18n.translate('xpack.uptime.editMonitorRoute.title', { @@ -225,6 +226,7 @@ const getRoutes = (config: UptimeConfig): RouteProps[] => { ), }, bottomBar: , + bottomBarProps: { paddingSize: 'm' as const }, }, { title: i18n.translate('xpack.uptime.monitorManagementRoute.title', { diff --git a/x-pack/plugins/uptime/public/state/api/monitor_management.ts b/x-pack/plugins/uptime/public/state/api/monitor_management.ts index 5f18869257386c..ee2e376990d2d4 100644 --- a/x-pack/plugins/uptime/public/state/api/monitor_management.ts +++ b/x-pack/plugins/uptime/public/state/api/monitor_management.ts @@ -17,6 +17,7 @@ import { import { SyntheticsMonitorSavedObject } from '../../../common/types'; import { apiService } from './utils'; +// TODO: Type the return type from runtime types export const setMonitor = async ({ monitor, id, @@ -31,6 +32,7 @@ export const setMonitor = async ({ } }; +// TODO, change to monitor runtime type export const getMonitor = async ({ id }: { id: string }): Promise => { return await apiService.get(`${API_URLS.SYNTHETICS_MONITORS}/${id}`); }; @@ -57,3 +59,13 @@ export const fetchServiceLocations = async (): Promise => { ); return locations; }; + +export const runOnceMonitor = async ({ + monitor, + id, +}: { + monitor: SyntheticsMonitor; + id: string; +}): Promise<{ errors: Array<{ error: Error }> }> => { + return await apiService.post(API_URLS.RUN_ONCE_MONITOR + `/${id}`, monitor); +}; diff --git a/x-pack/plugins/uptime/server/lib/requests/get_ping_histogram.ts b/x-pack/plugins/uptime/server/lib/requests/get_ping_histogram.ts index a8d722b4e059d7..8fedd926b8371b 100644 --- a/x-pack/plugins/uptime/server/lib/requests/get_ping_histogram.ts +++ b/x-pack/plugins/uptime/server/lib/requests/get_ping_histogram.ts @@ -11,6 +11,7 @@ import { QUERY } from '../../../common/constants'; import { UMElasticsearchQueryFn } from '../adapters/framework'; import { createEsQuery } from '../../../common/utils/es_search'; import { getHistogramInterval } from '../../../common/lib/get_histogram_interval'; +import { EXCLUDE_RUN_ONCE_FILTER } from '../../../common/constants/client_defaults'; export const getPingHistogram: UMElasticsearchQueryFn< GetPingHistogramParams, @@ -47,6 +48,7 @@ export const getPingHistogram: UMElasticsearchQueryFn< field: 'summary', }, }, + EXCLUDE_RUN_ONCE_FILTER, ], ...(query ? { diff --git a/x-pack/plugins/uptime/server/lib/requests/get_snapshot_counts.ts b/x-pack/plugins/uptime/server/lib/requests/get_snapshot_counts.ts index ee4e3eb96eb5af..2a43d539125bef 100644 --- a/x-pack/plugins/uptime/server/lib/requests/get_snapshot_counts.ts +++ b/x-pack/plugins/uptime/server/lib/requests/get_snapshot_counts.ts @@ -10,6 +10,7 @@ import { CONTEXT_DEFAULTS } from '../../../common/constants'; import { Snapshot } from '../../../common/runtime_types'; import { QueryContext } from './search'; import { ESFilter } from '../../../../../../src/core/types/elasticsearch'; +import { EXCLUDE_RUN_ONCE_FILTER } from '../../../common/constants/client_defaults'; export interface GetSnapshotCountParams { dateRangeStart: string; @@ -84,7 +85,7 @@ const statusCountBody = (filters: ESFilter[], context: QueryContext) => { field: 'summary', }, }, - + EXCLUDE_RUN_ONCE_FILTER, ...filters, ], }, diff --git a/x-pack/plugins/uptime/server/lib/requests/search/find_potential_matches.ts b/x-pack/plugins/uptime/server/lib/requests/search/find_potential_matches.ts index d0d8e61d02181a..1963afaf89a34c 100644 --- a/x-pack/plugins/uptime/server/lib/requests/search/find_potential_matches.ts +++ b/x-pack/plugins/uptime/server/lib/requests/search/find_potential_matches.ts @@ -7,6 +7,7 @@ import { set } from '@elastic/safer-lodash-set'; import { QueryContext } from './query_context'; +import { EXCLUDE_RUN_ONCE_FILTER } from '../../../../common/constants/client_defaults'; /** * This is the first phase of the query. In it, we find all monitor IDs that have ever matched the given filters. @@ -51,6 +52,8 @@ const queryBody = async (queryContext: QueryContext, searchAfter: any, size: num filters.push({ match: { 'monitor.status': queryContext.statusFilter } }); } + filters.push(EXCLUDE_RUN_ONCE_FILTER); + const body = { size: 0, query: { diff --git a/x-pack/plugins/uptime/server/lib/synthetics_service/formatters/browser.ts b/x-pack/plugins/uptime/server/lib/synthetics_service/formatters/browser.ts index c72f3598533b04..7eb89f17b44ada 100644 --- a/x-pack/plugins/uptime/server/lib/synthetics_service/formatters/browser.ts +++ b/x-pack/plugins/uptime/server/lib/synthetics_service/formatters/browser.ts @@ -22,7 +22,7 @@ export const browserFormatters: BrowserFormatMap = { [ConfigKey.SOURCE_INLINE]: null, [ConfigKey.PARAMS]: null, [ConfigKey.SCREENSHOTS]: null, - [ConfigKey.SYNTHETICS_ARGS]: (fields) => null, + [ConfigKey.SYNTHETICS_ARGS]: (fields) => arrayFormatter(fields[ConfigKey.SYNTHETICS_ARGS]), [ConfigKey.ZIP_URL_TLS_CERTIFICATE_AUTHORITIES]: null, [ConfigKey.ZIP_URL_TLS_CERTIFICATE]: null, [ConfigKey.ZIP_URL_TLS_KEY]: null, diff --git a/x-pack/plugins/uptime/server/lib/synthetics_service/formatters/convert_to_data_stream.ts b/x-pack/plugins/uptime/server/lib/synthetics_service/formatters/convert_to_data_stream.ts index bcddd6fffba95a..a7597c7c3ef341 100644 --- a/x-pack/plugins/uptime/server/lib/synthetics_service/formatters/convert_to_data_stream.ts +++ b/x-pack/plugins/uptime/server/lib/synthetics_service/formatters/convert_to_data_stream.ts @@ -31,7 +31,7 @@ export function convertToDataStreamFormat(monitor: Record): DataStr id: monitor.id, // Schedule is needed by service at root level as well schedule: monitor.schedule, - enabled: monitor.enabled, + enabled: monitor.enabled ?? true, data_stream: { namespace: monitor.namespace ?? 'default', }, diff --git a/x-pack/plugins/uptime/server/lib/synthetics_service/formatters/format_configs.test.ts b/x-pack/plugins/uptime/server/lib/synthetics_service/formatters/format_configs.test.ts index afb12ae5059578..815a02b9d4b3aa 100644 --- a/x-pack/plugins/uptime/server/lib/synthetics_service/formatters/format_configs.test.ts +++ b/x-pack/plugins/uptime/server/lib/synthetics_service/formatters/format_configs.test.ts @@ -95,7 +95,7 @@ describe('formatMonitorConfig', () => { "step('Go to https://www.google.com/', async () => {\n await page.goto('https://www.google.com/');\n});", params: '', screenshots: 'on', - synthetics_args: [], + synthetics_args: ['--hasTouch true'], 'filter_journeys.match': '', 'filter_journeys.tags': ['dev'], ignore_https_errors: false, @@ -119,6 +119,7 @@ describe('formatMonitorConfig', () => { throttling: '5d/3u/20l', timeout: '16s', type: 'browser', + synthetics_args: ['--hasTouch true'], }; }); diff --git a/x-pack/plugins/uptime/server/lib/synthetics_service/service_api_client.ts b/x-pack/plugins/uptime/server/lib/synthetics_service/service_api_client.ts index 1c55b8812d64fd..40759e64eb6bab 100644 --- a/x-pack/plugins/uptime/server/lib/synthetics_service/service_api_client.ts +++ b/x-pack/plugins/uptime/server/lib/synthetics_service/service_api_client.ts @@ -24,6 +24,7 @@ export interface ServiceData { hosts: string[]; api_key: string; }; + runOnce?: boolean; } export class ServiceAPIClient { @@ -79,7 +80,14 @@ export class ServiceAPIClient { return this.callAPI('DELETE', data); } - async callAPI(method: 'POST' | 'PUT' | 'DELETE', { monitors: allMonitors, output }: ServiceData) { + async runOnce(data: ServiceData) { + return this.callAPI('POST', { ...data, runOnce: true }); + } + + async callAPI( + method: 'POST' | 'PUT' | 'DELETE', + { monitors: allMonitors, output, runOnce }: ServiceData + ) { if (this.username === TEST_SERVICE_USERNAME) { // we don't want to call service while local integration tests are running return; @@ -93,7 +101,7 @@ export class ServiceAPIClient { return axios({ method, - url: (this.devUrl ?? url) + '/monitors', + url: (this.devUrl ?? url) + (runOnce ? '/run' : '/monitors'), data: { monitors: monitorsStreams, output }, headers: this.authorization ? { diff --git a/x-pack/plugins/uptime/server/lib/synthetics_service/synthetics_service.ts b/x-pack/plugins/uptime/server/lib/synthetics_service/synthetics_service.ts index d6fe86453a1c00..43adfabddad989 100644 --- a/x-pack/plugins/uptime/server/lib/synthetics_service/synthetics_service.ts +++ b/x-pack/plugins/uptime/server/lib/synthetics_service/synthetics_service.ts @@ -189,6 +189,32 @@ export class SyntheticsService { } } + async runOnceConfigs( + request?: KibanaRequest, + configs?: Array< + SyntheticsMonitorWithId & { + fields_under_root?: boolean; + fields?: { run_once: boolean; config_id: string }; + } + > + ) { + const monitors = this.formatConfigs(configs || (await this.getMonitorConfigs())); + if (monitors.length === 0) { + return; + } + const data = { + monitors, + output: await this.getOutput(request), + }; + + try { + return await this.apiClient.runOnce(data); + } catch (e) { + this.logger.error(e); + throw e; + } + } + async deleteConfigs(request: KibanaRequest, configs: SyntheticsMonitorWithId[]) { const data = { monitors: this.formatConfigs(configs), @@ -211,6 +237,8 @@ export class SyntheticsService { return (findResult.saved_objects ?? []).map(({ attributes, id }) => ({ ...attributes, id, + fields_under_root: true, + fields: { config_id: id }, })) as SyntheticsMonitorWithId[]; } diff --git a/x-pack/plugins/uptime/server/rest_api/index.ts b/x-pack/plugins/uptime/server/rest_api/index.ts index 905af60961d9a1..383d999f29cc68 100644 --- a/x-pack/plugins/uptime/server/rest_api/index.ts +++ b/x-pack/plugins/uptime/server/rest_api/index.ts @@ -36,6 +36,7 @@ import { import { addSyntheticsMonitorRoute } from './synthetics_service/add_monitor'; import { editSyntheticsMonitorRoute } from './synthetics_service/edit_monitor'; import { deleteSyntheticsMonitorRoute } from './synthetics_service/delete_monitor'; +import { runOnceSyntheticsMonitorRoute } from './synthetics_service/run_once_monitor'; export * from './types'; export { createRouteWithAuth } from './create_route_with_auth'; @@ -67,4 +68,5 @@ export const restApiRoutes: UMRestApiRouteFactory[] = [ addSyntheticsMonitorRoute, editSyntheticsMonitorRoute, deleteSyntheticsMonitorRoute, + runOnceSyntheticsMonitorRoute, ]; diff --git a/x-pack/plugins/uptime/server/rest_api/synthetics_service/add_monitor.ts b/x-pack/plugins/uptime/server/rest_api/synthetics_service/add_monitor.ts index 319d68d1b6e8b2..1750466b6c3e68 100644 --- a/x-pack/plugins/uptime/server/rest_api/synthetics_service/add_monitor.ts +++ b/x-pack/plugins/uptime/server/rest_api/synthetics_service/add_monitor.ts @@ -35,7 +35,10 @@ export const addSyntheticsMonitorRoute: UMRestApiRouteFactory = () => ({ const { syntheticsService } = server; const errors = await syntheticsService.pushConfigs(request, [ - { ...newMonitor.attributes, id: newMonitor.id }, + { + ...newMonitor.attributes, + id: newMonitor.id, + }, ]); if (errors) { diff --git a/x-pack/plugins/uptime/server/rest_api/synthetics_service/run_once_monitor.ts b/x-pack/plugins/uptime/server/rest_api/synthetics_service/run_once_monitor.ts new file mode 100644 index 00000000000000..409990a12fcf03 --- /dev/null +++ b/x-pack/plugins/uptime/server/rest_api/synthetics_service/run_once_monitor.ts @@ -0,0 +1,50 @@ +/* + * 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 { schema } from '@kbn/config-schema'; +import { MonitorFields } from '../../../common/runtime_types'; +import { UMRestApiRouteFactory } from '../types'; +import { API_URLS } from '../../../common/constants'; +import { validateMonitor } from './monitor_validation'; + +export const runOnceSyntheticsMonitorRoute: UMRestApiRouteFactory = () => ({ + method: 'POST', + path: API_URLS.RUN_ONCE_MONITOR + '/{monitorId}', + validate: { + body: schema.any(), + params: schema.object({ + monitorId: schema.string({ minLength: 1, maxLength: 1024 }), + }), + }, + handler: async ({ request, response, server }): Promise => { + const monitor = request.body as MonitorFields; + const { monitorId } = request.params; + + const validationResult = validateMonitor(monitor); + + if (!validationResult.valid) { + const { reason: message, details, payload } = validationResult; + return response.badRequest({ body: { message, attributes: { details, ...payload } } }); + } + + const { syntheticsService } = server; + + const errors = await syntheticsService.runOnceConfigs(request, [ + { + ...monitor, + id: monitorId, + fields_under_root: true, + fields: { run_once: true, config_id: monitorId }, + }, + ]); + + if (errors) { + return { errors }; + } + + return monitor; + }, +}); From 4282355fb6fdaccfdc3e593993617c8e7a24cb0c Mon Sep 17 00:00:00 2001 From: Angela Chuang <6295984+angorayc@users.noreply.github.com> Date: Thu, 20 Jan 2022 11:05:19 +0000 Subject: [PATCH 071/108] Update indexNames for general threat match timeline (#123358) Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../detection_engine/rules/prepackaged_timelines/README.md | 4 +++- .../detection_engine/rules/prepackaged_timelines/index.ndjson | 2 +- .../detection_engine/rules/prepackaged_timelines/threat.json | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_timelines/README.md b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_timelines/README.md index e0ada4aad08173..635839577fb2d7 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_timelines/README.md +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_timelines/README.md @@ -40,12 +40,14 @@ - templateTimelineId: Specify an unique uuid e.g.: `2c7e0663-5a91-0004-aa15-26bf756d2c40` - - templateTimelineVersion: just start from `1` + - templateTimelineVersion: start from `1`, bump it on update - timelineType: `template` - status: `immutable` + - indexNames: [] + 3. ```cd x-pack/plugins/security_solution/server/lib/detection_engine/scripts``` diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_timelines/index.ndjson b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_timelines/index.ndjson index 549f6733b0208e..84972a837a3e82 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_timelines/index.ndjson +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_timelines/index.ndjson @@ -11,4 +11,4 @@ {"savedObjectId":null,"version":null,"columns":[{"indexes":null,"name":null,"columnHeaderType":"not-filtered","id":"@timestamp","searchable":null},{"indexes":null,"name":null,"columnHeaderType":"not-filtered","id":"kibana.alert.rule.description","searchable":null},{"indexes":null,"name":null,"columnHeaderType":"not-filtered","id":"event.action","searchable":null},{"indexes":null,"name":null,"columnHeaderType":"not-filtered","id":"process.name","searchable":null},{"indexes":null,"aggregatable":true,"name":null,"description":"The working directory of the process.","columnHeaderType":"not-filtered","id":"process.working_directory","category":"process","type":"string","searchable":null,"example":"/home/alice"},{"indexes":null,"aggregatable":true,"name":null,"description":"Array of process arguments, starting with the absolute path to\nthe executable.\n\nMay be filtered to protect sensitive information.","columnHeaderType":"not-filtered","id":"process.args","category":"process","type":"string","searchable":null,"example":"[\"/usr/bin/ssh\",\"-l\",\"user\",\"10.0.0.16\"]"},{"indexes":null,"name":null,"columnHeaderType":"not-filtered","id":"process.pid","searchable":null},{"indexes":null,"aggregatable":true,"name":null,"description":"Absolute path to the process executable.","columnHeaderType":"not-filtered","id":"process.parent.executable","category":"process","type":"string","searchable":null,"example":"/usr/bin/ssh"},{"indexes":null,"aggregatable":true,"name":null,"description":"Array of process arguments.\n\nMay be filtered to protect sensitive information.","columnHeaderType":"not-filtered","id":"process.parent.args","category":"process","type":"string","searchable":null,"example":"[\"ssh\",\"-l\",\"user\",\"10.0.0.16\"]"},{"indexes":null,"aggregatable":true,"name":null,"description":"Process id.","columnHeaderType":"not-filtered","id":"process.parent.pid","category":"process","type":"number","searchable":null,"example":"4242"},{"indexes":null,"aggregatable":true,"name":null,"description":"Short name or login of the user.","columnHeaderType":"not-filtered","id":"user.name","category":"user","type":"string","searchable":null,"example":"albert"},{"indexes":null,"aggregatable":true,"name":null,"description":"Name of the host.\n\nIt can contain what `hostname` returns on Unix systems, the fully qualified\ndomain name, or a name specified by the user. The sender decides which value\nto use.","columnHeaderType":"not-filtered","id":"host.name","category":"host","type":"string","searchable":null}],"dataProviders":[{"excluded":false,"and":[],"kqlQuery":"","name":"","queryMatch":{"displayValue":"endpoint","field":"agent.type","displayField":"agent.type","value":"endpoint","operator":":"},"id":"timeline-1-4685da24-35c1-43f3-892d-1f926dbf5568","type":"default","enabled":true}],"description":"","eventType":"all","filters":[],"kqlMode":"filter","kqlQuery":{"filterQuery":{"kuery":{"kind":"kuery","expression":""},"serializedQuery":""}},"title":"Generic Endpoint Timeline","timelineType":"template","templateTimelineVersion":2,"templateTimelineId":"db366523-f1c6-4c1f-8731-6ce5ed9e5717","dateRange":{"start":1588161020848,"end":1588162280848},"savedQueryId":null,"sort":{"columnId":"@timestamp","sortDirection":"desc"},"created":1594735857110,"createdBy":"Elastic","updated":1611609999115,"updatedBy":"Elastic","eventNotes":[],"globalNotes":[],"pinnedEventIds":[],"status":"immutable"} {"savedObjectId":null,"version":null,"columns":[{"indexes":null,"name":null,"columnHeaderType":"not-filtered","id":"@timestamp","searchable":null},{"indexes":null,"name":null,"columnHeaderType":"not-filtered","id":"kibana.alert.rule.description","searchable":null},{"indexes":null,"aggregatable":true,"name":null,"description":"The action captured by the event.\n\nThis describes the information in the event. It is more specific than `event.category`.\nExamples are `group-add`, `process-started`, `file-created`. The value is\nnormally defined by the implementer.","columnHeaderType":"not-filtered","id":"event.action","category":"event","type":"string","searchable":null,"example":"user-password-change"},{"indexes":null,"aggregatable":true,"name":null,"description":"Array of process arguments, starting with the absolute path to\nthe executable.\n\nMay be filtered to protect sensitive information.","columnHeaderType":"not-filtered","id":"process.args","category":"process","type":"string","searchable":null,"example":"[\"/usr/bin/ssh\",\"-l\",\"user\",\"10.0.0.16\"]"},{"indexes":null,"name":null,"columnHeaderType":"not-filtered","id":"process.pid","searchable":null},{"indexes":null,"aggregatable":true,"name":null,"description":"IP address of the source (IPv4 or IPv6).","columnHeaderType":"not-filtered","id":"source.ip","category":"source","type":"ip","searchable":null},{"indexes":null,"aggregatable":true,"name":null,"description":"Port of the source.","columnHeaderType":"not-filtered","id":"source.port","category":"source","type":"number","searchable":null},{"indexes":null,"aggregatable":true,"name":null,"description":"IP address of the destination (IPv4 or IPv6).","columnHeaderType":"not-filtered","id":"destination.ip","category":"destination","type":"ip","searchable":null},{"indexes":null,"name":null,"columnHeaderType":"not-filtered","id":"destination.port","searchable":null},{"indexes":null,"aggregatable":true,"name":null,"description":"Short name or login of the user.","columnHeaderType":"not-filtered","id":"user.name","category":"user","type":"string","searchable":null,"example":"albert"},{"indexes":null,"name":null,"columnHeaderType":"not-filtered","id":"host.name","searchable":null}],"dataProviders":[{"and":[{"enabled":true,"excluded":false,"id":"timeline-1-e37e37c5-a6e7-4338-af30-47bfbc3c0e1e","kqlQuery":"","name":"{destination.ip}","queryMatch":{"displayField":"destination.ip","displayValue":"{destination.ip}","field":"destination.ip","operator":":","value":"{destination.ip}"},"type":"template"}],"enabled":true,"excluded":false,"id":"timeline-1-ec778f01-1802-40f0-9dfb-ed8de1f656cb","kqlQuery":"","name":"{source.ip}","queryMatch":{"displayField":"source.ip","displayValue":"{source.ip}","field":"source.ip","operator":":","value":"{source.ip}"},"type":"template"}],"description":"","eventType":"all","filters":[],"kqlMode":"filter","kqlQuery":{"filterQuery":{"kuery":{"kind":"kuery","expression":""},"serializedQuery":""}},"title":"Generic Network Timeline","timelineType":"template","templateTimelineVersion":2,"templateTimelineId":"91832785-286d-4ebe-b884-1a208d111a70","dateRange":{"start":1588255858373,"end":1588256218373},"savedQueryId":null,"sort":{"columnId":"@timestamp","sortDirection":"desc"},"created":1594735573866,"createdBy":"Elastic","updated":1611609960850,"updatedBy":"Elastic","eventNotes":[],"globalNotes":[],"pinnedEventIds":[],"status":"immutable"} {"savedObjectId":null,"version":null,"columns":[{"indexes":null,"name":null,"columnHeaderType":"not-filtered","id":"@timestamp","searchable":null},{"indexes":null,"name":null,"columnHeaderType":"not-filtered","id":"kibana.alert.rule.description","searchable":null},{"indexes":null,"name":null,"columnHeaderType":"not-filtered","id":"event.action","searchable":null},{"indexes":null,"name":null,"columnHeaderType":"not-filtered","id":"process.name","searchable":null},{"indexes":null,"aggregatable":true,"name":null,"description":"The working directory of the process.","columnHeaderType":"not-filtered","id":"process.working_directory","category":"process","type":"string","searchable":null,"example":"/home/alice"},{"indexes":null,"aggregatable":true,"name":null,"description":"Array of process arguments, starting with the absolute path to\nthe executable.\n\nMay be filtered to protect sensitive information.","columnHeaderType":"not-filtered","id":"process.args","category":"process","type":"string","searchable":null,"example":"[\"/usr/bin/ssh\",\"-l\",\"user\",\"10.0.0.16\"]"},{"indexes":null,"name":null,"columnHeaderType":"not-filtered","id":"process.pid","searchable":null},{"indexes":null,"aggregatable":true,"name":null,"description":"Absolute path to the process executable.","columnHeaderType":"not-filtered","id":"process.parent.executable","category":"process","type":"string","searchable":null,"example":"/usr/bin/ssh"},{"indexes":null,"aggregatable":true,"name":null,"description":"Array of process arguments.\n\nMay be filtered to protect sensitive information.","columnHeaderType":"not-filtered","id":"process.parent.args","category":"process","type":"string","searchable":null,"example":"[\"ssh\",\"-l\",\"user\",\"10.0.0.16\"]"},{"indexes":null,"aggregatable":true,"name":null,"description":"Process id.","columnHeaderType":"not-filtered","id":"process.parent.pid","category":"process","type":"number","searchable":null,"example":"4242"},{"indexes":null,"aggregatable":true,"name":null,"description":"Short name or login of the user.","columnHeaderType":"not-filtered","id":"user.name","category":"user","type":"string","searchable":null,"example":"albert"},{"indexes":null,"aggregatable":true,"name":null,"description":"Name of the host.\n\nIt can contain what `hostname` returns on Unix systems, the fully qualified\ndomain name, or a name specified by the user. The sender decides which value\nto use.","columnHeaderType":"not-filtered","id":"host.name","category":"host","type":"string","searchable":null}],"dataProviders":[{"excluded":false,"and":[],"kqlQuery":"","name":"{process.name}","queryMatch":{"displayValue":null,"field":"process.name","displayField":null,"value":"{process.name}","operator":":"},"id":"timeline-1-8622010a-61fb-490d-b162-beac9c36a853","type":"template","enabled":true}],"description":"","eventType":"all","filters":[],"kqlMode":"filter","kqlQuery":{"filterQuery":{"kuery":{"kind":"kuery","expression":""},"serializedQuery":""}},"title":"Generic Process Timeline","timelineType":"template","templateTimelineVersion":2,"templateTimelineId":"76e52245-7519-4251-91ab-262fb1a1728c","dateRange":{"start":1588161020848,"end":1588162280848},"savedQueryId":null,"sort":{"columnId":"@timestamp","sortDirection":"desc"},"created":1594735629389,"createdBy":"Elastic","updated":1611609848602,"updatedBy":"Elastic","eventNotes":[],"globalNotes":[],"pinnedEventIds":[],"status":"immutable"} -{"savedObjectId":null,"version":null,"columns":[{"columnHeaderType":"not-filtered","id":"@timestamp"},{"columnHeaderType":"not-filtered","id":"kibana.alert.rule.description"},{"aggregatable":true,"description":"The action captured by the event.\n\nThis describes the information in the event. It is more specific than `event.category`.\nExamples are `group-add`, `process-started`, `file-created`. The value is\nnormally defined by the implementer.","columnHeaderType":"not-filtered","id":"event.action","category":"event","type":"string","example":"user-password-change"},{"aggregatable":true,"description":"Array of process arguments, starting with the absolute path to\nthe executable.\n\nMay be filtered to protect sensitive information.","columnHeaderType":"not-filtered","id":"process.args","category":"process","type":"string","example":"[\"/usr/bin/ssh\",\"-l\",\"user\",\"10.0.0.16\"]"},{"columnHeaderType":"not-filtered","id":"process.pid"},{"aggregatable":true,"description":"IP address of the source (IPv4 or IPv6).","columnHeaderType":"not-filtered","id":"source.ip","category":"source","type":"ip"},{"aggregatable":true,"description":"Port of the source.","columnHeaderType":"not-filtered","id":"source.port","category":"source","type":"number"},{"aggregatable":true,"description":"IP address of the destination (IPv4 or IPv6).","columnHeaderType":"not-filtered","id":"destination.ip","category":"destination","type":"ip"},{"columnHeaderType":"not-filtered","id":"destination.port"},{"aggregatable":true,"description":"Short name or login of the user.","columnHeaderType":"not-filtered","id":"user.name","category":"user","type":"string","example":"albert"},{"columnHeaderType":"not-filtered","id":"host.name"}],"dataProviders":[{"excluded":false,"and":[{"excluded":false,"kqlQuery":"","name":"{threat.enrichments.matched.type}","queryMatch":{"displayValue":null,"field":"threat.enrichments.matched.type","displayField":null,"value":"{threat.enrichments.matched.type}","operator":":"},"id":"timeline-1-ae18ef4b-f690-4122-a24d-e13b6818fba8","type":"template","enabled":true},{"excluded":false,"kqlQuery":"","name":"{threat.enrichments.matched.field}","queryMatch":{"displayValue":null,"field":"threat.enrichments.matched.field","displayField":null,"value":"{threat.enrichments.matched.field}","operator":":"},"id":"timeline-1-7b4cf27e-6788-4d8e-9188-7687f0eba0f2","type":"template","enabled":true}],"kqlQuery":"","name":"{threat.enrichments.matched.atomic}","queryMatch":{"displayValue":null,"field":"threat.enrichments.matched.atomic","displayField":null,"value":"{threat.enrichments.matched.atomic}","operator":":"},"id":"timeline-1-7db7d278-a80a-4853-971a-904319c50777","type":"template","enabled":true}],"description":"This Timeline template is for alerts generated by Indicator Match detection rules.","eqlOptions":{"eventCategoryField":"event.category","tiebreakerField":"","timestampField":"@timestamp","query":"","size":100},"eventType":"alert","filters":[],"kqlMode":"filter","kqlQuery":{"filterQuery":{"kuery":{"kind":"kuery","expression":""},"serializedQuery":""}},"dataViewId": "security-solution","indexNames":[".siem-signals-default"],"title":"Generic Threat Match Timeline","timelineType":"template","templateTimelineVersion":2,"templateTimelineId":"495ad7a7-316e-4544-8a0f-9c098daee76e","dateRange":{"start":1588161020848,"end":1588162280848},"savedQueryId":null,"sort":[{"sortDirection":"desc","columnId":"@timestamp"}],"created":1616696609311,"createdBy":"elastic","updated":1616788372794,"updatedBy":"elastic","eventNotes":[],"globalNotes":[],"pinnedEventIds":[],"status":"immutable"} +{"savedObjectId":null,"version":null,"columns":[{"columnHeaderType":"not-filtered","id":"@timestamp"},{"columnHeaderType":"not-filtered","id":"kibana.alert.rule.description"},{"aggregatable":true,"description":"The action captured by the event.\n\nThis describes the information in the event. It is more specific than `event.category`.\nExamples are `group-add`, `process-started`, `file-created`. The value is\nnormally defined by the implementer.","columnHeaderType":"not-filtered","id":"event.action","category":"event","type":"string","example":"user-password-change"},{"aggregatable":true,"description":"Array of process arguments, starting with the absolute path to\nthe executable.\n\nMay be filtered to protect sensitive information.","columnHeaderType":"not-filtered","id":"process.args","category":"process","type":"string","example":"[\"/usr/bin/ssh\",\"-l\",\"user\",\"10.0.0.16\"]"},{"columnHeaderType":"not-filtered","id":"process.pid"},{"aggregatable":true,"description":"IP address of the source (IPv4 or IPv6).","columnHeaderType":"not-filtered","id":"source.ip","category":"source","type":"ip"},{"aggregatable":true,"description":"Port of the source.","columnHeaderType":"not-filtered","id":"source.port","category":"source","type":"number"},{"aggregatable":true,"description":"IP address of the destination (IPv4 or IPv6).","columnHeaderType":"not-filtered","id":"destination.ip","category":"destination","type":"ip"},{"columnHeaderType":"not-filtered","id":"destination.port"},{"aggregatable":true,"description":"Short name or login of the user.","columnHeaderType":"not-filtered","id":"user.name","category":"user","type":"string","example":"albert"},{"columnHeaderType":"not-filtered","id":"host.name"}],"dataProviders":[{"excluded":false,"and":[{"excluded":false,"kqlQuery":"","name":"{threat.enrichments.matched.type}","queryMatch":{"displayValue":null,"field":"threat.enrichments.matched.type","displayField":null,"value":"{threat.enrichments.matched.type}","operator":":"},"id":"timeline-1-ae18ef4b-f690-4122-a24d-e13b6818fba8","type":"template","enabled":true},{"excluded":false,"kqlQuery":"","name":"{threat.enrichments.matched.field}","queryMatch":{"displayValue":null,"field":"threat.enrichments.matched.field","displayField":null,"value":"{threat.enrichments.matched.field}","operator":":"},"id":"timeline-1-7b4cf27e-6788-4d8e-9188-7687f0eba0f2","type":"template","enabled":true}],"kqlQuery":"","name":"{threat.enrichments.matched.atomic}","queryMatch":{"displayValue":null,"field":"threat.enrichments.matched.atomic","displayField":null,"value":"{threat.enrichments.matched.atomic}","operator":":"},"id":"timeline-1-7db7d278-a80a-4853-971a-904319c50777","type":"template","enabled":true}],"description":"This Timeline template is for alerts generated by Indicator Match detection rules.","eqlOptions":{"eventCategoryField":"event.category","tiebreakerField":"","timestampField":"@timestamp","query":"","size":100},"eventType":"alert","filters":[],"kqlMode":"filter","kqlQuery":{"filterQuery":{"kuery":{"kind":"kuery","expression":""},"serializedQuery":""}},"dataViewId": "security-solution","indexNames":[],"title":"Generic Threat Match Timeline","timelineType":"template","templateTimelineVersion":3,"templateTimelineId":"495ad7a7-316e-4544-8a0f-9c098daee76e","dateRange":{"start":1588161020848,"end":1588162280848},"savedQueryId":null,"sort":[{"sortDirection":"desc","columnId":"@timestamp"}],"created":1616696609311,"createdBy":"elastic","updated":1616788372794,"updatedBy":"elastic","eventNotes":[],"globalNotes":[],"pinnedEventIds":[],"status":"immutable"} diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_timelines/threat.json b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_timelines/threat.json index 588ead3db2c44b..64ebd134b6805e 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_timelines/threat.json +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_timelines/threat.json @@ -1 +1 @@ -{"savedObjectId":null,"version":null,"columns":[{"columnHeaderType":"not-filtered","id":"@timestamp"},{"columnHeaderType":"not-filtered","id":"kibana.alert.rule.description"},{"aggregatable":true,"description":"The action captured by the event.\n\nThis describes the information in the event. It is more specific than `event.category`.\nExamples are `group-add`, `process-started`, `file-created`. The value is\nnormally defined by the implementer.","columnHeaderType":"not-filtered","id":"event.action","category":"event","type":"string","example":"user-password-change"},{"aggregatable":true,"description":"Array of process arguments, starting with the absolute path to\nthe executable.\n\nMay be filtered to protect sensitive information.","columnHeaderType":"not-filtered","id":"process.args","category":"process","type":"string","example":"[\"/usr/bin/ssh\",\"-l\",\"user\",\"10.0.0.16\"]"},{"columnHeaderType":"not-filtered","id":"process.pid"},{"aggregatable":true,"description":"IP address of the source (IPv4 or IPv6).","columnHeaderType":"not-filtered","id":"source.ip","category":"source","type":"ip"},{"aggregatable":true,"description":"Port of the source.","columnHeaderType":"not-filtered","id":"source.port","category":"source","type":"number"},{"aggregatable":true,"description":"IP address of the destination (IPv4 or IPv6).","columnHeaderType":"not-filtered","id":"destination.ip","category":"destination","type":"ip"},{"columnHeaderType":"not-filtered","id":"destination.port"},{"aggregatable":true,"description":"Short name or login of the user.","columnHeaderType":"not-filtered","id":"user.name","category":"user","type":"string","example":"albert"},{"columnHeaderType":"not-filtered","id":"host.name"}],"dataProviders":[{"excluded":false,"and":[{"excluded":false,"kqlQuery":"","name":"{threat.enrichments.matched.type}","queryMatch":{"displayValue":null,"field":"threat.enrichments.matched.type","displayField":null,"value":"{threat.enrichments.matched.type}","operator":":"},"id":"timeline-1-ae18ef4b-f690-4122-a24d-e13b6818fba8","type":"template","enabled":true},{"excluded":false,"kqlQuery":"","name":"{threat.enrichments.matched.field}","queryMatch":{"displayValue":null,"field":"threat.enrichments.matched.field","displayField":null,"value":"{threat.enrichments.matched.field}","operator":":"},"id":"timeline-1-7b4cf27e-6788-4d8e-9188-7687f0eba0f2","type":"template","enabled":true}],"kqlQuery":"","name":"{threat.enrichments.matched.atomic}","queryMatch":{"displayValue":null,"field":"threat.enrichments.matched.atomic","displayField":null,"value":"{threat.enrichments.matched.atomic}","operator":":"},"id":"timeline-1-7db7d278-a80a-4853-971a-904319c50777","type":"template","enabled":true}],"description":"This Timeline template is for alerts generated by Indicator Match detection rules.","eqlOptions":{"eventCategoryField":"event.category","tiebreakerField":"","timestampField":"@timestamp","query":"","size":100},"eventType":"alert","filters":[],"kqlMode":"filter","kqlQuery":{"filterQuery":{"kuery":{"kind":"kuery","expression":""},"serializedQuery":""}},"dataViewId": "security-solution","indexNames":[".siem-signals-default"],"title":"Generic Threat Match Timeline","timelineType":"template","templateTimelineVersion":2,"templateTimelineId":"495ad7a7-316e-4544-8a0f-9c098daee76e","dateRange":{"start":1588161020848,"end":1588162280848},"savedQueryId":null,"sort":[{"sortDirection":"desc","columnId":"@timestamp"}],"created":1616696609311,"createdBy":"elastic","updated":1616788372794,"updatedBy":"elastic","eventNotes":[],"globalNotes":[],"pinnedEventIds":[],"status":"immutable"} +{"savedObjectId":null,"version":null,"columns":[{"columnHeaderType":"not-filtered","id":"@timestamp"},{"columnHeaderType":"not-filtered","id":"kibana.alert.rule.description"},{"aggregatable":true,"description":"The action captured by the event.\n\nThis describes the information in the event. It is more specific than `event.category`.\nExamples are `group-add`, `process-started`, `file-created`. The value is\nnormally defined by the implementer.","columnHeaderType":"not-filtered","id":"event.action","category":"event","type":"string","example":"user-password-change"},{"aggregatable":true,"description":"Array of process arguments, starting with the absolute path to\nthe executable.\n\nMay be filtered to protect sensitive information.","columnHeaderType":"not-filtered","id":"process.args","category":"process","type":"string","example":"[\"/usr/bin/ssh\",\"-l\",\"user\",\"10.0.0.16\"]"},{"columnHeaderType":"not-filtered","id":"process.pid"},{"aggregatable":true,"description":"IP address of the source (IPv4 or IPv6).","columnHeaderType":"not-filtered","id":"source.ip","category":"source","type":"ip"},{"aggregatable":true,"description":"Port of the source.","columnHeaderType":"not-filtered","id":"source.port","category":"source","type":"number"},{"aggregatable":true,"description":"IP address of the destination (IPv4 or IPv6).","columnHeaderType":"not-filtered","id":"destination.ip","category":"destination","type":"ip"},{"columnHeaderType":"not-filtered","id":"destination.port"},{"aggregatable":true,"description":"Short name or login of the user.","columnHeaderType":"not-filtered","id":"user.name","category":"user","type":"string","example":"albert"},{"columnHeaderType":"not-filtered","id":"host.name"}],"dataProviders":[{"excluded":false,"and":[{"excluded":false,"kqlQuery":"","name":"{threat.enrichments.matched.type}","queryMatch":{"displayValue":null,"field":"threat.enrichments.matched.type","displayField":null,"value":"{threat.enrichments.matched.type}","operator":":"},"id":"timeline-1-ae18ef4b-f690-4122-a24d-e13b6818fba8","type":"template","enabled":true},{"excluded":false,"kqlQuery":"","name":"{threat.enrichments.matched.field}","queryMatch":{"displayValue":null,"field":"threat.enrichments.matched.field","displayField":null,"value":"{threat.enrichments.matched.field}","operator":":"},"id":"timeline-1-7b4cf27e-6788-4d8e-9188-7687f0eba0f2","type":"template","enabled":true}],"kqlQuery":"","name":"{threat.enrichments.matched.atomic}","queryMatch":{"displayValue":null,"field":"threat.enrichments.matched.atomic","displayField":null,"value":"{threat.enrichments.matched.atomic}","operator":":"},"id":"timeline-1-7db7d278-a80a-4853-971a-904319c50777","type":"template","enabled":true}],"description":"This Timeline template is for alerts generated by Indicator Match detection rules.","eqlOptions":{"eventCategoryField":"event.category","tiebreakerField":"","timestampField":"@timestamp","query":"","size":100},"eventType":"alert","filters":[],"kqlMode":"filter","kqlQuery":{"filterQuery":{"kuery":{"kind":"kuery","expression":""},"serializedQuery":""}},"dataViewId": "security-solution","indexNames":[],"title":"Generic Threat Match Timeline","timelineType":"template","templateTimelineVersion":3,"templateTimelineId":"495ad7a7-316e-4544-8a0f-9c098daee76e","dateRange":{"start":1588161020848,"end":1588162280848},"savedQueryId":null,"sort":[{"sortDirection":"desc","columnId":"@timestamp"}],"created":1616696609311,"createdBy":"elastic","updated":1616788372794,"updatedBy":"elastic","eventNotes":[],"globalNotes":[],"pinnedEventIds":[],"status":"immutable"} From b44f82e918ebc613a7c9a768b768ea68b9ce64f0 Mon Sep 17 00:00:00 2001 From: Dario Gieselaar Date: Thu, 20 Jan 2022 12:54:20 +0100 Subject: [PATCH 072/108] [APM] Restrict aggregated tx metrics search to date range (#123445) --- x-pack/plugins/apm/server/routes/services/route.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/x-pack/plugins/apm/server/routes/services/route.ts b/x-pack/plugins/apm/server/routes/services/route.ts index 0f4034a2187486..2b7a71ba13acf8 100644 --- a/x-pack/plugins/apm/server/routes/services/route.ts +++ b/x-pack/plugins/apm/server/routes/services/route.ts @@ -66,6 +66,8 @@ const servicesRoute = createApmServerRoute({ const searchAggregatedTransactions = await getSearchAggregatedTransactions({ ...setup, kuery, + start, + end, }); return getServices({ From ab5741ff78bfbf7a9df6a664c741278f21582ea7 Mon Sep 17 00:00:00 2001 From: Esteban Beltran Date: Thu, 20 Jan 2022 13:03:05 +0100 Subject: [PATCH 073/108] [Cases] Show toast when a case is updated from the cases list (#123357) Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../plugins/cases/public/containers/translations.ts | 2 +- .../cases/public/containers/use_get_cases.test.tsx | 6 ++++++ .../cases/public/containers/use_get_cases.tsx | 13 +++++++++++-- .../plugins/cases/public/containers/utils.test.ts | 2 +- x-pack/plugins/translations/translations/ja-JP.json | 1 - x-pack/plugins/translations/translations/zh-CN.json | 1 - 6 files changed, 19 insertions(+), 6 deletions(-) diff --git a/x-pack/plugins/cases/public/containers/translations.ts b/x-pack/plugins/cases/public/containers/translations.ts index eb7e5ff99e518a..72aeb66772c523 100644 --- a/x-pack/plugins/cases/public/containers/translations.ts +++ b/x-pack/plugins/cases/public/containers/translations.ts @@ -81,6 +81,6 @@ export const SYNC_CASE = (caseTitle: string) => export const STATUS_CHANGED_TOASTER_TEXT = i18n.translate( 'xpack.cases.containers.statusChangeToasterText', { - defaultMessage: 'Alerts in this case have been also had their status updated', + defaultMessage: 'Updated the statuses of attached alerts.', } ); diff --git a/x-pack/plugins/cases/public/containers/use_get_cases.test.tsx b/x-pack/plugins/cases/public/containers/use_get_cases.test.tsx index fd7b2eddfe7c9a..23b57004ca4d78 100644 --- a/x-pack/plugins/cases/public/containers/use_get_cases.test.tsx +++ b/x-pack/plugins/cases/public/containers/use_get_cases.test.tsx @@ -20,12 +20,15 @@ import { UpdateKey } from './types'; import { allCases, basicCase } from './mock'; import * as api from './api'; import { TestProviders } from '../common/mock'; +import { useToasts } from '../common/lib/kibana'; jest.mock('./api'); jest.mock('../common/lib/kibana'); describe('useGetCases', () => { const abortCtrl = new AbortController(); + const addSuccess = jest.fn(); + (useToasts as jest.Mock).mockReturnValue({ addSuccess, addError: jest.fn() }); beforeEach(() => { jest.clearAllMocks(); @@ -113,6 +116,9 @@ describe('useGetCases', () => { abortCtrl.signal ); }); + expect(addSuccess).toHaveBeenCalledWith({ + title: `Updated "${basicCase.title}"`, + }); }); it('refetch cases', async () => { diff --git a/x-pack/plugins/cases/public/containers/use_get_cases.tsx b/x-pack/plugins/cases/public/containers/use_get_cases.tsx index eacad3c8ca0203..de0f0f514da1bb 100644 --- a/x-pack/plugins/cases/public/containers/use_get_cases.tsx +++ b/x-pack/plugins/cases/public/containers/use_get_cases.tsx @@ -212,6 +212,7 @@ export const useGetCases = ( const dispatchUpdateCaseProperty = useCallback( async ({ updateKey, updateValue, caseId, refetchCasesStatus, version }: UpdateCase) => { + const caseData = state.data.cases.find((caseInfo) => caseInfo.id === caseId); try { didCancelUpdateCases.current = false; abortCtrlUpdateCases.current.abort(); @@ -230,6 +231,15 @@ export const useGetCases = ( dispatch({ type: 'FETCH_UPDATE_CASE_SUCCESS' }); fetchCases(state.filterOptions, state.queryParams); refetchCasesStatus(); + if (caseData) { + toasts.addSuccess({ + title: i18n.UPDATED_CASE(caseData.title), + text: + updateKey === 'status' && caseData.totalAlerts > 0 + ? i18n.STATUS_CHANGED_TOASTER_TEXT + : undefined, + }); + } } } catch (error) { if (!didCancelUpdateCases.current) { @@ -240,8 +250,7 @@ export const useGetCases = ( } } }, - // eslint-disable-next-line react-hooks/exhaustive-deps - [state.filterOptions, state.queryParams] + [fetchCases, state.data, state.filterOptions, state.queryParams, toasts] ); const refetchCases = useCallback(() => { diff --git a/x-pack/plugins/cases/public/containers/utils.test.ts b/x-pack/plugins/cases/public/containers/utils.test.ts index 3ee6182cb053dd..0dd55fbe8aacae 100644 --- a/x-pack/plugins/cases/public/containers/utils.test.ts +++ b/x-pack/plugins/cases/public/containers/utils.test.ts @@ -97,7 +97,7 @@ describe('utils', () => { expect(toast).toEqual({ title: 'Updated "My case"', - text: 'Alerts in this case have been also had their status updated', + text: 'Updated the statuses of attached alerts.', }); }); diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index bbc5309e476dda..e17ed6f278acd3 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -7694,7 +7694,6 @@ "xpack.cases.containers.markInProgressCases": "{totalCases, plural, =1 {\"{caseTitle}\"} other {{totalCases}件のケース}}を進行中に設定しました", "xpack.cases.containers.pushToExternalService": "{ serviceName }への送信が正常に完了しました", "xpack.cases.containers.reopenedCases": "{totalCases, plural, =1 {\"{caseTitle}\"} other {{totalCases}件のケース}}をオープンしました", - "xpack.cases.containers.statusChangeToasterText": "このケースのアラートはステータスが更新されました", "xpack.cases.containers.syncCase": "\"{caseTitle}\"のアラートが同期されました", "xpack.cases.containers.updatedCase": "\"{caseTitle}\"を更新しました", "xpack.cases.create.stepOneTitle": "ケースフィールド", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index ebfc41d0821b01..7850bfaba35c2b 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -7753,7 +7753,6 @@ "xpack.cases.containers.markInProgressCases": "已将{totalCases, plural, =1 {“{caseTitle}”} other { {totalCases} 个案例}}标记为进行中", "xpack.cases.containers.pushToExternalService": "已成功发送到 { serviceName }", "xpack.cases.containers.reopenedCases": "已打开{totalCases, plural, =1 {“{caseTitle}”} other { {totalCases} 个案例}}", - "xpack.cases.containers.statusChangeToasterText": "此案例中的告警也更新了状态", "xpack.cases.containers.syncCase": "“{caseTitle}”中的告警已同步", "xpack.cases.containers.updatedCase": "已更新“{caseTitle}”", "xpack.cases.create.stepOneTitle": "案例字段", From 946be82994d87a429f8061c34a99012237023b28 Mon Sep 17 00:00:00 2001 From: Matthew Kime Date: Thu, 20 Jan 2022 06:59:10 -0600 Subject: [PATCH 074/108] [data views] fix capabilities check (#122503) * fix permissions check * typescript fix * update jest test * Update workspace_panel.tsx * Update workspace_panel.test.tsx * first swing at functional test * refactor permissions code * type improvement * make client side specific service * cleanup Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../empty_prompts/empty_prompts.tsx | 2 +- .../data_view_editor/public/plugin.tsx | 4 +--- .../data_view_field_editor/public/plugin.ts | 9 ++----- .../field_editor/field_editor.test.tsx | 6 ++--- .../mount_management_section.tsx | 2 +- .../common/data_views/data_views.ts | 6 ++--- .../public/data_views_service_public.ts | 24 +++++++++++++++++++ src/plugins/data_views/public/index.ts | 8 +++++-- src/plugins/data_views/public/plugin.ts | 6 +++-- src/plugins/data_views/public/types.ts | 10 ++++++-- ...register_index_pattern_usage_collection.ts | 4 ++-- .../public/__mocks__/index_patterns.ts | 4 ++-- .../public/utils/popularize_field.test.ts | 12 +++++----- .../public/utils/use_data_grid_columns.ts | 2 +- 14 files changed, 64 insertions(+), 35 deletions(-) create mode 100644 src/plugins/data_views/public/data_views_service_public.ts diff --git a/src/plugins/data_view_editor/public/components/empty_prompts/empty_prompts.tsx b/src/plugins/data_view_editor/public/components/empty_prompts/empty_prompts.tsx index d44e793d4ef491..e5f4e6cec057e6 100644 --- a/src/plugins/data_view_editor/public/components/empty_prompts/empty_prompts.tsx +++ b/src/plugins/data_view_editor/public/components/empty_prompts/empty_prompts.tsx @@ -98,7 +98,7 @@ export const EmptyPrompts: FC = ({ allSources, onCancel, children, loadSo setGoToForm(true)} indexPatternsIntroUrl={docLinks.links.indexPatterns.introduction} - canSaveIndexPattern={application.capabilities.indexPatterns.save as boolean} + canSaveIndexPattern={dataViews.getCanSaveSync()} /> diff --git a/src/plugins/data_view_editor/public/plugin.tsx b/src/plugins/data_view_editor/public/plugin.tsx index 68a0191836291a..a8aa33620c456b 100644 --- a/src/plugins/data_view_editor/public/plugin.tsx +++ b/src/plugins/data_view_editor/public/plugin.tsx @@ -60,9 +60,7 @@ export class DataViewEditorPlugin * @returns boolean */ userPermissions: { - editDataView: () => { - return application.capabilities.management.kibana.indexPatterns; - }, + editDataView: () => dataViews.getCanSaveSync(), }, }; } diff --git a/src/plugins/data_view_field_editor/public/plugin.ts b/src/plugins/data_view_field_editor/public/plugin.ts index c0f09cdace9ba9..3b13bcd82c1109 100644 --- a/src/plugins/data_view_field_editor/public/plugin.ts +++ b/src/plugins/data_view_field_editor/public/plugin.ts @@ -30,10 +30,7 @@ export class IndexPatternFieldEditorPlugin public start(core: CoreStart, plugins: StartPlugins) { const { fieldFormatEditors } = this.formatEditorService.start(); - const { - application: { capabilities }, - http, - } = core; + const { http } = core; const { data, usageCollection, dataViews, fieldFormats } = plugins; const openDeleteModal = getFieldDeleteModalOpener({ core, @@ -53,9 +50,7 @@ export class IndexPatternFieldEditorPlugin }), openDeleteModal, userPermissions: { - editIndexPattern: () => { - return capabilities.management.kibana.indexPatterns; - }, + editIndexPattern: () => dataViews.getCanSaveSync(), }, DeleteRuntimeFieldProvider: getDeleteFieldProvider(openDeleteModal), }; diff --git a/src/plugins/data_view_management/public/components/field_editor/field_editor.test.tsx b/src/plugins/data_view_management/public/components/field_editor/field_editor.test.tsx index 39f8469dc09892..875b21ac52444d 100644 --- a/src/plugins/data_view_management/public/components/field_editor/field_editor.test.tsx +++ b/src/plugins/data_view_management/public/components/field_editor/field_editor.test.tsx @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { DataView, DataViewField, DataViewsService } from 'src/plugins/data_views/public'; +import { DataView, DataViewField, DataViewsContract } from 'src/plugins/data_views/public'; import { FieldFormatInstanceType } from 'src/plugins/field_formats/common'; import { findTestSubject } from '@elastic/eui/lib/test'; @@ -95,7 +95,7 @@ const field = { const services = { redirectAway: () => {}, saveIndexPattern: async () => {}, - indexPatternService: {} as DataViewsService, + indexPatternService: {} as DataViewsContract, }; describe('FieldEditor', () => { @@ -202,7 +202,7 @@ describe('FieldEditor', () => { redirectAway: () => {}, indexPatternService: { updateSavedObject: jest.fn(() => Promise.resolve()), - } as unknown as DataViewsService, + } as unknown as DataViewsContract, }, }, mockContext diff --git a/src/plugins/data_view_management/public/management_app/mount_management_section.tsx b/src/plugins/data_view_management/public/management_app/mount_management_section.tsx index 4f8e98d382d37c..1b876e34a42fb6 100644 --- a/src/plugins/data_view_management/public/management_app/mount_management_section.tsx +++ b/src/plugins/data_view_management/public/management_app/mount_management_section.tsx @@ -43,7 +43,7 @@ export async function mountManagementSection( { data, dataViewFieldEditor, dataViewEditor, dataViews, fieldFormats }, indexPatternManagementStart, ] = await getStartServices(); - const canSave = Boolean(application.capabilities.indexPatterns.save); + const canSave = dataViews.getCanSaveSync(); if (!canSave) { chrome.setBadge(readOnlyBadge); diff --git a/src/plugins/data_views/common/data_views/data_views.ts b/src/plugins/data_views/common/data_views/data_views.ts index ae7c9f03afc183..26e1683b600067 100644 --- a/src/plugins/data_views/common/data_views/data_views.ts +++ b/src/plugins/data_views/common/data_views/data_views.ts @@ -59,7 +59,7 @@ export interface DataViewListItem { export type IndexPatternListItem = DataViewListItem; -interface IndexPatternsServiceDeps { +export interface DataViewsServiceDeps { uiSettings: UiSettingsCommon; savedObjectsClient: SavedObjectsClientCommon; apiClient: IDataViewsApiClient; @@ -79,7 +79,7 @@ export class DataViewsService { private onNotification: OnNotification; private onError: OnError; private dataViewCache: ReturnType; - private getCanSave: () => Promise; + public getCanSave: () => Promise; /** * @deprecated Use `getDefaultDataView` instead (when loading data view) and handle @@ -96,7 +96,7 @@ export class DataViewsService { onError, onRedirectNoIndexPattern = () => {}, getCanSave = () => Promise.resolve(false), - }: IndexPatternsServiceDeps) { + }: DataViewsServiceDeps) { this.apiClient = apiClient; this.config = uiSettings; this.savedObjectsClient = savedObjectsClient; diff --git a/src/plugins/data_views/public/data_views_service_public.ts b/src/plugins/data_views/public/data_views_service_public.ts new file mode 100644 index 00000000000000..d89c4e37e872d4 --- /dev/null +++ b/src/plugins/data_views/public/data_views_service_public.ts @@ -0,0 +1,24 @@ +/* + * 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. + */ + +import { DataViewsService } from '.'; + +import { DataViewsServiceDeps } from '../common/data_views/data_views'; + +interface DataViewsServicePublicDeps extends DataViewsServiceDeps { + getCanSaveSync: () => boolean; +} + +export class DataViewsServicePublic extends DataViewsService { + public getCanSaveSync: () => boolean; + + constructor(deps: DataViewsServicePublicDeps) { + super(deps); + this.getCanSaveSync = deps.getCanSaveSync; + } +} diff --git a/src/plugins/data_views/public/index.ts b/src/plugins/data_views/public/index.ts index b15e6da7d940b3..9cb07d4f3c54f5 100644 --- a/src/plugins/data_views/public/index.ts +++ b/src/plugins/data_views/public/index.ts @@ -18,7 +18,7 @@ export { onRedirectNoIndexPattern } from './data_views'; export type { IIndexPatternFieldList, TypeMeta } from '../common'; export { IndexPatternField, DataViewField, DataViewType, META_FIELDS } from '../common'; -export type { IndexPatternsContract, DataViewsContract } from './data_views'; +export type { IndexPatternsContract } from './data_views'; export type { DataViewListItem } from './data_views'; export { IndexPatternsService, @@ -40,7 +40,11 @@ export function plugin() { return new DataViewsPublicPlugin(); } -export type { DataViewsPublicPluginSetup, DataViewsPublicPluginStart } from './types'; +export type { + DataViewsPublicPluginSetup, + DataViewsPublicPluginStart, + DataViewsContract, +} from './types'; // Export plugin after all other imports export type { DataViewsPublicPlugin as DataViewsPlugin }; diff --git a/src/plugins/data_views/public/plugin.ts b/src/plugins/data_views/public/plugin.ts index bf092d3fae1771..c2d0a70502b22b 100644 --- a/src/plugins/data_views/public/plugin.ts +++ b/src/plugins/data_views/public/plugin.ts @@ -16,13 +16,14 @@ import { } from './types'; import { - DataViewsService, onRedirectNoIndexPattern, DataViewsApiClient, UiSettingsPublicToCommon, SavedObjectsClientPublicToCommon, } from '.'; +import { DataViewsServicePublic } from './data_views_service_public'; + export class DataViewsPublicPlugin implements Plugin< @@ -47,7 +48,7 @@ export class DataViewsPublicPlugin ): DataViewsPublicPluginStart { const { uiSettings, http, notifications, savedObjects, theme, overlays, application } = core; - return new DataViewsService({ + return new DataViewsServicePublic({ uiSettings: new UiSettingsPublicToCommon(uiSettings), savedObjectsClient: new SavedObjectsClientPublicToCommon(savedObjects.client), apiClient: new DataViewsApiClient(http), @@ -63,6 +64,7 @@ export class DataViewsPublicPlugin theme ), getCanSave: () => Promise.resolve(application.capabilities.indexPatterns.save === true), + getCanSaveSync: () => application.capabilities.indexPatterns.save === true, }); } diff --git a/src/plugins/data_views/public/types.ts b/src/plugins/data_views/public/types.ts index 20b1cbaf090fa5..e012695dfc6b59 100644 --- a/src/plugins/data_views/public/types.ts +++ b/src/plugins/data_views/public/types.ts @@ -26,7 +26,13 @@ export interface DataViewsPublicStartDependencies { // eslint-disable-next-line @typescript-eslint/no-empty-interface export interface DataViewsPublicPluginSetup {} +export interface DataViewsServicePublic extends DataViewsService { + getCanSaveSync: () => boolean; +} + +export type DataViewsContract = PublicMethodsOf; + /** - * Data plugin public Start contract + * Data views plugin public Start contract */ -export type DataViewsPublicPluginStart = PublicMethodsOf; +export type DataViewsPublicPluginStart = PublicMethodsOf; diff --git a/src/plugins/data_views/server/register_index_pattern_usage_collection.ts b/src/plugins/data_views/server/register_index_pattern_usage_collection.ts index 6af2f6df6725e9..5b42db0f75a4d3 100644 --- a/src/plugins/data_views/server/register_index_pattern_usage_collection.ts +++ b/src/plugins/data_views/server/register_index_pattern_usage_collection.ts @@ -8,7 +8,7 @@ import { UsageCollectionSetup } from 'src/plugins/usage_collection/server'; import { StartServicesAccessor } from 'src/core/server'; -import { DataViewsService } from '../common'; +import { DataViewsContract } from '../common'; import { SavedObjectsClient } from '../../../core/server'; import { DataViewsServerPluginStartDependencies, DataViewsServerPluginStart } from './types'; @@ -57,7 +57,7 @@ export const updateMax = (currentMax: number | undefined, newVal: number): numbe } }; -export async function getIndexPatternTelemetry(indexPatterns: DataViewsService) { +export async function getIndexPatternTelemetry(indexPatterns: DataViewsContract) { const ids = await indexPatterns.getIds(); const countSummaryDefaults: CountSummary = { diff --git a/src/plugins/discover/public/__mocks__/index_patterns.ts b/src/plugins/discover/public/__mocks__/index_patterns.ts index 0e665890fedbad..0d6f3fa7236820 100644 --- a/src/plugins/discover/public/__mocks__/index_patterns.ts +++ b/src/plugins/discover/public/__mocks__/index_patterns.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { DataViewsService } from '../../../data/common'; +import { DataViewsContract } from '../../../data_views/public'; import { indexPatternMock } from './index_pattern'; export const indexPatternsMock = { @@ -21,4 +21,4 @@ export const indexPatternsMock = { } }, updateSavedObject: jest.fn(), -} as unknown as jest.Mocked; +} as unknown as jest.Mocked; diff --git a/src/plugins/discover/public/utils/popularize_field.test.ts b/src/plugins/discover/public/utils/popularize_field.test.ts index 084a147b5c9b68..bf81163463b873 100644 --- a/src/plugins/discover/public/utils/popularize_field.test.ts +++ b/src/plugins/discover/public/utils/popularize_field.test.ts @@ -7,7 +7,7 @@ */ import { Capabilities } from 'kibana/public'; -import { DataView, DataViewsService } from '../../../data/common'; +import { DataView, DataViewsContract } from '../../../data_views/public'; import { popularizeField } from './popularize_field'; const capabilities = { @@ -20,7 +20,7 @@ describe('Popularize field', () => { test('returns undefined if index pattern lacks id', async () => { const indexPattern = {} as unknown as DataView; const fieldName = '@timestamp'; - const dataViewsService = {} as unknown as DataViewsService; + const dataViewsService = {} as unknown as DataViewsContract; const result = await popularizeField(indexPattern, fieldName, dataViewsService, capabilities); expect(result).toBeUndefined(); }); @@ -32,7 +32,7 @@ describe('Popularize field', () => { }, } as unknown as DataView; const fieldName = '@timestamp'; - const dataViewsService = {} as unknown as DataViewsService; + const dataViewsService = {} as unknown as DataViewsContract; const result = await popularizeField(indexPattern, fieldName, dataViewsService, capabilities); expect(result).toBeUndefined(); }); @@ -50,7 +50,7 @@ describe('Popularize field', () => { const fieldName = '@timestamp'; const dataViewsService = { updateSavedObject: async () => {}, - } as unknown as DataViewsService; + } as unknown as DataViewsContract; const result = await popularizeField(indexPattern, fieldName, dataViewsService, capabilities); expect(result).toBeUndefined(); expect(field.count).toEqual(1); @@ -71,7 +71,7 @@ describe('Popularize field', () => { updateSavedObject: async () => { throw new Error('unknown error'); }, - } as unknown as DataViewsService; + } as unknown as DataViewsContract; const result = await popularizeField(indexPattern, fieldName, dataViewsService, capabilities); expect(result).toBeUndefined(); }); @@ -89,7 +89,7 @@ describe('Popularize field', () => { const fieldName = '@timestamp'; const dataViewsService = { updateSavedObject: jest.fn(), - } as unknown as DataViewsService; + } as unknown as DataViewsContract; const result = await popularizeField(indexPattern, fieldName, dataViewsService, { indexPatterns: { save: false }, } as unknown as Capabilities); diff --git a/src/plugins/discover/public/utils/use_data_grid_columns.ts b/src/plugins/discover/public/utils/use_data_grid_columns.ts index 8df97e84dcf2bd..ab492dc10f617d 100644 --- a/src/plugins/discover/public/utils/use_data_grid_columns.ts +++ b/src/plugins/discover/public/utils/use_data_grid_columns.ts @@ -7,7 +7,7 @@ */ import { useMemo } from 'react'; -import type { DataView, DataViewsContract } from 'src/plugins/data/common'; +import type { DataView, DataViewsContract } from 'src/plugins/data_views/public'; import { Capabilities, IUiSettingsClient } from 'kibana/public'; import { From 7fba1feaf3a7527dd1083e61ccbdfe93fc69b385 Mon Sep 17 00:00:00 2001 From: Nicolas Chaulet Date: Thu, 20 Jan 2022 08:20:30 -0500 Subject: [PATCH 075/108] [Fleet] Remove output id from agent policy APIs (#123403) --- x-pack/plugins/fleet/server/types/models/agent_policy.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/x-pack/plugins/fleet/server/types/models/agent_policy.ts b/x-pack/plugins/fleet/server/types/models/agent_policy.ts index 2e17c4ffe898ed..840dbd0ccb6074 100644 --- a/x-pack/plugins/fleet/server/types/models/agent_policy.ts +++ b/x-pack/plugins/fleet/server/types/models/agent_policy.ts @@ -22,8 +22,6 @@ export const AgentPolicyBaseSchema = { schema.oneOf([schema.literal(dataTypes.Logs), schema.literal(dataTypes.Metrics)]) ) ), - data_output_id: schema.maybe(schema.string()), - data_monitoring_output_id: schema.maybe(schema.string()), }; export const NewAgentPolicySchema = schema.object({ From d06104ef6cb0f13c8255d13a25f2ea3971fc9f2b Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Thu, 20 Jan 2022 15:30:28 +0100 Subject: [PATCH 076/108] Unskip search session api tests (#123158) --- .../api_integration/apis/search/session.ts | 45 ++++++++++--------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/x-pack/test/api_integration/apis/search/session.ts b/x-pack/test/api_integration/apis/search/session.ts index 868c91cd9ed129..2c8a03ddbc4f2d 100644 --- a/x-pack/test/api_integration/apis/search/session.ts +++ b/x-pack/test/api_integration/apis/search/session.ts @@ -16,8 +16,7 @@ export default function ({ getService }: FtrProviderContext) { const retry = getService('retry'); const spacesService = getService('spaces'); - // FLAKY: https://github.com/elastic/kibana/issues/119660 - describe.skip('search session', () => { + describe('search session', () => { describe('session management', () => { it('should fail to create a session with no name', async () => { const sessionId = `my-session-${Math.random()}`; @@ -189,7 +188,7 @@ export default function ({ getService }: FtrProviderContext) { const { id: id2 } = searchRes2.body; - await retry.waitForWithTimeout('searches persisted into session', 5000, async () => { + await retry.waitFor('searches persisted into session', async () => { const resp = await supertest .get(`/internal/session/${sessionId}`) .set('kbn-xsrf', 'foo') @@ -285,7 +284,7 @@ export default function ({ getService }: FtrProviderContext) { const { id: id2 } = searchRes2.body; - await retry.waitForWithTimeout('searches persisted into session', 5000, async () => { + await retry.waitFor('searches persisted into session', async () => { const resp = await supertest .get(`/internal/session/${sessionId}`) .set('kbn-xsrf', 'foo') @@ -342,7 +341,7 @@ export default function ({ getService }: FtrProviderContext) { }) .expect(200); - await retry.waitForWithTimeout('searches persisted into session', 5000, async () => { + await retry.waitFor('searches persisted into session', async () => { const resp = await supertest .get(`/internal/session/${sessionId}`) .set('kbn-xsrf', 'foo') @@ -361,9 +360,8 @@ export default function ({ getService }: FtrProviderContext) { // session refresh interval is 10 seconds, wait to give a chance for status to update await new Promise((resolve) => setTimeout(resolve, 10000)); - await retry.waitForWithTimeout( + await retry.waitFor( 'searches eventually complete and session gets into the complete state', - 5000, async () => { const resp = await supertest .get(`/internal/session/${sessionId}`) @@ -428,17 +426,21 @@ export default function ({ getService }: FtrProviderContext) { // it might take the session a moment to be updated await new Promise((resolve) => setTimeout(resolve, 2500)); - const getSessionSecondTime = await supertest - .get(`/internal/session/${sessionId}`) - .set('kbn-xsrf', 'foo') - .expect(200); + await retry.waitFor('search session touched time updated', async () => { + const getSessionSecondTime = await supertest + .get(`/internal/session/${sessionId}`) + .set('kbn-xsrf', 'foo') + .expect(200); - expect(getSessionFirstTime.body.attributes.sessionId).to.be.equal( - getSessionSecondTime.body.attributes.sessionId - ); - expect(getSessionFirstTime.body.attributes.touched).to.be.lessThan( - getSessionSecondTime.body.attributes.touched - ); + expect(getSessionFirstTime.body.attributes.sessionId).to.be.equal( + getSessionSecondTime.body.attributes.sessionId + ); + expect(getSessionFirstTime.body.attributes.touched).to.be.lessThan( + getSessionSecondTime.body.attributes.touched + ); + + return true; + }); }); describe('with security', () => { @@ -645,7 +647,7 @@ export default function ({ getService }: FtrProviderContext) { const { id } = searchRes.body; - await retry.waitForWithTimeout('searches persisted into session', 5000, async () => { + await retry.waitFor('searches persisted into session', async () => { const resp = await supertest .get(`/s/${spaceId}/internal/session/${sessionId}`) .set('kbn-xsrf', 'foo') @@ -682,7 +684,7 @@ export default function ({ getService }: FtrProviderContext) { ); }); - it('should complete persisten session', async () => { + it('should complete persisted session', async () => { const sessionId = `my-session-${Math.random()}`; // run search @@ -719,7 +721,7 @@ export default function ({ getService }: FtrProviderContext) { }) .expect(200); - await retry.waitForWithTimeout('searches persisted into session', 5000, async () => { + await retry.waitFor('searches persisted into session', async () => { const resp = await supertest .get(`/s/${spaceId}/internal/session/${sessionId}`) .set('kbn-xsrf', 'foo') @@ -738,9 +740,8 @@ export default function ({ getService }: FtrProviderContext) { // session refresh interval is 5 seconds, wait to give a chance for status to update await new Promise((resolve) => setTimeout(resolve, 5000)); - await retry.waitForWithTimeout( + await retry.waitFor( 'searches eventually complete and session gets into the complete state', - 5000, async () => { const resp = await supertest .get(`/s/${spaceId}/internal/session/${sessionId}`) From 460f89a200751d01da4159c80af87bbff540b673 Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Thu, 20 Jan 2022 16:05:04 +0100 Subject: [PATCH 077/108] [bfetch] Improve error handling (#123455) --- .../public/streaming/fetch_streaming.test.ts | 1 + .../streaming/from_streaming_xhr.test.ts | 32 ++++++++++++++++++- .../public/streaming/from_streaming_xhr.ts | 7 ++-- 3 files changed, 37 insertions(+), 3 deletions(-) diff --git a/src/plugins/bfetch/public/streaming/fetch_streaming.test.ts b/src/plugins/bfetch/public/streaming/fetch_streaming.test.ts index 67ebf8d5a1c230..21afa03c189204 100644 --- a/src/plugins/bfetch/public/streaming/fetch_streaming.test.ts +++ b/src/plugins/bfetch/public/streaming/fetch_streaming.test.ts @@ -22,6 +22,7 @@ const tick = () => new Promise((resolve) => setTimeout(resolve, 1)); const setup = () => { const { xhr, XMLHttpRequest } = mockXMLHttpRequest(); window.XMLHttpRequest = XMLHttpRequest; + (xhr as any).status = 200; return { xhr }; }; diff --git a/src/plugins/bfetch/public/streaming/from_streaming_xhr.test.ts b/src/plugins/bfetch/public/streaming/from_streaming_xhr.test.ts index bc5bf28183a504..d73f7a9b5099bc 100644 --- a/src/plugins/bfetch/public/streaming/from_streaming_xhr.test.ts +++ b/src/plugins/bfetch/public/streaming/from_streaming_xhr.test.ts @@ -15,7 +15,7 @@ const createXhr = (): XMLHttpRequest => onreadystatechange: () => {}, readyState: 0, responseText: '', - status: 0, + status: 200, } as unknown as XMLHttpRequest); test('returns observable', () => { @@ -156,6 +156,36 @@ test('errors observable if request returns with error', () => { ); }); +test('does not emit when gets error response', () => { + const xhr = createXhr(); + const observable = fromStreamingXhr(xhr); + + const next = jest.fn(); + const complete = jest.fn(); + const error = jest.fn(); + observable.subscribe({ + next, + complete, + error, + }); + + (xhr as any).responseText = 'error'; + (xhr as any).status = 400; + xhr.onprogress!({} as any); + + expect(next).toHaveBeenCalledTimes(0); + + (xhr as any).readyState = 4; + xhr.onreadystatechange!({} as any); + + expect(next).toHaveBeenCalledTimes(0); + expect(error).toHaveBeenCalledTimes(1); + expect(error.mock.calls[0][0]).toBeInstanceOf(Error); + expect(error.mock.calls[0][0].message).toMatchInlineSnapshot( + `"Batch request failed with status 400"` + ); +}); + test('when .onprogress called multiple times with same text, does not create new observable events', () => { const xhr = createXhr(); const observable = fromStreamingXhr(xhr); diff --git a/src/plugins/bfetch/public/streaming/from_streaming_xhr.ts b/src/plugins/bfetch/public/streaming/from_streaming_xhr.ts index c630554c73fa0c..d81c7bfa694c21 100644 --- a/src/plugins/bfetch/public/streaming/from_streaming_xhr.ts +++ b/src/plugins/bfetch/public/streaming/from_streaming_xhr.ts @@ -23,8 +23,12 @@ export const fromStreamingXhr = ( let index = 0; let aborted = false; + // 0 indicates a network failure. 400+ messages are considered server errors + const isErrorStatus = () => xhr.status === 0 || xhr.status >= 400; + const processBatch = () => { if (aborted) return; + if (isErrorStatus()) return; const { responseText } = xhr; if (index >= responseText.length) return; @@ -56,8 +60,7 @@ export const fromStreamingXhr = ( if (xhr.readyState === 4) { if (signal) signal.removeEventListener('abort', onBatchAbort); - // 0 indicates a network failure. 400+ messages are considered server errors - if (xhr.status === 0 || xhr.status >= 400) { + if (isErrorStatus()) { subject.error(new Error(`Batch request failed with status ${xhr.status}`)); } else { subject.complete(); From b1d7731afaa2a1e4e86296364da6f4e795c9975a Mon Sep 17 00:00:00 2001 From: Hannah Mudge Date: Thu, 20 Jan 2022 08:33:14 -0700 Subject: [PATCH 078/108] [Dashboard] Clone ReferenceOrValueEmbeddables by value. (#122199) * Clone all panels by value. * Moved removal of byReference properties to getInputAsValueType. * Fixed handling of clone titles. * Fixed functional and unit clone tests. * Removed duplicate check for byReference. * Unset title on Visualize embeddable when by value. * Remove unused import. * Added by reference logic for saved search embeddables. * Re-added unit tests for cloning by reference. * Added functional tests. * Added Jest unit tests. * Ignored TypeScript errors for calling private functions in Jest tests. * Adjusted logic for generating clone titles. * Edited unit and functional tests for clone titles. * Fixed typo in Jest tests. * Keep hidden panel title status. * Fix Jest test description. * Remove unused import. * Fixed Jest tests after new title logic. Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../actions/clone_panel_action.test.tsx | 192 ++++++++++++++---- .../actions/clone_panel_action.tsx | 123 +++++++---- .../actions/unlink_from_library_action.tsx | 3 - .../embeddable/dashboard_container.tsx | 14 ++ .../attribute_service/attribute_service.tsx | 6 +- .../embeddable/visualize_embeddable.tsx | 4 +- .../apps/dashboard/panel_cloning.ts | 21 ++ 7 files changed, 286 insertions(+), 77 deletions(-) diff --git a/src/plugins/dashboard/public/application/actions/clone_panel_action.test.tsx b/src/plugins/dashboard/public/application/actions/clone_panel_action.test.tsx index 3c3872226ffb02..84c968e1c2b24a 100644 --- a/src/plugins/dashboard/public/application/actions/clone_panel_action.test.tsx +++ b/src/plugins/dashboard/public/application/actions/clone_panel_action.test.tsx @@ -33,7 +33,8 @@ setup.registerEmbeddableFactory( const start = doStart(); let container: DashboardContainer; -let embeddable: ContactCardEmbeddable; +let byRefOrValEmbeddable: ContactCardEmbeddable; +let genericEmbeddable: ContactCardEmbeddable; let coreStart: CoreStart; beforeEach(async () => { coreStart = coreMock.createStart(); @@ -70,18 +71,38 @@ beforeEach(async () => { }); container = new DashboardContainer(input, options); - const contactCardEmbeddable = await container.addNewEmbeddable< + const refOrValContactCardEmbeddable = await container.addNewEmbeddable< ContactCardEmbeddableInput, ContactCardEmbeddableOutput, ContactCardEmbeddable >(CONTACT_CARD_EMBEDDABLE, { - firstName: 'Kibana', + firstName: 'RefOrValEmbeddable', + }); + const genericContactCardEmbeddable = await container.addNewEmbeddable< + ContactCardEmbeddableInput, + ContactCardEmbeddableOutput, + ContactCardEmbeddable + >(CONTACT_CARD_EMBEDDABLE, { + firstName: 'NotRefOrValEmbeddable', }); - if (isErrorEmbeddable(contactCardEmbeddable)) { - throw new Error('Failed to create embeddable'); + if ( + isErrorEmbeddable(refOrValContactCardEmbeddable) || + isErrorEmbeddable(genericContactCardEmbeddable) + ) { + throw new Error('Failed to create embeddables'); } else { - embeddable = contactCardEmbeddable; + byRefOrValEmbeddable = embeddablePluginMock.mockRefOrValEmbeddable< + ContactCardEmbeddable, + ContactCardEmbeddableInput + >(refOrValContactCardEmbeddable, { + mockedByReferenceInput: { + savedObjectId: 'testSavedObjectId', + id: refOrValContactCardEmbeddable.id, + }, + mockedByValueInput: { firstName: 'Kibanana', id: refOrValContactCardEmbeddable.id }, + }); + genericEmbeddable = genericContactCardEmbeddable; } }); @@ -90,17 +111,17 @@ test('Clone is incompatible with Error Embeddables', async () => { const errorEmbeddable = new ErrorEmbeddable( 'Wow what an awful error', { id: ' 404' }, - embeddable.getRoot() as IContainer + byRefOrValEmbeddable.getRoot() as IContainer ); expect(await action.isCompatible({ embeddable: errorEmbeddable })).toBe(false); }); test('Clone adds a new embeddable', async () => { - const dashboard = embeddable.getRoot() as IContainer; + const dashboard = byRefOrValEmbeddable.getRoot() as IContainer; const originalPanelCount = Object.keys(dashboard.getInput().panels).length; const originalPanelKeySet = new Set(Object.keys(dashboard.getInput().panels)); const action = new ClonePanelAction(coreStart); - await action.execute({ embeddable }); + await action.execute({ embeddable: byRefOrValEmbeddable }); expect(Object.keys(container.getInput().panels).length).toEqual(originalPanelCount + 1); const newPanelId = Object.keys(container.getInput().panels).find( (key) => !originalPanelKeySet.has(key) @@ -113,56 +134,159 @@ test('Clone adds a new embeddable', async () => { await new Promise((r) => process.nextTick(r)); // Allow the current loop of the event loop to run to completion // now wait for the full embeddable to replace it const loadedPanel = await dashboard.untilEmbeddableLoaded(newPanelId!); - expect(loadedPanel.type).toEqual(embeddable.type); + expect(loadedPanel.type).toEqual(byRefOrValEmbeddable.type); }); -test('Clones an embeddable without a saved object ID', async () => { - const dashboard = embeddable.getRoot() as IContainer; - const panel = dashboard.getInput().panels[embeddable.id] as DashboardPanelState; +test('Clones a RefOrVal embeddable by value', async () => { + const dashboard = byRefOrValEmbeddable.getRoot() as IContainer; + const panel = dashboard.getInput().panels[byRefOrValEmbeddable.id] as DashboardPanelState; const action = new ClonePanelAction(coreStart); // @ts-ignore - const newPanel = await action.cloneEmbeddable(panel, embeddable.type); - expect(newPanel.type).toEqual(embeddable.type); + const newPanel = await action.cloneEmbeddable(panel, byRefOrValEmbeddable); + expect(coreStart.savedObjects.client.get).toHaveBeenCalledTimes(0); + expect(coreStart.savedObjects.client.find).toHaveBeenCalledTimes(0); + expect(coreStart.savedObjects.client.create).toHaveBeenCalledTimes(0); + expect(newPanel.type).toEqual(byRefOrValEmbeddable.type); }); -test('Clones an embeddable with a saved object ID', async () => { - const dashboard = embeddable.getRoot() as IContainer; - const panel = dashboard.getInput().panels[embeddable.id] as DashboardPanelState; +test('Clones a non-RefOrVal embeddable by value if the panel does not have a savedObjectId', async () => { + const dashboard = genericEmbeddable.getRoot() as IContainer; + const panel = dashboard.getInput().panels[genericEmbeddable.id] as DashboardPanelState; + const action = new ClonePanelAction(coreStart); + // @ts-ignore + const newPanelWithoutId = await action.cloneEmbeddable(panel, genericEmbeddable); + expect(coreStart.savedObjects.client.get).toHaveBeenCalledTimes(0); + expect(coreStart.savedObjects.client.find).toHaveBeenCalledTimes(0); + expect(coreStart.savedObjects.client.create).toHaveBeenCalledTimes(0); + expect(newPanelWithoutId.type).toEqual(genericEmbeddable.type); +}); + +test('Clones a non-RefOrVal embeddable by reference if the panel has a savedObjectId', async () => { + const dashboard = genericEmbeddable.getRoot() as IContainer; + const panel = dashboard.getInput().panels[genericEmbeddable.id] as DashboardPanelState; panel.explicitInput.savedObjectId = 'holySavedObjectBatman'; const action = new ClonePanelAction(coreStart); // @ts-ignore - const newPanel = await action.cloneEmbeddable(panel, embeddable.type); + const newPanel = await action.cloneEmbeddable(panel, genericEmbeddable); expect(coreStart.savedObjects.client.get).toHaveBeenCalledTimes(1); expect(coreStart.savedObjects.client.find).toHaveBeenCalledTimes(1); expect(coreStart.savedObjects.client.create).toHaveBeenCalledTimes(1); - expect(newPanel.type).toEqual(embeddable.type); + expect(newPanel.type).toEqual(genericEmbeddable.type); }); -test('Gets a unique title ', async () => { +test('Gets a unique title from the saved objects library', async () => { + const dashboard = genericEmbeddable.getRoot() as IContainer; + const panel = dashboard.getInput().panels[genericEmbeddable.id] as DashboardPanelState; + panel.explicitInput.savedObjectId = 'holySavedObjectBatman'; coreStart.savedObjects.client.find = jest.fn().mockImplementation(({ search }) => { - if (search === '"testFirstTitle"') return { total: 1 }; - else if (search === '"testSecondTitle"') return { total: 41 }; - else if (search === '"testThirdTitle"') return { total: 90 }; + if (search === '"testFirstClone"') { + return { + savedObjects: [ + { + attributes: { title: 'testFirstClone' }, + get: jest.fn().mockReturnValue('testFirstClone'), + }, + ], + total: 1, + }; + } else if (search === '"testBeforePageLimit"') { + return { + savedObjects: [ + { + attributes: { title: 'testBeforePageLimit (copy 9)' }, + get: jest.fn().mockReturnValue('testBeforePageLimit (copy 9)'), + }, + ], + total: 10, + }; + } else if (search === '"testMaxLogic"') { + return { + savedObjects: [ + { + attributes: { title: 'testMaxLogic (copy 10000)' }, + get: jest.fn().mockReturnValue('testMaxLogic (copy 10000)'), + }, + ], + total: 2, + }; + } else if (search === '"testAfterPageLimit"') { + return { total: 11 }; + } }); + + const action = new ClonePanelAction(coreStart); + // @ts-ignore + expect(await action.getCloneTitle(genericEmbeddable, 'testFirstClone')).toEqual( + 'testFirstClone (copy)' + ); + // @ts-ignore + expect(await action.getCloneTitle(genericEmbeddable, 'testBeforePageLimit')).toEqual( + 'testBeforePageLimit (copy 10)' + ); + // @ts-ignore + expect(await action.getCloneTitle(genericEmbeddable, 'testBeforePageLimit (copy 9)')).toEqual( + 'testBeforePageLimit (copy 10)' + ); + // @ts-ignore + expect(await action.getCloneTitle(genericEmbeddable, 'testMaxLogic')).toEqual( + 'testMaxLogic (copy 10001)' + ); + // @ts-ignore + expect(await action.getCloneTitle(genericEmbeddable, 'testAfterPageLimit')).toEqual( + 'testAfterPageLimit (copy 11)' + ); + // @ts-ignore + expect(await action.getCloneTitle(genericEmbeddable, 'testAfterPageLimit (copy 10)')).toEqual( + 'testAfterPageLimit (copy 11)' + ); + // @ts-ignore + expect(await action.getCloneTitle(genericEmbeddable, 'testAfterPageLimit (copy 10000)')).toEqual( + 'testAfterPageLimit (copy 11)' + ); +}); + +test('Gets a unique title from the dashboard', async () => { + const dashboard = genericEmbeddable.getRoot() as DashboardContainer; const action = new ClonePanelAction(coreStart); + // @ts-ignore - expect(await action.getUniqueTitle('testFirstTitle', embeddable.type)).toEqual( - 'testFirstTitle (copy)' + expect(await action.getCloneTitle(byRefOrValEmbeddable, '')).toEqual(''); + + dashboard.getPanelTitles = jest.fn().mockImplementation(() => { + return ['testDuplicateTitle', 'testDuplicateTitle (copy)', 'testUniqueTitle']; + }); + // @ts-ignore + expect(await action.getCloneTitle(byRefOrValEmbeddable, 'testUniqueTitle')).toEqual( + 'testUniqueTitle (copy)' ); // @ts-ignore - expect(await action.getUniqueTitle('testSecondTitle (copy 39)', embeddable.type)).toEqual( - 'testSecondTitle (copy 40)' + expect(await action.getCloneTitle(byRefOrValEmbeddable, 'testDuplicateTitle')).toEqual( + 'testDuplicateTitle (copy 1)' ); + + dashboard.getPanelTitles = jest.fn().mockImplementation(() => { + return ['testDuplicateTitle', 'testDuplicateTitle (copy)'].concat( + Array.from([...Array(39)], (_, index) => `testDuplicateTitle (copy ${index + 1})`) + ); + }); // @ts-ignore - expect(await action.getUniqueTitle('testSecondTitle (copy 20)', embeddable.type)).toEqual( - 'testSecondTitle (copy 40)' + expect(await action.getCloneTitle(byRefOrValEmbeddable, 'testDuplicateTitle')).toEqual( + 'testDuplicateTitle (copy 40)' ); // @ts-ignore - expect(await action.getUniqueTitle('testThirdTitle', embeddable.type)).toEqual( - 'testThirdTitle (copy 89)' + expect(await action.getCloneTitle(byRefOrValEmbeddable, 'testDuplicateTitle (copy 100)')).toEqual( + 'testDuplicateTitle (copy 40)' + ); + + dashboard.getPanelTitles = jest.fn().mockImplementation(() => { + return ['testDuplicateTitle (copy 100)']; + }); + // @ts-ignore + expect(await action.getCloneTitle(byRefOrValEmbeddable, 'testDuplicateTitle')).toEqual( + 'testDuplicateTitle (copy 101)' ); // @ts-ignore - expect(await action.getUniqueTitle('testThirdTitle (copy 10000)', embeddable.type)).toEqual( - 'testThirdTitle (copy 89)' + expect(await action.getCloneTitle(byRefOrValEmbeddable, 'testDuplicateTitle (copy 100)')).toEqual( + 'testDuplicateTitle (copy 101)' ); }); diff --git a/src/plugins/dashboard/public/application/actions/clone_panel_action.tsx b/src/plugins/dashboard/public/application/actions/clone_panel_action.tsx index 829344504b16b1..4b2e1e39818ad3 100644 --- a/src/plugins/dashboard/public/application/actions/clone_panel_action.tsx +++ b/src/plugins/dashboard/public/application/actions/clone_panel_action.tsx @@ -20,6 +20,7 @@ import { EmbeddableInput, SavedObjectEmbeddableInput, isErrorEmbeddable, + isReferenceOrValueEmbeddable, } from '../../services/embeddable'; import { placePanelBeside, @@ -78,7 +79,7 @@ export class ClonePanelAction implements Action { } dashboard.showPlaceholderUntil( - this.cloneEmbeddable(panelToClone, embeddable.type), + this.cloneEmbeddable(panelToClone, embeddable), placePanelBeside, { width: panelToClone.gridData.w, @@ -89,56 +90,106 @@ export class ClonePanelAction implements Action { ); } - private async getUniqueTitle(rawTitle: string, embeddableType: string): Promise { + private async getCloneTitle(embeddable: IEmbeddable, rawTitle: string) { + if (rawTitle === '') return ''; // If + const clonedTag = dashboardClonePanelAction.getClonedTag(); const cloneRegex = new RegExp(`\\(${clonedTag}\\)`, 'g'); const cloneNumberRegex = new RegExp(`\\(${clonedTag} [0-9]+\\)`, 'g'); const baseTitle = rawTitle.replace(cloneNumberRegex, '').replace(cloneRegex, '').trim(); + let similarTitles: string[]; + if ( + isReferenceOrValueEmbeddable(embeddable) || + !_.has(embeddable.getExplicitInput(), 'savedObjectId') + ) { + const dashboard: DashboardContainer = embeddable.getRoot() as DashboardContainer; + similarTitles = _.filter(await dashboard.getPanelTitles(), (title: string) => { + return title.startsWith(baseTitle); + }); + } else { + const perPage = 10; + const similarSavedObjects = await this.core.savedObjects.client.find({ + type: embeddable.type, + perPage, + fields: ['title'], + searchFields: ['title'], + search: `"${baseTitle}"`, + }); + if (similarSavedObjects.total <= perPage) { + similarTitles = similarSavedObjects.savedObjects.map((savedObject) => { + return savedObject.get('title'); + }); + } else { + similarTitles = [baseTitle + ` (${clonedTag} ${similarSavedObjects.total - 1})`]; + } + } - const similarSavedObjects = await this.core.savedObjects.client.find({ - type: embeddableType, - perPage: 0, - fields: ['title'], - searchFields: ['title'], - search: `"${baseTitle}"`, + const cloneNumbers = _.map(similarTitles, (title: string) => { + if (title.match(cloneRegex)) return 0; + const cloneTag = title.match(cloneNumberRegex); + return cloneTag ? parseInt(cloneTag[0].replace(/[^0-9.]/g, ''), 10) : -1; }); - const similarBaseTitlesCount: number = similarSavedObjects.total - 1; + const similarBaseTitlesCount = _.max(cloneNumbers) || 0; - return similarBaseTitlesCount <= 0 + return similarBaseTitlesCount < 0 ? baseTitle + ` (${clonedTag})` - : baseTitle + ` (${clonedTag} ${similarBaseTitlesCount})`; + : baseTitle + ` (${clonedTag} ${similarBaseTitlesCount + 1})`; + } + + private async addCloneToLibrary( + embeddable: IEmbeddable, + objectIdToClone: string + ): Promise { + const savedObjectToClone = await this.core.savedObjects.client.get( + embeddable.type, + objectIdToClone + ); + + // Clone the saved object + const newTitle = await this.getCloneTitle(embeddable, savedObjectToClone.attributes.title); + const clonedSavedObject = await this.core.savedObjects.client.create( + embeddable.type, + { + ..._.cloneDeep(savedObjectToClone.attributes), + title: newTitle, + }, + { references: _.cloneDeep(savedObjectToClone.references) } + ); + return clonedSavedObject.id; } private async cloneEmbeddable( panelToClone: DashboardPanelState, - embeddableType: string + embeddable: IEmbeddable ): Promise> { - const panelState: PanelState = { - type: embeddableType, - explicitInput: { - ...panelToClone.explicitInput, - id: uuid.v4(), - }, - }; - let newTitle: string = ''; - if (panelToClone.explicitInput.savedObjectId) { - // Fetch existing saved object - const savedObjectToClone = await this.core.savedObjects.client.get( - embeddableType, - panelToClone.explicitInput.savedObjectId - ); - - // Clone the saved object - newTitle = await this.getUniqueTitle(savedObjectToClone.attributes.title, embeddableType); - const clonedSavedObject = await this.core.savedObjects.client.create( - embeddableType, - { - ..._.cloneDeep(savedObjectToClone.attributes), + let panelState: PanelState; + if (isReferenceOrValueEmbeddable(embeddable)) { + const newTitle = await this.getCloneTitle(embeddable, embeddable.getTitle() || ''); + panelState = { + type: embeddable.type, + explicitInput: { + ...(await embeddable.getInputAsValueType()), + id: uuid.v4(), title: newTitle, + hidePanelTitles: panelToClone.explicitInput.hidePanelTitles, + }, + }; + } else { + panelState = { + type: embeddable.type, + explicitInput: { + ...panelToClone.explicitInput, + id: uuid.v4(), }, - { references: _.cloneDeep(savedObjectToClone.references) } - ); - (panelState.explicitInput as SavedObjectEmbeddableInput).savedObjectId = clonedSavedObject.id; + }; + if (panelToClone.explicitInput.savedObjectId) { + const clonedSavedObjectId = await this.addCloneToLibrary( + embeddable, + panelToClone.explicitInput.savedObjectId + ); + (panelState.explicitInput as SavedObjectEmbeddableInput).savedObjectId = + clonedSavedObjectId; + } } this.core.notifications.toasts.addSuccess({ title: dashboardClonePanelAction.getSuccessMessage(), diff --git a/src/plugins/dashboard/public/application/actions/unlink_from_library_action.tsx b/src/plugins/dashboard/public/application/actions/unlink_from_library_action.tsx index 68a5950269517e..4eae24bc892f75 100644 --- a/src/plugins/dashboard/public/application/actions/unlink_from_library_action.tsx +++ b/src/plugins/dashboard/public/application/actions/unlink_from_library_action.tsx @@ -79,9 +79,6 @@ export class UnlinkFromLibraryAction implements Action { + const titles: string[] = []; + const ids: string[] = Object.keys(this.getInput().panels); + for (const panelId of ids) { + await this.untilEmbeddableLoaded(panelId); + const child: IEmbeddable = this.getChild(panelId); + const title = child.getTitle(); + if (title) { + titles.push(title); + } + } + return titles; + } + constructor( initialInput: DashboardContainerInput, private readonly services: DashboardContainerServices, diff --git a/src/plugins/embeddable/public/lib/attribute_service/attribute_service.tsx b/src/plugins/embeddable/public/lib/attribute_service/attribute_service.tsx index 3826162aa65900..81b836796d31d0 100644 --- a/src/plugins/embeddable/public/lib/attribute_service/attribute_service.tsx +++ b/src/plugins/embeddable/public/lib/attribute_service/attribute_service.tsx @@ -137,10 +137,14 @@ export class AttributeService< return input as ValType; } const { attributes } = await this.unwrapAttributes(input); + const libraryTitle = attributes.title; const { savedObjectId, ...originalInputToPropagate } = input; + return { ...originalInputToPropagate, - attributes, + // by value visualizations should not have default titles and/or descriptions + ...{ attributes: omit(attributes, ['title', 'description']) }, + title: libraryTitle, } as unknown as ValType; }; diff --git a/src/plugins/visualizations/public/embeddable/visualize_embeddable.tsx b/src/plugins/visualizations/public/embeddable/visualize_embeddable.tsx index 9c328a175c10b6..c3b8834605d1d6 100644 --- a/src/plugins/visualizations/public/embeddable/visualize_embeddable.tsx +++ b/src/plugins/visualizations/public/embeddable/visualize_embeddable.tsx @@ -455,10 +455,8 @@ export class VisualizeEmbeddable const input = { savedVis: this.vis.serialize(), }; - if (this.getTitle()) { - input.savedVis.title = this.getTitle(); - } delete input.savedVis.id; + _.unset(input, 'savedVis.title'); return new Promise((resolve) => { resolve({ ...(input as VisualizeByValueInput) }); }); diff --git a/test/functional/apps/dashboard/panel_cloning.ts b/test/functional/apps/dashboard/panel_cloning.ts index 1be9175e45ad9d..a2cadd89f486ae 100644 --- a/test/functional/apps/dashboard/panel_cloning.ts +++ b/test/functional/apps/dashboard/panel_cloning.ts @@ -13,6 +13,7 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ getService, getPageObjects }: FtrProviderContext) { const dashboardPanelActions = getService('dashboardPanelActions'); const dashboardAddPanel = getService('dashboardAddPanel'); + const testSubjects = getService('testSubjects'); const PageObjects = getPageObjects([ 'dashboard', 'header', @@ -53,6 +54,16 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { expect(panelDimensions[0]).to.eql(panelDimensions[1]); }); + it('clone of a by reference embeddable is by value', async () => { + const panelName = PIE_CHART_VIS_NAME.replace(/\s+/g, ''); + const clonedPanel = await testSubjects.find(`embeddablePanelHeading-${panelName}(copy)`); + const descendants = await testSubjects.findAllDescendant( + 'embeddablePanelNotification-ACTION_LIBRARY_NOTIFICATION', + clonedPanel + ); + expect(descendants.length).to.equal(0); + }); + it('gives a correct title to the clone of a clone', async () => { const initialPanelTitles = await PageObjects.dashboard.getPanelTitles(); const clonedPanelName = initialPanelTitles[initialPanelTitles.length - 1]; @@ -65,5 +76,15 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { PIE_CHART_VIS_NAME + ' (copy 1)' ); }); + + it('clone of a by value embeddable is by value', async () => { + const panelName = PIE_CHART_VIS_NAME.replace(/\s+/g, ''); + const clonedPanel = await testSubjects.find(`embeddablePanelHeading-${panelName}(copy1)`); + const descendants = await testSubjects.findAllDescendant( + 'embeddablePanelNotification-ACTION_LIBRARY_NOTIFICATION', + clonedPanel + ); + expect(descendants.length).to.equal(0); + }); }); } From c5aa390f1ce2e9677886aa10dd0a73b7e0fde664 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20S=C3=A1nchez?= Date: Thu, 20 Jan 2022 16:45:33 +0100 Subject: [PATCH 079/108] [Security Solution][Endpoint] Prevent event filter list to be created twice from policy details page. (#123350) * Adds new module with service actions to be used in the service class and in the hooks without using the class. Also marks the class as deprecated. * New service actions to be used in service class and hooks Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../pages/event_filters/service/index.ts | 108 +++---------- .../event_filters/service/service_actions.ts | 148 ++++++++++++++++++ ...policy_event_filters_delete_modal.test.tsx | 4 +- .../policy_event_filters_flyout.test.tsx | 4 +- .../pages/policy/view/event_filters/hooks.ts | 31 ++-- 5 files changed, 185 insertions(+), 110 deletions(-) create mode 100644 x-pack/plugins/security_solution/public/management/pages/event_filters/service/service_actions.ts diff --git a/x-pack/plugins/security_solution/public/management/pages/event_filters/service/index.ts b/x-pack/plugins/security_solution/public/management/pages/event_filters/service/index.ts index e5c7a35d89c001..6145f869a660ad 100644 --- a/x-pack/plugins/security_solution/public/management/pages/event_filters/service/index.ts +++ b/x-pack/plugins/security_solution/public/management/pages/event_filters/service/index.ts @@ -13,36 +13,25 @@ import type { UpdateExceptionListItemSchema, ExceptionListSummarySchema, } from '@kbn/securitysolution-io-ts-list-types'; -import { ENDPOINT_EVENT_FILTERS_LIST_ID } from '@kbn/securitysolution-list-constants'; import { Immutable } from '../../../../../common/endpoint/types'; -import { EVENT_FILTER_LIST, EXCEPTION_LIST_ITEM_URL, EXCEPTION_LIST_URL } from '../constants'; import { EventFiltersService } from '../types'; - +import { + addEventFilters, + getList, + getOne, + updateOne, + deleteOne, + getSummary, +} from './service_actions'; + +/** + * @deprecated Don't use this class for future implementations, use the service_actions module instead! + */ export class EventFiltersHttpService implements EventFiltersService { - private listHasBeenCreated: boolean; - constructor(private http: HttpStart) { - this.listHasBeenCreated = false; - } - - private async createEndpointEventList() { - try { - await this.http.post(EXCEPTION_LIST_URL, { - body: JSON.stringify(EVENT_FILTER_LIST), - }); - this.listHasBeenCreated = true; - } catch (err) { - // Ignore 409 errors. List already created - if (err.response.status === 409) this.listHasBeenCreated = true; - else throw err; - } - } - - private async httpWrapper() { - if (!this.listHasBeenCreated) await this.createEndpointEventList(); - return this.http; + this.http = http; } async getList({ @@ -58,87 +47,28 @@ export class EventFiltersHttpService implements EventFiltersService { sortOrder: string; filter: string; }> = {}): Promise { - const http = await this.httpWrapper(); - return http.get(`${EXCEPTION_LIST_ITEM_URL}/_find`, { - query: { - page, - per_page: perPage, - sort_field: sortField, - sort_order: sortOrder, - list_id: [ENDPOINT_EVENT_FILTERS_LIST_ID], - namespace_type: ['agnostic'], - filter, - }, - }); + return getList({ http: this.http, perPage, page, sortField, sortOrder, filter }); } async addEventFilters(exception: ExceptionListItemSchema | CreateExceptionListItemSchema) { - return (await this.httpWrapper()).post(EXCEPTION_LIST_ITEM_URL, { - body: JSON.stringify(exception), - }); + return addEventFilters(this.http, exception); } async getOne(id: string) { - return (await this.httpWrapper()).get(EXCEPTION_LIST_ITEM_URL, { - query: { - id, - namespace_type: 'agnostic', - }, - }); + return getOne(this.http, id); } async updateOne( exception: Immutable ): Promise { - return (await this.httpWrapper()).put(EXCEPTION_LIST_ITEM_URL, { - body: JSON.stringify(EventFiltersHttpService.cleanEventFilterToUpdate(exception)), - }); + return updateOne(this.http, exception); } async deleteOne(id: string): Promise { - return (await this.httpWrapper()).delete(EXCEPTION_LIST_ITEM_URL, { - query: { - id, - namespace_type: 'agnostic', - }, - }); + return deleteOne(this.http, id); } async getSummary(): Promise { - return (await this.httpWrapper()).get( - `${EXCEPTION_LIST_URL}/summary`, - { - query: { - list_id: ENDPOINT_EVENT_FILTERS_LIST_ID, - namespace_type: 'agnostic', - }, - } - ); - } - - static cleanEventFilterToUpdate( - exception: Immutable - ): UpdateExceptionListItemSchema { - const exceptionToUpdateCleaned = { ...exception }; - // Clean unnecessary fields for update action - [ - 'created_at', - 'created_by', - 'created_at', - 'created_by', - 'list_id', - 'tie_breaker_id', - 'updated_at', - 'updated_by', - ].forEach((field) => { - delete exceptionToUpdateCleaned[field as keyof UpdateExceptionListItemSchema]; - }); - - exceptionToUpdateCleaned.comments = exceptionToUpdateCleaned.comments?.map((comment) => ({ - comment: comment.comment, - id: comment.id, - })); - - return exceptionToUpdateCleaned as UpdateExceptionListItemSchema; + return getSummary(this.http); } } diff --git a/x-pack/plugins/security_solution/public/management/pages/event_filters/service/service_actions.ts b/x-pack/plugins/security_solution/public/management/pages/event_filters/service/service_actions.ts new file mode 100644 index 00000000000000..19c56cb5fed903 --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/pages/event_filters/service/service_actions.ts @@ -0,0 +1,148 @@ +/* + * 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 { + CreateExceptionListItemSchema, + ExceptionListItemSchema, + ExceptionListSummarySchema, + FoundExceptionListItemSchema, + UpdateExceptionListItemSchema, +} from '@kbn/securitysolution-io-ts-list-types'; +import { HttpStart } from 'kibana/public'; +import { + EXCEPTION_LIST_ITEM_URL, + EXCEPTION_LIST_URL, + EVENT_FILTER_LIST, + ENDPOINT_EVENT_FILTERS_LIST_ID, +} from '../constants'; +import { Immutable } from '../../../../../common/endpoint/types'; + +async function createEventFilterList(http: HttpStart): Promise { + try { + await http.post(EXCEPTION_LIST_URL, { + body: JSON.stringify(EVENT_FILTER_LIST), + }); + } catch (err) { + // Ignore 409 errors. List already created + if (err.response?.status !== 409) { + throw err; + } + } +} + +let listExistsPromise: Promise; +export async function ensureEventFiltersListExists(http: HttpStart): Promise { + if (!listExistsPromise) { + listExistsPromise = createEventFilterList(http); + } + await listExistsPromise; +} + +export async function getList({ + http, + perPage, + page, + sortField, + sortOrder, + filter, +}: { + http: HttpStart; + page?: number; + perPage?: number; + sortField?: string; + sortOrder?: string; + filter?: string; +}): Promise { + await ensureEventFiltersListExists(http); + return http.get(`${EXCEPTION_LIST_ITEM_URL}/_find`, { + query: { + page, + per_page: perPage, + sort_field: sortField, + sort_order: sortOrder, + list_id: [ENDPOINT_EVENT_FILTERS_LIST_ID], + namespace_type: ['agnostic'], + filter, + }, + }); +} + +export async function addEventFilters( + http: HttpStart, + exception: ExceptionListItemSchema | CreateExceptionListItemSchema +) { + await ensureEventFiltersListExists(http); + return http.post(EXCEPTION_LIST_ITEM_URL, { + body: JSON.stringify(exception), + }); +} + +export async function getOne(http: HttpStart, id: string) { + await ensureEventFiltersListExists(http); + return http.get(EXCEPTION_LIST_ITEM_URL, { + query: { + id, + namespace_type: 'agnostic', + }, + }); +} + +export async function updateOne( + http: HttpStart, + exception: Immutable +): Promise { + await ensureEventFiltersListExists(http); + return http.put(EXCEPTION_LIST_ITEM_URL, { + body: JSON.stringify(cleanEventFilterToUpdate(exception)), + }); +} + +export async function deleteOne(http: HttpStart, id: string): Promise { + await ensureEventFiltersListExists(http); + return http.delete(EXCEPTION_LIST_ITEM_URL, { + query: { + id, + namespace_type: 'agnostic', + }, + }); +} + +export async function getSummary(http: HttpStart): Promise { + await ensureEventFiltersListExists(http); + return http.get(`${EXCEPTION_LIST_URL}/summary`, { + query: { + list_id: ENDPOINT_EVENT_FILTERS_LIST_ID, + namespace_type: 'agnostic', + }, + }); +} + +export function cleanEventFilterToUpdate( + exception: Immutable +): UpdateExceptionListItemSchema { + const exceptionToUpdateCleaned = { ...exception }; + // Clean unnecessary fields for update action + [ + 'created_at', + 'created_by', + 'created_at', + 'created_by', + 'list_id', + 'tie_breaker_id', + 'updated_at', + 'updated_by', + ].forEach((field) => { + delete exceptionToUpdateCleaned[field as keyof UpdateExceptionListItemSchema]; + }); + + exceptionToUpdateCleaned.comments = exceptionToUpdateCleaned.comments?.map((comment) => ({ + comment: comment.comment, + id: comment.id, + })); + + return exceptionToUpdateCleaned as UpdateExceptionListItemSchema; +} diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/event_filters/delete_modal/policy_event_filters_delete_modal.test.tsx b/x-pack/plugins/security_solution/public/management/pages/policy/view/event_filters/delete_modal/policy_event_filters_delete_modal.test.tsx index 6711b48326bbf3..20522e35e89839 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/view/event_filters/delete_modal/policy_event_filters_delete_modal.test.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/policy/view/event_filters/delete_modal/policy_event_filters_delete_modal.test.tsx @@ -17,7 +17,7 @@ import { } from '../../../../../../common/mock/endpoint'; import { PolicyEventFiltersDeleteModal } from './policy_event_filters_delete_modal'; import { eventFiltersListQueryHttpMock } from '../../../../event_filters/test_utils'; -import { EventFiltersHttpService } from '../../../../event_filters/service'; +import { cleanEventFilterToUpdate } from '../../../../event_filters/service/service_actions'; describe('Policy details event filter delete modal', () => { let policyId: string; @@ -73,7 +73,7 @@ describe('Policy details event filter delete modal', () => { await waitFor(() => { expect(mockedApi.responseProvider.eventFiltersUpdateOne).toHaveBeenLastCalledWith({ body: JSON.stringify( - EventFiltersHttpService.cleanEventFilterToUpdate({ + cleanEventFilterToUpdate({ ...exception, tags: ['policy:1234', 'policy:4321', 'not-a-policy-tag'], }) diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/event_filters/flyout/policy_event_filters_flyout.test.tsx b/x-pack/plugins/security_solution/public/management/pages/policy/view/event_filters/flyout/policy_event_filters_flyout.test.tsx index ef1cbc81637056..7d984cdb2a382a 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/view/event_filters/flyout/policy_event_filters_flyout.test.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/policy/view/event_filters/flyout/policy_event_filters_flyout.test.tsx @@ -25,7 +25,7 @@ import { FoundExceptionListItemSchema, UpdateExceptionListItemSchema, } from '@kbn/securitysolution-io-ts-list-types'; -import { EventFiltersHttpService } from '../../../../event_filters/service'; +import { cleanEventFilterToUpdate } from '../../../../event_filters/service/service_actions'; const getDefaultQueryParameters = (customFilter: string | undefined = '') => ({ path: '/api/exception_lists/items/_find', @@ -56,7 +56,7 @@ const getCleanedExceptionWithNewTags = ( tags: [...testTags, `policy:${policy.id}`], }; - return EventFiltersHttpService.cleanEventFilterToUpdate(exceptionToUpdateWithNewTags); + return cleanEventFilterToUpdate(exceptionToUpdateWithNewTags); }; describe('Policy details event filters flyout', () => { diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/event_filters/hooks.ts b/x-pack/plugins/security_solution/public/management/pages/policy/view/event_filters/hooks.ts index fd5e00668c1646..24e3cb464d4d3c 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/view/event_filters/hooks.ts +++ b/x-pack/plugins/security_solution/public/management/pages/policy/view/event_filters/hooks.ts @@ -4,7 +4,6 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { useMemo } from 'react'; import pMap from 'p-map'; import { ExceptionListItemSchema, @@ -13,24 +12,20 @@ import { import { QueryObserverResult, useMutation, useQuery, useQueryClient } from 'react-query'; import { ServerApiError } from '../../../../../common/types'; import { useHttp } from '../../../../../common/lib/kibana'; -import { EventFiltersHttpService } from '../../../event_filters/service'; +import { getList, updateOne } from '../../../event_filters/service/service_actions'; import { parseQueryFilterToKQL, parsePoliciesAndFilterToKql } from '../../../../common/utils'; import { SEARCHABLE_FIELDS } from '../../../event_filters/constants'; -export function useGetEventFiltersService() { - const http = useHttp(); - return useMemo(() => new EventFiltersHttpService(http), [http]); -} - export function useGetAllAssignedEventFilters( policyId: string, enabled: boolean = true ): QueryObserverResult { - const service = useGetEventFiltersService(); + const http = useHttp(); return useQuery( ['eventFilters', 'assigned', policyId], () => { - return service.getList({ + return getList({ + http, filter: parsePoliciesAndFilterToKql({ policies: [...(policyId ? [policyId] : []), 'all'] }), }); }, @@ -48,13 +43,14 @@ export function useSearchAssignedEventFilters( policyId: string, options: { filter?: string; page?: number; perPage?: number } ): QueryObserverResult { - const service = useGetEventFiltersService(); + const http = useHttp(); const { filter, page, perPage } = options; return useQuery( ['eventFilters', 'assigned', 'search', policyId, options], () => { - return service.getList({ + return getList({ + http, filter: parsePoliciesAndFilterToKql({ policies: [policyId, 'all'], kuery: parseQueryFilterToKQL(filter || '', SEARCHABLE_FIELDS), @@ -75,13 +71,14 @@ export function useSearchNotAssignedEventFilters( policyId: string, options: { filter?: string; perPage?: number; enabled?: boolean } ): QueryObserverResult { - const service = useGetEventFiltersService(); + const http = useHttp(); return useQuery( ['eventFilters', 'notAssigned', policyId, options], () => { const { filter, perPage } = options; - return service.getList({ + return getList({ + http, filter: parsePoliciesAndFilterToKql({ excludedPolicies: [policyId, 'all'], kuery: parseQueryFilterToKQL(filter || '', SEARCHABLE_FIELDS), @@ -106,7 +103,7 @@ export function useBulkUpdateEventFilters( onSettledCallback?: () => void; } = {} ) { - const service = useGetEventFiltersService(); + const http = useHttp(); const queryClient = useQueryClient(); const { @@ -125,7 +122,7 @@ export function useBulkUpdateEventFilters( return pMap( eventFilters, (eventFilter) => { - return service.updateOne(eventFilter); + return updateOne(http, eventFilter); }, { concurrency: 5, @@ -148,11 +145,11 @@ export function useGetAllEventFilters(): QueryObserverResult< FoundExceptionListItemSchema, ServerApiError > { - const service = useGetEventFiltersService(); + const http = useHttp(); return useQuery( ['eventFilters', 'all'], () => { - return service.getList(); + return getList({ http }); }, { refetchIntervalInBackground: false, From 067da143b6eba6802dbe00d26384e1c6482bd308 Mon Sep 17 00:00:00 2001 From: Justin Kambic Date: Thu, 20 Jan 2022 11:42:13 -0500 Subject: [PATCH 080/108] Make duration line series use `local` for time zone value. (#123470) --- .../components/common/charts/duration_line_series_list.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/x-pack/plugins/uptime/public/components/common/charts/duration_line_series_list.tsx b/x-pack/plugins/uptime/public/components/common/charts/duration_line_series_list.tsx index adb76d4cbc8ac8..bc744be1632239 100644 --- a/x-pack/plugins/uptime/public/components/common/charts/duration_line_series_list.tsx +++ b/x-pack/plugins/uptime/public/components/common/charts/duration_line_series_list.tsx @@ -31,6 +31,7 @@ export const DurationLineSeriesList = ({ monitorType, lines }: Props) => ( yAccessors={[1]} yScaleType={ScaleType.Linear} fit={Fit.Linear} + timeZone="local" tickFormat={(d) => monitorType === 'browser' ? `${microToSec(d)} ${SEC_LABEL}` From 8b2c40bcb53736ede457dd9f944c1c4b196c524b Mon Sep 17 00:00:00 2001 From: Lisa Cawley Date: Thu, 20 Jan 2022 09:03:56 -0800 Subject: [PATCH 081/108] Update more ML URLs in doc link service (#123432) --- src/core/public/doc_links/doc_links_service.ts | 18 +++++++++--------- .../ml/common/constants/messages.test.ts | 18 +++++++++--------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/core/public/doc_links/doc_links_service.ts b/src/core/public/doc_links/doc_links_service.ts index 4db97c1b9e256b..b85572e650f269 100644 --- a/src/core/public/doc_links/doc_links_service.ts +++ b/src/core/public/doc_links/doc_links_service.ts @@ -350,19 +350,19 @@ export class DocLinksService { anomalyDetection: `${ELASTIC_WEBSITE_URL}guide/en/machine-learning/${DOC_LINK_VERSION}/ml-ad-overview.html`, anomalyDetectionJobs: `${ELASTIC_WEBSITE_URL}guide/en/machine-learning/${DOC_LINK_VERSION}/ml-ad-finding-anomalies.html`, anomalyDetectionConfiguringCategories: `${ELASTIC_WEBSITE_URL}guide/en/machine-learning/${DOC_LINK_VERSION}/ml-configuring-categories.html`, - anomalyDetectionBucketSpan: `${ELASTIC_WEBSITE_URL}guide/en/machine-learning/${DOC_LINK_VERSION}/ml-ad-finding-anomalies.html`, - anomalyDetectionCardinality: `${ELASTIC_WEBSITE_URL}guide/en/machine-learning/${DOC_LINK_VERSION}/ml-ad-finding-anomalies.html`, - anomalyDetectionCreateJobs: `${ELASTIC_WEBSITE_URL}guide/en/machine-learning/${DOC_LINK_VERSION}/ml-ad-finding-anomalies.html`, - anomalyDetectionDetectors: `${ELASTIC_WEBSITE_URL}guide/en/machine-learning/${DOC_LINK_VERSION}/ml-ad-finding-anomalies.html`, - anomalyDetectionInfluencers: `${ELASTIC_WEBSITE_URL}guide/en/machine-learning/${DOC_LINK_VERSION}/ml-ad-finding-anomalies.html`, + anomalyDetectionBucketSpan: `${ELASTIC_WEBSITE_URL}guide/en/machine-learning/${DOC_LINK_VERSION}/ml-ad-run-jobs.html#ml-ad-bucket-span`, + anomalyDetectionCardinality: `${ELASTIC_WEBSITE_URL}guide/en/machine-learning/${DOC_LINK_VERSION}/ml-ad-run-jobs.html#ml-ad-cardinality`, + anomalyDetectionCreateJobs: `${ELASTIC_WEBSITE_URL}guide/en/machine-learning/${DOC_LINK_VERSION}/ml-ad-run-jobs.html#ml-ad-create-job`, + anomalyDetectionDetectors: `${ELASTIC_WEBSITE_URL}guide/en/machine-learning/${DOC_LINK_VERSION}/ml-ad-run-jobs.html#ml-ad-detectors`, + anomalyDetectionInfluencers: `${ELASTIC_WEBSITE_URL}guide/en/machine-learning/${DOC_LINK_VERSION}/ml-ad-run-jobs.html#ml-ad-influencers`, anomalyDetectionJobResource: `${ELASTICSEARCH_DOCS}ml-put-job.html#ml-put-job-path-parms`, anomalyDetectionJobResourceAnalysisConfig: `${ELASTICSEARCH_DOCS}ml-put-job.html#put-analysisconfig`, - anomalyDetectionJobTips: `${ELASTIC_WEBSITE_URL}guide/en/machine-learning/${DOC_LINK_VERSION}/ml-ad-finding-anomalies.html`, + anomalyDetectionJobTips: `${ELASTIC_WEBSITE_URL}guide/en/machine-learning/${DOC_LINK_VERSION}/ml-ad-run-jobs.html#ml-ad-job-tips`, alertingRules: `${ELASTIC_WEBSITE_URL}guide/en/machine-learning/${DOC_LINK_VERSION}/ml-configuring-alerts.html`, - anomalyDetectionModelMemoryLimits: `${ELASTIC_WEBSITE_URL}guide/en/machine-learning/${DOC_LINK_VERSION}/ml-ad-finding-anomalies.html`, - calendars: `${ELASTIC_WEBSITE_URL}guide/en/machine-learning/${DOC_LINK_VERSION}/ml-ad-finding-anomalies.html`, + anomalyDetectionModelMemoryLimits: `${ELASTIC_WEBSITE_URL}guide/en/machine-learning/${DOC_LINK_VERSION}/ml-ad-run-jobs.html#ml-ad-model-memory-limits`, + calendars: `${ELASTIC_WEBSITE_URL}guide/en/machine-learning/${DOC_LINK_VERSION}/ml-ad-run-jobs.html#ml-ad-calendars`, classificationEvaluation: `${ELASTIC_WEBSITE_URL}guide/en/machine-learning/${DOC_LINK_VERSION}/ml-dfa-classification.html#ml-dfanalytics-classification-evaluation`, - customRules: `${ELASTIC_WEBSITE_URL}guide/en/machine-learning/${DOC_LINK_VERSION}/ml-ad-finding-anomalies.html`, + customRules: `${ELASTIC_WEBSITE_URL}guide/en/machine-learning/${DOC_LINK_VERSION}/ml-ad-run-jobs.html#ml-ad-rules`, customUrls: `${ELASTIC_WEBSITE_URL}guide/en/machine-learning/${DOC_LINK_VERSION}/ml-configuring-url.html`, dataFrameAnalytics: `${ELASTIC_WEBSITE_URL}guide/en/machine-learning/${DOC_LINK_VERSION}/ml-dfanalytics.html`, featureImportance: `${ELASTIC_WEBSITE_URL}guide/en/machine-learning/${DOC_LINK_VERSION}/ml-feature-importance.html`, diff --git a/x-pack/plugins/ml/common/constants/messages.test.ts b/x-pack/plugins/ml/common/constants/messages.test.ts index 13ef103ae0ff17..e77de53b5cb700 100644 --- a/x-pack/plugins/ml/common/constants/messages.test.ts +++ b/x-pack/plugins/ml/common/constants/messages.test.ts @@ -32,7 +32,7 @@ describe('Constants: Messages parseMessages()', () => { id: 'detectors_function_not_empty', status: 'success', text: 'Presence of detector functions validated in all detectors.', - url: 'https://www.elastic.co/guide/en/machine-learning/mocked-test-branch/ml-ad-finding-anomalies.html', + url: 'https://www.elastic.co/guide/en/machine-learning/mocked-test-branch/ml-ad-run-jobs.html#ml-ad-detectors', }, { bucketSpan: '15m', @@ -40,7 +40,7 @@ describe('Constants: Messages parseMessages()', () => { id: 'success_bucket_span', status: 'success', text: 'Format of "15m" is valid and passed validation checks.', - url: 'https://www.elastic.co/guide/en/machine-learning/mocked-test-branch/ml-ad-finding-anomalies.html', + url: 'https://www.elastic.co/guide/en/machine-learning/mocked-test-branch/ml-ad-run-jobs.html#ml-ad-bucket-span', }, { heading: 'Time range', @@ -53,7 +53,7 @@ describe('Constants: Messages parseMessages()', () => { id: 'success_mml', status: 'success', text: 'Valid and within the estimated model memory limit.', - url: 'https://www.elastic.co/guide/en/machine-learning/mocked-test-branch/ml-ad-finding-anomalies.html', + url: 'https://www.elastic.co/guide/en/machine-learning/mocked-test-branch/ml-ad-run-jobs.html#ml-ad-model-memory-limits', }, ]); }); @@ -71,7 +71,7 @@ describe('Constants: Messages parseMessages()', () => { id: 'detectors_function_not_empty', status: 'success', text: 'Presence of detector functions validated in all detectors.', - url: 'https://www.elastic.co/guide/en/machine-learning/mocked-test-branch/ml-ad-finding-anomalies.html', + url: 'https://www.elastic.co/guide/en/machine-learning/mocked-test-branch/ml-ad-run-jobs.html#ml-ad-detectors', }, { bucketSpan: '15m', @@ -103,7 +103,7 @@ describe('Constants: Messages parseMessages()', () => { id: 'detectors_function_not_empty', status: 'success', text: 'Presence of detector functions validated in all detectors.', - url: 'https://www.elastic.co/guide/en/machine-learning/mocked-test-branch/ml-ad-finding-anomalies.html', + url: 'https://www.elastic.co/guide/en/machine-learning/mocked-test-branch/ml-ad-run-jobs.html#ml-ad-detectors', }, { id: 'cardinality_model_plot_high', @@ -115,14 +115,14 @@ describe('Constants: Messages parseMessages()', () => { id: 'cardinality_partition_field', status: 'warning', text: 'Cardinality of partition_field "order_id" is above 1000 and might result in high memory usage.', - url: 'https://www.elastic.co/guide/en/machine-learning/mocked-test-branch/ml-ad-finding-anomalies.html', + url: 'https://www.elastic.co/guide/en/machine-learning/mocked-test-branch/ml-ad-run-jobs.html#ml-ad-cardinality', }, { heading: 'Bucket span', id: 'bucket_span_high', status: 'info', text: 'Bucket span is 1 day or more. Be aware that days are considered as UTC days, not local days.', - url: 'https://www.elastic.co/guide/en/machine-learning/mocked-test-branch/ml-ad-finding-anomalies.html', + url: 'https://www.elastic.co/guide/en/machine-learning/mocked-test-branch/ml-ad-run-jobs.html#ml-ad-bucket-span', }, { bucketSpanCompareFactor: 25, @@ -136,14 +136,14 @@ describe('Constants: Messages parseMessages()', () => { id: 'success_influencers', status: 'success', text: 'Influencer configuration passed the validation checks.', - url: 'https://www.elastic.co/guide/en/machine-learning/mocked-test-branch/ml-ad-finding-anomalies.html', + url: 'https://www.elastic.co/guide/en/machine-learning/mocked-test-branch/ml-ad-run-jobs.html#ml-ad-influencers', }, { id: 'half_estimated_mml_greater_than_mml', mml: '1MB', status: 'warning', text: 'The specified model memory limit is less than half of the estimated model memory limit and will likely hit the hard limit.', - url: 'https://www.elastic.co/guide/en/machine-learning/mocked-test-branch/ml-ad-finding-anomalies.html', + url: 'https://www.elastic.co/guide/en/machine-learning/mocked-test-branch/ml-ad-run-jobs.html#ml-ad-model-memory-limits', }, { id: 'missing_summary_count_field_name', From f4046b7f56f78a8e547d2e80cdf09ecf7c6e455b Mon Sep 17 00:00:00 2001 From: Michael Dokolin Date: Thu, 20 Jan 2022 18:06:09 +0100 Subject: [PATCH 082/108] [Reporting] Add deprecation flag for v1 PDF and PNG export types (#123235) * Rename deprecated reporting jobs parameters interfaces * Add deprecation flag to the deprecated reporting jobs payloads --- .../common/types/export_types/png.ts | 5 +++- .../types/export_types/printable_pdf.ts | 7 +++-- .../plugins/reporting/common/types/index.ts | 4 +-- .../export_types/png/create_job/index.ts | 20 +++++++------ .../server/export_types/png/index.ts | 4 +-- .../server/export_types/png/types.ts | 5 +++- .../printable_pdf/create_job/index.ts | 28 ++++++++++--------- .../export_types/printable_pdf/index.ts | 4 +-- .../export_types/printable_pdf/types.ts | 2 +- .../server/routes/lib/request_handler.test.ts | 7 +++-- .../services/scenarios.ts | 8 +++--- 11 files changed, 54 insertions(+), 40 deletions(-) diff --git a/x-pack/plugins/reporting/common/types/export_types/png.ts b/x-pack/plugins/reporting/common/types/export_types/png.ts index 5afde424127a14..635de9823c8b30 100644 --- a/x-pack/plugins/reporting/common/types/export_types/png.ts +++ b/x-pack/plugins/reporting/common/types/export_types/png.ts @@ -15,7 +15,10 @@ interface BaseParamsPNG { } // Job params: structure of incoming user request data -export type JobParamsPNG = BaseParamsPNG & BaseParams; +/** + * @deprecated + */ +export type JobParamsPNGDeprecated = BaseParamsPNG & BaseParams; // Job payload: structure of stored job data provided by create_job export type TaskPayloadPNG = BaseParamsPNG & BasePayload; diff --git a/x-pack/plugins/reporting/common/types/export_types/printable_pdf.ts b/x-pack/plugins/reporting/common/types/export_types/printable_pdf.ts index 55a686cc829bed..d5b8ec21cc13b5 100644 --- a/x-pack/plugins/reporting/common/types/export_types/printable_pdf.ts +++ b/x-pack/plugins/reporting/common/types/export_types/printable_pdf.ts @@ -15,9 +15,12 @@ interface BaseParamsPDF { } // Job params: structure of incoming user request data, after being parsed from RISON -export type JobParamsPDF = BaseParamsPDF & BaseParams; +/** + * @deprecated + */ +export type JobParamsPDFDeprecated = BaseParamsPDF & BaseParams; -export type JobAppParamsPDF = Omit; +export type JobAppParamsPDF = Omit; // Job payload: structure of stored job data provided by create_job export interface TaskPayloadPDF extends BasePayload { diff --git a/x-pack/plugins/reporting/common/types/index.ts b/x-pack/plugins/reporting/common/types/index.ts index 4056b40a7f4548..4ccd11f8522e68 100644 --- a/x-pack/plugins/reporting/common/types/index.ts +++ b/x-pack/plugins/reporting/common/types/index.ts @@ -7,9 +7,9 @@ import type { BaseParams, BaseParamsV2, BasePayload, BasePayloadV2, JobId } from './base'; -export type { JobParamsPNG } from './export_types/png'; +export type { JobParamsPNGDeprecated } from './export_types/png'; export type { JobParamsPNGV2 } from './export_types/png_v2'; -export type { JobAppParamsPDF, JobParamsPDF } from './export_types/printable_pdf'; +export type { JobAppParamsPDF, JobParamsPDFDeprecated } from './export_types/printable_pdf'; export type { JobAppParamsPDFV2, JobParamsPDFV2 } from './export_types/printable_pdf_v2'; export type { DownloadReportFn, diff --git a/x-pack/plugins/reporting/server/export_types/png/create_job/index.ts b/x-pack/plugins/reporting/server/export_types/png/create_job/index.ts index f18c0fe2778bd0..70822c29119d51 100644 --- a/x-pack/plugins/reporting/server/export_types/png/create_job/index.ts +++ b/x-pack/plugins/reporting/server/export_types/png/create_job/index.ts @@ -7,16 +7,18 @@ import { CreateJobFn, CreateJobFnFactory } from '../../../types'; import { validateUrls } from '../../common'; -import { JobParamsPNG, TaskPayloadPNG } from '../types'; +import { JobParamsPNGDeprecated, TaskPayloadPNG } from '../types'; -export const createJobFnFactory: CreateJobFnFactory> = - function createJobFactoryFn() { - return async function createJob(jobParams) { - validateUrls([jobParams.relativeUrl]); +export const createJobFnFactory: CreateJobFnFactory< + CreateJobFn +> = function createJobFactoryFn() { + return async function createJob(jobParams) { + validateUrls([jobParams.relativeUrl]); - return { - ...jobParams, - forceNow: new Date().toISOString(), - }; + return { + ...jobParams, + isDeprecated: true, + forceNow: new Date().toISOString(), }; }; +}; diff --git a/x-pack/plugins/reporting/server/export_types/png/index.ts b/x-pack/plugins/reporting/server/export_types/png/index.ts index 7d3e65540fe3ab..f4c3155c7b8a5b 100644 --- a/x-pack/plugins/reporting/server/export_types/png/index.ts +++ b/x-pack/plugins/reporting/server/export_types/png/index.ts @@ -17,10 +17,10 @@ import { CreateJobFn, ExportTypeDefinition, RunTaskFn } from '../../types'; import { createJobFnFactory } from './create_job'; import { runTaskFnFactory } from './execute_job'; import { metadata } from './metadata'; -import { JobParamsPNG, TaskPayloadPNG } from './types'; +import { JobParamsPNGDeprecated, TaskPayloadPNG } from './types'; export const getExportType = (): ExportTypeDefinition< - CreateJobFn, + CreateJobFn, RunTaskFn > => ({ ...metadata, diff --git a/x-pack/plugins/reporting/server/export_types/png/types.ts b/x-pack/plugins/reporting/server/export_types/png/types.ts index 8b8768467155eb..3940f24b762a87 100644 --- a/x-pack/plugins/reporting/server/export_types/png/types.ts +++ b/x-pack/plugins/reporting/server/export_types/png/types.ts @@ -5,4 +5,7 @@ * 2.0. */ -export type { JobParamsPNG, TaskPayloadPNG } from '../../../common/types/export_types/png'; +export type { + JobParamsPNGDeprecated, + TaskPayloadPNG, +} from '../../../common/types/export_types/png'; diff --git a/x-pack/plugins/reporting/server/export_types/printable_pdf/create_job/index.ts b/x-pack/plugins/reporting/server/export_types/printable_pdf/create_job/index.ts index 00702341f0dc9a..eeaf0f82f16989 100644 --- a/x-pack/plugins/reporting/server/export_types/printable_pdf/create_job/index.ts +++ b/x-pack/plugins/reporting/server/export_types/printable_pdf/create_job/index.ts @@ -7,20 +7,22 @@ import { CreateJobFn, CreateJobFnFactory } from '../../../types'; import { validateUrls } from '../../common'; -import { JobParamsPDF, TaskPayloadPDF } from '../types'; +import { JobParamsPDFDeprecated, TaskPayloadPDF } from '../types'; -export const createJobFnFactory: CreateJobFnFactory> = - function createJobFactoryFn() { - return async function createJobFn( - { relativeUrls, ...jobParams }: JobParamsPDF // relativeUrls does not belong in the payload of PDFV1 - ) { - validateUrls(relativeUrls); +export const createJobFnFactory: CreateJobFnFactory< + CreateJobFn +> = function createJobFactoryFn() { + return async function createJobFn( + { relativeUrls, ...jobParams }: JobParamsPDFDeprecated // relativeUrls does not belong in the payload of PDFV1 + ) { + validateUrls(relativeUrls); - // return the payload - return { - ...jobParams, - forceNow: new Date().toISOString(), - objects: relativeUrls.map((u) => ({ relativeUrl: u })), - }; + // return the payload + return { + ...jobParams, + isDeprecated: true, + forceNow: new Date().toISOString(), + objects: relativeUrls.map((u) => ({ relativeUrl: u })), }; }; +}; diff --git a/x-pack/plugins/reporting/server/export_types/printable_pdf/index.ts b/x-pack/plugins/reporting/server/export_types/printable_pdf/index.ts index d429c0fd6d001b..4a4b63bae930b2 100644 --- a/x-pack/plugins/reporting/server/export_types/printable_pdf/index.ts +++ b/x-pack/plugins/reporting/server/export_types/printable_pdf/index.ts @@ -17,10 +17,10 @@ import { CreateJobFn, ExportTypeDefinition, RunTaskFn } from '../../types'; import { createJobFnFactory } from './create_job'; import { runTaskFnFactory } from './execute_job'; import { metadata } from './metadata'; -import { JobParamsPDF, TaskPayloadPDF } from './types'; +import { JobParamsPDFDeprecated, TaskPayloadPDF } from './types'; export const getExportType = (): ExportTypeDefinition< - CreateJobFn, + CreateJobFn, RunTaskFn > => ({ ...metadata, diff --git a/x-pack/plugins/reporting/server/export_types/printable_pdf/types.ts b/x-pack/plugins/reporting/server/export_types/printable_pdf/types.ts index f57d6a709fedba..ebf258f73a41ff 100644 --- a/x-pack/plugins/reporting/server/export_types/printable_pdf/types.ts +++ b/x-pack/plugins/reporting/server/export_types/printable_pdf/types.ts @@ -6,6 +6,6 @@ */ export type { - JobParamsPDF, + JobParamsPDFDeprecated, TaskPayloadPDF, } from '../../../common/types/export_types/printable_pdf'; diff --git a/x-pack/plugins/reporting/server/routes/lib/request_handler.test.ts b/x-pack/plugins/reporting/server/routes/lib/request_handler.test.ts index 13408db8813170..0028073290f204 100644 --- a/x-pack/plugins/reporting/server/routes/lib/request_handler.test.ts +++ b/x-pack/plugins/reporting/server/routes/lib/request_handler.test.ts @@ -8,7 +8,7 @@ import { KibanaRequest, KibanaResponseFactory } from 'kibana/server'; import { coreMock, httpServerMock } from 'src/core/server/mocks'; import { ReportingCore } from '../..'; -import { JobParamsPDF, TaskPayloadPDF } from '../../export_types/printable_pdf/types'; +import { JobParamsPDFDeprecated, TaskPayloadPDF } from '../../export_types/printable_pdf/types'; import { Report, ReportingStore } from '../../lib/store'; import { ReportApiJSON } from '../../lib/store/report'; import { @@ -52,7 +52,7 @@ describe('Handle request to generate', () => { let mockResponseFactory: ReturnType; let requestHandler: RequestHandler; - const mockJobParams: JobParamsPDF = { + const mockJobParams: JobParamsPDFDeprecated = { browserTimezone: 'UTC', objectType: 'cool_object_type', title: 'cool_title', @@ -110,7 +110,7 @@ describe('Handle request to generate', () => { "kibana_name": undefined, "max_attempts": undefined, "meta": Object { - "isDeprecated": undefined, + "isDeprecated": true, "layout": "preserve_layout", "objectType": "cool_object_type", }, @@ -127,6 +127,7 @@ describe('Handle request to generate', () => { Object { "browserTimezone": "UTC", "headers": "hello mock cypher text", + "isDeprecated": true, "layout": Object { "id": "preserve_layout", }, diff --git a/x-pack/test/reporting_api_integration/services/scenarios.ts b/x-pack/test/reporting_api_integration/services/scenarios.ts index 6af60018d01dad..6535694db042c9 100644 --- a/x-pack/test/reporting_api_integration/services/scenarios.ts +++ b/x-pack/test/reporting_api_integration/services/scenarios.ts @@ -12,8 +12,8 @@ import { } from '../../../plugins/reporting/common/constants'; import { JobParamsCSV } from '../../../plugins/reporting/server/export_types/csv_searchsource/types'; import { JobParamsDownloadCSV } from '../../../plugins/reporting/server/export_types/csv_searchsource_immediate/types'; -import { JobParamsPNG } from '../../../plugins/reporting/server/export_types/png/types'; -import { JobParamsPDF } from '../../../plugins/reporting/server/export_types/printable_pdf/types'; +import { JobParamsPNGDeprecated } from '../../../plugins/reporting/server/export_types/png/types'; +import { JobParamsPDFDeprecated } from '../../../plugins/reporting/server/export_types/printable_pdf/types'; import { FtrProviderContext } from '../ftr_provider_context'; function removeWhitespace(str: string) { @@ -141,7 +141,7 @@ export function createScenarios({ getService }: Pick { + const generatePdf = async (username: string, password: string, job: JobParamsPDFDeprecated) => { const jobParams = rison.encode(job as object as RisonValue); return await supertestWithoutAuth .post(`/api/reporting/generate/printablePdf`) @@ -149,7 +149,7 @@ export function createScenarios({ getService }: Pick { + const generatePng = async (username: string, password: string, job: JobParamsPNGDeprecated) => { const jobParams = rison.encode(job as object as RisonValue); return await supertestWithoutAuth .post(`/api/reporting/generate/png`) From a3181a53387e838a76cd60237f71c235122275ed Mon Sep 17 00:00:00 2001 From: Paul Tavares <56442535+paul-tavares@users.noreply.github.com> Date: Thu, 20 Jan 2022 12:16:10 -0500 Subject: [PATCH 083/108] [Security Solution][Lists] Add API level validation for Trusted Application via Lists Plugin extension points (#122454) ## Lists Plugin changes: - Modified ExceptionListClient to accept an optional KibanaRequest when instantiating a new instance of the class - Changes the extension points callback argument structure to an object having context and data. Context provides to the callbacks the HTTP request so that additional validation can be performed (ex. Authz to certain features) - ExtensionPointStorageClient#pipeRun() will now throw if an extension point callback also throws an error (instead of logging it and continuing on with callback execution) - ErrorWithStatusCode was export'ed out of the server (as ListsErrorWithStatusCode) and available for use by dependent plugins ## Security Solution Plugin (endpoint) changes: - Added new getEndpointAuthz(request) and getExceptionListsClient() methods to EndpointAppContextService - Added new server lists integration modules. Registers extension points with the Lists plugin for create and update of exception items. Currently validates only Trusted Apps - Added exception item artifact validators: - a BaseValidator with several generic and reusable methods that can be applied to any artifact - a TrustedAppValidator to specifically validate Trusted Applications - Refactor: - moved EndpointFleetServices to its own folder and also renamed it to include the word Factory (will help in the future if we create server-side service clients for working with Endpoint Policies) - Created common Artifact utilities and const's for working with ExceptionListItemSchema items --- x-pack/plugins/lists/server/index.ts | 5 +- x-pack/plugins/lists/server/mocks.ts | 6 +- x-pack/plugins/lists/server/plugin.ts | 1 + .../exception_list_client.test.ts | 9 +- .../exception_lists/exception_list_client.ts | 18 +- .../exception_list_client_types.ts | 4 +- .../extension_point_storage.mock.ts | 15 +- .../extension_point_storage_client.test.ts | 103 ++++---- .../extension_point_storage_client.ts | 30 +-- .../server/services/extension_points/types.ts | 55 +++-- x-pack/plugins/lists/server/types.ts | 2 +- .../exceptions_list_item_generator.ts | 152 +++++++++++- .../endpoint/service/artifacts/constants.ts | 10 + .../endpoint/service/artifacts/index.ts | 10 + .../endpoint/service/artifacts/utils.ts | 32 +++ .../endpoint/service/trusted_apps/mapping.ts | 9 +- .../service/trusted_apps/validations.ts | 6 +- .../effected_policy_select/utils.ts | 9 +- .../pages/mocks/trusted_apps_http_mocks.ts | 6 +- .../pages/trusted_apps/service/mappers.ts | 10 +- .../view/trusted_apps_page.test.tsx | 1 - .../endpoint/endpoint_app_context_services.ts | 53 ++-- .../server/endpoint/mocks.ts | 32 ++- .../endpoint/routes/metadata/handlers.ts | 2 +- .../endpoint/routes/policy/handlers.test.ts | 24 +- .../endpoint_fleet_services_factory.ts} | 14 +- .../server/endpoint/services/fleet/index.ts | 8 + .../metadata/endpoint_metadata_service.ts | 2 +- .../endpoint/services/metadata/mocks.ts | 17 +- .../handlers/exceptions_pre_create_handler.ts | 26 ++ .../handlers/exceptions_pre_update_handler.ts | 43 ++++ .../register_endpoint_extension_points.ts | 28 +++ .../lists_integration/endpoint/types.ts | 19 ++ .../validators/base_validator.test.ts | 187 ++++++++++++++ .../endpoint/validators/base_validator.ts | 164 +++++++++++++ .../endpoint/validators/errors.ts | 14 ++ .../endpoint/validators/index.ts | 8 + .../endpoint/validators/mocks.ts | 60 +++++ .../validators/trusted_app_validator.ts | 224 +++++++++++++++++ .../server/lists_integration/index.ts | 8 + .../server/lists_integration/jest.config.js | 26 ++ .../security_solution/server/plugin.ts | 29 ++- .../services/endpoint_artifacts.ts | 89 +++++++ .../services/index.ts | 2 + .../apis/endpoint_artifacts.ts | 229 ++++++++++++++++++ .../apis/index.ts | 1 + .../services/index.ts | 4 + 47 files changed, 1634 insertions(+), 172 deletions(-) create mode 100644 x-pack/plugins/security_solution/common/endpoint/service/artifacts/constants.ts create mode 100644 x-pack/plugins/security_solution/common/endpoint/service/artifacts/index.ts create mode 100644 x-pack/plugins/security_solution/common/endpoint/service/artifacts/utils.ts rename x-pack/plugins/security_solution/server/endpoint/services/{endpoint_fleet_services.ts => fleet/endpoint_fleet_services_factory.ts} (81%) create mode 100644 x-pack/plugins/security_solution/server/endpoint/services/fleet/index.ts create mode 100644 x-pack/plugins/security_solution/server/lists_integration/endpoint/handlers/exceptions_pre_create_handler.ts create mode 100644 x-pack/plugins/security_solution/server/lists_integration/endpoint/handlers/exceptions_pre_update_handler.ts create mode 100644 x-pack/plugins/security_solution/server/lists_integration/endpoint/register_endpoint_extension_points.ts create mode 100644 x-pack/plugins/security_solution/server/lists_integration/endpoint/types.ts create mode 100644 x-pack/plugins/security_solution/server/lists_integration/endpoint/validators/base_validator.test.ts create mode 100644 x-pack/plugins/security_solution/server/lists_integration/endpoint/validators/base_validator.ts create mode 100644 x-pack/plugins/security_solution/server/lists_integration/endpoint/validators/errors.ts create mode 100644 x-pack/plugins/security_solution/server/lists_integration/endpoint/validators/index.ts create mode 100644 x-pack/plugins/security_solution/server/lists_integration/endpoint/validators/mocks.ts create mode 100644 x-pack/plugins/security_solution/server/lists_integration/endpoint/validators/trusted_app_validator.ts create mode 100644 x-pack/plugins/security_solution/server/lists_integration/index.ts create mode 100644 x-pack/plugins/security_solution/server/lists_integration/jest.config.js create mode 100644 x-pack/test/security_solution_endpoint/services/endpoint_artifacts.ts create mode 100644 x-pack/test/security_solution_endpoint_api_int/apis/endpoint_artifacts.ts diff --git a/x-pack/plugins/lists/server/index.ts b/x-pack/plugins/lists/server/index.ts index cbdd4722dde9f2..dd7fbf4548f751 100644 --- a/x-pack/plugins/lists/server/index.ts +++ b/x-pack/plugins/lists/server/index.ts @@ -23,12 +23,15 @@ export type { ListsServerExtensionRegistrar, ExtensionPoint, ExceptionsListPreCreateItemServerExtension, - ExceptionListPreUpdateItemServerExtension, + ExceptionsListPreUpdateItemServerExtension, } from './types'; export type { ExportExceptionListAndItemsReturn } from './services/exception_lists/export_exception_list_and_items'; export const config: PluginConfigDescriptor = { schema: ConfigSchema, }; + +export { ErrorWithStatusCode as ListsErrorWithStatusCode } from './error_with_status_code'; + export const plugin = (initializerContext: PluginInitializerContext): ListPlugin => new ListPlugin(initializerContext); diff --git a/x-pack/plugins/lists/server/mocks.ts b/x-pack/plugins/lists/server/mocks.ts index 9cc130fc7d0d36..642fff817949eb 100644 --- a/x-pack/plugins/lists/server/mocks.ts +++ b/x-pack/plugins/lists/server/mocks.ts @@ -7,7 +7,10 @@ import { ListPluginSetup } from './types'; import { getListClientMock } from './services/lists/list_client.mock'; -import { getExceptionListClientMock } from './services/exception_lists/exception_list_client.mock'; +import { + getCreateExceptionListItemOptionsMock, + getExceptionListClientMock, +} from './services/exception_lists/exception_list_client.mock'; const createSetupMock = (): jest.Mocked => { const mock: jest.Mocked = { @@ -20,6 +23,7 @@ const createSetupMock = (): jest.Mocked => { export const listMock = { createSetup: createSetupMock, + getCreateExceptionListItemOptionsMock, getExceptionListClient: getExceptionListClientMock, getListClient: getListClientMock, }; diff --git a/x-pack/plugins/lists/server/plugin.ts b/x-pack/plugins/lists/server/plugin.ts index 5e59cbe2ba7193..c824c6889c362d 100644 --- a/x-pack/plugins/lists/server/plugin.ts +++ b/x-pack/plugins/lists/server/plugin.ts @@ -114,6 +114,7 @@ export class ListPlugin implements Plugin new ExceptionListClient({ + request, savedObjectsClient, serverExtensionsClient: this.extensionPoints.getClient(), user, diff --git a/x-pack/plugins/lists/server/services/exception_lists/exception_list_client.test.ts b/x-pack/plugins/lists/server/services/exception_lists/exception_list_client.test.ts index ed072b0ed7a92b..c94b956c92bf73 100644 --- a/x-pack/plugins/lists/server/services/exception_lists/exception_list_client.test.ts +++ b/x-pack/plugins/lists/server/services/exception_lists/exception_list_client.test.ts @@ -11,7 +11,7 @@ import { ExtensionPointStorageContextMock, createExtensionPointStorageMock, } from '../extension_points/extension_point_storage.mock'; -import type { ExtensionPointCallbackArgument } from '../extension_points'; +import type { ExtensionPointCallbackDataArgument } from '../extension_points'; import { getCreateExceptionListItemOptionsMock, @@ -112,10 +112,12 @@ describe('exception_list_client', () => { it('should validate extension point callback returned data and throw if not valid', async () => { const extensionPointCallback = getExtensionPointCallback(); extensionPointCallback.mockImplementation(async (args) => { - const { entries, ...rest } = args as ExtensionPointCallbackArgument; + const { + data: { entries, ...rest }, + } = args as { data: ExtensionPointCallbackDataArgument }; expect(entries).toBeTruthy(); // Test entries to exist since we exclude it. - return rest as ExtensionPointCallbackArgument; + return rest as ExtensionPointCallbackDataArgument; }); const methodResponsePromise = callExceptionListClientMethod(); @@ -126,6 +128,7 @@ describe('exception_list_client', () => { reason: ['Invalid value "undefined" supplied to "entries"'], }) ); + expect(extensionPointStorageContext.logger.error).toHaveBeenCalled(); }); it('should use data returned from extension point callbacks when saving', async () => { diff --git a/x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts b/x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts index 061a4d305821b6..61dd47867b3ffc 100644 --- a/x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts +++ b/x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { SavedObjectsClientContract } from 'kibana/server'; +import { KibanaRequest, SavedObjectsClientContract } from 'kibana/server'; import { ExceptionListItemSchema, ExceptionListSchema, @@ -18,7 +18,10 @@ import { } from '@kbn/securitysolution-io-ts-list-types'; import { ENDPOINT_LIST_ID } from '@kbn/securitysolution-list-constants'; -import type { ExtensionPointStorageClientInterface } from '../extension_points'; +import type { + ExtensionPointStorageClientInterface, + ServerExtensionCallbackContext, +} from '../extension_points'; import { ConstructorOptions, @@ -81,17 +84,26 @@ export class ExceptionListClient { private readonly savedObjectsClient: SavedObjectsClientContract; private readonly serverExtensionsClient: ExtensionPointStorageClientInterface; private readonly enableServerExtensionPoints: boolean; + private readonly request?: KibanaRequest; constructor({ user, savedObjectsClient, serverExtensionsClient, enableServerExtensionPoints = true, + request, }: ConstructorOptions) { this.user = user; this.savedObjectsClient = savedObjectsClient; this.serverExtensionsClient = serverExtensionsClient; this.enableServerExtensionPoints = enableServerExtensionPoints; + this.request = request; + } + + private getServerExtensionCallbackContext(): ServerExtensionCallbackContext { + return { + request: this.request, + }; } /** @@ -404,6 +416,7 @@ export class ExceptionListClient { itemData = await this.serverExtensionsClient.pipeRun( 'exceptionsListPreCreateItem', itemData, + this.getServerExtensionCallbackContext(), (data) => { return validateData( createExceptionListItemSchema, @@ -470,6 +483,7 @@ export class ExceptionListClient { updatedItem = await this.serverExtensionsClient.pipeRun( 'exceptionsListPreUpdateItem', updatedItem, + this.getServerExtensionCallbackContext(), (data) => { return validateData( updateExceptionListItemSchema, diff --git a/x-pack/plugins/lists/server/services/exception_lists/exception_list_client_types.ts b/x-pack/plugins/lists/server/services/exception_lists/exception_list_client_types.ts index 93a45358daafa0..e4fdd5ef2b5ce6 100644 --- a/x-pack/plugins/lists/server/services/exception_lists/exception_list_client_types.ts +++ b/x-pack/plugins/lists/server/services/exception_lists/exception_list_client_types.ts @@ -7,7 +7,7 @@ import { Readable } from 'stream'; -import { SavedObjectsClientContract } from 'kibana/server'; +import type { KibanaRequest, SavedObjectsClientContract } from 'kibana/server'; import type { CreateCommentsArray, Description, @@ -58,6 +58,8 @@ export interface ConstructorOptions { serverExtensionsClient: ExtensionPointStorageClientInterface; /** Set to `false` if wanting to disable executing registered server extension points. Default is true. */ enableServerExtensionPoints?: boolean; + /** Should be provided when creating an instance from an HTTP request handler */ + request?: KibanaRequest; } export interface GetExceptionListOptions { diff --git a/x-pack/plugins/lists/server/services/extension_points/extension_point_storage.mock.ts b/x-pack/plugins/lists/server/services/extension_points/extension_point_storage.mock.ts index 2610e9808dac49..fb453e00492c75 100644 --- a/x-pack/plugins/lists/server/services/extension_points/extension_point_storage.mock.ts +++ b/x-pack/plugins/lists/server/services/extension_points/extension_point_storage.mock.ts @@ -7,11 +7,14 @@ import { MockedLogger, loggerMock } from '@kbn/logging/mocks'; +import { httpServerMock } from '../../../../../../src/core/server/mocks'; + import { ExtensionPointStorage } from './extension_point_storage'; import { - ExceptionListPreUpdateItemServerExtension, ExceptionsListPreCreateItemServerExtension, + ExceptionsListPreUpdateItemServerExtension, ExtensionPointStorageInterface, + ServerExtensionCallbackContext, } from './types'; export interface ExtensionPointStorageContextMock { @@ -21,7 +24,8 @@ export interface ExtensionPointStorageContextMock { /** An Exception List Item pre-create extension point added to the storage. Appends `-1` to the data's `name` attribute */ exceptionPreCreate: jest.Mocked; /** An Exception List Item pre-update extension point added to the storage. Appends `-2` to the data's `name` attribute */ - exceptionPreUpdate: jest.Mocked; + exceptionPreUpdate: jest.Mocked; + callbackContext: jest.Mocked; } export const createExtensionPointStorageMock = ( @@ -30,7 +34,7 @@ export const createExtensionPointStorageMock = ( const extensionPointStorage = new ExtensionPointStorage(logger); const exceptionPreCreate: ExtensionPointStorageContextMock['exceptionPreCreate'] = { - callback: jest.fn(async (data) => { + callback: jest.fn(async ({ data }) => { return { ...data, name: `${data.name}-1`, @@ -40,7 +44,7 @@ export const createExtensionPointStorageMock = ( }; const exceptionPreUpdate: ExtensionPointStorageContextMock['exceptionPreUpdate'] = { - callback: jest.fn(async (data) => { + callback: jest.fn(async ({ data }) => { return { ...data, name: `${data.name}-1`, @@ -53,6 +57,9 @@ export const createExtensionPointStorageMock = ( extensionPointStorage.add(exceptionPreUpdate); return { + callbackContext: { + request: httpServerMock.createKibanaRequest(), + }, exceptionPreCreate, exceptionPreUpdate, extensionPointStorage, diff --git a/x-pack/plugins/lists/server/services/extension_points/extension_point_storage_client.test.ts b/x-pack/plugins/lists/server/services/extension_points/extension_point_storage_client.test.ts index b7a687064e2e2c..25d4a4902a0b7f 100644 --- a/x-pack/plugins/lists/server/services/extension_points/extension_point_storage_client.test.ts +++ b/x-pack/plugins/lists/server/services/extension_points/extension_point_storage_client.test.ts @@ -13,11 +13,12 @@ import { DataValidationError } from '../exception_lists/utils/errors'; import { ExtensionPointError } from './errors'; import { - ExceptionListPreUpdateItemServerExtension, ExceptionsListPreCreateItemServerExtension, + ExceptionsListPreUpdateItemServerExtension, ExtensionPoint, ExtensionPointStorageClientInterface, ExtensionPointStorageInterface, + ServerExtensionCallbackContext, } from './types'; import { createExtensionPointStorageMock } from './extension_point_storage.mock'; @@ -25,6 +26,7 @@ describe('When using the ExtensionPointStorageClient', () => { let storageClient: ExtensionPointStorageClientInterface; let logger: ReturnType; let extensionPointStorage: ExtensionPointStorageInterface; + let callbackContext: ServerExtensionCallbackContext; let preCreateExtensionPointMock1: jest.Mocked; let extensionPointsMocks: Array>; let callbackRunLog: string; @@ -34,10 +36,10 @@ describe('When using the ExtensionPointStorageClient', () => { }; beforeEach(() => { - const storageContext = createExtensionPointStorageMock(); + const extensionPointStorageMock = createExtensionPointStorageMock(); callbackRunLog = ''; - ({ logger, extensionPointStorage } = storageContext); + ({ logger, extensionPointStorage, callbackContext } = extensionPointStorageMock); extensionPointStorage.clear(); // Generic callback function that also logs to the `callbackRunLog` its id, so we know the order in which they ran. @@ -48,12 +50,12 @@ describe('When using the ExtensionPointStorageClient', () => { A extends Parameters[0] = Parameters[0] >( id: number, - arg: A - ): Promise
=> { + { data }: A + ): Promise => { callbackRunLog += id; return { - ...arg, - name: `${arg.name}-${id}`, + ...data, + name: `${data.name}-${id}`, }; }; preCreateExtensionPointMock1 = { @@ -72,7 +74,7 @@ describe('When using the ExtensionPointStorageClient', () => { }, { callback: jest.fn( - callbackFn.bind(window, 3) as ExceptionListPreUpdateItemServerExtension['callback'] + callbackFn.bind(window, 3) as ExceptionsListPreUpdateItemServerExtension['callback'] ), type: 'exceptionsListPreUpdateItem', }, @@ -115,38 +117,70 @@ describe('When using the ExtensionPointStorageClient', () => { it('should run extension point callbacks serially', async () => { await storageClient.pipeRun( 'exceptionsListPreCreateItem', - createExceptionListItemOptionsMock + createExceptionListItemOptionsMock, + callbackContext ); expect(callbackRunLog).toEqual('1245'); }); - it('should pass the return value of one extensionPoint to the next', async () => { + it('should provide `context` to every callback', async () => { await storageClient.pipeRun( 'exceptionsListPreCreateItem', - createExceptionListItemOptionsMock + createExceptionListItemOptionsMock, + callbackContext ); + for (const extensionPointsMock of extensionPointsMocks) { + if (extensionPointsMock.type === 'exceptionsListPreCreateItem') { + expect(extensionPointsMock.callback).toHaveBeenCalledWith( + expect.objectContaining({ + context: { + request: expect.any(Object), + }, + }) + ); + } + } + }); - expect(extensionPointsMocks[0].callback).toHaveBeenCalledWith( - createExceptionListItemOptionsMock + it('should pass the return value of one extensionPoint to the next', async () => { + await storageClient.pipeRun( + 'exceptionsListPreCreateItem', + createExceptionListItemOptionsMock, + callbackContext ); + + expect(extensionPointsMocks[0].callback).toHaveBeenCalledWith({ + context: callbackContext, + data: createExceptionListItemOptionsMock, + }); expect(extensionPointsMocks[1].callback).toHaveBeenCalledWith({ - ...createExceptionListItemOptionsMock, - name: `${createExceptionListItemOptionsMock.name}-1`, + context: callbackContext, + data: { + ...createExceptionListItemOptionsMock, + name: `${createExceptionListItemOptionsMock.name}-1`, + }, }); expect(extensionPointsMocks[3].callback).toHaveBeenCalledWith({ - ...createExceptionListItemOptionsMock, - name: `${createExceptionListItemOptionsMock.name}-1-2`, + context: callbackContext, + data: { + ...createExceptionListItemOptionsMock, + name: `${createExceptionListItemOptionsMock.name}-1-2`, + }, }); expect(extensionPointsMocks[4].callback).toHaveBeenCalledWith({ - ...createExceptionListItemOptionsMock, - name: `${createExceptionListItemOptionsMock.name}-1-2-4`, + context: callbackContext, + data: { + ...createExceptionListItemOptionsMock, + name: `${createExceptionListItemOptionsMock.name}-1-2-4`, + }, }); }); it('should return a data structure similar to the one provided initially', async () => { const result = await storageClient.pipeRun( 'exceptionsListPreCreateItem', - createExceptionListItemOptionsMock + createExceptionListItemOptionsMock, + callbackContext ); expect(result).toEqual({ @@ -155,36 +189,20 @@ describe('When using the ExtensionPointStorageClient', () => { }); }); - it("should log an error if extension point callback Throw's", async () => { - const extensionError = new Error('foo'); - preCreateExtensionPointMock1.callback.mockImplementation(async () => { - throw extensionError; - }); - - await storageClient.pipeRun( - 'exceptionsListPreCreateItem', - createExceptionListItemOptionsMock - ); - - expect(logger.error).toHaveBeenCalledWith(expect.any(ExtensionPointError)); - expect(logger.error.mock.calls[0][0]).toMatchObject({ meta: extensionError }); - }); - - it('should continue to other extension points after encountering one that `throw`s', async () => { + it('should stop execution of other extension points after encountering one that `throw`s', async () => { const extensionError = new Error('foo'); preCreateExtensionPointMock1.callback.mockImplementation(async () => { throw extensionError; }); - const result = await storageClient.pipeRun( + const resultPromise = storageClient.pipeRun( 'exceptionsListPreCreateItem', - createExceptionListItemOptionsMock + createExceptionListItemOptionsMock, + callbackContext ); - expect(result).toEqual({ - ...createExceptionListItemOptionsMock, - name: `${createExceptionListItemOptionsMock.name}-2-4-5`, - }); + await expect(resultPromise).rejects.toBe(extensionError); + expect(extensionPointsMocks[1].callback).not.toHaveBeenCalled(); }); it('should log an error and Throw if external callback returned invalid data', async () => { @@ -194,6 +212,7 @@ describe('When using the ExtensionPointStorageClient', () => { storageClient.pipeRun( 'exceptionsListPreCreateItem', createExceptionListItemOptionsMock, + callbackContext, () => { return validationError; } diff --git a/x-pack/plugins/lists/server/services/extension_points/extension_point_storage_client.ts b/x-pack/plugins/lists/server/services/extension_points/extension_point_storage_client.ts index e430972157b75e..453d5deccc8c8a 100644 --- a/x-pack/plugins/lists/server/services/extension_points/extension_point_storage_client.ts +++ b/x-pack/plugins/lists/server/services/extension_points/extension_point_storage_client.ts @@ -9,10 +9,11 @@ import { Logger } from 'kibana/server'; import type { ExtensionPoint, - ExtensionPointCallbackArgument, + ExtensionPointCallbackDataArgument, ExtensionPointStorageClientInterface, ExtensionPointStorageInterface, NarrowExtensionPointToType, + ServerExtensionCallbackContext, } from './types'; import { ExtensionPointError } from './errors'; @@ -38,6 +39,7 @@ export class ExtensionPointStorageClient implements ExtensionPointStorageClientI * * @param extensionType * @param initialCallbackInput The initial argument given to the first extension point callback + * @param callbackContext * @param callbackResponseValidator A function to validate the returned data from an extension point callback */ async pipeRun< @@ -46,9 +48,10 @@ export class ExtensionPointStorageClient implements ExtensionPointStorageClientI P extends Parameters = Parameters >( extensionType: T, - initialCallbackInput: P[0], - callbackResponseValidator?: (data: P[0]) => Error | undefined - ): Promise { + initialCallbackInput: P[0]['data'], + callbackContext: ServerExtensionCallbackContext, + callbackResponseValidator?: (data: P[0]['data']) => Error | undefined + ): Promise { let inputArgument = initialCallbackInput; const externalExtensions = this.get(extensionType); @@ -60,26 +63,17 @@ export class ExtensionPointStorageClient implements ExtensionPointStorageClientI const extensionRegistrationSource = this.storage.getExtensionRegistrationSource(externalExtension); - try { - inputArgument = await externalExtension.callback( - inputArgument as ExtensionPointCallbackArgument - ); - } catch (error) { - // Log the error that the external callback threw and keep going with the running of others - this.logger?.error( - new ExtensionPointError( - `Extension point execution error for ${externalExtension.type}: ${extensionRegistrationSource}`, - error - ) - ); - } + inputArgument = await externalExtension.callback({ + context: callbackContext, + data: inputArgument as ExtensionPointCallbackDataArgument, + }); if (callbackResponseValidator) { // Before calling the next one, make sure the returned payload is valid const validationError = callbackResponseValidator(inputArgument); if (validationError) { - this.logger?.error( + this.logger.error( new ExtensionPointError( `Extension point for ${externalExtension.type} returned data that failed validation: ${extensionRegistrationSource}`, { diff --git a/x-pack/plugins/lists/server/services/extension_points/types.ts b/x-pack/plugins/lists/server/services/extension_points/types.ts index 7ae2b5971f825f..3dcec1fae63e83 100644 --- a/x-pack/plugins/lists/server/services/extension_points/types.ts +++ b/x-pack/plugins/lists/server/services/extension_points/types.ts @@ -5,24 +5,51 @@ * 2.0. */ -import { PromiseType } from 'utility-types'; import { UnionToIntersection } from '@kbn/utility-types'; +import { KibanaRequest } from 'kibana/server'; import { CreateExceptionListItemOptions, UpdateExceptionListItemOptions, } from '../exception_lists/exception_list_client_types'; -export type ServerExtensionCallback = ( - args: A -) => Promise; +/** + * The `this` context provided to extension point's callback function + * NOTE: in order to access this context, callbacks **MUST** be defined using `function()` instead of arrow functions. + */ +export interface ServerExtensionCallbackContext { + /** + * The Lists plugin HTTP Request. May be undefined if the callback is executed from a area of code that + * is not triggered via one of the HTTP handlers + */ + request?: KibanaRequest; +} + +export type ServerExtensionCallback = (args: { + context: ServerExtensionCallbackContext; + data: A; +}) => Promise; interface ServerExtensionPointDefinition< T extends string, Args extends object | void = void, - Response = void + Response = Args > { type: T; + /** + * The callback that will be executed at the given extension point. The Function will be provided a context (`this)` + * that includes supplemental data associated with its type. In order to access that data, the callback **MUST** + * be defined using `function()` and NOT an arrow function. + * + * @example + * + * { + * type: 'some type', + * callback: function() { + * // this === context is available + * } + * } + */ callback: ServerExtensionCallback; } @@ -32,7 +59,6 @@ interface ServerExtensionPointDefinition< */ export type ExceptionsListPreCreateItemServerExtension = ServerExtensionPointDefinition< 'exceptionsListPreCreateItem', - CreateExceptionListItemOptions, CreateExceptionListItemOptions >; @@ -40,15 +66,14 @@ export type ExceptionsListPreCreateItemServerExtension = ServerExtensionPointDef * Extension point is triggered prior to updating the Exception List Item. Throw'ing will cause the * update operation to fail */ -export type ExceptionListPreUpdateItemServerExtension = ServerExtensionPointDefinition< +export type ExceptionsListPreUpdateItemServerExtension = ServerExtensionPointDefinition< 'exceptionsListPreUpdateItem', - UpdateExceptionListItemOptions, UpdateExceptionListItemOptions >; export type ExtensionPoint = | ExceptionsListPreCreateItemServerExtension - | ExceptionListPreUpdateItemServerExtension; + | ExceptionsListPreUpdateItemServerExtension; /** * A Map of extension point type and associated Set of callbacks @@ -57,6 +82,7 @@ export type ExtensionPoint = * Registration function for server-side extension points */ export type ListsServerExtensionRegistrar = (extension: ExtensionPoint) => void; + export type NarrowExtensionPointToType = { type: T; } & ExtensionPoint; @@ -65,8 +91,8 @@ export type NarrowExtensionPointToType = { * An intersection of all callback arguments for use internally when * casting (ex. in `ExtensionPointStorageClient#pipeRun()` */ -export type ExtensionPointCallbackArgument = UnionToIntersection< - PromiseType> +export type ExtensionPointCallbackDataArgument = UnionToIntersection< + Parameters[0]['data'] >; export interface ExtensionPointStorageClientInterface { @@ -80,9 +106,10 @@ export interface ExtensionPointStorageClientInterface { P extends Parameters = Parameters >( extensionType: T, - initialCallbackInput: P[0], - callbackResponseValidator?: (data: P[0]) => Error | undefined - ): Promise; + initialCallbackInput: P[0]['data'], + callbackContext: ServerExtensionCallbackContext, + callbackResponseValidator?: (data: P[0]['data']) => Error | undefined + ): Promise; } export interface ExtensionPointStorageInterface { diff --git a/x-pack/plugins/lists/server/types.ts b/x-pack/plugins/lists/server/types.ts index cdaa81f6971173..4eece62b9b0a3c 100644 --- a/x-pack/plugins/lists/server/types.ts +++ b/x-pack/plugins/lists/server/types.ts @@ -75,7 +75,7 @@ export type ContextProviderReturn = Promise; export type { ExtensionPoint, - ExceptionListPreUpdateItemServerExtension, + ExceptionsListPreUpdateItemServerExtension, ExceptionsListPreCreateItemServerExtension, ListsServerExtensionRegistrar, } from './services/extension_points'; diff --git a/x-pack/plugins/security_solution/common/endpoint/data_generators/exceptions_list_item_generator.ts b/x-pack/plugins/security_solution/common/endpoint/data_generators/exceptions_list_item_generator.ts index d66f1e950c34f7..3ff333232a6773 100644 --- a/x-pack/plugins/security_solution/common/endpoint/data_generators/exceptions_list_item_generator.ts +++ b/x-pack/plugins/security_solution/common/endpoint/data_generators/exceptions_list_item_generator.ts @@ -5,10 +5,34 @@ * 2.0. */ -import type { ExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; +import type { + ExceptionListItemSchema, + CreateExceptionListItemSchema, + UpdateExceptionListItemSchema, +} from '@kbn/securitysolution-io-ts-list-types'; +import { ENDPOINT_TRUSTED_APPS_LIST_ID } from '@kbn/securitysolution-list-constants'; import { BaseDataGenerator } from './base_data_generator'; -import { POLICY_REFERENCE_PREFIX } from '../service/trusted_apps/mapping'; import { ConditionEntryField } from '../types'; +import { BY_POLICY_ARTIFACT_TAG_PREFIX } from '../service/artifacts/constants'; + +/** Utility that removes null and undefined from a Type's property value */ +type NonNullableTypeProperties = { + [P in keyof T]-?: NonNullable; +}; + +/** + * Normalizes the create type to remove `undefined`/`null` from the returned type since the generator or sure to + * create a value for (almost) all properties + */ +type CreateExceptionListItemSchemaWithNonNullProps = NonNullableTypeProperties< + Omit +> & + Pick; + +type UpdateExceptionListItemSchemaWithNonNullProps = NonNullableTypeProperties< + Omit +> & + Pick; export class ExceptionsListItemGenerator extends BaseDataGenerator { generate(overrides: Partial = {}): ExceptionListItemSchema { @@ -38,11 +62,11 @@ export class ExceptionsListItemGenerator extends BaseDataGenerator = {} + ): CreateExceptionListItemSchemaWithNonNullProps { + const { + /* eslint-disable @typescript-eslint/naming-convention */ + description, + entries, + list_id, + name, + type, + comments, + item_id, + meta, + namespace_type, + os_types, + tags, + /* eslint-enable @typescript-eslint/naming-convention */ + } = this.generate(); + + return { + description, + entries, + list_id, + name, + type, + comments, + item_id, + meta, + namespace_type, + os_types, + tags, + ...overrides, + }; + } + + generateTrustedApp(overrides: Partial = {}): ExceptionListItemSchema { + const trustedApp = this.generate(overrides); + + return { + ...trustedApp, + name: `Trusted app (${this.randomString(5)})`, + list_id: ENDPOINT_TRUSTED_APPS_LIST_ID, + // Remove the hash field which the generator above currently still sets to a field that is not + // actually valid when used with the Exception List + entries: trustedApp.entries.filter((entry) => entry.field !== ConditionEntryField.HASH), + }; + } + + generateTrustedAppForCreate( + overrides: Partial = {} + ): CreateExceptionListItemSchemaWithNonNullProps { + const { + /* eslint-disable @typescript-eslint/naming-convention */ + description, + entries, + list_id, + name, + type, + comments, + item_id, + meta, + namespace_type, + os_types, + tags, + /* eslint-enable @typescript-eslint/naming-convention */ + } = this.generateTrustedApp(); + + return { + description, + entries, + list_id, + name, + type, + comments, + item_id, + meta, + namespace_type, + os_types, + tags, + ...overrides, + }; + } + + generateTrustedAppForUpdate( + overrides: Partial = {} + ): UpdateExceptionListItemSchemaWithNonNullProps { + const { + /* eslint-disable @typescript-eslint/naming-convention */ + description, + entries, + name, + type, + comments, + id, + item_id, + meta, + namespace_type, + os_types, + tags, + _version, + /* eslint-enable @typescript-eslint/naming-convention */ + } = this.generateTrustedApp(); + + return { + description, + entries, + name, + type, + comments, + id, + item_id, + meta, + namespace_type, + os_types, + tags, + _version: _version ?? 'some value', + ...overrides, + }; + } } diff --git a/x-pack/plugins/security_solution/common/endpoint/service/artifacts/constants.ts b/x-pack/plugins/security_solution/common/endpoint/service/artifacts/constants.ts new file mode 100644 index 00000000000000..eadc52941da059 --- /dev/null +++ b/x-pack/plugins/security_solution/common/endpoint/service/artifacts/constants.ts @@ -0,0 +1,10 @@ +/* + * 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 const BY_POLICY_ARTIFACT_TAG_PREFIX = 'policy:'; + +export const GLOBAL_ARTIFACT_TAG = `${BY_POLICY_ARTIFACT_TAG_PREFIX}all`; diff --git a/x-pack/plugins/security_solution/common/endpoint/service/artifacts/index.ts b/x-pack/plugins/security_solution/common/endpoint/service/artifacts/index.ts new file mode 100644 index 00000000000000..6bdf0fb59a3a8c --- /dev/null +++ b/x-pack/plugins/security_solution/common/endpoint/service/artifacts/index.ts @@ -0,0 +1,10 @@ +/* + * 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 { isArtifactGlobal, isArtifactByPolicy, getPolicyIdsFromArtifact } from './utils'; + +export { BY_POLICY_ARTIFACT_TAG_PREFIX, GLOBAL_ARTIFACT_TAG } from './constants'; diff --git a/x-pack/plugins/security_solution/common/endpoint/service/artifacts/utils.ts b/x-pack/plugins/security_solution/common/endpoint/service/artifacts/utils.ts new file mode 100644 index 00000000000000..4cc39e9fb89802 --- /dev/null +++ b/x-pack/plugins/security_solution/common/endpoint/service/artifacts/utils.ts @@ -0,0 +1,32 @@ +/* + * 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 { ExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; +import { BY_POLICY_ARTIFACT_TAG_PREFIX, GLOBAL_ARTIFACT_TAG } from './constants'; + +const POLICY_ID_START_POSITION = BY_POLICY_ARTIFACT_TAG_PREFIX.length; + +export const isArtifactGlobal = (item: Pick): boolean => { + return (item.tags ?? []).find((tag) => tag === GLOBAL_ARTIFACT_TAG) !== undefined; +}; + +export const isArtifactByPolicy = (item: Pick): boolean => { + return !isArtifactGlobal(item); +}; + +export const getPolicyIdsFromArtifact = (item: Pick): string[] => { + const policyIds = []; + const tags = item.tags ?? []; + + for (const tag of tags) { + if (tag !== GLOBAL_ARTIFACT_TAG && tag.startsWith(BY_POLICY_ARTIFACT_TAG_PREFIX)) { + policyIds.push(tag.substring(POLICY_ID_START_POSITION)); + } + } + + return policyIds; +}; diff --git a/x-pack/plugins/security_solution/common/endpoint/service/trusted_apps/mapping.ts b/x-pack/plugins/security_solution/common/endpoint/service/trusted_apps/mapping.ts index ddc366f49ed954..cf36c6911ca91d 100644 --- a/x-pack/plugins/security_solution/common/endpoint/service/trusted_apps/mapping.ts +++ b/x-pack/plugins/security_solution/common/endpoint/service/trusted_apps/mapping.ts @@ -6,8 +6,7 @@ */ import { EffectScope } from '../../types'; - -export const POLICY_REFERENCE_PREFIX = 'policy:'; +import { BY_POLICY_ARTIFACT_TAG_PREFIX } from '../artifacts/constants'; /** * Looks at an array of `tags` (attributed defined on the `ExceptionListItemSchema`) and returns back @@ -15,16 +14,16 @@ export const POLICY_REFERENCE_PREFIX = 'policy:'; * @param tags */ export const tagsToEffectScope = (tags: string[]): EffectScope => { - const policyReferenceTags = tags.filter((tag) => tag.startsWith(POLICY_REFERENCE_PREFIX)); + const policyReferenceTags = tags.filter((tag) => tag.startsWith(BY_POLICY_ARTIFACT_TAG_PREFIX)); - if (policyReferenceTags.some((tag) => tag === `${POLICY_REFERENCE_PREFIX}all`)) { + if (policyReferenceTags.some((tag) => tag === `${BY_POLICY_ARTIFACT_TAG_PREFIX}all`)) { return { type: 'global', }; } else { return { type: 'policy', - policies: policyReferenceTags.map((tag) => tag.substr(POLICY_REFERENCE_PREFIX.length)), + policies: policyReferenceTags.map((tag) => tag.substr(BY_POLICY_ARTIFACT_TAG_PREFIX.length)), }; } }; diff --git a/x-pack/plugins/security_solution/common/endpoint/service/trusted_apps/validations.ts b/x-pack/plugins/security_solution/common/endpoint/service/trusted_apps/validations.ts index 3fee05e2f00617..0e6f2a5a7df418 100644 --- a/x-pack/plugins/security_solution/common/endpoint/service/trusted_apps/validations.ts +++ b/x-pack/plugins/security_solution/common/endpoint/service/trusted_apps/validations.ts @@ -26,7 +26,11 @@ export const getDuplicateFields = (entries: ConditionEntry[]) => { const groupedFields = new Map(); entries.forEach((entry) => { - groupedFields.set(entry.field, [...(groupedFields.get(entry.field) || []), entry]); + // With the move to the Exception Lists api, the server side now validates individual + // `process.hash.[type]`'s, so we need to account for that here + const field = entry.field.startsWith('process.hash') ? ConditionEntryField.HASH : entry.field; + + groupedFields.set(field, [...(groupedFields.get(field) || []), entry]); }); return [...groupedFields.entries()] diff --git a/x-pack/plugins/security_solution/public/management/components/effected_policy_select/utils.ts b/x-pack/plugins/security_solution/public/management/components/effected_policy_select/utils.ts index b3c1dd6648f833..3f90df40391bc8 100644 --- a/x-pack/plugins/security_solution/public/management/components/effected_policy_select/utils.ts +++ b/x-pack/plugins/security_solution/public/management/components/effected_policy_select/utils.ts @@ -7,8 +7,7 @@ import { PolicyData } from '../../../../common/endpoint/types'; import { EffectedPolicySelection } from './effected_policy_select'; - -export const GLOBAL_POLICY_TAG = 'policy:all'; +import { GLOBAL_ARTIFACT_TAG } from '../../../../common/endpoint/service/artifacts/constants'; /** * Given a list of artifact tags, returns the tags that are not policy tags @@ -27,7 +26,7 @@ export function getArtifactTagsByEffectedPolicySelection( otherTags: string[] = [] ): string[] { if (selection.isGlobal) { - return [GLOBAL_POLICY_TAG, ...otherTags]; + return [GLOBAL_ARTIFACT_TAG, ...otherTags]; } const newTags = selection.selected.map((policy) => { return `policy:${policy.id}`; @@ -47,7 +46,7 @@ export function getEffectedPolicySelectionByTags( tags: string[], policies: PolicyData[] ): EffectedPolicySelection { - if (tags.find((tag) => tag === GLOBAL_POLICY_TAG)) { + if (tags.find((tag) => tag === GLOBAL_ARTIFACT_TAG)) { return { isGlobal: true, selected: [], @@ -71,7 +70,7 @@ export function getEffectedPolicySelectionByTags( } export function isGlobalPolicyEffected(tags?: string[]): boolean { - return tags !== undefined && tags.find((tag) => tag === GLOBAL_POLICY_TAG) !== undefined; + return tags !== undefined && tags.find((tag) => tag === GLOBAL_ARTIFACT_TAG) !== undefined; } /** diff --git a/x-pack/plugins/security_solution/public/management/pages/mocks/trusted_apps_http_mocks.ts b/x-pack/plugins/security_solution/public/management/pages/mocks/trusted_apps_http_mocks.ts index 45bb3841c00984..347f1dc088c10a 100644 --- a/x-pack/plugins/security_solution/public/management/pages/mocks/trusted_apps_http_mocks.ts +++ b/x-pack/plugins/security_solution/public/management/pages/mocks/trusted_apps_http_mocks.ts @@ -26,7 +26,6 @@ import { ResponseProvidersInterface, } from '../../../common/mock/endpoint/http_handler_mock_factory'; import { ExceptionsListItemGenerator } from '../../../../common/endpoint/data_generators/exceptions_list_item_generator'; -import { POLICY_REFERENCE_PREFIX } from '../../../../common/endpoint/service/trusted_apps/mapping'; import { getTrustedAppsListSchemaMock } from '../../../../../lists/common/schemas/response/exception_list_schema.mock'; import { fleetGetAgentPolicyListHttpMock, @@ -34,6 +33,7 @@ import { fleetGetEndpointPackagePolicyListHttpMock, FleetGetEndpointPackagePolicyListHttpMockInterface, } from './fleet_mocks'; +import { BY_POLICY_ARTIFACT_TAG_PREFIX } from '../../../../common/endpoint/service/artifacts/constants'; interface FindExceptionListItemSchemaQueryParams extends Omit { @@ -67,8 +67,8 @@ export const trustedAppsGetListHttpMocks = data[2].tags = [ // IDs below are those generated by the `fleetGetEndpointPackagePolicyListHttpMock()` mock, // so if using in combination with that API mock, these should just "work" - `${POLICY_REFERENCE_PREFIX}ddf6570b-9175-4a6d-b288-61a09771c647`, - `${POLICY_REFERENCE_PREFIX}b8e616ae-44fc-4be7-846c-ce8fa5c082dd`, + `${BY_POLICY_ARTIFACT_TAG_PREFIX}ddf6570b-9175-4a6d-b288-61a09771c647`, + `${BY_POLICY_ARTIFACT_TAG_PREFIX}b8e616ae-44fc-4be7-846c-ce8fa5c082dd`, ]; return { diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/service/mappers.ts b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/service/mappers.ts index cab162fe30250b..8069d18169dd1c 100644 --- a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/service/mappers.ts +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/service/mappers.ts @@ -27,10 +27,8 @@ import { TrustedAppEntryTypes, UpdateTrustedApp, } from '../../../../../common/endpoint/types'; -import { - POLICY_REFERENCE_PREFIX, - tagsToEffectScope, -} from '../../../../../common/endpoint/service/trusted_apps/mapping'; +import { tagsToEffectScope } from '../../../../../common/endpoint/service/trusted_apps/mapping'; +import { BY_POLICY_ARTIFACT_TAG_PREFIX } from '../../../../../common/endpoint/service/artifacts/constants'; type ConditionEntriesMap = { [K in ConditionEntryField]?: ConditionEntry }; type Mapping = { [K in T]: U }; @@ -177,9 +175,9 @@ const createEntryNested = (field: string, entries: NestedEntriesArray): EntryNes const effectScopeToTags = (effectScope: EffectScope) => { if (effectScope.type === 'policy') { - return effectScope.policies.map((policy) => `${POLICY_REFERENCE_PREFIX}${policy}`); + return effectScope.policies.map((policy) => `${BY_POLICY_ARTIFACT_TAG_PREFIX}${policy}`); } else { - return [`${POLICY_REFERENCE_PREFIX}all`]; + return [`${BY_POLICY_ARTIFACT_TAG_PREFIX}all`]; } }; diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/trusted_apps_page.test.tsx b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/trusted_apps_page.test.tsx index 7443e4b0d12a94..4808857849cb3a 100644 --- a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/trusted_apps_page.test.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/trusted_apps_page.test.tsx @@ -301,7 +301,6 @@ describe('When on the Trusted Apps Page', () => { id: '05b5e350-0cad-4dc3-a61d-6e6796b0af39', comments: [], item_id: '2d95bec3-b48f-4db7-9622-a2b061cc031d', - meta: {}, namespace_type: 'agnostic', type: 'simple', }); diff --git a/x-pack/plugins/security_solution/server/endpoint/endpoint_app_context_services.ts b/x-pack/plugins/security_solution/server/endpoint/endpoint_app_context_services.ts index b61e850df2ef5a..3a8616f5d36271 100644 --- a/x-pack/plugins/security_solution/server/endpoint/endpoint_app_context_services.ts +++ b/x-pack/plugins/security_solution/server/endpoint/endpoint_app_context_services.ts @@ -6,7 +6,7 @@ */ import { KibanaRequest, Logger } from 'src/core/server'; -import { CreateExceptionListItemOptions, ExceptionListClient } from '../../../lists/server'; +import { ExceptionListClient } from '../../../lists/server'; import { CasesClient, PluginStartContract as CasesPluginStartContract, @@ -35,11 +35,14 @@ import { EndpointAppContentServicesNotStartedError, } from './errors'; import { - EndpointFleetServicesFactory, + EndpointFleetServicesFactoryInterface, EndpointInternalFleetServicesInterface, EndpointScopedFleetServicesInterface, -} from './services/endpoint_fleet_services'; +} from './services/fleet/endpoint_fleet_services_factory'; import type { ListsServerExtensionRegistrar } from '../../../lists/server'; +import { registerListsPluginEndpointExtensionPoints } from '../lists_integration'; +import { EndpointAuthz } from '../../common/endpoint/types/authz'; +import { calculateEndpointAuthz } from '../../common/endpoint/service/authz'; export interface EndpointAppContextServiceSetupContract { securitySolutionRequestContextFactory: IRequestContextFactory; @@ -51,8 +54,10 @@ export type EndpointAppContextServiceStartContract = Partial< 'agentService' | 'packageService' | 'packagePolicyService' | 'agentPolicyService' > > & { + fleetAuthzService?: FleetStartContract['authz']; logger: Logger; endpointMetadataService: EndpointMetadataService; + endpointFleetServicesFactory: EndpointFleetServicesFactoryInterface; manifestManager?: ManifestManager; security: SecurityPluginStart; alerting: AlertsPluginStartContract; @@ -71,7 +76,7 @@ export type EndpointAppContextServiceStartContract = Partial< export class EndpointAppContextService { private setupDependencies: EndpointAppContextServiceSetupContract | null = null; private startDependencies: EndpointAppContextServiceStartContract | null = null; - private fleetServicesFactory: EndpointFleetServicesFactory | null = null; + private fleetServicesFactory: EndpointFleetServicesFactoryInterface | null = null; public security: SecurityPluginStart | undefined; public setup(dependencies: EndpointAppContextServiceSetupContract) { @@ -85,17 +90,7 @@ export class EndpointAppContextService { this.startDependencies = dependencies; this.security = dependencies.security; - - // let's try to avoid turning off eslint's Forbidden non-null assertion rule - const { agentService, agentPolicyService, packagePolicyService, packageService } = - dependencies as Required; - - this.fleetServicesFactory = new EndpointFleetServicesFactory({ - agentService, - agentPolicyService, - packagePolicyService, - packageService, - }); + this.fleetServicesFactory = dependencies.endpointFleetServicesFactory; if (dependencies.registerIngestCallback && dependencies.manifestManager) { dependencies.registerIngestCallback( @@ -124,13 +119,7 @@ export class EndpointAppContextService { if (this.startDependencies.registerListsServerExtension) { const { registerListsServerExtension } = this.startDependencies; - registerListsServerExtension({ - type: 'exceptionsListPreCreateItem', - callback: async (arg: CreateExceptionListItemOptions) => { - // this.startDependencies?.logger.info('exceptionsListPreCreateItem called!'); - return arg; - }, - }); + registerListsPluginEndpointExtensionPoints(registerListsServerExtension, this); } } @@ -140,6 +129,19 @@ export class EndpointAppContextService { return this.startDependencies?.config.experimentalFeatures; } + private getFleetAuthzService(): FleetStartContract['authz'] { + if (!this.startDependencies?.fleetAuthzService) { + throw new EndpointAppContentServicesNotStartedError(); + } + + return this.startDependencies.fleetAuthzService; + } + + public async getEndpointAuthz(request: KibanaRequest): Promise { + const fleetAuthz = await this.getFleetAuthzService().fromRequest(request); + return calculateEndpointAuthz(this.getLicenseService(), fleetAuthz); + } + public getEndpointMetadataService(): EndpointMetadataService { if (this.startDependencies == null) { throw new EndpointAppContentServicesNotStartedError(); @@ -198,4 +200,11 @@ export class EndpointAppContextService { } return this.startDependencies.cases.getCasesClientWithRequest(req); } + + public getExceptionListsClient(): ExceptionListClient { + if (!this.startDependencies?.exceptionListsClient) { + throw new EndpointAppContentServicesNotStartedError(); + } + return this.startDependencies.exceptionListsClient; + } } diff --git a/x-pack/plugins/security_solution/server/endpoint/mocks.ts b/x-pack/plugins/security_solution/server/endpoint/mocks.ts index 4da108859691ff..fa22869b391ab8 100644 --- a/x-pack/plugins/security_solution/server/endpoint/mocks.ts +++ b/x-pack/plugins/security_solution/server/endpoint/mocks.ts @@ -29,7 +29,6 @@ import { ManifestManager } from './services/artifacts/manifest_manager/manifest_ import { getManifestManagerMock } from './services/artifacts/manifest_manager/manifest_manager.mock'; import { EndpointAppContext } from './types'; import { MetadataRequestContext } from './routes/metadata/handlers'; -import { LicenseService } from '../../common/license'; import { SecuritySolutionRequestHandlerContext } from '../types'; import { parseExperimentalConfigValue } from '../../common/experimental_features'; // A TS error (TS2403) is thrown when attempting to export the mock function below from Cases @@ -45,6 +44,8 @@ import { createMockClients } from '../lib/detection_engine/routes/__mocks__/requ import { createEndpointMetadataServiceTestContextMock } from './services/metadata/mocks'; import type { EndpointAuthz } from '../../common/endpoint/types/authz'; +import { EndpointFleetServicesFactory } from './services/fleet'; +import { createLicenseServiceMock } from '../../common/license/mocks'; /** * Creates a mocked EndpointAppContext. @@ -102,12 +103,22 @@ export const createMockEndpointAppContextServiceStartContract = const agentService = createMockAgentService(); const agentPolicyService = createMockAgentPolicyService(); const packagePolicyService = createPackagePolicyServiceMock(); + const packageService = createMockPackageService(); const endpointMetadataService = new EndpointMetadataService( savedObjectsStart, agentPolicyService, packagePolicyService, logger ); + const endpointFleetServicesFactory = new EndpointFleetServicesFactory( + { + packageService, + packagePolicyService, + agentPolicyService, + agentService, + }, + savedObjectsStart + ); packagePolicyService.list.mockImplementation(async (_, options) => { return { @@ -122,14 +133,16 @@ export const createMockEndpointAppContextServiceStartContract = agentService, agentPolicyService, endpointMetadataService, + endpointFleetServicesFactory, packagePolicyService, logger, - packageService: createMockPackageService(), + packageService, + fleetAuthzService: createFleetAuthzServiceMock(), manifestManager: getManifestManagerMock(), security: securityMock.createStart(), alerting: alertsMock.createStart(), config, - licenseService: new LicenseService(), + licenseService: createLicenseServiceMock(), registerIngestCallback: jest.fn< ReturnType, Parameters @@ -141,18 +154,21 @@ export const createMockEndpointAppContextServiceStartContract = }; }; +export const createFleetAuthzServiceMock = (): jest.Mocked => { + return { + fromRequest: jest.fn(async (_) => createFleetAuthzMock()), + }; +}; + /** - * Creates a mock IndexPatternService for use in tests that need to interact with the Fleet's - * ESIndexPatternService. + * Creates the Fleet Start contract mock return by the Fleet Plugin * * @param indexPattern a string index pattern to return when called by a test * @returns the same value as `indexPattern` parameter */ export const createMockFleetStartContract = (indexPattern: string): FleetStartContract => { return { - authz: { - fromRequest: jest.fn().mockResolvedValue(createFleetAuthzMock()), - }, + authz: createFleetAuthzServiceMock(), fleetSetupCompleted: jest.fn().mockResolvedValue(undefined), esIndexPatternService: { getESIndexPattern: jest.fn().mockResolvedValue(indexPattern), diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/handlers.ts b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/handlers.ts index 4b1ea1fe9efaa0..02d13c7c057d18 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/handlers.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/handlers.ts @@ -42,7 +42,7 @@ import { ENDPOINT_DEFAULT_PAGE_SIZE, METADATA_TRANSFORMS_PATTERN, } from '../../../../common/endpoint/constants'; -import { EndpointFleetServicesInterface } from '../../services/endpoint_fleet_services'; +import { EndpointFleetServicesInterface } from '../../services/fleet/endpoint_fleet_services_factory'; export interface MetadataRequestContext { esClient?: IScopedClusterClient; diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/policy/handlers.test.ts b/x-pack/plugins/security_solution/server/endpoint/routes/policy/handlers.test.ts index 527afe23b694db..9ad26443cf0d58 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/policy/handlers.test.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/policy/handlers.test.ts @@ -11,11 +11,7 @@ import { createMockEndpointAppContextServiceStartContract, createRouteHandlerContext, } from '../../mocks'; -import { - createMockAgentClient, - createMockAgentService, - createPackagePolicyServiceMock, -} from '../../../../../fleet/server/mocks'; +import { createMockAgentClient, createMockAgentService } from '../../../../../fleet/server/mocks'; import { PACKAGE_POLICY_SAVED_OBJECT_TYPE } from '../../../../../fleet/common'; import { getHostPolicyResponseHandler, @@ -251,10 +247,20 @@ describe('test policy response handler', () => { let policyHandler: ReturnType; beforeEach(() => { + const endpointAppContextServiceStartContract = + createMockEndpointAppContextServiceStartContract(); + mockScopedClient = elasticsearchServiceMock.createScopedClusterClient(); mockSavedObjectClient = savedObjectsClientMock.create(); mockResponse = httpServerMock.createResponseFactory(); - mockPackagePolicyService = createPackagePolicyServiceMock(); + + if (endpointAppContextServiceStartContract.packagePolicyService) { + mockPackagePolicyService = + endpointAppContextServiceStartContract.packagePolicyService as jest.Mocked; + } else { + expect(endpointAppContextServiceStartContract.packagePolicyService).toBeTruthy(); + } + mockPackagePolicyService.list.mockImplementation(() => { return Promise.resolve({ items: [], @@ -265,10 +271,7 @@ describe('test policy response handler', () => { }); endpointAppContextService = new EndpointAppContextService(); endpointAppContextService.setup(createMockEndpointAppContextServiceSetupContract()); - endpointAppContextService.start({ - ...createMockEndpointAppContextServiceStartContract(), - ...{ packagePolicyService: mockPackagePolicyService }, - }); + endpointAppContextService.start(endpointAppContextServiceStartContract); policyHandler = getPolicyListHandler({ logFactory: loggingSystemMock.create(), service: endpointAppContextService, @@ -289,6 +292,7 @@ describe('test policy response handler', () => { mockRequest, mockResponse ); + expect(mockPackagePolicyService.list).toHaveBeenCalled(); expect(mockPackagePolicyService.list.mock.calls[0][1]).toEqual({ kuery: `${PACKAGE_POLICY_SAVED_OBJECT_TYPE}.package.name: endpoint`, perPage: undefined, diff --git a/x-pack/plugins/security_solution/server/endpoint/services/endpoint_fleet_services.ts b/x-pack/plugins/security_solution/server/endpoint/services/fleet/endpoint_fleet_services_factory.ts similarity index 81% rename from x-pack/plugins/security_solution/server/endpoint/services/endpoint_fleet_services.ts rename to x-pack/plugins/security_solution/server/endpoint/services/fleet/endpoint_fleet_services_factory.ts index 915070a9b064fd..7ab263705eaaf9 100644 --- a/x-pack/plugins/security_solution/server/endpoint/services/endpoint_fleet_services.ts +++ b/x-pack/plugins/security_solution/server/endpoint/services/fleet/endpoint_fleet_services_factory.ts @@ -5,14 +5,15 @@ * 2.0. */ -import { KibanaRequest } from 'kibana/server'; +import { KibanaRequest, SavedObjectsClientContract, SavedObjectsServiceStart } from 'kibana/server'; import type { AgentClient, AgentPolicyServiceInterface, FleetStartContract, PackagePolicyServiceInterface, PackageClient, -} from '../../../../fleet/server'; +} from '../../../../../fleet/server'; +import { createInternalReadonlySoClient } from '../../utils/create_internal_readonly_so_client'; export interface EndpointFleetServicesFactoryInterface { asScoped(req: KibanaRequest): EndpointScopedFleetServicesInterface; @@ -25,7 +26,8 @@ export class EndpointFleetServicesFactory implements EndpointFleetServicesFactor private readonly fleetDependencies: Pick< FleetStartContract, 'agentService' | 'packageService' | 'packagePolicyService' | 'agentPolicyService' - > + >, + private savedObjectsStart: SavedObjectsServiceStart ) {} asScoped(req: KibanaRequest): EndpointScopedFleetServicesInterface { @@ -61,6 +63,7 @@ export class EndpointFleetServicesFactory implements EndpointFleetServicesFactor packagePolicy, asScoped: this.asScoped.bind(this), + internalReadonlySoClient: createInternalReadonlySoClient(this.savedObjectsStart), }; } } @@ -87,4 +90,9 @@ export interface EndpointInternalFleetServicesInterface extends EndpointFleetSer * get scoped endpoint fleet services instance */ asScoped: EndpointFleetServicesFactoryInterface['asScoped']; + + /** + * An internal SO client (readonly) that can be used with the Fleet services that require it + */ + internalReadonlySoClient: SavedObjectsClientContract; } diff --git a/x-pack/plugins/security_solution/server/endpoint/services/fleet/index.ts b/x-pack/plugins/security_solution/server/endpoint/services/fleet/index.ts new file mode 100644 index 00000000000000..6e1088a21ee02f --- /dev/null +++ b/x-pack/plugins/security_solution/server/endpoint/services/fleet/index.ts @@ -0,0 +1,8 @@ +/* + * 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 * from './endpoint_fleet_services_factory'; diff --git a/x-pack/plugins/security_solution/server/endpoint/services/metadata/endpoint_metadata_service.ts b/x-pack/plugins/security_solution/server/endpoint/services/metadata/endpoint_metadata_service.ts index 5251992a5d3d4d..857b9ca18163c7 100644 --- a/x-pack/plugins/security_solution/server/endpoint/services/metadata/endpoint_metadata_service.ts +++ b/x-pack/plugins/security_solution/server/endpoint/services/metadata/endpoint_metadata_service.ts @@ -56,7 +56,7 @@ import { getAllEndpointPackagePolicies } from '../../routes/metadata/support/end import { getAgentStatus } from '../../../../../fleet/common/services/agent_status'; import { GetMetadataListRequestQuery } from '../../../../common/endpoint/schema/metadata'; import { EndpointError } from '../../../../common/endpoint/errors'; -import { EndpointFleetServicesInterface } from '../endpoint_fleet_services'; +import { EndpointFleetServicesInterface } from '../fleet/endpoint_fleet_services_factory'; type AgentPolicyWithPackagePolicies = Omit & { package_policies: PackagePolicy[]; diff --git a/x-pack/plugins/security_solution/server/endpoint/services/metadata/mocks.ts b/x-pack/plugins/security_solution/server/endpoint/services/metadata/mocks.ts index 3cd368d35b6575..599f153e19e05b 100644 --- a/x-pack/plugins/security_solution/server/endpoint/services/metadata/mocks.ts +++ b/x-pack/plugins/security_solution/server/endpoint/services/metadata/mocks.ts @@ -21,7 +21,7 @@ import { AgentPolicyServiceInterface, AgentService } from '../../../../../fleet/ import { EndpointFleetServicesFactory, EndpointInternalFleetServicesInterface, -} from '../endpoint_fleet_services'; +} from '../fleet/endpoint_fleet_services_factory'; const createCustomizedPackagePolicyService = () => { const service = createPackagePolicyServiceMock(); @@ -62,12 +62,15 @@ export const createEndpointMetadataServiceTestContextMock = ( .create() .get() ): EndpointMetadataServiceTestContextMock => { - const fleetServices = new EndpointFleetServicesFactory({ - agentService, - packageService, - packagePolicyService, - agentPolicyService, - }).asInternalUser(); + const fleetServices = new EndpointFleetServicesFactory( + { + agentService, + packageService, + packagePolicyService, + agentPolicyService, + }, + savedObjectsStart + ).asInternalUser(); const endpointMetadataService = new EndpointMetadataService( savedObjectsStart, diff --git a/x-pack/plugins/security_solution/server/lists_integration/endpoint/handlers/exceptions_pre_create_handler.ts b/x-pack/plugins/security_solution/server/lists_integration/endpoint/handlers/exceptions_pre_create_handler.ts new file mode 100644 index 00000000000000..08a6f80162d034 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lists_integration/endpoint/handlers/exceptions_pre_create_handler.ts @@ -0,0 +1,26 @@ +/* + * 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 { + CreateExceptionListItemOptions, + ExceptionsListPreCreateItemServerExtension, +} from '../../../../../lists/server'; +import { EndpointAppContextService } from '../../../endpoint/endpoint_app_context_services'; +import { TrustedAppValidator } from '../validators'; + +export const getExceptionsPreCreateItemHandler = ( + endpointAppContext: EndpointAppContextService +): ExceptionsListPreCreateItemServerExtension['callback'] => { + return async function ({ data, context: { request } }): Promise { + // Validate trusted apps + if (TrustedAppValidator.isTrustedApp(data)) { + return new TrustedAppValidator(endpointAppContext, request).validatePreCreateItem(data); + } + + return data; + }; +}; diff --git a/x-pack/plugins/security_solution/server/lists_integration/endpoint/handlers/exceptions_pre_update_handler.ts b/x-pack/plugins/security_solution/server/lists_integration/endpoint/handlers/exceptions_pre_update_handler.ts new file mode 100644 index 00000000000000..4c162bb03a5e93 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lists_integration/endpoint/handlers/exceptions_pre_update_handler.ts @@ -0,0 +1,43 @@ +/* + * 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 { + ExceptionsListPreUpdateItemServerExtension, + UpdateExceptionListItemOptions, +} from '../../../../../lists/server'; +import { EndpointAppContextService } from '../../../endpoint/endpoint_app_context_services'; +import { TrustedAppValidator } from '../validators'; + +export const getExceptionsPreUpdateItemHandler = ( + endpointAppContextService: EndpointAppContextService +): ExceptionsListPreUpdateItemServerExtension['callback'] => { + return async function ({ data, context: { request } }): Promise { + const currentSavedItem = await endpointAppContextService + .getExceptionListsClient() + .getExceptionListItem({ + id: data.id, + itemId: data.itemId, + namespaceType: data.namespaceType, + }); + + // We don't want to `throw` here becuase we don't know for sure that the item is one we care about. + // So we just return the data and the Lists plugin will likely error out because it can't find the item + if (!currentSavedItem) { + return data; + } + + // Validate trusted apps + if (TrustedAppValidator.isTrustedApp({ listId: currentSavedItem.list_id })) { + return new TrustedAppValidator(endpointAppContextService, request).validatePreUpdateItem( + data, + currentSavedItem + ); + } + + return data; + }; +}; diff --git a/x-pack/plugins/security_solution/server/lists_integration/endpoint/register_endpoint_extension_points.ts b/x-pack/plugins/security_solution/server/lists_integration/endpoint/register_endpoint_extension_points.ts new file mode 100644 index 00000000000000..bc0c59f44be135 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lists_integration/endpoint/register_endpoint_extension_points.ts @@ -0,0 +1,28 @@ +/* + * 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 { EndpointAppContextService } from '../../endpoint/endpoint_app_context_services'; +import { getExceptionsPreCreateItemHandler } from './handlers/exceptions_pre_create_handler'; +import { getExceptionsPreUpdateItemHandler } from './handlers/exceptions_pre_update_handler'; +import type { ListsServerExtensionRegistrar } from '../../../../lists/server'; + +export const registerListsPluginEndpointExtensionPoints = ( + registerListsExtensionPoint: ListsServerExtensionRegistrar, + endpointAppContextService: EndpointAppContextService +): void => { + // PRE-CREATE handler + registerListsExtensionPoint({ + type: 'exceptionsListPreCreateItem', + callback: getExceptionsPreCreateItemHandler(endpointAppContextService), + }); + + // PRE-UPDATE handler + registerListsExtensionPoint({ + type: 'exceptionsListPreUpdateItem', + callback: getExceptionsPreUpdateItemHandler(endpointAppContextService), + }); +}; diff --git a/x-pack/plugins/security_solution/server/lists_integration/endpoint/types.ts b/x-pack/plugins/security_solution/server/lists_integration/endpoint/types.ts new file mode 100644 index 00000000000000..4b00bafafc967c --- /dev/null +++ b/x-pack/plugins/security_solution/server/lists_integration/endpoint/types.ts @@ -0,0 +1,19 @@ +/* + * 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 { CreateExceptionListItemOptions } from '../../../../lists/server'; + +/** + * An Exception Like item is a structure used internally by several of the Exceptions api/service in that + * the keys are camelCased. Because different methods of the ExceptionListClient have slightly different + * structures, this one attempt to normalize the properties we care about here that can be found across + * those service methods. + */ +export type ExceptionItemLikeOptions = Pick< + CreateExceptionListItemOptions, + 'osTypes' | 'tags' | 'description' | 'name' | 'entries' | 'namespaceType' +> & { listId?: string }; diff --git a/x-pack/plugins/security_solution/server/lists_integration/endpoint/validators/base_validator.test.ts b/x-pack/plugins/security_solution/server/lists_integration/endpoint/validators/base_validator.test.ts new file mode 100644 index 00000000000000..728e3b8559ed32 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lists_integration/endpoint/validators/base_validator.test.ts @@ -0,0 +1,187 @@ +/* + * 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 { EndpointAppContextService } from '../../../endpoint/endpoint_app_context_services'; +import { + createMockEndpointAppContextServiceSetupContract, + createMockEndpointAppContextServiceStartContract, +} from '../../../endpoint/mocks'; +import { BaseValidatorMock, createExceptionItemLikeOptionsMock } from './mocks'; +import { EndpointArtifactExceptionValidationError } from './errors'; +import { httpServerMock } from '../../../../../../../src/core/server/mocks'; +import { createFleetAuthzMock, PackagePolicy } from '../../../../../fleet/common'; +import { PackagePolicyServiceInterface } from '../../../../../fleet/server'; +import { ExceptionItemLikeOptions } from '../types'; +import { + BY_POLICY_ARTIFACT_TAG_PREFIX, + GLOBAL_ARTIFACT_TAG, +} from '../../../../common/endpoint/service/artifacts'; + +describe('When using Artifacts Exceptions BaseValidator', () => { + let endpointAppContextServices: EndpointAppContextService; + let kibanaRequest: ReturnType; + let exceptionLikeItem: ExceptionItemLikeOptions; + let validator: BaseValidatorMock; + let packagePolicyService: jest.Mocked; + let initValidator: (withNoAuth?: boolean, withBasicLicense?: boolean) => BaseValidatorMock; + + beforeEach(() => { + kibanaRequest = httpServerMock.createKibanaRequest(); + exceptionLikeItem = createExceptionItemLikeOptionsMock(); + + const servicesStart = createMockEndpointAppContextServiceStartContract(); + + packagePolicyService = + servicesStart.packagePolicyService as jest.Mocked; + + endpointAppContextServices = new EndpointAppContextService(); + endpointAppContextServices.setup(createMockEndpointAppContextServiceSetupContract()); + endpointAppContextServices.start(servicesStart); + + initValidator = (withNoAuth: boolean = false, withBasicLicense = false) => { + if (withNoAuth) { + const fleetAuthz = createFleetAuthzMock(); + fleetAuthz.fleet.all = false; + (servicesStart.fleetAuthzService?.fromRequest as jest.Mock).mockResolvedValue(fleetAuthz); + } + + if (withBasicLicense) { + (servicesStart.licenseService.isPlatinumPlus as jest.Mock).mockResolvedValue(false); + } + + validator = new BaseValidatorMock(endpointAppContextServices, kibanaRequest); + + return validator; + }; + }); + + it('should use default endpoint authz (no access) when `request` is not provided', async () => { + const baseValidator = new BaseValidatorMock(endpointAppContextServices); + + await expect(baseValidator._isAllowedToCreateArtifactsByPolicy()).resolves.toBe(false); + await expect(baseValidator._validateCanManageEndpointArtifacts()).rejects.toBeInstanceOf( + EndpointArtifactExceptionValidationError + ); + }); + + it('should validate is allowed to manage endpoint artifacts', async () => { + await expect(initValidator()._validateCanManageEndpointArtifacts()).resolves.toBeUndefined(); + }); + + it('should throw if not allowed to manage endpoint artifacts', async () => { + await expect(initValidator(true)._validateCanManageEndpointArtifacts()).rejects.toBeInstanceOf( + EndpointArtifactExceptionValidationError + ); + }); + + it('should validate basic artifact data', async () => { + await expect(initValidator()._validateBasicData(exceptionLikeItem)).resolves.toBeUndefined(); + }); + + it.each([ + [ + 'name is empty', + () => { + exceptionLikeItem.name = ''; + }, + ], + [ + 'namespace is not agnostic', + () => { + exceptionLikeItem.namespaceType = 'single'; + }, + ], + [ + 'osTypes has more than 1 value', + () => { + exceptionLikeItem.osTypes = ['macos', 'linux']; + }, + ], + [ + 'osType has invalid value', + () => { + exceptionLikeItem.osTypes = ['xunil' as 'linux']; + }, + ], + ])('should throw if %s', async (_, setupData) => { + setupData(); + + await expect(initValidator()._validateBasicData(exceptionLikeItem)).rejects.toBeInstanceOf( + EndpointArtifactExceptionValidationError + ); + }); + + it('should validate is allowed to create artifacts by policy', async () => { + await expect( + initValidator()._validateCanCreateByPolicyArtifacts(exceptionLikeItem) + ).resolves.toBeUndefined(); + }); + + it('should throw if not allowed to create artifacts by policy', async () => { + await expect( + initValidator(false, true)._validateCanCreateByPolicyArtifacts(exceptionLikeItem) + ).rejects.toBeInstanceOf(EndpointArtifactExceptionValidationError); + }); + + it('should validate policy ids for by policy artifacts', async () => { + packagePolicyService.getByIDs.mockResolvedValue([ + { + id: '123', + version: '123', + } as PackagePolicy, + ]); + + await expect(initValidator()._validateByPolicyItem(exceptionLikeItem)).resolves.toBeUndefined(); + }); + + it('should throw if policy ids for by policy artifacts are not valid', async () => { + packagePolicyService.getByIDs.mockResolvedValue([ + { + id: '123', + version: undefined, + } as PackagePolicy, + ]); + + await expect(initValidator()._validateByPolicyItem(exceptionLikeItem)).rejects.toBeInstanceOf( + EndpointArtifactExceptionValidationError + ); + }); + + it.each([ + ['no policies (unassigned)', () => createExceptionItemLikeOptionsMock({ tags: [] })], + [ + 'different policy', + () => createExceptionItemLikeOptionsMock({ tags: [`${BY_POLICY_ARTIFACT_TAG_PREFIX}:456`] }), + ], + [ + 'additional policies', + () => + createExceptionItemLikeOptionsMock({ + tags: [`${BY_POLICY_ARTIFACT_TAG_PREFIX}:123`, `${BY_POLICY_ARTIFACT_TAG_PREFIX}:456`], + }), + ], + ])( + 'should return `true` when `wasByPolicyEffectScopeChanged()` is called with: %s', + (_, getUpdated) => { + expect(initValidator()._wasByPolicyEffectScopeChanged(getUpdated(), exceptionLikeItem)).toBe( + true + ); + } + ); + + it.each([ + ['identical data', () => createExceptionItemLikeOptionsMock()], + [ + 'scope changed to all', + () => createExceptionItemLikeOptionsMock({ tags: [GLOBAL_ARTIFACT_TAG] }), + ], + ])('should return `false` when `wasByPolicyEffectScopeChanged()` with: %s', (_, getUpdated) => { + expect(initValidator()._wasByPolicyEffectScopeChanged(getUpdated(), exceptionLikeItem)).toBe( + false + ); + }); +}); diff --git a/x-pack/plugins/security_solution/server/lists_integration/endpoint/validators/base_validator.ts b/x-pack/plugins/security_solution/server/lists_integration/endpoint/validators/base_validator.ts new file mode 100644 index 00000000000000..d320a2ecc8aef7 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lists_integration/endpoint/validators/base_validator.ts @@ -0,0 +1,164 @@ +/* + * 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 { KibanaRequest } from 'kibana/server'; +import { schema } from '@kbn/config-schema'; +import { isEqual } from 'lodash/fp'; +import { ExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; +import { EndpointAppContextService } from '../../../endpoint/endpoint_app_context_services'; +import { ExceptionItemLikeOptions } from '../types'; +import { getEndpointAuthzInitialState } from '../../../../common/endpoint/service/authz'; +import { + getPolicyIdsFromArtifact, + isArtifactByPolicy, +} from '../../../../common/endpoint/service/artifacts'; +import { OperatingSystem } from '../../../../common/endpoint/types'; +import { EndpointArtifactExceptionValidationError } from './errors'; + +const BasicEndpointExceptionDataSchema = schema.object( + { + // must have a name + name: schema.string({ minLength: 1, maxLength: 256 }), + + description: schema.maybe(schema.string({ minLength: 0, maxLength: 256, defaultValue: '' })), + + // We only support agnostic entries + namespaceType: schema.literal('agnostic'), + + // only one OS per entry + osTypes: schema.arrayOf( + schema.oneOf([ + schema.literal(OperatingSystem.WINDOWS), + schema.literal(OperatingSystem.LINUX), + schema.literal(OperatingSystem.MAC), + ]), + { minSize: 1, maxSize: 1 } + ), + }, + // Because we are only validating some fields from the Exception Item, we set `unknowns` to `ignore` here + { unknowns: 'ignore' } +); + +/** + * Provides base methods for doing validation that apply across endpoint exception entries + */ +export class BaseValidator { + private readonly endpointAuthzPromise: ReturnType; + + constructor( + protected readonly endpointAppContext: EndpointAppContextService, + /** + * Request is optional only because it needs to be optional in the Lists ExceptionListClient + */ + private readonly request?: KibanaRequest + ) { + if (this.request) { + this.endpointAuthzPromise = this.endpointAppContext.getEndpointAuthz(this.request); + } else { + this.endpointAuthzPromise = Promise.resolve(getEndpointAuthzInitialState()); + } + } + + protected isItemByPolicy(item: ExceptionItemLikeOptions): boolean { + return isArtifactByPolicy(item); + } + + protected async isAllowedToCreateArtifactsByPolicy(): Promise { + return (await this.endpointAuthzPromise).canCreateArtifactsByPolicy; + } + + protected async validateCanManageEndpointArtifacts(): Promise { + if (!(await this.endpointAuthzPromise).canAccessEndpointManagement) { + throw new EndpointArtifactExceptionValidationError('Endpoint authorization failure', 403); + } + } + + /** + * validates some basic common data that can be found across all endpoint exceptions + * @param item + * @protected + */ + protected async validateBasicData(item: ExceptionItemLikeOptions) { + try { + BasicEndpointExceptionDataSchema.validate(item); + } catch (error) { + throw new EndpointArtifactExceptionValidationError(error.message); + } + } + + protected async validateCanCreateByPolicyArtifacts( + item: ExceptionItemLikeOptions + ): Promise { + if (this.isItemByPolicy(item) && !(await this.isAllowedToCreateArtifactsByPolicy())) { + throw new EndpointArtifactExceptionValidationError( + 'Your license level does not allow create/update of by policy artifacts', + 403 + ); + } + } + + /** + * Validates that by-policy artifacts is permitted and that each policy referenced in the item is valid + * @protected + */ + protected async validateByPolicyItem(item: ExceptionItemLikeOptions): Promise { + if (this.isItemByPolicy(item)) { + const { packagePolicy, internalReadonlySoClient } = + this.endpointAppContext.getInternalFleetServices(); + const policyIds = getPolicyIdsFromArtifact(item); + + if (policyIds.length === 0) { + return; + } + + const policiesFromFleet = await packagePolicy.getByIDs(internalReadonlySoClient, policyIds); + + if (!policiesFromFleet) { + throw new EndpointArtifactExceptionValidationError( + `invalid policy ids: ${policyIds.join(', ')}` + ); + } + + const invalidPolicyIds = policiesFromFleet + .filter((policy) => policy.version === undefined) + .map((policy) => policy.id); + + if (invalidPolicyIds.length) { + throw new EndpointArtifactExceptionValidationError( + `invalid policy ids: ${invalidPolicyIds.join(', ')}` + ); + } + } + } + + /** + * If the item being updated is `by policy`, method validates if anyting was changes in regard to + * the effected scope of the by policy settings. + * + * @param updatedItem + * @param currentItem + * @protected + */ + protected wasByPolicyEffectScopeChanged( + updatedItem: ExceptionItemLikeOptions, + currentItem: Pick + ): boolean { + // if global, then return. Nothing to validate and setting the trusted app to global is allowed + if (!this.isItemByPolicy(updatedItem)) { + return false; + } + + if (updatedItem.tags) { + return !isEqual( + getPolicyIdsFromArtifact({ tags: updatedItem.tags }), + getPolicyIdsFromArtifact(currentItem) + ); + } + + return false; + } +} diff --git a/x-pack/plugins/security_solution/server/lists_integration/endpoint/validators/errors.ts b/x-pack/plugins/security_solution/server/lists_integration/endpoint/validators/errors.ts new file mode 100644 index 00000000000000..69a8d9c5914de9 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lists_integration/endpoint/validators/errors.ts @@ -0,0 +1,14 @@ +/* + * 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 { ListsErrorWithStatusCode } from '../../../../../lists/server'; + +export class EndpointArtifactExceptionValidationError extends ListsErrorWithStatusCode { + constructor(message: string, statusCode: number = 400) { + super(`EndpointArtifactError: ${message}`, statusCode); + } +} diff --git a/x-pack/plugins/security_solution/server/lists_integration/endpoint/validators/index.ts b/x-pack/plugins/security_solution/server/lists_integration/endpoint/validators/index.ts new file mode 100644 index 00000000000000..be26c31e2e155d --- /dev/null +++ b/x-pack/plugins/security_solution/server/lists_integration/endpoint/validators/index.ts @@ -0,0 +1,8 @@ +/* + * 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 { TrustedAppValidator } from './trusted_app_validator'; diff --git a/x-pack/plugins/security_solution/server/lists_integration/endpoint/validators/mocks.ts b/x-pack/plugins/security_solution/server/lists_integration/endpoint/validators/mocks.ts new file mode 100644 index 00000000000000..97a29aee962e55 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lists_integration/endpoint/validators/mocks.ts @@ -0,0 +1,60 @@ +/* + * 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 { ExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; +import { BaseValidator } from './base_validator'; +import { ExceptionItemLikeOptions } from '../types'; +import { listMock } from '../../../../../lists/server/mocks'; +import { BY_POLICY_ARTIFACT_TAG_PREFIX } from '../../../../common/endpoint/service/artifacts'; + +/** + * Exposes all `protected` methods of `BaseValidator` by prefixing them with an underscore. + */ +export class BaseValidatorMock extends BaseValidator { + _isItemByPolicy(item: ExceptionItemLikeOptions): boolean { + return this.isItemByPolicy(item); + } + + async _isAllowedToCreateArtifactsByPolicy(): Promise { + return this.isAllowedToCreateArtifactsByPolicy(); + } + + async _validateCanManageEndpointArtifacts(): Promise { + return this.validateCanManageEndpointArtifacts(); + } + + async _validateBasicData(item: ExceptionItemLikeOptions) { + return this.validateBasicData(item); + } + + async _validateCanCreateByPolicyArtifacts(item: ExceptionItemLikeOptions): Promise { + return this.validateCanCreateByPolicyArtifacts(item); + } + + async _validateByPolicyItem(item: ExceptionItemLikeOptions): Promise { + return this.validateByPolicyItem(item); + } + + _wasByPolicyEffectScopeChanged( + updatedItem: ExceptionItemLikeOptions, + currentItem: Pick + ): boolean { + return this.wasByPolicyEffectScopeChanged(updatedItem, currentItem); + } +} + +export const createExceptionItemLikeOptionsMock = ( + overrides: Partial = {} +): ExceptionItemLikeOptions => { + return { + ...listMock.getCreateExceptionListItemOptionsMock(), + namespaceType: 'agnostic', + osTypes: ['windows'], + tags: [`${BY_POLICY_ARTIFACT_TAG_PREFIX}123`], + ...overrides, + }; +}; diff --git a/x-pack/plugins/security_solution/server/lists_integration/endpoint/validators/trusted_app_validator.ts b/x-pack/plugins/security_solution/server/lists_integration/endpoint/validators/trusted_app_validator.ts new file mode 100644 index 00000000000000..26208661b4b6bb --- /dev/null +++ b/x-pack/plugins/security_solution/server/lists_integration/endpoint/validators/trusted_app_validator.ts @@ -0,0 +1,224 @@ +/* + * 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 { ENDPOINT_TRUSTED_APPS_LIST_ID } from '@kbn/securitysolution-list-constants'; +import { schema, TypeOf } from '@kbn/config-schema'; +import { ExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; +import { BaseValidator } from './base_validator'; +import { ExceptionItemLikeOptions } from '../types'; +import { + CreateExceptionListItemOptions, + UpdateExceptionListItemOptions, +} from '../../../../../lists/server'; +import { + ConditionEntry, + OperatingSystem, + TrustedAppEntryTypes, +} from '../../../../common/endpoint/types'; +import { + getDuplicateFields, + isValidHash, +} from '../../../../common/endpoint/service/trusted_apps/validations'; +import { EndpointArtifactExceptionValidationError } from './errors'; + +const ProcessHashField = schema.oneOf([ + schema.literal('process.hash.md5'), + schema.literal('process.hash.sha1'), + schema.literal('process.hash.sha256'), +]); +const ProcessExecutablePath = schema.literal('process.executable.caseless'); +const ProcessCodeSigner = schema.literal('process.Ext.code_signature'); + +const ConditionEntryTypeSchema = schema.conditional( + schema.siblingRef('field'), + ProcessExecutablePath, + schema.oneOf([schema.literal('match'), schema.literal('wildcard')]), + schema.literal('match') +); +const ConditionEntryOperatorSchema = schema.literal('included'); + +type ConditionEntryFieldAllowedType = + | TypeOf + | TypeOf + | TypeOf; + +type TrustedAppConditionEntry< + T extends ConditionEntryFieldAllowedType = ConditionEntryFieldAllowedType +> = + | { + field: T; + type: TrustedAppEntryTypes; + operator: 'included'; + value: string; + } + | TypeOf; + +/* + * A generic Entry schema to be used for a specific entry schema depending on the OS + */ +const CommonEntrySchema = { + field: schema.oneOf([ProcessHashField, ProcessExecutablePath]), + type: ConditionEntryTypeSchema, + operator: ConditionEntryOperatorSchema, + // If field === HASH then validate hash with custom method, else validate string with minLength = 1 + value: schema.conditional( + schema.siblingRef('field'), + ProcessHashField, + schema.string({ + validate: (hash: string) => (isValidHash(hash) ? undefined : `invalid hash value [${hash}]`), + }), + schema.conditional( + schema.siblingRef('field'), + ProcessExecutablePath, + schema.string({ + validate: (pathValue: string) => + pathValue.length > 0 ? undefined : `invalid path value [${pathValue}]`, + }), + schema.string({ + validate: (signerValue: string) => + signerValue.length > 0 ? undefined : `invalid signer value [${signerValue}]`, + }) + ) + ), +}; + +// Windows Signer entries use a Nested field that checks to ensure +// that the certificate is trusted +const WindowsSignerEntrySchema = schema.object({ + type: schema.literal('nested'), + field: ProcessCodeSigner, + entries: schema.arrayOf( + schema.oneOf([ + schema.object({ + field: schema.literal('trusted'), + value: schema.literal('true'), + type: schema.literal('match'), + operator: schema.literal('included'), + }), + schema.object({ + field: schema.literal('subject_name'), + value: schema.string({ minLength: 1 }), + type: schema.literal('match'), + operator: schema.literal('included'), + }), + ]), + { minSize: 2, maxSize: 2 } + ), +}); + +const WindowsEntrySchema = schema.oneOf([ + WindowsSignerEntrySchema, + schema.object({ + ...CommonEntrySchema, + field: schema.oneOf([ProcessHashField, ProcessExecutablePath]), + }), +]); + +const LinuxEntrySchema = schema.object({ + ...CommonEntrySchema, +}); + +const MacEntrySchema = schema.object({ + ...CommonEntrySchema, +}); + +const entriesSchemaOptions = { + minSize: 1, + validate(entries: TrustedAppConditionEntry[]) { + const dups = getDuplicateFields(entries as ConditionEntry[]); + return dups.map((field) => `Duplicated entry: ${field}`).join(', ') || undefined; + }, +}; + +/* + * Entities array schema depending on Os type using schema.conditional. + * If OS === WINDOWS then use Windows schema, + * else if OS === LINUX then use Linux schema, + * else use Mac schema + * + * The validate function checks there is no duplicated entry inside the array + */ +const EntriesSchema = schema.conditional( + schema.contextRef('os'), + OperatingSystem.WINDOWS, + schema.arrayOf(WindowsEntrySchema, entriesSchemaOptions), + schema.conditional( + schema.contextRef('os'), + OperatingSystem.LINUX, + schema.arrayOf(LinuxEntrySchema, entriesSchemaOptions), + schema.arrayOf(MacEntrySchema, entriesSchemaOptions) + ) +); + +/** + * Schema to validate Trusted Apps data for create and update. + * When called, it must be given an `context` with a `os` property set + * + * @example + * + * TrustedAppDataSchema.validate(item, { os: 'windows' }); + */ +const TrustedAppDataSchema = schema.object( + { + entries: EntriesSchema, + }, + + // Because we are only validating some fields from the Exception Item, we set `unknowns` to `ignore` here + { unknowns: 'ignore' } +); + +export class TrustedAppValidator extends BaseValidator { + static isTrustedApp(item: { listId: string }): boolean { + return item.listId === ENDPOINT_TRUSTED_APPS_LIST_ID; + } + + async validatePreCreateItem( + item: CreateExceptionListItemOptions + ): Promise { + await this.validateCanManageEndpointArtifacts(); + await this.validateTrustedAppData(item); + await this.validateCanCreateByPolicyArtifacts(item); + await this.validateByPolicyItem(item); + + return item; + } + + async validatePreUpdateItem( + _updatedItem: UpdateExceptionListItemOptions, + currentItem: ExceptionListItemSchema + ): Promise { + const updatedItem = _updatedItem as ExceptionItemLikeOptions; + + await this.validateCanManageEndpointArtifacts(); + await this.validateTrustedAppData(updatedItem); + + try { + await this.validateCanCreateByPolicyArtifacts(updatedItem); + } catch (noByPolicyAuthzError) { + // Not allowed to create/update by policy data. Validate that the effective scope of the item + // remained unchanged with this update or was set to `global` (only allowed update). If not, + // then throw the validation error that was catch'ed + if (this.wasByPolicyEffectScopeChanged(updatedItem, currentItem)) { + throw noByPolicyAuthzError; + } + } + + await this.validateByPolicyItem(updatedItem); + + return updatedItem as UpdateExceptionListItemOptions; + } + + private async validateTrustedAppData(item: ExceptionItemLikeOptions): Promise { + await this.validateBasicData(item); + + try { + TrustedAppDataSchema.validate(item, { os: item.osTypes[0] }); + } catch (error) { + throw new EndpointArtifactExceptionValidationError(error.message); + } + } +} diff --git a/x-pack/plugins/security_solution/server/lists_integration/index.ts b/x-pack/plugins/security_solution/server/lists_integration/index.ts new file mode 100644 index 00000000000000..19f30492d0cb52 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lists_integration/index.ts @@ -0,0 +1,8 @@ +/* + * 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 { registerListsPluginEndpointExtensionPoints } from './endpoint/register_endpoint_extension_points'; diff --git a/x-pack/plugins/security_solution/server/lists_integration/jest.config.js b/x-pack/plugins/security_solution/server/lists_integration/jest.config.js new file mode 100644 index 00000000000000..0831c87ee59d4e --- /dev/null +++ b/x-pack/plugins/security_solution/server/lists_integration/jest.config.js @@ -0,0 +1,26 @@ +/* + * 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. + */ + +module.exports = { + preset: '@kbn/test', + rootDir: '../../../../..', + roots: ['/x-pack/plugins/security_solution/server/lists_integration'], + coverageDirectory: + '/target/kibana-coverage/jest/x-pack/plugins/security_solution/server/lists_integration', + coverageReporters: ['text', 'html'], + collectCoverageFrom: [ + '/x-pack/plugins/security_solution/server/lists_integration/**/*.{ts,tsx}', + ], + // See: https://github.com/elastic/kibana/issues/117255, the moduleNameMapper creates mocks to avoid memory leaks from kibana core. + moduleNameMapper: { + 'core/server$': '/x-pack/plugins/security_solution/server/__mocks__/core.mock.ts', + 'task_manager/server$': + '/x-pack/plugins/security_solution/server/__mocks__/task_manager.mock.ts', + 'alerting/server$': '/x-pack/plugins/security_solution/server/__mocks__/alert.mock.ts', + 'actions/server$': '/x-pack/plugins/security_solution/server/__mocks__/action.mock.ts', + }, +}; diff --git a/x-pack/plugins/security_solution/server/plugin.ts b/x-pack/plugins/security_solution/server/plugin.ts index a8e6d49a994c0e..91118d0ef4e896 100644 --- a/x-pack/plugins/security_solution/server/plugin.ts +++ b/x-pack/plugins/security_solution/server/plugin.ts @@ -90,6 +90,7 @@ import type { PluginInitializerContext, } from './plugin_contract'; import { alertsFieldMap, rulesFieldMap } from '../common/field_maps'; +import { EndpointFleetServicesFactory } from './endpoint/services/fleet'; export type { SetupPlugins, StartPlugins, PluginSetup, PluginStart } from './plugin_contract'; @@ -394,19 +395,31 @@ export class Plugin implements ISecuritySolutionPlugin { // eslint-disable-next-line @typescript-eslint/no-non-null-assertion const exceptionListClient = this.lists!.getExceptionListClient(savedObjectsClient, 'kibana'); + const { authz, agentService, packageService, packagePolicyService, agentPolicyService } = + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + plugins.fleet!; + this.endpointAppContextService.start({ - agentService: plugins.fleet?.agentService, - packageService: plugins.fleet?.packageService, - packagePolicyService: plugins.fleet?.packagePolicyService, - agentPolicyService: plugins.fleet?.agentPolicyService, + fleetAuthzService: authz, + agentService, + packageService, + packagePolicyService, + agentPolicyService, endpointMetadataService: new EndpointMetadataService( core.savedObjects, - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - plugins.fleet?.agentPolicyService!, - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - plugins.fleet?.packagePolicyService!, + agentPolicyService, + packagePolicyService, logger ), + endpointFleetServicesFactory: new EndpointFleetServicesFactory( + { + agentService, + packageService, + packagePolicyService, + agentPolicyService, + }, + core.savedObjects + ), security: plugins.security, alerting: plugins.alerting, config: this.config, diff --git a/x-pack/test/security_solution_endpoint/services/endpoint_artifacts.ts b/x-pack/test/security_solution_endpoint/services/endpoint_artifacts.ts new file mode 100644 index 00000000000000..093e55216b9afc --- /dev/null +++ b/x-pack/test/security_solution_endpoint/services/endpoint_artifacts.ts @@ -0,0 +1,89 @@ +/* + * 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 type { + ExceptionListItemSchema, + CreateExceptionListSchema, + CreateExceptionListItemSchema, +} from '@kbn/securitysolution-io-ts-list-types'; +import { EXCEPTION_LIST_ITEM_URL, EXCEPTION_LIST_URL } from '@kbn/securitysolution-list-constants'; +import { Response } from 'superagent'; +import { FtrService } from '../../functional/ftr_provider_context'; +import { ExceptionsListItemGenerator } from '../../../plugins/security_solution/common/endpoint/data_generators/exceptions_list_item_generator'; +import { TRUSTED_APPS_EXCEPTION_LIST_DEFINITION } from '../../../plugins/security_solution/public/management/pages/trusted_apps/constants'; +import { EndpointError } from '../../../plugins/security_solution/common/endpoint/errors'; + +export interface ArtifactTestData { + artifact: ExceptionListItemSchema; + cleanup: () => Promise; +} + +export class EndpointArtifactsTestResources extends FtrService { + private readonly exceptionsGenerator = new ExceptionsListItemGenerator(); + private readonly supertest = this.ctx.getService('supertest'); + private readonly log = this.ctx.getService('log'); + + private getHttpResponseFailureHandler( + ignoredStatusCodes: number[] = [] + ): (res: Response) => Promise { + return async (res) => { + if (!res.ok && !ignoredStatusCodes.includes(res.status)) { + throw new EndpointError(JSON.stringify(res.error, null, 2)); + } + + return res; + }; + } + + private async ensureListExists(listDefinition: CreateExceptionListSchema): Promise { + // attempt to create it and ignore 409 (already exists) errors + await this.supertest + .post(EXCEPTION_LIST_URL) + .set('kbn-xsrf', 'true') + .send(listDefinition) + .then(this.getHttpResponseFailureHandler([409])); + } + + private async createExceptionItem( + createPayload: CreateExceptionListItemSchema + ): Promise { + const artifact = await this.supertest + .post(EXCEPTION_LIST_ITEM_URL) + .set('kbn-xsrf', 'true') + .send(createPayload) + .then(this.getHttpResponseFailureHandler()) + .then((response) => response.body as ExceptionListItemSchema); + + const { item_id: itemId, namespace_type: namespaceType } = artifact; + + this.log.info(`Created exception list item: ${itemId}`); + + const cleanup = async () => { + const deleteResponse = await this.supertest + .delete(`${EXCEPTION_LIST_ITEM_URL}?item_id=${itemId}&namespace_type=${namespaceType}`) + .set('kbn-xsrf', 'true') + .send() + .then(this.getHttpResponseFailureHandler([404])); + + this.log.info(`Deleted exception list item: ${itemId} (${deleteResponse.status})`); + }; + + return { + artifact, + cleanup, + }; + } + + async createTrustedApp( + overrides: Partial = {} + ): Promise { + await this.ensureListExists(TRUSTED_APPS_EXCEPTION_LIST_DEFINITION); + const trustedApp = this.exceptionsGenerator.generateTrustedAppForCreate(overrides); + + return this.createExceptionItem(trustedApp); + } +} diff --git a/x-pack/test/security_solution_endpoint/services/index.ts b/x-pack/test/security_solution_endpoint/services/index.ts index a7e89855411916..6880ce54e99aa9 100644 --- a/x-pack/test/security_solution_endpoint/services/index.ts +++ b/x-pack/test/security_solution_endpoint/services/index.ts @@ -10,10 +10,12 @@ import { EndpointPolicyTestResourcesProvider } from './endpoint_policy'; import { IngestManagerProvider } from '../../common/services/ingest_manager'; import { EndpointTelemetryTestResourcesProvider } from './endpoint_telemetry'; import { EndpointTestResources } from './endpoint'; +import { EndpointArtifactsTestResources } from './endpoint_artifacts'; export const services = { ...xPackFunctionalServices, endpointTestResources: EndpointTestResources, + endpointArtifactTestResources: EndpointArtifactsTestResources, policyTestResources: EndpointPolicyTestResourcesProvider, telemetryTestResources: EndpointTelemetryTestResourcesProvider, ingestManager: IngestManagerProvider, diff --git a/x-pack/test/security_solution_endpoint_api_int/apis/endpoint_artifacts.ts b/x-pack/test/security_solution_endpoint_api_int/apis/endpoint_artifacts.ts new file mode 100644 index 00000000000000..58f6fbf58ccb5b --- /dev/null +++ b/x-pack/test/security_solution_endpoint_api_int/apis/endpoint_artifacts.ts @@ -0,0 +1,229 @@ +/* + * 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 { EXCEPTION_LIST_ITEM_URL } from '@kbn/securitysolution-list-constants'; +import { ExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../ftr_provider_context'; +import { PolicyTestResourceInfo } from '../../security_solution_endpoint/services/endpoint_policy'; +import { ArtifactTestData } from '../../security_solution_endpoint/services/endpoint_artifacts'; +import { BY_POLICY_ARTIFACT_TAG_PREFIX } from '../../../plugins/security_solution/common/endpoint/service/artifacts'; +import { ExceptionsListItemGenerator } from '../../../plugins/security_solution/common/endpoint/data_generators/exceptions_list_item_generator'; +import { + createUserAndRole, + deleteUserAndRole, + ROLES, +} from '../../common/services/security_solution'; + +export default function ({ getService }: FtrProviderContext) { + const supertest = getService('supertest'); + const supertestWithoutAuth = getService('supertestWithoutAuth'); + const endpointPolicyTestResources = getService('endpointPolicyTestResources'); + const endpointArtifactTestResources = getService('endpointArtifactTestResources'); + + describe('Endpoint artifacts (via lists plugin)', () => { + let fleetEndpointPolicy: PolicyTestResourceInfo; + + before(async () => { + // Create an endpoint policy in fleet we can work with + fleetEndpointPolicy = await endpointPolicyTestResources.createPolicy(); + + // create role/user + await createUserAndRole(getService, ROLES.detections_admin); + }); + + after(async () => { + if (fleetEndpointPolicy) { + await fleetEndpointPolicy.cleanup(); + } + + // delete role/user + await deleteUserAndRole(getService, ROLES.detections_admin); + }); + + const anEndpointArtifactError = (res: { body: { message: string } }) => { + expect(res.body.message).to.match(/EndpointArtifactError/); + }; + const anErrorMessageWith = ( + value: string | RegExp + ): ((res: { body: { message: string } }) => void) => { + return (res) => { + if (value instanceof RegExp) { + expect(res.body.message).to.match(value); + } else { + expect(res.body.message).to.be(value); + } + }; + }; + + describe('and accessing trusted apps', () => { + const exceptionsGenerator = new ExceptionsListItemGenerator(); + let trustedAppData: ArtifactTestData; + + type TrustedAppApiCallsInterface = Array<{ + method: keyof Pick; + path: string; + // The body just needs to have the properties we care about in the tests. This should cover most + // mocks used for testing that support different interfaces + getBody: () => Pick; + }>; + + beforeEach(async () => { + trustedAppData = await endpointArtifactTestResources.createTrustedApp({ + tags: [`${BY_POLICY_ARTIFACT_TAG_PREFIX}${fleetEndpointPolicy.packagePolicy.id}`], + }); + }); + + afterEach(async () => { + if (trustedAppData) { + await trustedAppData.cleanup(); + } + }); + + const trustedAppApiCalls: TrustedAppApiCallsInterface = [ + { + method: 'post', + path: EXCEPTION_LIST_ITEM_URL, + getBody: () => exceptionsGenerator.generateTrustedAppForCreate(), + }, + { + method: 'put', + path: EXCEPTION_LIST_ITEM_URL, + getBody: () => + exceptionsGenerator.generateTrustedAppForUpdate({ + id: trustedAppData.artifact.id, + item_id: trustedAppData.artifact.item_id, + }), + }, + ]; + + describe('and has authorization to manage endpoint security', () => { + for (const trustedAppApiCall of trustedAppApiCalls) { + it(`should error on [${trustedAppApiCall.method}] if invalid condition entry fields are used`, async () => { + const body = trustedAppApiCall.getBody(); + + body.entries[0].field = 'some.invalid.field'; + + await supertest[trustedAppApiCall.method](trustedAppApiCall.path) + .set('kbn-xsrf', 'true') + .send(body) + .expect(400) + .expect(anEndpointArtifactError) + .expect(anErrorMessageWith(/types that failed validation:/)); + }); + + it(`should error on [${trustedAppApiCall.method}] if a condition entry field is used more than once`, async () => { + const body = trustedAppApiCall.getBody(); + + body.entries.push({ ...body.entries[0] }); + + await supertest[trustedAppApiCall.method](trustedAppApiCall.path) + .set('kbn-xsrf', 'true') + .send(body) + .expect(400) + .expect(anEndpointArtifactError) + .expect(anErrorMessageWith(/Duplicate/)); + }); + + it(`should error on [${trustedAppApiCall.method}] if an invalid hash is used`, async () => { + const body = trustedAppApiCall.getBody(); + + body.entries = [ + { + field: 'process.hash.md5', + operator: 'included', + type: 'match', + value: '1', + }, + ]; + + await supertest[trustedAppApiCall.method](trustedAppApiCall.path) + .set('kbn-xsrf', 'true') + .send(body) + .expect(400) + .expect(anEndpointArtifactError) + .expect(anErrorMessageWith(/invalid hash/)); + }); + + it(`should error on [${trustedAppApiCall.method}] if signer is set for a non windows os entry item`, async () => { + const body = trustedAppApiCall.getBody(); + + body.os_types = ['linux']; + body.entries = [ + { + field: 'process.Ext.code_signature', + entries: [ + { + field: 'trusted', + value: 'true', + type: 'match', + operator: 'included', + }, + { + field: 'subject_name', + value: 'foo', + type: 'match', + operator: 'included', + }, + ], + type: 'nested', + }, + ]; + + await supertest[trustedAppApiCall.method](trustedAppApiCall.path) + .set('kbn-xsrf', 'true') + .send(body) + .expect(400) + .expect(anEndpointArtifactError) + .expect(anErrorMessageWith(/^.*(?!process\.Ext\.code_signature)/)); + }); + + it(`should error on [${trustedAppApiCall.method}] if more than one OS is set`, async () => { + const body = trustedAppApiCall.getBody(); + + body.os_types = ['linux', 'windows']; + + await supertest[trustedAppApiCall.method](trustedAppApiCall.path) + .set('kbn-xsrf', 'true') + .send(body) + .expect(400) + .expect(anEndpointArtifactError) + .expect(anErrorMessageWith(/\[osTypes\]: array size is \[2\]/)); + }); + + it(`should error on [${trustedAppApiCall.method}] if policy id is invalid`, async () => { + const body = trustedAppApiCall.getBody(); + + body.tags = [`${BY_POLICY_ARTIFACT_TAG_PREFIX}123`]; + + await supertest[trustedAppApiCall.method](trustedAppApiCall.path) + .set('kbn-xsrf', 'true') + .send(body) + .expect(400) + .expect(anEndpointArtifactError) + .expect(anErrorMessageWith(/invalid policy ids/)); + }); + } + }); + + describe('and user DOES NOT have authorization to manage endpoint security', () => { + for (const trustedAppApiCall of trustedAppApiCalls) { + it(`should error on [${trustedAppApiCall.method}]`, async () => { + await supertestWithoutAuth[trustedAppApiCall.method](trustedAppApiCall.path) + .auth(ROLES.detections_admin, 'changeme') + .set('kbn-xsrf', 'true') + .send(trustedAppApiCall.getBody()) + .expect(403, { + status_code: 403, + message: 'EndpointArtifactError: Endpoint authorization failure', + }); + }); + } + }); + }); + }); +} diff --git a/x-pack/test/security_solution_endpoint_api_int/apis/index.ts b/x-pack/test/security_solution_endpoint_api_int/apis/index.ts index db2de64b3bbe43..5c2a3f168248c6 100644 --- a/x-pack/test/security_solution_endpoint_api_int/apis/index.ts +++ b/x-pack/test/security_solution_endpoint_api_int/apis/index.ts @@ -32,5 +32,6 @@ export default function endpointAPIIntegrationTests(providerContext: FtrProvider loadTestFile(require.resolve('./policy')); loadTestFile(require.resolve('./package')); loadTestFile(require.resolve('./endpoint_authz')); + loadTestFile(require.resolve('./endpoint_artifacts')); }); } diff --git a/x-pack/test/security_solution_endpoint_api_int/services/index.ts b/x-pack/test/security_solution_endpoint_api_int/services/index.ts index e4f96333bac314..eb66d738af1b0d 100644 --- a/x-pack/test/security_solution_endpoint_api_int/services/index.ts +++ b/x-pack/test/security_solution_endpoint_api_int/services/index.ts @@ -8,9 +8,13 @@ import { services as xPackAPIServices } from '../../api_integration/services'; import { ResolverGeneratorProvider } from './resolver'; import { EndpointTestResources } from '../../security_solution_endpoint/services/endpoint'; +import { EndpointPolicyTestResourcesProvider } from '../../security_solution_endpoint/services/endpoint_policy'; +import { EndpointArtifactsTestResources } from '../../security_solution_endpoint/services/endpoint_artifacts'; export const services = { ...xPackAPIServices, resolverGenerator: ResolverGeneratorProvider, endpointTestResources: EndpointTestResources, + endpointPolicyTestResources: EndpointPolicyTestResourcesProvider, + endpointArtifactTestResources: EndpointArtifactsTestResources, }; From 43569cb6850ce23a593830b2db9d4d03972d19ab Mon Sep 17 00:00:00 2001 From: Paul Tavares <56442535+paul-tavares@users.noreply.github.com> Date: Thu, 20 Jan 2022 12:20:40 -0500 Subject: [PATCH 084/108] [Security Solution][Endpoint] Change endpoint authz service to again check for `superuser` role in addition to `fleet.all` (#123425) * Change endpoint authz to use `user.roles` in determining user's authorization * Removed hook that was manually checking for isolation authz --- .../common/endpoint/actions.ts | 14 ------- .../endpoint/service/authz/authz.test.ts | 27 ++++++++++--- .../common/endpoint/service/authz/authz.ts | 7 +++- .../endpoint/use_endpoint_privileges.ts | 24 +++++++++-- .../hooks/endpoint/use_isolate_privileges.ts | 40 ------------------- .../use_host_isolation_action.tsx | 4 +- .../take_action_dropdown/index.test.tsx | 5 +-- .../server/request_context_factory.ts | 3 +- 8 files changed, 52 insertions(+), 72 deletions(-) delete mode 100644 x-pack/plugins/security_solution/common/endpoint/actions.ts delete mode 100644 x-pack/plugins/security_solution/public/common/hooks/endpoint/use_isolate_privileges.ts diff --git a/x-pack/plugins/security_solution/common/endpoint/actions.ts b/x-pack/plugins/security_solution/common/endpoint/actions.ts deleted file mode 100644 index 287ebddacad9a0..00000000000000 --- a/x-pack/plugins/security_solution/common/endpoint/actions.ts +++ /dev/null @@ -1,14 +0,0 @@ -/* - * 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 const userCanIsolate = (roles: readonly string[] | undefined): boolean => { - // only superusers can write to the fleet index (or look up endpoint data to convert endp ID to agent ID) - if (!roles || roles.length === 0) { - return false; - } - return roles.includes('superuser'); -}; diff --git a/x-pack/plugins/security_solution/common/endpoint/service/authz/authz.test.ts b/x-pack/plugins/security_solution/common/endpoint/service/authz/authz.test.ts index 947615bdf7e888..3d64bd98b758ed 100644 --- a/x-pack/plugins/security_solution/common/endpoint/service/authz/authz.test.ts +++ b/x-pack/plugins/security_solution/common/endpoint/service/authz/authz.test.ts @@ -13,10 +13,12 @@ import { EndpointAuthzKeyList } from '../../types/authz'; describe('Endpoint Authz service', () => { let licenseService: ReturnType; let fleetAuthz: FleetAuthz; + let userRoles: string[]; beforeEach(() => { licenseService = createLicenseServiceMock(); fleetAuthz = createFleetAuthzMock(); + userRoles = ['superuser']; }); describe('calculateEndpointAuthz()', () => { @@ -27,24 +29,33 @@ describe('Endpoint Authz service', () => { ['canIsolateHost'], ['canUnIsolateHost'], ])('should set `%s` to `true`', (authProperty) => { - expect(calculateEndpointAuthz(licenseService, fleetAuthz)[authProperty]).toBe(true); + expect(calculateEndpointAuthz(licenseService, fleetAuthz, userRoles)[authProperty]).toBe( + true + ); }); it('should set `canIsolateHost` to false if not proper license', () => { licenseService.isPlatinumPlus.mockReturnValue(false); - expect(calculateEndpointAuthz(licenseService, fleetAuthz).canIsolateHost).toBe(false); + expect(calculateEndpointAuthz(licenseService, fleetAuthz, userRoles).canIsolateHost).toBe( + false + ); }); it('should set `canUnIsolateHost` to true even if not proper license', () => { licenseService.isPlatinumPlus.mockReturnValue(false); - expect(calculateEndpointAuthz(licenseService, fleetAuthz).canUnIsolateHost).toBe(true); + expect(calculateEndpointAuthz(licenseService, fleetAuthz, userRoles).canUnIsolateHost).toBe( + true + ); }); }); describe('and `fleet.all` access is false', () => { - beforeEach(() => (fleetAuthz.fleet.all = false)); + beforeEach(() => { + fleetAuthz.fleet.all = false; + userRoles = []; + }); it.each([ ['canAccessFleet'], @@ -52,13 +63,17 @@ describe('Endpoint Authz service', () => { ['canIsolateHost'], ['canUnIsolateHost'], ])('should set `%s` to `false`', (authProperty) => { - expect(calculateEndpointAuthz(licenseService, fleetAuthz)[authProperty]).toBe(false); + expect(calculateEndpointAuthz(licenseService, fleetAuthz, userRoles)[authProperty]).toBe( + false + ); }); it('should set `canUnIsolateHost` to false when policy is also not platinum', () => { licenseService.isPlatinumPlus.mockReturnValue(false); - expect(calculateEndpointAuthz(licenseService, fleetAuthz).canUnIsolateHost).toBe(false); + expect(calculateEndpointAuthz(licenseService, fleetAuthz, userRoles).canUnIsolateHost).toBe( + false + ); }); }); }); diff --git a/x-pack/plugins/security_solution/common/endpoint/service/authz/authz.ts b/x-pack/plugins/security_solution/common/endpoint/service/authz/authz.ts index 83bd267e56c53d..6b20a376bbf61d 100644 --- a/x-pack/plugins/security_solution/common/endpoint/service/authz/authz.ts +++ b/x-pack/plugins/security_solution/common/endpoint/service/authz/authz.ts @@ -8,6 +8,7 @@ import { LicenseService } from '../../../license'; import { FleetAuthz } from '../../../../../fleet/common'; import { EndpointAuthz } from '../../types/authz'; +import { MaybeImmutable } from '../../types'; /** * Used by both the server and the UI to generate the Authorization for access to Endpoint related @@ -15,13 +16,15 @@ import { EndpointAuthz } from '../../types/authz'; * * @param licenseService * @param fleetAuthz + * @param userRoles */ export const calculateEndpointAuthz = ( licenseService: LicenseService, - fleetAuthz: FleetAuthz + fleetAuthz: FleetAuthz, + userRoles: MaybeImmutable ): EndpointAuthz => { const isPlatinumPlusLicense = licenseService.isPlatinumPlus(); - const hasAllAccessToFleet = fleetAuthz.fleet.all; + const hasAllAccessToFleet = fleetAuthz.fleet.all || userRoles.includes('superuser'); return { canAccessFleet: hasAllAccessToFleet, diff --git a/x-pack/plugins/security_solution/public/common/components/user_privileges/endpoint/use_endpoint_privileges.ts b/x-pack/plugins/security_solution/public/common/components/user_privileges/endpoint/use_endpoint_privileges.ts index 6fa0c51f500da0..e6c7b9a5d0e95a 100644 --- a/x-pack/plugins/security_solution/public/common/components/user_privileges/endpoint/use_endpoint_privileges.ts +++ b/x-pack/plugins/security_solution/public/common/components/user_privileges/endpoint/use_endpoint_privileges.ts @@ -8,7 +8,11 @@ import { useEffect, useMemo, useRef, useState } from 'react'; import { useCurrentUser, useKibana } from '../../../lib/kibana'; import { useLicense } from '../../../hooks/use_license'; -import { EndpointPrivileges, Immutable } from '../../../../../common/endpoint/types'; +import { + EndpointPrivileges, + Immutable, + MaybeImmutable, +} from '../../../../../common/endpoint/types'; import { calculateEndpointAuthz, getEndpointAuthzInitialState, @@ -28,17 +32,19 @@ export const useEndpointPrivileges = (): Immutable => { const licenseService = useLicense(); const [fleetCheckDone, setFleetCheckDone] = useState(false); const [fleetAuthz, setFleetAuthz] = useState(null); + const [userRolesCheckDone, setUserRolesCheckDone] = useState(false); + const [userRoles, setUserRoles] = useState>([]); const privileges = useMemo(() => { const privilegeList: EndpointPrivileges = Object.freeze({ - loading: !fleetCheckDone || !user, + loading: !fleetCheckDone || !userRolesCheckDone || !user, ...(fleetAuthz - ? calculateEndpointAuthz(licenseService, fleetAuthz) + ? calculateEndpointAuthz(licenseService, fleetAuthz, userRoles) : getEndpointAuthzInitialState()), }); return privilegeList; - }, [fleetCheckDone, user, fleetAuthz, licenseService]); + }, [fleetCheckDone, userRolesCheckDone, user, fleetAuthz, licenseService, userRoles]); // Check if user can access fleet useEffect(() => { @@ -64,6 +70,16 @@ export const useEndpointPrivileges = (): Immutable => { })(); }, [fleetServices]); + // get user roles + useEffect(() => { + (async () => { + if (user && isMounted.current) { + setUserRoles(user?.roles); + setUserRolesCheckDone(true); + } + })(); + }, [user]); + // Capture if component is unmounted useEffect( () => () => { diff --git a/x-pack/plugins/security_solution/public/common/hooks/endpoint/use_isolate_privileges.ts b/x-pack/plugins/security_solution/public/common/hooks/endpoint/use_isolate_privileges.ts deleted file mode 100644 index 23ef6d586adc54..00000000000000 --- a/x-pack/plugins/security_solution/public/common/hooks/endpoint/use_isolate_privileges.ts +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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 { useEffect, useState } from 'react'; -import { userCanIsolate } from '../../../../common/endpoint/actions'; -import { useKibana } from '../../lib/kibana'; -import { useLicense } from '../use_license'; - -interface IsolationPriviledgesStatus { - isLoading: boolean; - isAllowed: boolean; -} - -/* - * Host isolation requires superuser privileges and at least a platinum license - */ -export const useIsolationPrivileges = (): IsolationPriviledgesStatus => { - const [isLoading, setIsLoading] = useState(false); - const [canIsolate, setCanIsolate] = useState(false); - - const isPlatinumPlus = useLicense().isPlatinumPlus(); - const services = useKibana().services; - - useEffect(() => { - setIsLoading(true); - const user = services.security.authc.getCurrentUser(); - if (user) { - user.then((authenticatedUser) => { - setCanIsolate(userCanIsolate(authenticatedUser.roles)); - setIsLoading(false); - }); - } - }, [services.security.authc]); - - return { isLoading, isAllowed: canIsolate && isPlatinumPlus ? true : false }; -}; diff --git a/x-pack/plugins/security_solution/public/detections/components/host_isolation/use_host_isolation_action.tsx b/x-pack/plugins/security_solution/public/detections/components/host_isolation/use_host_isolation_action.tsx index a7c3cb900d7c9c..57d81d48fca05b 100644 --- a/x-pack/plugins/security_solution/public/detections/components/host_isolation/use_host_isolation_action.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/host_isolation/use_host_isolation_action.tsx @@ -9,11 +9,11 @@ import { EuiContextMenuItem } from '@elastic/eui'; import type { TimelineEventsDetailsItem } from '../../../../common/search_strategy'; import { isIsolationSupported } from '../../../../common/endpoint/service/host_isolation/utils'; import { HostStatus } from '../../../../common/endpoint/types'; -import { useIsolationPrivileges } from '../../../common/hooks/endpoint/use_isolate_privileges'; import { isAlertFromEndpointEvent } from '../../../common/utils/endpoint_alert_check'; import { useHostIsolationStatus } from '../../containers/detection_engine/alerts/use_host_isolation_status'; import { ISOLATE_HOST, UNISOLATE_HOST } from './translations'; import { getFieldValue } from './helpers'; +import { useUserPrivileges } from '../../../common/components/user_privileges'; interface UseHostIsolationActionProps { closePopover: () => void; @@ -62,7 +62,7 @@ export const useHostIsolationAction = ({ capabilities, }); - const { isAllowed: isIsolationAllowed } = useIsolationPrivileges(); + const isIsolationAllowed = useUserPrivileges().endpointPrivileges.canIsolateHost; const isolateHostHandler = useCallback(() => { closePopover(); diff --git a/x-pack/plugins/security_solution/public/detections/components/take_action_dropdown/index.test.tsx b/x-pack/plugins/security_solution/public/detections/components/take_action_dropdown/index.test.tsx index e12f01458da4c4..0c525a2d77706a 100644 --- a/x-pack/plugins/security_solution/public/detections/components/take_action_dropdown/index.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/take_action_dropdown/index.test.tsx @@ -21,9 +21,6 @@ import { useKibana } from '../../../common/lib/kibana'; jest.mock('../user_info', () => ({ useUserData: jest.fn().mockReturnValue([{ canUserCRUD: true, hasIndexWrite: true }]), })); -jest.mock('../../../common/hooks/endpoint/use_isolate_privileges', () => ({ - useIsolationPrivileges: jest.fn().mockReturnValue({ isAllowed: true }), -})); jest.mock('../../../common/lib/kibana', () => ({ useKibana: jest.fn(), useGetUserCasesPermissions: jest.fn().mockReturnValue({ crud: true }), @@ -60,6 +57,8 @@ jest.mock('../../containers/detection_engine/alerts/use_host_isolation_status', }; }); +jest.mock('../../../common/components/user_privileges'); + describe('take action dropdown', () => { const defaultProps: TakeActionDropdownProps = { detailsData: mockAlertDetailsData as TimelineEventsDetailsItem[], diff --git a/x-pack/plugins/security_solution/server/request_context_factory.ts b/x-pack/plugins/security_solution/server/request_context_factory.ts index c84f2e9eab9edf..26bb56113e635e 100644 --- a/x-pack/plugins/security_solution/server/request_context_factory.ts +++ b/x-pack/plugins/security_solution/server/request_context_factory.ts @@ -83,7 +83,8 @@ export class RequestContextFactory implements IRequestContextFactory { if (!startPlugins.fleet) { endpointAuthz = getEndpointAuthzInitialState(); } else { - endpointAuthz = calculateEndpointAuthz(licenseService, fleetAuthz); + const userRoles = security?.authc.getCurrentUser(request)?.roles ?? []; + endpointAuthz = calculateEndpointAuthz(licenseService, fleetAuthz, userRoles); } } From ff51bb7fef26d99a4fedad9db77ae8045098913c Mon Sep 17 00:00:00 2001 From: Scotty Bollinger Date: Thu, 20 Jan 2022 11:25:28 -0600 Subject: [PATCH 085/108] Prevent Negative boosts in Relevance Tuning (#123468) --- .../boosts/boost_item_content/boost_item_content.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/relevance_tuning/boosts/boost_item_content/boost_item_content.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/relevance_tuning/boosts/boost_item_content/boost_item_content.tsx index 5abf3652d66229..44c5f276cd20c5 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/relevance_tuning/boosts/boost_item_content/boost_item_content.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/relevance_tuning/boosts/boost_item_content/boost_item_content.tsx @@ -55,7 +55,7 @@ export const BoostItemContent: React.FC = ({ boost, index, name }) => { fullWidth > Date: Thu, 20 Jan 2022 13:07:46 -0500 Subject: [PATCH 086/108] [Maps][ML] Integration part 1: Create anomalies layer in maps (#122862) * wip: create anomalies layer in maps * ensure anomaly search respects time filter * add custom color ramp and connected layer * update ml api service types * add tooltip * update naming and types * update warning messages. make actual layer default * remove any --- x-pack/plugins/maps/common/index.ts | 1 + .../plugins/ml/common/constants/anomalies.ts | 19 + x-pack/plugins/ml/common/index.ts | 7 +- x-pack/plugins/ml/common/util/job_utils.ts | 6 + x-pack/plugins/ml/public/application/app.tsx | 2 +- .../explorer/explorer_charts/map_config.ts | 20 +- .../services/ml_api_service/jobs.ts | 7 + .../ml/public/maps/anomaly_job_selector.tsx | 86 +++++ .../ml/public/maps/anomaly_layer_wizard.tsx | 30 ++ .../maps/anomaly_layer_wizard_factory.tsx | 101 +++++ .../plugins/ml/public/maps/anomaly_source.tsx | 360 ++++++++++++++++++ .../ml/public/maps/anomaly_source_factory.ts | 42 ++ .../ml/public/maps/anomaly_source_field.ts | 169 ++++++++ .../maps/create_anomaly_source_editor.tsx | 89 +++++ .../plugins/ml/public/maps/layer_selector.tsx | 68 ++++ .../ml/public/maps/register_map_extension.ts | 31 ++ .../maps/update_anomaly_source_editor.tsx | 50 +++ x-pack/plugins/ml/public/maps/util.ts | 153 ++++++++ x-pack/plugins/ml/public/plugin.ts | 19 +- .../ml/public/register_helper/index.ts | 1 + .../ml/server/models/job_service/jobs.ts | 7 + .../plugins/ml/server/routes/job_service.ts | 36 ++ 22 files changed, 1280 insertions(+), 24 deletions(-) create mode 100644 x-pack/plugins/ml/public/maps/anomaly_job_selector.tsx create mode 100644 x-pack/plugins/ml/public/maps/anomaly_layer_wizard.tsx create mode 100644 x-pack/plugins/ml/public/maps/anomaly_layer_wizard_factory.tsx create mode 100644 x-pack/plugins/ml/public/maps/anomaly_source.tsx create mode 100644 x-pack/plugins/ml/public/maps/anomaly_source_factory.ts create mode 100644 x-pack/plugins/ml/public/maps/anomaly_source_field.ts create mode 100644 x-pack/plugins/ml/public/maps/create_anomaly_source_editor.tsx create mode 100644 x-pack/plugins/ml/public/maps/layer_selector.tsx create mode 100644 x-pack/plugins/ml/public/maps/register_map_extension.ts create mode 100644 x-pack/plugins/ml/public/maps/update_anomaly_source_editor.tsx create mode 100644 x-pack/plugins/ml/public/maps/util.ts diff --git a/x-pack/plugins/maps/common/index.ts b/x-pack/plugins/maps/common/index.ts index f3b8595efc8d19..3e26cdc82fbbba 100644 --- a/x-pack/plugins/maps/common/index.ts +++ b/x-pack/plugins/maps/common/index.ts @@ -33,4 +33,5 @@ export type { TooltipFeature, VectorLayerDescriptor, VectorStyleDescriptor, + VectorSourceRequestMeta, } from './descriptor_types'; diff --git a/x-pack/plugins/ml/common/constants/anomalies.ts b/x-pack/plugins/ml/common/constants/anomalies.ts index 5cca321482a000..4decdcb2b2d28a 100644 --- a/x-pack/plugins/ml/common/constants/anomalies.ts +++ b/x-pack/plugins/ml/common/constants/anomalies.ts @@ -31,6 +31,25 @@ export const SEVERITY_COLORS = { BLANK: '#ffffff', }; +export const SEVERITY_COLOR_RAMP = [ + { + stop: ANOMALY_THRESHOLD.LOW, + color: SEVERITY_COLORS.WARNING, + }, + { + stop: ANOMALY_THRESHOLD.MINOR, + color: SEVERITY_COLORS.MINOR, + }, + { + stop: ANOMALY_THRESHOLD.MAJOR, + color: SEVERITY_COLORS.MAJOR, + }, + { + stop: ANOMALY_THRESHOLD.CRITICAL, + color: SEVERITY_COLORS.CRITICAL, + }, +]; + export const ANOMALY_RESULT_TYPE = { BUCKET: 'bucket', RECORD: 'record', diff --git a/x-pack/plugins/ml/common/index.ts b/x-pack/plugins/ml/common/index.ts index c76b662df7a5a0..de5989d92d2088 100644 --- a/x-pack/plugins/ml/common/index.ts +++ b/x-pack/plugins/ml/common/index.ts @@ -7,7 +7,12 @@ export { ES_CLIENT_TOTAL_HITS_RELATION } from './types/es_client'; export type { ChartData } from './types/field_histograms'; -export { ANOMALY_SEVERITY, ANOMALY_THRESHOLD, SEVERITY_COLORS } from './constants/anomalies'; +export { + ANOMALY_SEVERITY, + ANOMALY_THRESHOLD, + SEVERITY_COLOR_RAMP, + SEVERITY_COLORS, +} from './constants/anomalies'; export { getSeverityColor, getSeverityType } from './util/anomaly_utils'; export { isPopulatedObject } from './util/object_utils'; export { composeValidators, patternValidator } from './util/validators'; diff --git a/x-pack/plugins/ml/common/util/job_utils.ts b/x-pack/plugins/ml/common/util/job_utils.ts index e66d8de5bd15e7..f1991118d4e368 100644 --- a/x-pack/plugins/ml/common/util/job_utils.ts +++ b/x-pack/plugins/ml/common/util/job_utils.ts @@ -73,6 +73,12 @@ export function isMappableJob(job: CombinedJob, detectorIndex: number): boolean return isMappable; } +// Returns a boolean indicating whether the specified job is suitable for maps plugin. +export function isJobWithGeoData(job: Job): boolean { + const { detectors } = job.analysis_config; + return detectors.some((detector) => detector.function === ML_JOB_AGGREGATION.LAT_LONG); +} + /** * Validates that composite definition only have sources that are only terms and date_histogram * if composite is defined. diff --git a/x-pack/plugins/ml/public/application/app.tsx b/x-pack/plugins/ml/public/application/app.tsx index e61549efe8adc9..d38a37716b82cd 100644 --- a/x-pack/plugins/ml/public/application/app.tsx +++ b/x-pack/plugins/ml/public/application/app.tsx @@ -28,7 +28,7 @@ import { mlApiServicesProvider } from './services/ml_api_service'; import { HttpService } from './services/http_service'; import { ML_APP_LOCATOR, ML_PAGES } from '../../common/constants/locator'; -export type MlDependencies = Omit & +export type MlDependencies = Omit & MlStartDependencies; interface AppProps { diff --git a/x-pack/plugins/ml/public/application/explorer/explorer_charts/map_config.ts b/x-pack/plugins/ml/public/application/explorer/explorer_charts/map_config.ts index 7f3378fc1c858c..51b9732aebdd0c 100644 --- a/x-pack/plugins/ml/public/application/explorer/explorer_charts/map_config.ts +++ b/x-pack/plugins/ml/public/application/explorer/explorer_charts/map_config.ts @@ -6,29 +6,11 @@ */ import { FIELD_ORIGIN, LAYER_TYPE, STYLE_TYPE } from '../../../../../maps/common'; -import { ANOMALY_THRESHOLD, SEVERITY_COLORS } from '../../../../common'; +import { SEVERITY_COLOR_RAMP } from '../../../../common'; import { AnomaliesTableData } from '../explorer_utils'; const FEATURE = 'Feature'; const POINT = 'Point'; -const SEVERITY_COLOR_RAMP = [ - { - stop: ANOMALY_THRESHOLD.LOW, - color: SEVERITY_COLORS.WARNING, - }, - { - stop: ANOMALY_THRESHOLD.MINOR, - color: SEVERITY_COLORS.MINOR, - }, - { - stop: ANOMALY_THRESHOLD.MAJOR, - color: SEVERITY_COLORS.MAJOR, - }, - { - stop: ANOMALY_THRESHOLD.CRITICAL, - color: SEVERITY_COLORS.CRITICAL, - }, -]; function getAnomalyFeatures( anomalies: AnomaliesTableData['anomalies'], diff --git a/x-pack/plugins/ml/public/application/services/ml_api_service/jobs.ts b/x-pack/plugins/ml/public/application/services/ml_api_service/jobs.ts index 96c5e1abce1707..f1492074ed7622 100644 --- a/x-pack/plugins/ml/public/application/services/ml_api_service/jobs.ts +++ b/x-pack/plugins/ml/public/application/services/ml_api_service/jobs.ts @@ -45,6 +45,13 @@ export const jobsApiProvider = (httpService: HttpService) => ({ }); }, + jobIdsWithGeo() { + return httpService.http({ + path: `${ML_BASE_PATH}/jobs/jobs_with_geo`, + method: 'GET', + }); + }, + jobsWithTimerange(dateFormatTz: string) { const body = JSON.stringify({ dateFormatTz }); return httpService.http<{ diff --git a/x-pack/plugins/ml/public/maps/anomaly_job_selector.tsx b/x-pack/plugins/ml/public/maps/anomaly_job_selector.tsx new file mode 100644 index 00000000000000..aacc8e37d935ba --- /dev/null +++ b/x-pack/plugins/ml/public/maps/anomaly_job_selector.tsx @@ -0,0 +1,86 @@ +/* + * 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 React, { Component } from 'react'; + +import { EuiComboBox, EuiFormRow, EuiComboBoxOptionOption } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { isEqual } from 'lodash'; +import type { MlApiServices } from '../application/services/ml_api_service'; + +interface Props { + onJobChange: (jobId: string) => void; + mlJobsService: MlApiServices['jobs']; +} + +interface State { + jobId?: string; + jobIdList?: Array>; +} + +export class AnomalyJobSelector extends Component { + private _isMounted: boolean = false; + + state: State = {}; + + private async _loadJobs() { + const jobIdList = await this.props.mlJobsService.jobIdsWithGeo(); + const options = jobIdList.map((jobId) => { + return { label: jobId, value: jobId }; + }); + if (this._isMounted && !isEqual(options, this.state.jobIdList)) { + this.setState({ + jobIdList: options, + }); + } + } + + componentDidUpdate(prevProps: Readonly, prevState: Readonly): void { + this._loadJobs(); + } + + componentDidMount(): void { + this._isMounted = true; + this._loadJobs(); + } + + componentWillUnmount() { + this._isMounted = false; + } + + onJobIdSelect = (selectedOptions: Array>) => { + const jobId: string = selectedOptions[0].value!; + if (this._isMounted) { + this.setState({ jobId }); + this.props.onJobChange(jobId); + } + }; + + render() { + if (!this.state.jobIdList) { + return null; + } + + return ( + + + + ); + } +} diff --git a/x-pack/plugins/ml/public/maps/anomaly_layer_wizard.tsx b/x-pack/plugins/ml/public/maps/anomaly_layer_wizard.tsx new file mode 100644 index 00000000000000..b45cce35a89ba6 --- /dev/null +++ b/x-pack/plugins/ml/public/maps/anomaly_layer_wizard.tsx @@ -0,0 +1,30 @@ +/* + * 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 { i18n } from '@kbn/i18n'; +import { LAYER_WIZARD_CATEGORY } from '../../../maps/common'; +import type { LayerWizard } from '../../../maps/public'; + +export const anomalyLayerWizard: Partial = { + categories: [LAYER_WIZARD_CATEGORY.SOLUTIONS, LAYER_WIZARD_CATEGORY.ELASTICSEARCH], + description: i18n.translate('xpack.ml.maps.anomalyLayerDescription', { + defaultMessage: 'Display anomalies from a machine learning job', + }), + disabledReason: i18n.translate('xpack.ml.maps.anomalyLayerUnavailableMessage', { + defaultMessage: + 'Anomalies layers are a subscription feature. Ensure you have the right subscription and access to Machine Learning.', + }), + icon: 'outlierDetectionJob', + getIsDisabled: () => { + // return false by default + return false; + }, + title: i18n.translate('xpack.ml.maps.anomalyLayerTitle', { + defaultMessage: 'ML Anomalies', + }), + order: 100, +}; diff --git a/x-pack/plugins/ml/public/maps/anomaly_layer_wizard_factory.tsx b/x-pack/plugins/ml/public/maps/anomaly_layer_wizard_factory.tsx new file mode 100644 index 00000000000000..70a81c89816a2d --- /dev/null +++ b/x-pack/plugins/ml/public/maps/anomaly_layer_wizard_factory.tsx @@ -0,0 +1,101 @@ +/* + * 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 React from 'react'; +import { htmlIdGenerator } from '@elastic/eui'; +import type { StartServicesAccessor } from 'kibana/public'; +import type { LayerWizard, RenderWizardArguments } from '../../../maps/public'; +import { FIELD_ORIGIN, LAYER_TYPE, STYLE_TYPE } from '../../../maps/common'; +import { SEVERITY_COLOR_RAMP } from '../../common'; +import { CreateAnomalySourceEditor } from './create_anomaly_source_editor'; +import { + VectorLayerDescriptor, + VectorStylePropertiesDescriptor, +} from '../../../maps/common/descriptor_types'; +import { AnomalySource, AnomalySourceDescriptor } from './anomaly_source'; + +import { HttpService } from '../application/services/http_service'; +import type { MlPluginStart, MlStartDependencies } from '../plugin'; +import type { MlApiServices } from '../application/services/ml_api_service'; + +export const ML_ANOMALY = 'ML_ANOMALIES'; +const CUSTOM_COLOR_RAMP = { + type: STYLE_TYPE.DYNAMIC, + options: { + customColorRamp: SEVERITY_COLOR_RAMP, + field: { + name: 'record_score', + origin: FIELD_ORIGIN.SOURCE, + }, + useCustomColorRamp: true, + }, +}; + +export class AnomalyLayerWizardFactory { + public readonly type = ML_ANOMALY; + + constructor( + private getStartServices: StartServicesAccessor, + private canGetJobs: boolean + ) { + this.canGetJobs = canGetJobs; + } + + private async getServices(): Promise<{ mlJobsService: MlApiServices['jobs'] }> { + const [coreStart] = await this.getStartServices(); + const { jobsApiProvider } = await import('../application/services/ml_api_service/jobs'); + + const httpService = new HttpService(coreStart.http); + const mlJobsService = jobsApiProvider(httpService); + + return { mlJobsService }; + } + + public async create(): Promise { + const { mlJobsService } = await this.getServices(); + const { anomalyLayerWizard } = await import('./anomaly_layer_wizard'); + + anomalyLayerWizard.getIsDisabled = () => !this.canGetJobs; + + anomalyLayerWizard.renderWizard = ({ previewLayers }: RenderWizardArguments) => { + const onSourceConfigChange = (sourceConfig: Partial | null) => { + if (!sourceConfig) { + previewLayers([]); + return; + } + + const anomalyLayerDescriptor: VectorLayerDescriptor = { + id: htmlIdGenerator()(), + type: LAYER_TYPE.GEOJSON_VECTOR, + sourceDescriptor: AnomalySource.createDescriptor({ + jobId: sourceConfig.jobId, + typicalActual: sourceConfig.typicalActual, + }), + style: { + type: 'VECTOR', + properties: { + fillColor: CUSTOM_COLOR_RAMP, + lineColor: CUSTOM_COLOR_RAMP, + } as unknown as VectorStylePropertiesDescriptor, + isTimeAware: false, + }, + }; + + previewLayers([anomalyLayerDescriptor]); + }; + + return ( + + ); + }; + + return anomalyLayerWizard as LayerWizard; + } +} diff --git a/x-pack/plugins/ml/public/maps/anomaly_source.tsx b/x-pack/plugins/ml/public/maps/anomaly_source.tsx new file mode 100644 index 00000000000000..1159f97dcbec97 --- /dev/null +++ b/x-pack/plugins/ml/public/maps/anomaly_source.tsx @@ -0,0 +1,360 @@ +/* + * 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 { i18n } from '@kbn/i18n'; +import React, { ReactElement } from 'react'; +import { + FieldFormatter, + MAX_ZOOM, + MIN_ZOOM, + VECTOR_SHAPE_TYPE, + VectorSourceRequestMeta, +} from '../../../maps/common'; +import { AbstractSourceDescriptor, MapExtent } from '../../../maps/common/descriptor_types'; +import { ITooltipProperty } from '../../../maps/public'; +import { + AnomalySourceField, + AnomalySourceTooltipProperty, + ANOMALY_SOURCE_FIELDS, +} from './anomaly_source_field'; +import type { Adapters } from '../../../../../src/plugins/inspector/common/adapters'; +import type { GeoJsonWithMeta } from '../../../maps/public'; +import type { IField } from '../../../maps/public'; +import type { Attribution, ImmutableSourceProperty, PreIndexedShape } from '../../../maps/public'; +import type { SourceEditorArgs } from '../../../maps/public'; +import type { DataRequest } from '../../../maps/public'; +import type { IVectorSource, SourceStatus } from '../../../maps/public'; +import { ML_ANOMALY } from './anomaly_source_factory'; +import { getResultsForJobId, MlAnomalyLayers } from './util'; +import { UpdateAnomalySourceEditor } from './update_anomaly_source_editor'; +import type { MlApiServices } from '../application/services/ml_api_service'; + +export interface AnomalySourceDescriptor extends AbstractSourceDescriptor { + jobId: string; + typicalActual: MlAnomalyLayers; +} + +export class AnomalySource implements IVectorSource { + static mlResultsService: MlApiServices['results']; + static canGetJobs: boolean; + + static createDescriptor(descriptor: Partial) { + if (typeof descriptor.jobId !== 'string') { + throw new Error('Job id is required for anomaly layer creation'); + } + + return { + type: ML_ANOMALY, + jobId: descriptor.jobId, + typicalActual: descriptor.typicalActual || 'actual', + }; + } + + private readonly _descriptor: AnomalySourceDescriptor; + + constructor(sourceDescriptor: Partial, adapters?: Adapters) { + this._descriptor = AnomalySource.createDescriptor(sourceDescriptor); + } + // TODO: implement query awareness + async getGeoJsonWithMeta( + layerName: string, + searchFilters: VectorSourceRequestMeta, + registerCancelCallback: (callback: () => void) => void, + isRequestStillActive: () => boolean + ): Promise { + const results = await getResultsForJobId( + AnomalySource.mlResultsService, + this._descriptor.jobId, + this._descriptor.typicalActual, + searchFilters + ); + + return { + data: results, + meta: { + // Set this to true if data is incomplete (e.g. capping number of results to first 1k) + areResultsTrimmed: false, + }, + }; + } + + canFormatFeatureProperties(): boolean { + return false; + } + + cloneDescriptor(): AnomalySourceDescriptor { + return { + type: this._descriptor.type, + jobId: this._descriptor.jobId, + typicalActual: this._descriptor.typicalActual, + }; + } + + createField({ fieldName }: { fieldName: string }): IField { + if (fieldName !== 'record_score') { + throw new Error('Record score field name is required'); + } + return new AnomalySourceField({ source: this, field: fieldName }); + } + + async createFieldFormatter(field: IField): Promise { + return null; + } + + destroy(): void {} + + getApplyGlobalQuery(): boolean { + return false; + } + + getApplyForceRefresh(): boolean { + return false; + } + + getApplyGlobalTime(): boolean { + return true; + } + + async getAttributions(): Promise { + return []; + } + + async getBoundsForFilters( + boundsFilters: object, + registerCancelCallback: (callback: () => void) => void + ): Promise { + return null; + } + + async getDisplayName(): Promise { + return i18n.translate('xpack.ml.maps.anomalySource.displayLabel', { + defaultMessage: '{typicalActual} for {jobId}', + values: { + typicalActual: this._descriptor.typicalActual, + jobId: this._descriptor.jobId, + }, + }); + } + + getFieldByName(fieldName: string): IField | null { + if (fieldName === 'record_score') { + return new AnomalySourceField({ source: this, field: fieldName }); + } + return null; + } + + getSourceStatus() { + return { tooltipContent: null, areResultsTrimmed: true }; + } + + getType(): string { + return this._descriptor.type; + } + + isMvt() { + return true; + } + + showJoinEditor(): boolean { + // Ignore, only show if joins are enabled for current configuration + return false; + } + + getFieldNames(): string[] { + return Object.keys(ANOMALY_SOURCE_FIELDS); + } + + async getFields(): Promise { + return this.getFieldNames().map((field) => new AnomalySourceField({ source: this, field })); + } + + getGeoGridPrecision(zoom: number): number { + return 0; + } + + isBoundsAware(): boolean { + return false; + } + + async getImmutableProperties(): Promise { + return [ + { + label: i18n.translate('xpack.ml.maps.anomalySourcePropLabel', { + defaultMessage: 'Job Id', + }), + value: this._descriptor.jobId, + }, + ]; + } + + async isTimeAware(): Promise { + return true; + } + + renderSourceSettingsEditor({ onChange }: SourceEditorArgs): ReactElement | null { + return ( + + ); + } + + async supportsFitToBounds(): Promise { + // Return true if you can compute bounds of data + return true; + } + + async getLicensedFeatures(): Promise<[]> { + return []; + } + + getMaxZoom(): number { + return MAX_ZOOM; + } + + getMinZoom(): number { + return MIN_ZOOM; + } + + getSourceTooltipContent(sourceDataRequest?: DataRequest): SourceStatus { + return { + tooltipContent: i18n.translate('xpack.ml.maps.sourceTooltip', { + defaultMessage: 'Shows anomalies', + }), + // set to true if data is incomplete (we limit to first 1000 results) + areResultsTrimmed: true, + }; + } + + async getSupportedShapeTypes(): Promise { + return this._descriptor.typicalActual === 'connected' + ? [VECTOR_SHAPE_TYPE.LINE] + : [VECTOR_SHAPE_TYPE.POINT]; + } + + getSyncMeta(): object | null { + return { + jobId: this._descriptor.jobId, + typicalActual: this._descriptor.typicalActual, + }; + } + + async getTooltipProperties(properties: { [p: string]: any } | null): Promise { + const tooltipProperties: ITooltipProperty[] = []; + for (const key in properties) { + if (properties.hasOwnProperty(key)) { + const label = ANOMALY_SOURCE_FIELDS[key]?.label; + if (label) { + tooltipProperties.push(new AnomalySourceTooltipProperty(label, properties[key])); + } + } + } + return tooltipProperties; + } + + isFieldAware(): boolean { + return true; + } + + // This is for type-ahead support in the UX for by-value styling + async getValueSuggestions(field: IField, query: string): Promise { + return []; + } + + // ----------------- + // API ML probably can ignore + getAttributionProvider() { + return null; + } + + getIndexPatternIds(): string[] { + // IGNORE: This is only relevant if your source is backed by an index-pattern + return []; + } + + getInspectorAdapters(): Adapters | undefined { + // IGNORE: This is only relevant if your source is backed by an index-pattern + return undefined; + } + + getJoinsDisabledReason(): string | null { + // IGNORE: This is only relevant if your source can be joined to other data + return null; + } + + async getLeftJoinFields(): Promise { + // IGNORE: This is only relevant if your source can be joined to other data + return []; + } + + async getPreIndexedShape( + properties: { [p: string]: any } | null + ): Promise { + // IGNORE: This is only relevant if your source is backed by an index-pattern + return null; + } + + getQueryableIndexPatternIds(): string[] { + // IGNORE: This is only relevant if your source is backed by an index-pattern + return []; + } + + isESSource(): boolean { + // IGNORE: This is only relevant if your source is backed by an index-pattern + return false; + } + + isFilterByMapBounds(): boolean { + // Only implement if you can query this data with a bounding-box + return false; + } + + isGeoGridPrecisionAware(): boolean { + // Ignore: only implement if your data is scale-dependent (probably not) + return false; + } + + isQueryAware(): boolean { + // IGNORE: This is only relevant if your source is backed by an index-pattern + return false; + } + + isRefreshTimerAware(): boolean { + // Allow force-refresh when user clicks "refresh" button in the global time-picker + return true; + } + + async getTimesliceMaskFieldName() { + return null; + } + + async supportsFeatureEditing() { + return false; + } + + hasTooltipProperties() { + return true; + } + + async addFeature() { + // should not be called + } + + async deleteFeature() { + // should not be called + } + + getUpdateDueToTimeslice() { + // TODO + return true; + } + + async getDefaultFields(): Promise>> { + return {}; + } +} diff --git a/x-pack/plugins/ml/public/maps/anomaly_source_factory.ts b/x-pack/plugins/ml/public/maps/anomaly_source_factory.ts new file mode 100644 index 00000000000000..71aefbfd0fdb95 --- /dev/null +++ b/x-pack/plugins/ml/public/maps/anomaly_source_factory.ts @@ -0,0 +1,42 @@ +/* + * 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 type { StartServicesAccessor } from 'kibana/public'; +import { HttpService } from '../application/services/http_service'; +import type { MlPluginStart, MlStartDependencies } from '../plugin'; +import type { MlApiServices } from '../application/services/ml_api_service'; + +export const ML_ANOMALY = 'ML_ANOMALIES'; + +export class AnomalySourceFactory { + public readonly type = ML_ANOMALY; + + constructor( + private getStartServices: StartServicesAccessor, + private canGetJobs: boolean + ) { + this.canGetJobs = canGetJobs; + } + + private async getServices(): Promise<{ mlResultsService: MlApiServices['results'] }> { + const [coreStart] = await this.getStartServices(); + const { mlApiServicesProvider } = await import('../application/services/ml_api_service'); + + const httpService = new HttpService(coreStart.http); + const mlResultsService = mlApiServicesProvider(httpService).results; + + return { mlResultsService }; + } + + public async create(): Promise { + const { mlResultsService } = await this.getServices(); + const { AnomalySource } = await import('./anomaly_source'); + AnomalySource.mlResultsService = mlResultsService; + AnomalySource.canGetJobs = this.canGetJobs; + return AnomalySource; + } +} diff --git a/x-pack/plugins/ml/public/maps/anomaly_source_field.ts b/x-pack/plugins/ml/public/maps/anomaly_source_field.ts new file mode 100644 index 00000000000000..8a0e1f0104ee04 --- /dev/null +++ b/x-pack/plugins/ml/public/maps/anomaly_source_field.ts @@ -0,0 +1,169 @@ +/* + * 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. + */ + +// eslint-disable-next-line max-classes-per-file +import { escape } from 'lodash'; +import { i18n } from '@kbn/i18n'; +import { IField, IVectorSource } from '../../../maps/public'; +import { FIELD_ORIGIN } from '../../../maps/common'; +import { TileMetaFeature } from '../../../maps/common/descriptor_types'; +import { AnomalySource } from './anomaly_source'; +import { ITooltipProperty } from '../../../maps/public'; +import { Filter } from '../../../../../src/plugins/data/public'; + +export const ANOMALY_SOURCE_FIELDS: Record> = { + record_score: { + label: i18n.translate('xpack.ml.maps.anomalyLayerRecordScoreLabel', { + defaultMessage: 'Record score', + }), + type: 'number', + }, + timestamp: { + label: i18n.translate('xpack.ml.maps.anomalyLayerTimeStampLabel', { + defaultMessage: 'Time', + }), + type: 'string', + }, + fieldName: { + label: i18n.translate('xpack.ml.maps.anomalyLayerFieldNameLabel', { + defaultMessage: 'Field name', + }), + type: 'string', + }, + functionDescription: { + label: i18n.translate('xpack.ml.maps.anomalyLayerFunctionDescriptionLabel', { + defaultMessage: 'Function', + }), + type: 'string', + }, + actualDisplay: { + label: i18n.translate('xpack.ml.maps.anomalyLayerActualLabel', { + defaultMessage: 'Actual', + }), + type: 'string', + }, + typicalDisplay: { + label: i18n.translate('xpack.ml.maps.anomalyLayerTypicalLabel', { + defaultMessage: 'Typical', + }), + type: 'string', + }, +}; + +export class AnomalySourceTooltipProperty implements ITooltipProperty { + constructor(private readonly _label: string, private readonly _value: string) {} + + async getESFilters(): Promise { + return []; + } + + getHtmlDisplayValue(): string { + return this._value.toString(); + } + + getPropertyKey(): string { + return this._label; + } + + getPropertyName(): string { + return this._label; + } + + getRawValue(): string | string[] | undefined { + return this._value.toString(); + } + + isFilterable(): boolean { + return false; + } +} + +// this needs to be generic so it works for all fields in anomaly record result +export class AnomalySourceField implements IField { + private readonly _source: AnomalySource; + private readonly _field: string; + + constructor({ source, field }: { source: AnomalySource; field: string }) { + this._source = source; + this._field = field; + } + + async createTooltipProperty(value: string | string[] | undefined): Promise { + return new AnomalySourceTooltipProperty( + await this.getLabel(), + escape(Array.isArray(value) ? value.join() : value ? value : '') + ); + } + + async getDataType(): Promise { + return ANOMALY_SOURCE_FIELDS[this._field].type; + } + + async getLabel(): Promise { + return ANOMALY_SOURCE_FIELDS[this._field].label; + } + + getName(): string { + return this._field; + } + + getMbFieldName(): string { + return this.getName(); + } + + getOrigin(): FIELD_ORIGIN { + return FIELD_ORIGIN.SOURCE; + } + + getRootName(): string { + return this.getName(); + } + + getSource(): IVectorSource { + return this._source; + } + + isEqual(field: IField): boolean { + return this.getName() === field.getName(); + } + + isValid(): boolean { + return true; + } + + supportsFieldMetaFromLocalData(): boolean { + return true; + } + + supportsFieldMetaFromEs(): boolean { + return false; + } + + canValueBeFormatted(): boolean { + return false; + } + + async getExtendedStatsFieldMetaRequest(): Promise { + return null; + } + + async getPercentilesFieldMetaRequest(percentiles: number[]): Promise { + return null; + } + + async getCategoricalFieldMetaRequest(size: number): Promise { + return null; + } + + pluckRangeFromTileMetaFeature(metaFeature: TileMetaFeature): { min: number; max: number } | null { + return null; + } + + isCount(): boolean { + return false; + } +} diff --git a/x-pack/plugins/ml/public/maps/create_anomaly_source_editor.tsx b/x-pack/plugins/ml/public/maps/create_anomaly_source_editor.tsx new file mode 100644 index 00000000000000..e04fd40f9416be --- /dev/null +++ b/x-pack/plugins/ml/public/maps/create_anomaly_source_editor.tsx @@ -0,0 +1,89 @@ +/* + * 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 React, { Component } from 'react'; + +import { EuiPanel } from '@elastic/eui'; +import { AnomalySourceDescriptor } from './anomaly_source'; +import { AnomalyJobSelector } from './anomaly_job_selector'; +import { LayerSelector } from './layer_selector'; +import { MlAnomalyLayers } from './util'; +import type { MlApiServices } from '../application/services/ml_api_service'; + +interface Props { + onSourceConfigChange: (sourceConfig: Partial | null) => void; + mlJobsService: MlApiServices['jobs']; +} + +interface State { + jobId?: string; + typicalActual?: MlAnomalyLayers; +} + +export class CreateAnomalySourceEditor extends Component { + private _isMounted: boolean = false; + state: State = {}; + + private configChange() { + if (this.state.jobId) { + this.props.onSourceConfigChange({ + jobId: this.state.jobId, + typicalActual: this.state.typicalActual, + }); + } + } + + componentDidMount(): void { + this._isMounted = true; + } + + private onTypicalActualChange = (typicalActual: MlAnomalyLayers) => { + if (!this._isMounted) { + return; + } + this.setState( + { + typicalActual, + }, + () => { + this.configChange(); + } + ); + }; + + private previewLayer = (jobId: string) => { + if (!this._isMounted) { + return; + } + this.setState( + { + jobId, + }, + () => { + this.configChange(); + } + ); + }; + + render() { + const selector = this.state.jobId ? ( + + ) : null; + return ( + + + {selector} + + ); + } +} diff --git a/x-pack/plugins/ml/public/maps/layer_selector.tsx b/x-pack/plugins/ml/public/maps/layer_selector.tsx new file mode 100644 index 00000000000000..2998187ad465b7 --- /dev/null +++ b/x-pack/plugins/ml/public/maps/layer_selector.tsx @@ -0,0 +1,68 @@ +/* + * 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 React, { Component } from 'react'; + +import { EuiComboBox, EuiFormRow, EuiComboBoxOptionOption } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { MlAnomalyLayers } from './util'; + +interface Props { + onChange: (typicalActual: MlAnomalyLayers) => void; + typicalActual: MlAnomalyLayers; +} + +// eslint-disable-next-line @typescript-eslint/no-empty-interface +interface State {} + +export class LayerSelector extends Component { + private _isMounted: boolean = false; + + state: State = {}; + + componentDidMount(): void { + this._isMounted = true; + } + + componentWillUnmount() { + this._isMounted = false; + } + + onSelect = (selectedOptions: Array>) => { + const typicalActual: MlAnomalyLayers = selectedOptions[0].value! as + | 'typical' + | 'actual' + | 'connected'; + if (this._isMounted) { + this.setState({ typicalActual }); + this.props.onChange(typicalActual); + } + }; + + render() { + const options = [{ value: this.props.typicalActual, label: this.props.typicalActual }]; + return ( + + + + ); + } +} diff --git a/x-pack/plugins/ml/public/maps/register_map_extension.ts b/x-pack/plugins/ml/public/maps/register_map_extension.ts new file mode 100644 index 00000000000000..6cd8bd1f2a3e86 --- /dev/null +++ b/x-pack/plugins/ml/public/maps/register_map_extension.ts @@ -0,0 +1,31 @@ +/* + * 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 { MapsSetupApi } from '../../../maps/public'; +import type { MlCoreSetup } from '../plugin'; +import { AnomalySourceFactory } from './anomaly_source_factory'; +import { AnomalyLayerWizardFactory } from './anomaly_layer_wizard_factory'; + +export async function registerMapExtension( + mapsSetupApi: MapsSetupApi, + core: MlCoreSetup, + canGetJobs: boolean +) { + const anomalySourceFactory = new AnomalySourceFactory(core.getStartServices, canGetJobs); + const anomalyLayerWizardFactory = new AnomalyLayerWizardFactory( + core.getStartServices, + canGetJobs + ); + const anomalylayerWizard = await anomalyLayerWizardFactory.create(); + + mapsSetupApi.registerSource({ + type: anomalySourceFactory.type, + ConstructorFunction: await anomalySourceFactory.create(), + }); + + mapsSetupApi.registerLayerWizard(anomalylayerWizard); +} diff --git a/x-pack/plugins/ml/public/maps/update_anomaly_source_editor.tsx b/x-pack/plugins/ml/public/maps/update_anomaly_source_editor.tsx new file mode 100644 index 00000000000000..7e53e6ebf9f5d6 --- /dev/null +++ b/x-pack/plugins/ml/public/maps/update_anomaly_source_editor.tsx @@ -0,0 +1,50 @@ +/* + * 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 React, { Fragment, Component } from 'react'; + +import { FormattedMessage } from '@kbn/i18n-react'; +import { EuiPanel, EuiSpacer, EuiTitle } from '@elastic/eui'; +import { LayerSelector } from './layer_selector'; +import { MlAnomalyLayers } from './util'; + +interface Props { + onChange: (...args: Array<{ propName: string; value: unknown }>) => void; + typicalActual: MlAnomalyLayers; +} + +// eslint-disable-next-line @typescript-eslint/no-empty-interface +interface State {} + +export class UpdateAnomalySourceEditor extends Component { + state: State = {}; + + render() { + return ( + + + +
+ +
+
+ + { + this.props.onChange({ + propName: 'typicalActual', + value: typicalActual, + }); + }} + typicalActual={this.props.typicalActual} + /> +
+ +
+ ); + } +} diff --git a/x-pack/plugins/ml/public/maps/util.ts b/x-pack/plugins/ml/public/maps/util.ts new file mode 100644 index 00000000000000..6a9d55ad64d385 --- /dev/null +++ b/x-pack/plugins/ml/public/maps/util.ts @@ -0,0 +1,153 @@ +/* + * 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 { FeatureCollection, Feature, Geometry } from 'geojson'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import { ESSearchResponse } from '../../../../../src/core/types/elasticsearch'; +import { formatHumanReadableDateTimeSeconds } from '../../common/util/date_utils'; +import type { MlApiServices } from '../application/services/ml_api_service'; +import { MLAnomalyDoc } from '../../common/types/anomalies'; +import { VectorSourceRequestMeta } from '../../../maps/common'; + +export type MlAnomalyLayers = 'typical' | 'actual' | 'connected'; + +// Must reverse coordinates here. Map expects [lon, lat] - anomalies are stored as [lat, lon] for lat_lon jobs +function getCoordinates(actualCoordinateStr: string, round: boolean = false): number[] { + const convertWithRounding = (point: string) => Math.round(Number(point) * 100) / 100; + const convert = (point: string) => Number(point); + return actualCoordinateStr + .split(',') + .map(round ? convertWithRounding : convert) + .reverse(); +} + +export async function getResultsForJobId( + mlResultsService: MlApiServices['results'], + jobId: string, + locationType: MlAnomalyLayers, + searchFilters: VectorSourceRequestMeta +): Promise { + const { timeFilters } = searchFilters; + + const must: estypes.QueryDslQueryContainer[] = [ + { term: { job_id: jobId } }, + { term: { result_type: 'record' } }, + ]; + + // Query to look for the highest scoring anomaly. + const body: estypes.SearchRequest['body'] = { + query: { + bool: { + must, + }, + }, + size: 1000, + _source: { + excludes: [], + }, + }; + + if (timeFilters) { + const timerange = { + range: { + timestamp: { + gte: `${timeFilters.from}`, + lte: timeFilters.to, + }, + }, + }; + must.push(timerange); + } + + let resp: ESSearchResponse | null = null; + let hits: Array<{ + actual: number[]; + actualDisplay: number[]; + fieldName?: string; + functionDescription: string; + typical: number[]; + typicalDisplay: number[]; + record_score: number; + timestamp: string; + }> = []; + + try { + resp = await mlResultsService.anomalySearch( + { + body, + }, + [jobId] + ); + } catch (error) { + // search may fail if the job doesn't already exist + // ignore this error as the outer function call will raise a toast + } + if (resp !== null && resp.hits.total.value > 0) { + hits = resp.hits.hits.map(({ _source }) => { + const geoResults = _source.geo_results; + const actualCoordStr = geoResults && geoResults.actual_point; + const typicalCoordStr = geoResults && geoResults.typical_point; + let typical: number[] = []; + let typicalDisplay: number[] = []; + let actual: number[] = []; + let actualDisplay: number[] = []; + + if (actualCoordStr !== undefined) { + actual = getCoordinates(actualCoordStr); + actualDisplay = getCoordinates(actualCoordStr, true); + } + if (typicalCoordStr !== undefined) { + typical = getCoordinates(typicalCoordStr); + typicalDisplay = getCoordinates(typicalCoordStr, true); + } + return { + fieldName: _source.field_name, + functionDescription: _source.function_description, + timestamp: formatHumanReadableDateTimeSeconds(_source.timestamp), + typical, + typicalDisplay, + actual, + actualDisplay, + record_score: Math.floor(_source.record_score), + }; + }); + } + + const features: Feature[] = hits.map((result) => { + let geometry: Geometry; + if (locationType === 'typical' || locationType === 'actual') { + geometry = { + type: 'Point', + coordinates: locationType === 'typical' ? result.typical : result.actual, + }; + } else { + geometry = { + type: 'LineString', + coordinates: [result.typical, result.actual], + }; + } + return { + type: 'Feature', + geometry, + properties: { + actual: result.actual, + actualDisplay: result.actualDisplay, + typical: result.typical, + typicalDisplay: result.typicalDisplay, + fieldName: result.fieldName, + functionDescription: result.functionDescription, + timestamp: result.timestamp, + record_score: result.record_score, + }, + }; + }); + + return { + type: 'FeatureCollection', + features, + }; +} diff --git a/x-pack/plugins/ml/public/plugin.ts b/x-pack/plugins/ml/public/plugin.ts index 2a5cb2ab4ae2af..6563a7bc5b5513 100644 --- a/x-pack/plugins/ml/public/plugin.ts +++ b/x-pack/plugins/ml/public/plugin.ts @@ -36,7 +36,7 @@ import { isFullLicense, isMlEnabled } from '../common/license'; import { setDependencyCache } from './application/util/dependency_cache'; import { registerFeature } from './register_feature'; import { MlLocatorDefinition, MlLocator } from './locator'; -import type { MapsStartApi } from '../../maps/public'; +import type { MapsStartApi, MapsSetupApi } from '../../maps/public'; import { TriggersAndActionsUIPublicPluginSetup, TriggersAndActionsUIPublicPluginStart, @@ -66,6 +66,7 @@ export interface MlStartDependencies { export interface MlSetupDependencies { security?: SecurityPluginSetup; + maps?: MapsSetupApi; licensing: LicensingPluginSetup; management?: ManagementSetup; licenseManagement?: LicenseManagementUIPluginSetup; @@ -159,11 +160,23 @@ export class MlPlugin implements Plugin { // register various ML plugin features which require a full license // note including registerFeature in register_helper would cause the page bundle size to increase significantly - const { registerEmbeddables, registerMlUiActions, registerSearchLinks, registerMlAlerts } = - await import('./register_helper'); + const { + registerEmbeddables, + registerMlUiActions, + registerSearchLinks, + registerMlAlerts, + registerMapExtension, + } = await import('./register_helper'); const mlEnabled = isMlEnabled(license); const fullLicense = isFullLicense(license); + + if (pluginsSetup.maps) { + // Pass capabilites.ml.canGetJobs as minimum permission to show anomalies card in maps layers + const canGetJobs = capabilities.ml?.canGetJobs === true || false; + await registerMapExtension(pluginsSetup.maps, core, canGetJobs); + } + if (mlEnabled) { registerSearchLinks(this.appUpdater$, fullLicense); diff --git a/x-pack/plugins/ml/public/register_helper/index.ts b/x-pack/plugins/ml/public/register_helper/index.ts index 278f32f683053d..47d9bad31997a2 100644 --- a/x-pack/plugins/ml/public/register_helper/index.ts +++ b/x-pack/plugins/ml/public/register_helper/index.ts @@ -10,3 +10,4 @@ export { registerManagementSection } from '../application/management'; export { registerMlUiActions } from '../ui_actions'; export { registerSearchLinks } from './register_search_links'; export { registerMlAlerts } from '../alerting'; +export { registerMapExtension } from '../maps/register_map_extension'; diff --git a/x-pack/plugins/ml/server/models/job_service/jobs.ts b/x-pack/plugins/ml/server/models/job_service/jobs.ts index a79093caabbefc..c4e215fc3c38e1 100644 --- a/x-pack/plugins/ml/server/models/job_service/jobs.ts +++ b/x-pack/plugins/ml/server/models/job_service/jobs.ts @@ -11,6 +11,7 @@ import { IScopedClusterClient } from 'kibana/server'; import { getSingleMetricViewerJobErrorMessage, parseTimeIntervalForJob, + isJobWithGeoData, } from '../../../common/util/job_utils'; import { JOB_STATE, DATAFEED_STATE } from '../../../common/constants/states'; import { @@ -272,6 +273,11 @@ export function jobsProvider( return jobs; } + async function getJobIdsWithGeo(): Promise { + const { body } = await mlClient.getJobs(); + return body.jobs.filter(isJobWithGeoData).map((job) => job.job_id); + } + async function jobsWithTimerange() { const fullJobsList = await createFullJobsList(); const jobsMap: { [id: string]: string[] } = {}; @@ -669,5 +675,6 @@ export function jobsProvider( getAllJobAndGroupIds, getLookBackProgress, bulkCreate, + getJobIdsWithGeo, }; } diff --git a/x-pack/plugins/ml/server/routes/job_service.ts b/x-pack/plugins/ml/server/routes/job_service.ts index 96ca56baa38da7..123b38e9cd7de4 100644 --- a/x-pack/plugins/ml/server/routes/job_service.ts +++ b/x-pack/plugins/ml/server/routes/job_service.ts @@ -285,6 +285,42 @@ export function jobServiceRoutes({ router, routeGuard }: RouteInitialization) { }) ); + /** + * @apiGroup JobService + * + * @api {post} /api/ml/jobs/jobs_with_geo Jobs summary + * @apiName JobsSummary + * @apiDescription Returns a list of anomaly detection jobs with analysis config with fields supported by maps. + * + * @apiSuccess {Array} jobIds list of job ids. + */ + router.get( + { + path: '/api/ml/jobs/jobs_with_geo', + validate: false, + options: { + tags: ['access:ml:canGetJobs'], + }, + }, + routeGuard.fullLicenseAPIGuard(async ({ client, mlClient, response, context }) => { + try { + const { getJobIdsWithGeo } = jobServiceProvider( + client, + mlClient, + context.alerting?.getRulesClient() + ); + + const resp = await getJobIdsWithGeo(); + + return response.ok({ + body: resp, + }); + } catch (e) { + return response.customError(wrapError(e)); + } + }) + ); + /** * @apiGroup JobService * From d49880b807e9d8e3ab46265cb1abf7f02fc93250 Mon Sep 17 00:00:00 2001 From: Gloria Hornero Date: Thu, 20 Jan 2022 19:09:33 +0100 Subject: [PATCH 087/108] fixes advanced seetings default message (#123480) --- .../public/common/components/news_feed/translations.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/public/common/components/news_feed/translations.ts b/x-pack/plugins/security_solution/public/common/components/news_feed/translations.ts index 6b4c342b57b29b..e21f6165f3763f 100644 --- a/x-pack/plugins/security_solution/public/common/components/news_feed/translations.ts +++ b/x-pack/plugins/security_solution/public/common/components/news_feed/translations.ts @@ -22,6 +22,6 @@ export const NO_NEWS_MESSAGE_ADMIN = i18n.translate( export const ADVANCED_SETTINGS_LINK_TITLE = i18n.translate( 'xpack.securitySolution.newsFeed.advancedSettingsLinkTitle', { - defaultMessage: 'SIEM advanced settings', + defaultMessage: 'Security Solution advanced settings', } ); From d744500c2466aaecfad4364749b6d4a5c33af373 Mon Sep 17 00:00:00 2001 From: Walter Rafelsberger Date: Thu, 20 Jan 2022 19:12:44 +0100 Subject: [PATCH 088/108] [ML] Remove export wildcard syntax for file upload plugin. (#123205) Remove export wildcard syntax for file upload plugin. --- .../plugins/data_visualizer/common/constants.ts | 7 +++++++ .../common/components/combined_fields/utils.ts | 2 +- .../application/common/components/utils/utils.ts | 8 ++------ .../analysis_summary/analysis_summary.tsx | 3 ++- .../components/edit_flyout/options/options.ts | 2 +- .../components/edit_flyout/overrides.js | 2 +- .../components/edit_flyout/overrides.test.js | 2 +- x-pack/plugins/file_upload/common/constants.ts | 2 -- x-pack/plugins/file_upload/common/index.ts | 16 +++++++++++----- x-pack/plugins/file_upload/common/types.ts | 4 ++-- x-pack/plugins/file_upload/public/api/index.ts | 2 +- .../geojson_upload_form/geojson_file_picker.tsx | 2 +- .../public/components/json_upload_and_parse.tsx | 2 +- .../geojson_importer/geojson_importer.ts | 3 ++- .../file_upload/public/importer/get_max_bytes.ts | 6 +++--- .../file_upload/public/importer/importer.ts | 6 +++--- .../public/importer/message_importer.ts | 8 ++++---- .../plugins/file_upload/public/importer/types.ts | 4 ++-- x-pack/plugins/file_upload/public/index.ts | 5 ----- .../plugins/file_upload/server/analyze_file.tsx | 7 ++++++- x-pack/plugins/file_upload/server/import_data.ts | 2 +- x-pack/plugins/file_upload/server/plugin.ts | 2 +- x-pack/plugins/file_upload/server/routes.ts | 9 ++------- .../ml/common/constants/data_frame_analytics.ts | 5 +++++ .../data_frame_analytics/analytics_manager.ts | 6 +++--- 25 files changed, 63 insertions(+), 54 deletions(-) diff --git a/x-pack/plugins/data_visualizer/common/constants.ts b/x-pack/plugins/data_visualizer/common/constants.ts index cc661ca6ffeffe..ab25ecff4045d1 100644 --- a/x-pack/plugins/data_visualizer/common/constants.ts +++ b/x-pack/plugins/data_visualizer/common/constants.ts @@ -21,6 +21,13 @@ export const FILE_SIZE_DISPLAY_FORMAT = '0,0.[0] b'; // index as having been created by the File Data Visualizer. export const INDEX_META_DATA_CREATED_BY = 'file-data-visualizer'; +export const FILE_FORMATS = { + DELIMITED: 'delimited', + NDJSON: 'ndjson', + SEMI_STRUCTURED_TEXT: 'semi_structured_text', + // XML: 'xml', +}; + export const JOB_FIELD_TYPES = { BOOLEAN: 'boolean', DATE: 'date', diff --git a/x-pack/plugins/data_visualizer/public/application/common/components/combined_fields/utils.ts b/x-pack/plugins/data_visualizer/public/application/common/components/combined_fields/utils.ts index e021de5e5beca2..84f67c3222885e 100644 --- a/x-pack/plugins/data_visualizer/public/application/common/components/combined_fields/utils.ts +++ b/x-pack/plugins/data_visualizer/public/application/common/components/combined_fields/utils.ts @@ -9,7 +9,7 @@ import { i18n } from '@kbn/i18n'; import { cloneDeep } from 'lodash'; import uuid from 'uuid/v4'; import { CombinedField } from './types'; -import { +import type { FindFileStructureResponse, IngestPipeline, Mappings, diff --git a/x-pack/plugins/data_visualizer/public/application/common/components/utils/utils.ts b/x-pack/plugins/data_visualizer/public/application/common/components/utils/utils.ts index 3dd889976eb113..5f9317be6d7c59 100644 --- a/x-pack/plugins/data_visualizer/public/application/common/components/utils/utils.ts +++ b/x-pack/plugins/data_visualizer/public/application/common/components/utils/utils.ts @@ -6,12 +6,8 @@ */ import { isEqual } from 'lodash'; -import { - AnalysisResult, - InputOverrides, - MB, - FILE_FORMATS, -} from '../../../../../../file_upload/common'; +import type { AnalysisResult, InputOverrides } from '../../../../../../file_upload/common'; +import { MB, FILE_FORMATS } from '../../../../../common'; export const DEFAULT_LINES_TO_SAMPLE = 1000; const UPLOAD_SIZE_MB = 5; diff --git a/x-pack/plugins/data_visualizer/public/application/file_data_visualizer/components/analysis_summary/analysis_summary.tsx b/x-pack/plugins/data_visualizer/public/application/file_data_visualizer/components/analysis_summary/analysis_summary.tsx index b00266e5d3580e..b754bfd4691ec5 100644 --- a/x-pack/plugins/data_visualizer/public/application/file_data_visualizer/components/analysis_summary/analysis_summary.tsx +++ b/x-pack/plugins/data_visualizer/public/application/file_data_visualizer/components/analysis_summary/analysis_summary.tsx @@ -9,7 +9,8 @@ import { FormattedMessage } from '@kbn/i18n-react'; import React, { FC } from 'react'; import { EuiTitle, EuiSpacer, EuiDescriptionList } from '@elastic/eui'; -import { FindFileStructureResponse, FILE_FORMATS } from '../../../../../../file_upload/common'; +import type { FindFileStructureResponse } from '../../../../../../file_upload/common'; +import { FILE_FORMATS } from '../../../../../common'; export const AnalysisSummary: FC<{ results: FindFileStructureResponse }> = ({ results }) => { const items = createDisplayItems(results); diff --git a/x-pack/plugins/data_visualizer/public/application/file_data_visualizer/components/edit_flyout/options/options.ts b/x-pack/plugins/data_visualizer/public/application/file_data_visualizer/components/edit_flyout/options/options.ts index 066778705724de..e0c3e7f2d58ccf 100644 --- a/x-pack/plugins/data_visualizer/public/application/file_data_visualizer/components/edit_flyout/options/options.ts +++ b/x-pack/plugins/data_visualizer/public/application/file_data_visualizer/components/edit_flyout/options/options.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { FILE_FORMATS } from '../../../../../../../file_upload/common'; +import { FILE_FORMATS } from '../../../../../../common/'; import { TIMESTAMP_OPTIONS, diff --git a/x-pack/plugins/data_visualizer/public/application/file_data_visualizer/components/edit_flyout/overrides.js b/x-pack/plugins/data_visualizer/public/application/file_data_visualizer/components/edit_flyout/overrides.js index 84e207dd5b01e3..d0213813c8f161 100644 --- a/x-pack/plugins/data_visualizer/public/application/file_data_visualizer/components/edit_flyout/overrides.js +++ b/x-pack/plugins/data_visualizer/public/application/file_data_visualizer/components/edit_flyout/overrides.js @@ -23,7 +23,7 @@ import { EuiTextArea, } from '@elastic/eui'; -import { FILE_FORMATS } from '../../../../../../file_upload/common'; +import { FILE_FORMATS } from '../../../../../common'; import { getFormatOptions, diff --git a/x-pack/plugins/data_visualizer/public/application/file_data_visualizer/components/edit_flyout/overrides.test.js b/x-pack/plugins/data_visualizer/public/application/file_data_visualizer/components/edit_flyout/overrides.test.js index aac12c386f3465..8e9b0d0806fc1e 100644 --- a/x-pack/plugins/data_visualizer/public/application/file_data_visualizer/components/edit_flyout/overrides.test.js +++ b/x-pack/plugins/data_visualizer/public/application/file_data_visualizer/components/edit_flyout/overrides.test.js @@ -7,7 +7,7 @@ import { mountWithIntl, shallowWithIntl } from '@kbn/test/jest'; import React from 'react'; -import { FILE_FORMATS } from '../../../../../../file_upload/common/constants'; +import { FILE_FORMATS } from '../../../../../common'; import { Overrides } from './overrides'; diff --git a/x-pack/plugins/file_upload/common/constants.ts b/x-pack/plugins/file_upload/common/constants.ts index ce1c13e18c8032..725cd3f81a6504 100644 --- a/x-pack/plugins/file_upload/common/constants.ts +++ b/x-pack/plugins/file_upload/common/constants.ts @@ -6,11 +6,9 @@ */ export const UI_SETTING_MAX_FILE_SIZE = 'fileUpload:maxFileSize'; - export const MB = Math.pow(2, 20); export const MAX_FILE_SIZE = '100MB'; export const MAX_FILE_SIZE_BYTES = 104857600; // 100MB - export const ABSOLUTE_MAX_FILE_SIZE_BYTES = 1073741274; // 1GB export const FILE_SIZE_DISPLAY_FORMAT = '0,0.[0] b'; diff --git a/x-pack/plugins/file_upload/common/index.ts b/x-pack/plugins/file_upload/common/index.ts index 58159dfc3d7efc..5d312835c3e061 100644 --- a/x-pack/plugins/file_upload/common/index.ts +++ b/x-pack/plugins/file_upload/common/index.ts @@ -5,8 +5,14 @@ * 2.0. */ -// TODO: https://github.com/elastic/kibana/issues/110898 -/* eslint-disable @kbn/eslint/no_export_all */ - -export * from './constants'; -export * from './types'; +/** + * @internal + */ +export type { + AnalysisResult, + FindFileStructureErrorResponse, + FindFileStructureResponse, + InputOverrides, + IngestPipeline, + Mappings, +} from './types'; diff --git a/x-pack/plugins/file_upload/common/types.ts b/x-pack/plugins/file_upload/common/types.ts index 6e72b749bdb61c..5a4ec4a3872add 100644 --- a/x-pack/plugins/file_upload/common/types.ts +++ b/x-pack/plugins/file_upload/common/types.ts @@ -118,11 +118,11 @@ export interface ImportFailure { doc: ImportDoc; } -export interface Doc { +export interface ImportDocMessage { message: string; } -export type ImportDoc = Doc | string | object; +export type ImportDoc = ImportDocMessage | string | object; export interface Settings { pipeline?: string; diff --git a/x-pack/plugins/file_upload/public/api/index.ts b/x-pack/plugins/file_upload/public/api/index.ts index f3a184f27dfac8..d34cb2099120e3 100644 --- a/x-pack/plugins/file_upload/public/api/index.ts +++ b/x-pack/plugins/file_upload/public/api/index.ts @@ -7,7 +7,7 @@ import { lazyLoadModules } from '../lazy_load_bundle'; import type { IImporter, ImportFactoryOptions } from '../importer'; -import type { HasImportPermission, FindFileStructureResponse } from '../../common'; +import type { HasImportPermission, FindFileStructureResponse } from '../../common/types'; import type { getMaxBytes, getMaxBytesFormatted } from '../importer/get_max_bytes'; import { JsonUploadAndParseAsyncWrapper } from './json_upload_and_parse_async_wrapper'; import { IndexNameFormAsyncWrapper } from './index_name_form_async_wrapper'; diff --git a/x-pack/plugins/file_upload/public/components/geojson_upload_form/geojson_file_picker.tsx b/x-pack/plugins/file_upload/public/components/geojson_upload_form/geojson_file_picker.tsx index 6cd55e3a0a74a0..20c3189a8f346a 100644 --- a/x-pack/plugins/file_upload/public/components/geojson_upload_form/geojson_file_picker.tsx +++ b/x-pack/plugins/file_upload/public/components/geojson_upload_form/geojson_file_picker.tsx @@ -8,7 +8,7 @@ import React, { Component } from 'react'; import { EuiFilePicker, EuiFormRow } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { MB } from '../../../common'; +import { MB } from '../../../common/constants'; import { getMaxBytesFormatted } from '../../importer/get_max_bytes'; import { validateFile } from '../../importer'; import { diff --git a/x-pack/plugins/file_upload/public/components/json_upload_and_parse.tsx b/x-pack/plugins/file_upload/public/components/json_upload_and_parse.tsx index 80ff5910ac1ef4..5b786d91e25aa0 100644 --- a/x-pack/plugins/file_upload/public/components/json_upload_and_parse.tsx +++ b/x-pack/plugins/file_upload/public/components/json_upload_and_parse.tsx @@ -15,7 +15,7 @@ import { ES_FIELD_TYPES } from '../../../../../src/plugins/data/public'; import type { FileUploadComponentProps, FileUploadGeoResults } from '../lazy_load_bundle'; import { ImportResults } from '../importer'; import { GeoJsonImporter } from '../importer/geojson_importer'; -import { Settings } from '../../common'; +import type { Settings } from '../../common/types'; import { hasImportPermission } from '../api'; enum PHASE { diff --git a/x-pack/plugins/file_upload/public/importer/geojson_importer/geojson_importer.ts b/x-pack/plugins/file_upload/public/importer/geojson_importer/geojson_importer.ts index 24150051771a1f..40d6abdb1603aa 100644 --- a/x-pack/plugins/file_upload/public/importer/geojson_importer/geojson_importer.ts +++ b/x-pack/plugins/file_upload/public/importer/geojson_importer/geojson_importer.ts @@ -14,7 +14,8 @@ import { callImportRoute, Importer, IMPORT_RETRIES, MAX_CHUNK_CHAR_COUNT } from import { ES_FIELD_TYPES } from '../../../../../../src/plugins/data/public'; // @ts-expect-error import { geoJsonCleanAndValidate } from './geojson_clean_and_validate'; -import { ImportDoc, ImportFailure, ImportResponse, MB } from '../../../common'; +import { MB } from '../../../common/constants'; +import type { ImportDoc, ImportFailure, ImportResponse } from '../../../common/types'; const BLOCK_SIZE_MB = 5 * MB; export const GEOJSON_FILE_TYPES = ['.json', '.geojson']; diff --git a/x-pack/plugins/file_upload/public/importer/get_max_bytes.ts b/x-pack/plugins/file_upload/public/importer/get_max_bytes.ts index f1ca532692e77f..e05f1978dcf95f 100644 --- a/x-pack/plugins/file_upload/public/importer/get_max_bytes.ts +++ b/x-pack/plugins/file_upload/public/importer/get_max_bytes.ts @@ -7,12 +7,12 @@ import numeral from '@elastic/numeral'; import { - MAX_FILE_SIZE, - MAX_FILE_SIZE_BYTES, ABSOLUTE_MAX_FILE_SIZE_BYTES, FILE_SIZE_DISPLAY_FORMAT, + MAX_FILE_SIZE, + MAX_FILE_SIZE_BYTES, UI_SETTING_MAX_FILE_SIZE, -} from '../../common'; +} from '../../common/constants'; import { getUiSettings } from '../kibana_services'; export function getMaxBytes() { diff --git a/x-pack/plugins/file_upload/public/importer/importer.ts b/x-pack/plugins/file_upload/public/importer/importer.ts index 103afe4992c714..58809e736720cb 100644 --- a/x-pack/plugins/file_upload/public/importer/importer.ts +++ b/x-pack/plugins/file_upload/public/importer/importer.ts @@ -9,15 +9,15 @@ import { chunk, intersection } from 'lodash'; import moment from 'moment'; import { i18n } from '@kbn/i18n'; import { getHttp } from '../kibana_services'; -import { +import { MB } from '../../common/constants'; +import type { ImportDoc, ImportFailure, ImportResponse, Mappings, Settings, IngestPipeline, - MB, -} from '../../common'; +} from '../../common/types'; import { CreateDocsResponse, IImporter, ImportResults } from './types'; import { isPopulatedObject } from '../../common/utils'; diff --git a/x-pack/plugins/file_upload/public/importer/message_importer.ts b/x-pack/plugins/file_upload/public/importer/message_importer.ts index 21f884d22bc350..1322437f471d00 100644 --- a/x-pack/plugins/file_upload/public/importer/message_importer.ts +++ b/x-pack/plugins/file_upload/public/importer/message_importer.ts @@ -6,7 +6,7 @@ */ import { Importer } from './importer'; -import { Doc } from '../../common'; +import { ImportDocMessage } from '../../common/types'; import { CreateDocsResponse, ImportFactoryOptions } from './types'; export class MessageImporter extends Importer { @@ -33,7 +33,7 @@ export class MessageImporter extends Importer { protected _createDocs(text: string, isLastPart: boolean): CreateDocsResponse { let remainder = 0; try { - const docs: Doc[] = []; + const docs: ImportDocMessage[] = []; let message = ''; let line = ''; @@ -82,7 +82,7 @@ export class MessageImporter extends Importer { } } - private _processLine(data: Doc[], message: string, line: string) { + private _processLine(data: ImportDocMessage[], message: string, line: string) { if (this._excludeLinesRegex === null || line.match(this._excludeLinesRegex) === null) { if (this._multilineStartRegex === null || line.match(this._multilineStartRegex) !== null) { this._addMessage(data, message); @@ -100,7 +100,7 @@ export class MessageImporter extends Importer { return message; } - private _addMessage(data: Doc[], message: string) { + private _addMessage(data: ImportDocMessage[], message: string) { // if the message ended \r\n (Windows line endings) // then omit the \r as well as the \n for consistency message = message.replace(/\r$/, ''); diff --git a/x-pack/plugins/file_upload/public/importer/types.ts b/x-pack/plugins/file_upload/public/importer/types.ts index 7300b7cacfc7ff..0ef8ace26f5468 100644 --- a/x-pack/plugins/file_upload/public/importer/types.ts +++ b/x-pack/plugins/file_upload/public/importer/types.ts @@ -5,14 +5,14 @@ * 2.0. */ -import { +import type { ImportFailure, IngestPipeline, ImportDoc, ImportResponse, Mappings, Settings, -} from '../../common'; +} from '../../common/types'; export interface ImportConfig { settings: Settings; diff --git a/x-pack/plugins/file_upload/public/index.ts b/x-pack/plugins/file_upload/public/index.ts index 00b39dca1180d1..ba591b5c8d9426 100644 --- a/x-pack/plugins/file_upload/public/index.ts +++ b/x-pack/plugins/file_upload/public/index.ts @@ -5,17 +5,12 @@ * 2.0. */ -// TODO: https://github.com/elastic/kibana/issues/110898 -/* eslint-disable @kbn/eslint/no_export_all */ - import { FileUploadPlugin } from './plugin'; export function plugin() { return new FileUploadPlugin(); } -export * from './importer/types'; - export type { Props as IndexNameFormProps } from './components/geojson_upload_form/index_name_form'; export type { FileUploadPluginStart } from './plugin'; diff --git a/x-pack/plugins/file_upload/server/analyze_file.tsx b/x-pack/plugins/file_upload/server/analyze_file.tsx index 22396970834928..ecefd34b0cefc7 100644 --- a/x-pack/plugins/file_upload/server/analyze_file.tsx +++ b/x-pack/plugins/file_upload/server/analyze_file.tsx @@ -6,7 +6,12 @@ */ import { IScopedClusterClient } from 'kibana/server'; -import { AnalysisResult, FormattedOverrides, InputData, InputOverrides } from '../common'; +import type { + AnalysisResult, + FormattedOverrides, + InputData, + InputOverrides, +} from '../common/types'; export async function analyzeFile( client: IScopedClusterClient, diff --git a/x-pack/plugins/file_upload/server/import_data.ts b/x-pack/plugins/file_upload/server/import_data.ts index 1289adb59925b3..2419710c04c5a2 100644 --- a/x-pack/plugins/file_upload/server/import_data.ts +++ b/x-pack/plugins/file_upload/server/import_data.ts @@ -14,7 +14,7 @@ import { Settings, Mappings, IngestPipelineWrapper, -} from '../common'; +} from '../common/types'; export function importDataProvider({ asCurrentUser }: IScopedClusterClient) { async function importData( diff --git a/x-pack/plugins/file_upload/server/plugin.ts b/x-pack/plugins/file_upload/server/plugin.ts index bd5eebe372a752..9ec234c415e14f 100644 --- a/x-pack/plugins/file_upload/server/plugin.ts +++ b/x-pack/plugins/file_upload/server/plugin.ts @@ -10,7 +10,7 @@ import { CoreSetup, CoreStart, Logger, Plugin, PluginInitializerContext } from ' import { schema } from '@kbn/config-schema'; import { fileUploadRoutes } from './routes'; import { initFileUploadTelemetry } from './telemetry'; -import { UI_SETTING_MAX_FILE_SIZE, MAX_FILE_SIZE } from '../common'; +import { MAX_FILE_SIZE, UI_SETTING_MAX_FILE_SIZE } from '../common/constants'; import { setupCapabilities } from './capabilities'; import { StartDeps, SetupDeps } from './types'; diff --git a/x-pack/plugins/file_upload/server/routes.ts b/x-pack/plugins/file_upload/server/routes.ts index cb7c37a586b641..e8d32152c8afc2 100644 --- a/x-pack/plugins/file_upload/server/routes.ts +++ b/x-pack/plugins/file_upload/server/routes.ts @@ -8,13 +8,8 @@ import { schema } from '@kbn/config-schema'; import { IScopedClusterClient } from 'kibana/server'; import { CoreSetup, Logger } from 'src/core/server'; -import { - MAX_FILE_SIZE_BYTES, - IngestPipelineWrapper, - InputData, - Mappings, - Settings, -} from '../common'; +import { MAX_FILE_SIZE_BYTES } from '../common/constants'; +import type { IngestPipelineWrapper, InputData, Mappings, Settings } from '../common/types'; import { wrapError } from './error_wrapper'; import { importDataProvider } from './import_data'; import { getTimeFieldRange } from './get_time_field_range'; diff --git a/x-pack/plugins/ml/common/constants/data_frame_analytics.ts b/x-pack/plugins/ml/common/constants/data_frame_analytics.ts index f13537892875d3..0a4bc0b165e025 100644 --- a/x-pack/plugins/ml/common/constants/data_frame_analytics.ts +++ b/x-pack/plugins/ml/common/constants/data_frame_analytics.ts @@ -29,6 +29,11 @@ export const JOB_MAP_NODE_TYPES = { TRAINED_MODEL: 'trainedModel', } as const; +export const INDEX_CREATED_BY = { + FILE_DATA_VISUALIZER: 'file-data-visualizer', + DATA_FRAME_ANALYTICS: 'data-frame-analytics', +} as const; + export const BUILT_IN_MODEL_TAG = 'prepackaged'; export type JobMapNodeTypes = typeof JOB_MAP_NODE_TYPES[keyof typeof JOB_MAP_NODE_TYPES]; diff --git a/x-pack/plugins/ml/server/models/data_frame_analytics/analytics_manager.ts b/x-pack/plugins/ml/server/models/data_frame_analytics/analytics_manager.ts index dc39a8005b99e3..bf0ffc05dd0147 100644 --- a/x-pack/plugins/ml/server/models/data_frame_analytics/analytics_manager.ts +++ b/x-pack/plugins/ml/server/models/data_frame_analytics/analytics_manager.ts @@ -8,6 +8,7 @@ import Boom from '@hapi/boom'; import { IScopedClusterClient } from 'kibana/server'; import { + INDEX_CREATED_BY, JOB_MAP_NODE_TYPES, JobMapNodeTypes, } from '../../../common/constants/data_frame_analytics'; @@ -19,7 +20,6 @@ import { DataFrameAnalyticsStats, MapElements, } from '../../../common/types/data_frame_analytics'; -import { INDEX_META_DATA_CREATED_BY } from '../../../../file_upload/common'; import { getAnalysisType } from '../../../common/util/analytics_utils'; import { ExtendAnalyticsMapArgs, @@ -458,14 +458,14 @@ export class AnalyticsManager { if ( link.isWildcardIndexPattern === false && (link.meta === undefined || - link.meta?.created_by.includes(INDEX_META_DATA_CREATED_BY)) + link.meta?.created_by.includes(INDEX_CREATED_BY.FILE_DATA_VISUALIZER)) ) { rootIndexPattern = nextLinkId; complete = true; break; } - if (link.meta?.created_by === 'data-frame-analytics') { + if (link.meta?.created_by === INDEX_CREATED_BY.DATA_FRAME_ANALYTICS) { nextLinkId = link.meta.analytics; nextType = JOB_MAP_NODE_TYPES.ANALYTICS; } From ee34a7a694aa05f9ccc35908a7ce2c8ddb04d9bc Mon Sep 17 00:00:00 2001 From: Ryland Herrick Date: Thu, 20 Jan 2022 12:36:41 -0600 Subject: [PATCH 089/108] [Rule Registry] Remove constant_keyword field mappings from ECS component template (#123486) * Remove constant_keyword field mappings from ECS component template These ECS fields are meant for specific indices (datastreams), but do not make sense (especially as `constant_keyword`) on our alerts-as-data indices, as they will cause errors when attempting to ingest different values from different indices. * Filter out constant_keyword fields from ECS fieldmap The results of this were already applied to the fields themselves, but this ensures that the script does not accidentally repopulate them in the future. Implementation-wise, it was simpler to refactor this into a reduce() rather than explicitly using filter() and then generating a new object. --- .../common/assets/field_maps/ecs_field_map.ts | 15 --------- .../scripts/generate_ecs_fieldmap/index.js | 32 ++++++++++++------- 2 files changed, 20 insertions(+), 27 deletions(-) diff --git a/x-pack/plugins/rule_registry/common/assets/field_maps/ecs_field_map.ts b/x-pack/plugins/rule_registry/common/assets/field_maps/ecs_field_map.ts index 7c4095cca039fd..dc81e200032f7a 100644 --- a/x-pack/plugins/rule_registry/common/assets/field_maps/ecs_field_map.ts +++ b/x-pack/plugins/rule_registry/common/assets/field_maps/ecs_field_map.ts @@ -415,21 +415,6 @@ export const ecsFieldMap = { array: false, required: false, }, - 'data_stream.dataset': { - type: 'constant_keyword', - array: false, - required: false, - }, - 'data_stream.namespace': { - type: 'constant_keyword', - array: false, - required: false, - }, - 'data_stream.type': { - type: 'constant_keyword', - array: false, - required: false, - }, 'destination.address': { type: 'keyword', array: false, diff --git a/x-pack/plugins/rule_registry/scripts/generate_ecs_fieldmap/index.js b/x-pack/plugins/rule_registry/scripts/generate_ecs_fieldmap/index.js index 5e90a3c16aa7c6..9f28f87b492c55 100644 --- a/x-pack/plugins/rule_registry/scripts/generate_ecs_fieldmap/index.js +++ b/x-pack/plugins/rule_registry/scripts/generate_ecs_fieldmap/index.js @@ -9,7 +9,7 @@ const fs = require('fs'); const util = require('util'); const yaml = require('js-yaml'); const { exec: execCb } = require('child_process'); -const { mapValues } = require('lodash'); +const { reduce } = require('lodash'); const exists = util.promisify(fs.exists); const readFile = util.promisify(fs.readFile); @@ -32,19 +32,27 @@ async function generate() { const flatYaml = await yaml.safeLoad(await readFile(ecsYamlFilename)); - const fields = mapValues(flatYaml, (description) => { - const field = { - type: description.type, - array: description.normalize.includes('array'), - required: !!description.required, - }; + const fields = reduce( + flatYaml, + (fieldsObj, value, key) => { + const field = { + type: value.type, + array: value.normalize.includes('array'), + required: !!value.required, + }; - if (description.scaling_factor) { - field.scaling_factor = description.scaling_factor; - } + if (value.scaling_factor) { + field.scaling_factor = value.scaling_factor; + } - return field; - }); + if (field.type !== 'constant_keyword') { + fieldsObj[key] = field; + } + + return fieldsObj; + }, + {} + ); await Promise.all([ writeFile( From 855bfd30d1766948470fde55613140fc3739be5a Mon Sep 17 00:00:00 2001 From: Paul Tavares <56442535+paul-tavares@users.noreply.github.com> Date: Thu, 20 Jan 2022 14:17:15 -0500 Subject: [PATCH 090/108] Fix endpointAppContextServices use of calculateEndpointAuthz (#123494) --- .../server/endpoint/endpoint_app_context_services.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/server/endpoint/endpoint_app_context_services.ts b/x-pack/plugins/security_solution/server/endpoint/endpoint_app_context_services.ts index 3a8616f5d36271..eedc2fac4fb203 100644 --- a/x-pack/plugins/security_solution/server/endpoint/endpoint_app_context_services.ts +++ b/x-pack/plugins/security_solution/server/endpoint/endpoint_app_context_services.ts @@ -139,7 +139,9 @@ export class EndpointAppContextService { public async getEndpointAuthz(request: KibanaRequest): Promise { const fleetAuthz = await this.getFleetAuthzService().fromRequest(request); - return calculateEndpointAuthz(this.getLicenseService(), fleetAuthz); + const userRoles = this.startDependencies?.security.authc.getCurrentUser(request)?.roles ?? []; + + return calculateEndpointAuthz(this.getLicenseService(), fleetAuthz, userRoles); } public getEndpointMetadataService(): EndpointMetadataService { From 77d633fd53585c04e731ff3ff2d3d0103e013b3a Mon Sep 17 00:00:00 2001 From: Esteban Beltran Date: Thu, 20 Jan 2022 20:21:08 +0100 Subject: [PATCH 091/108] [Cases] Fix missing displayName for some react components (#123460) --- x-pack/plugins/cases/public/common/mock/test_providers.tsx | 1 + x-pack/plugins/cases/public/components/all_cases/columns.tsx | 1 + x-pack/plugins/cases/public/components/all_cases/count.tsx | 1 + x-pack/plugins/cases/public/components/all_cases/header.tsx | 1 + x-pack/plugins/cases/public/components/all_cases/index.tsx | 1 + .../plugins/cases/public/components/all_cases/nav_buttons.tsx | 1 + .../plugins/cases/public/components/all_cases/status_filter.tsx | 1 + x-pack/plugins/cases/public/components/all_cases/table.tsx | 1 + .../plugins/cases/public/components/all_cases/utility_bar.tsx | 1 + x-pack/plugins/cases/public/components/app/routes.tsx | 1 + .../plugins/cases/public/components/case_action_bar/actions.tsx | 1 + .../plugins/cases/public/components/case_action_bar/index.tsx | 1 + .../public/components/case_action_bar/status_context_menu.tsx | 1 + x-pack/plugins/cases/public/components/cases_context/index.tsx | 1 + .../cases/public/components/configure_cases/closure_options.tsx | 1 + .../public/components/configure_cases/closure_options_radio.tsx | 1 + .../cases/public/components/configure_cases/connectors.tsx | 1 + .../public/components/configure_cases/connectors_dropdown.tsx | 1 + .../cases/public/components/configure_cases/field_mapping.tsx | 1 + .../components/configure_cases/field_mapping_row_static.tsx | 1 + .../plugins/cases/public/components/configure_cases/mapping.tsx | 1 + .../cases/public/components/confirm_delete_case/index.tsx | 1 + .../plugins/cases/public/components/connector_selector/form.tsx | 1 + x-pack/plugins/cases/public/components/connectors/card.tsx | 1 + .../cases/public/components/connectors/case/alert_fields.tsx | 1 + .../cases/public/components/connectors/case/cases_dropdown.tsx | 1 + .../cases/public/components/connectors/case/existing_case.tsx | 1 + .../cases/public/components/connectors/deprecated_callout.tsx | 1 + .../plugins/cases/public/components/connectors/fields_form.tsx | 1 + .../cases/public/components/connectors/jira/case_fields.tsx | 1 + .../cases/public/components/connectors/jira/search_issues.tsx | 1 + .../cases/public/components/connectors/swimlane/case_fields.tsx | 1 + x-pack/plugins/cases/public/components/create/connector.tsx | 1 + .../plugins/cases/public/components/create/owner_selector.tsx | 1 + x-pack/plugins/cases/public/components/create/submit_button.tsx | 1 + x-pack/plugins/cases/public/components/formatted_date/index.tsx | 1 + .../header_page/__snapshots__/editable_title.test.tsx.snap | 2 +- .../components/header_page/__snapshots__/index.test.tsx.snap | 2 +- .../components/header_page/__snapshots__/title.test.tsx.snap | 2 +- .../cases/public/components/header_page/editable_title.tsx | 1 + x-pack/plugins/cases/public/components/header_page/index.tsx | 1 + x-pack/plugins/cases/public/components/header_page/title.tsx | 1 + .../cases/public/components/markdown_editor/markdown_link.tsx | 1 + .../public/components/markdown_editor/plugins/lens/plugin.tsx | 1 + .../components/markdown_editor/plugins/lens/processor.tsx | 1 + .../cases/public/components/markdown_editor/renderer.tsx | 1 + .../cases/public/components/recent_cases/recent_cases.tsx | 1 + x-pack/plugins/cases/public/components/status/button.tsx | 1 + x-pack/plugins/cases/public/components/status/status.tsx | 1 + x-pack/plugins/cases/public/components/tag_list/tags.tsx | 1 + x-pack/plugins/cases/public/components/truncated_text/index.tsx | 1 + .../components/use_create_case_modal/create_case_modal.tsx | 1 + .../public/components/use_push_to_service/callout/callout.tsx | 1 + .../public/components/use_push_to_service/callout/index.tsx | 1 + x-pack/plugins/cases/public/components/user_actions/avatar.tsx | 1 + .../cases/public/components/user_actions/avatar_username.tsx | 1 + .../public/components/user_actions/comment/alert_event.tsx | 1 + .../components/user_actions/comment/host_isolation_event.tsx | 1 + .../cases/public/components/user_actions/comment/show_alert.tsx | 1 + .../cases/public/components/user_actions/content_toolbar.tsx | 1 + .../plugins/cases/public/components/user_actions/copy_link.tsx | 1 + .../cases/public/components/user_actions/move_to_reference.tsx | 1 + .../cases/public/components/user_actions/property_actions.tsx | 1 + .../plugins/cases/public/components/user_actions/timestamp.tsx | 1 + .../plugins/cases/public/components/user_actions/username.tsx | 1 + 65 files changed, 65 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/cases/public/common/mock/test_providers.tsx b/x-pack/plugins/cases/public/common/mock/test_providers.tsx index b5a3df84c97125..477738ddeac16a 100644 --- a/x-pack/plugins/cases/public/common/mock/test_providers.tsx +++ b/x-pack/plugins/cases/public/common/mock/test_providers.tsx @@ -43,6 +43,7 @@ const TestProvidersComponent: React.FC = ({ ); }; +TestProvidersComponent.displayName = 'TestProviders'; export const TestProviders = React.memo(TestProvidersComponent); diff --git a/x-pack/plugins/cases/public/components/all_cases/columns.tsx b/x-pack/plugins/cases/public/components/all_cases/columns.tsx index 663779029fcecc..e67ec11fef03d0 100644 --- a/x-pack/plugins/cases/public/components/all_cases/columns.tsx +++ b/x-pack/plugins/cases/public/components/all_cases/columns.tsx @@ -456,3 +456,4 @@ export const ExternalServiceColumn: React.FC = ({ theCase, connectors })

); }; +ExternalServiceColumn.displayName = 'ExternalServiceColumn'; diff --git a/x-pack/plugins/cases/public/components/all_cases/count.tsx b/x-pack/plugins/cases/public/components/all_cases/count.tsx index 1f6e71c377ee69..cd4abdd08b8e70 100644 --- a/x-pack/plugins/cases/public/components/all_cases/count.tsx +++ b/x-pack/plugins/cases/public/components/all_cases/count.tsx @@ -56,3 +56,4 @@ export const Count: FunctionComponent = ({ refresh }) => {
); }; +Count.displayName = 'Count'; diff --git a/x-pack/plugins/cases/public/components/all_cases/header.tsx b/x-pack/plugins/cases/public/components/all_cases/header.tsx index bca8ea3cf07119..19a1a897221e70 100644 --- a/x-pack/plugins/cases/public/components/all_cases/header.tsx +++ b/x-pack/plugins/cases/public/components/all_cases/header.tsx @@ -64,3 +64,4 @@ export const CasesTableHeader: FunctionComponent = ({ ); +CasesTableHeader.displayName = 'CasesTableHeader'; diff --git a/x-pack/plugins/cases/public/components/all_cases/index.tsx b/x-pack/plugins/cases/public/components/all_cases/index.tsx index e163d9ada4a515..8ea7681eb44d94 100644 --- a/x-pack/plugins/cases/public/components/all_cases/index.tsx +++ b/x-pack/plugins/cases/public/components/all_cases/index.tsx @@ -33,6 +33,7 @@ export const AllCases: React.FC = () => { ); }; +AllCases.displayName = 'AllCases'; // eslint-disable-next-line import/no-default-export export { AllCases as default }; diff --git a/x-pack/plugins/cases/public/components/all_cases/nav_buttons.tsx b/x-pack/plugins/cases/public/components/all_cases/nav_buttons.tsx index c05210f4e719ff..5409cf092d8c95 100644 --- a/x-pack/plugins/cases/public/components/all_cases/nav_buttons.tsx +++ b/x-pack/plugins/cases/public/components/all_cases/nav_buttons.tsx @@ -64,3 +64,4 @@ export const NavButtons: FunctionComponent = ({ actionsErrors }) => { ); }; +NavButtons.displayName = 'NavButtons'; diff --git a/x-pack/plugins/cases/public/components/all_cases/status_filter.tsx b/x-pack/plugins/cases/public/components/all_cases/status_filter.tsx index 71359c2e505823..ca211107bcf9a2 100644 --- a/x-pack/plugins/cases/public/components/all_cases/status_filter.tsx +++ b/x-pack/plugins/cases/public/components/all_cases/status_filter.tsx @@ -50,5 +50,6 @@ const StatusFilterComponent: React.FC = ({ /> ); }; +StatusFilterComponent.displayName = 'StatusFilter'; export const StatusFilter = memo(StatusFilterComponent); diff --git a/x-pack/plugins/cases/public/components/all_cases/table.tsx b/x-pack/plugins/cases/public/components/all_cases/table.tsx index 2a613395119bc3..0d4a4cb6b38f1f 100644 --- a/x-pack/plugins/cases/public/components/all_cases/table.tsx +++ b/x-pack/plugins/cases/public/components/all_cases/table.tsx @@ -164,3 +164,4 @@ export const CasesTable: FunctionComponent = ({
); }; +CasesTable.displayName = 'CasesTable'; diff --git a/x-pack/plugins/cases/public/components/all_cases/utility_bar.tsx b/x-pack/plugins/cases/public/components/all_cases/utility_bar.tsx index b6ab44517bb66c..3ff3f89de210b9 100644 --- a/x-pack/plugins/cases/public/components/all_cases/utility_bar.tsx +++ b/x-pack/plugins/cases/public/components/all_cases/utility_bar.tsx @@ -161,3 +161,4 @@ export const CasesTableUtilityBar: FunctionComponent = ({ ); }; +CasesTableUtilityBar.displayName = 'CasesTableUtilityBar'; diff --git a/x-pack/plugins/cases/public/components/app/routes.tsx b/x-pack/plugins/cases/public/components/app/routes.tsx index 06387072c2323f..ab4bf2ac51f194 100644 --- a/x-pack/plugins/cases/public/components/app/routes.tsx +++ b/x-pack/plugins/cases/public/components/app/routes.tsx @@ -98,5 +98,6 @@ const CasesRoutesComponent: React.FC = ({ ); }; +CasesRoutesComponent.displayName = 'CasesRoutes'; export const CasesRoutes = React.memo(CasesRoutesComponent); diff --git a/x-pack/plugins/cases/public/components/case_action_bar/actions.tsx b/x-pack/plugins/cases/public/components/case_action_bar/actions.tsx index 4cad00535d1655..a6db64b83bf099 100644 --- a/x-pack/plugins/cases/public/components/case_action_bar/actions.tsx +++ b/x-pack/plugins/cases/public/components/case_action_bar/actions.tsx @@ -64,5 +64,6 @@ const ActionsComponent: React.FC = ({ caseData, currentExternal ); }; +ActionsComponent.displayName = 'Actions'; export const Actions = React.memo(ActionsComponent); diff --git a/x-pack/plugins/cases/public/components/case_action_bar/index.tsx b/x-pack/plugins/cases/public/components/case_action_bar/index.tsx index 1432d6d707df4b..c9e54e87db8d40 100644 --- a/x-pack/plugins/cases/public/components/case_action_bar/index.tsx +++ b/x-pack/plugins/cases/public/components/case_action_bar/index.tsx @@ -164,5 +164,6 @@ const CaseActionBarComponent: React.FC = ({ ); }; +CaseActionBarComponent.displayName = 'CaseActionBar'; export const CaseActionBar = React.memo(CaseActionBarComponent); diff --git a/x-pack/plugins/cases/public/components/case_action_bar/status_context_menu.tsx b/x-pack/plugins/cases/public/components/case_action_bar/status_context_menu.tsx index 193ef4a708e380..dce26fcbd5965e 100644 --- a/x-pack/plugins/cases/public/components/case_action_bar/status_context_menu.tsx +++ b/x-pack/plugins/cases/public/components/case_action_bar/status_context_menu.tsx @@ -69,5 +69,6 @@ const StatusContextMenuComponent: React.FC = ({ ); }; +StatusContextMenuComponent.displayName = 'StatusContextMenu'; export const StatusContextMenu = memo(StatusContextMenuComponent); diff --git a/x-pack/plugins/cases/public/components/cases_context/index.tsx b/x-pack/plugins/cases/public/components/cases_context/index.tsx index e24a08c38cfeb6..aceefad97382a3 100644 --- a/x-pack/plugins/cases/public/components/cases_context/index.tsx +++ b/x-pack/plugins/cases/public/components/cases_context/index.tsx @@ -61,6 +61,7 @@ export const CasesProvider: React.FC<{ value: CasesContextProps }> = ({ {children} ) : null; }; +CasesProvider.displayName = 'CasesProvider'; function isCasesContextValue(value: CasesContextStateValue): value is CasesContextValue { return value.appId != null && value.appTitle != null && value.userCanCrud != null; diff --git a/x-pack/plugins/cases/public/components/configure_cases/closure_options.tsx b/x-pack/plugins/cases/public/components/configure_cases/closure_options.tsx index 0c76341e9c3401..2bcb137d348ad8 100644 --- a/x-pack/plugins/cases/public/components/configure_cases/closure_options.tsx +++ b/x-pack/plugins/cases/public/components/configure_cases/closure_options.tsx @@ -48,5 +48,6 @@ const ClosureOptionsComponent: React.FC = ({ ); +ClosureOptionsComponent.displayName = 'ClosureOptions'; export const ClosureOptions = React.memo(ClosureOptionsComponent); diff --git a/x-pack/plugins/cases/public/components/configure_cases/closure_options_radio.tsx b/x-pack/plugins/cases/public/components/configure_cases/closure_options_radio.tsx index cb6fa0953a7964..88ee18db805fff 100644 --- a/x-pack/plugins/cases/public/components/configure_cases/closure_options_radio.tsx +++ b/x-pack/plugins/cases/public/components/configure_cases/closure_options_radio.tsx @@ -56,5 +56,6 @@ const ClosureOptionsRadioComponent: React.FC /> ); }; +ClosureOptionsRadioComponent.displayName = 'ClosureOptionsRadio'; export const ClosureOptionsRadio = React.memo(ClosureOptionsRadioComponent); diff --git a/x-pack/plugins/cases/public/components/configure_cases/connectors.tsx b/x-pack/plugins/cases/public/components/configure_cases/connectors.tsx index 11026acde2bf6c..e75f7ed2bdffad 100644 --- a/x-pack/plugins/cases/public/components/configure_cases/connectors.tsx +++ b/x-pack/plugins/cases/public/components/configure_cases/connectors.tsx @@ -131,5 +131,6 @@ const ConnectorsComponent: React.FC = ({ ); }; +ConnectorsComponent.displayName = 'Connectors'; export const Connectors = React.memo(ConnectorsComponent); diff --git a/x-pack/plugins/cases/public/components/configure_cases/connectors_dropdown.tsx b/x-pack/plugins/cases/public/components/configure_cases/connectors_dropdown.tsx index af518e3c773b69..9082fc572324e8 100644 --- a/x-pack/plugins/cases/public/components/configure_cases/connectors_dropdown.tsx +++ b/x-pack/plugins/cases/public/components/configure_cases/connectors_dropdown.tsx @@ -139,5 +139,6 @@ const ConnectorsDropdownComponent: React.FC = ({ /> ); }; +ConnectorsDropdownComponent.displayName = 'ConnectorsDropdown'; export const ConnectorsDropdown = React.memo(ConnectorsDropdownComponent); diff --git a/x-pack/plugins/cases/public/components/configure_cases/field_mapping.tsx b/x-pack/plugins/cases/public/components/configure_cases/field_mapping.tsx index fe99f718c14012..7c521849680132 100644 --- a/x-pack/plugins/cases/public/components/configure_cases/field_mapping.tsx +++ b/x-pack/plugins/cases/public/components/configure_cases/field_mapping.tsx @@ -62,5 +62,6 @@ const FieldMappingComponent: React.FC = ({ ) : null; }; +FieldMappingComponent.displayName = 'FieldMapping'; export const FieldMapping = React.memo(FieldMappingComponent); diff --git a/x-pack/plugins/cases/public/components/configure_cases/field_mapping_row_static.tsx b/x-pack/plugins/cases/public/components/configure_cases/field_mapping_row_static.tsx index 09e3546b2e2e3b..d7949362e4a1b6 100644 --- a/x-pack/plugins/cases/public/components/configure_cases/field_mapping_row_static.tsx +++ b/x-pack/plugins/cases/public/components/configure_cases/field_mapping_row_static.tsx @@ -57,5 +57,6 @@ const FieldMappingRowComponent: React.FC = ({ ); }; +FieldMappingRowComponent.displayName = 'FieldMappingRow'; export const FieldMappingRowStatic = React.memo(FieldMappingRowComponent); diff --git a/x-pack/plugins/cases/public/components/configure_cases/mapping.tsx b/x-pack/plugins/cases/public/components/configure_cases/mapping.tsx index eb14c22b900c43..4ce971d6528794 100644 --- a/x-pack/plugins/cases/public/components/configure_cases/mapping.tsx +++ b/x-pack/plugins/cases/public/components/configure_cases/mapping.tsx @@ -56,5 +56,6 @@ const MappingComponent: React.FC = ({ actionTypeName, isLoading, m ); }; +MappingComponent.displayName = 'Mapping'; export const Mapping = React.memo(MappingComponent); diff --git a/x-pack/plugins/cases/public/components/confirm_delete_case/index.tsx b/x-pack/plugins/cases/public/components/confirm_delete_case/index.tsx index baf34daea0d99c..ce8287310fb179 100644 --- a/x-pack/plugins/cases/public/components/confirm_delete_case/index.tsx +++ b/x-pack/plugins/cases/public/components/confirm_delete_case/index.tsx @@ -42,5 +42,6 @@ const ConfirmDeleteCaseModalComp: React.FC = ({ ); }; +ConfirmDeleteCaseModalComp.displayName = 'ConfirmDeleteCaseModalComp'; export const ConfirmDeleteCaseModal = React.memo(ConfirmDeleteCaseModalComp); diff --git a/x-pack/plugins/cases/public/components/connector_selector/form.tsx b/x-pack/plugins/cases/public/components/connector_selector/form.tsx index 05db3474fdb994..83733ea7e97ddb 100644 --- a/x-pack/plugins/cases/public/components/connector_selector/form.tsx +++ b/x-pack/plugins/cases/public/components/connector_selector/form.tsx @@ -76,3 +76,4 @@ export const ConnectorSelector = ({ ) : null; }; +ConnectorSelector.displayName = 'ConnectorSelector'; diff --git a/x-pack/plugins/cases/public/components/connectors/card.tsx b/x-pack/plugins/cases/public/components/connectors/card.tsx index 9870c77fda7439..d6ef92572e5069 100644 --- a/x-pack/plugins/cases/public/components/connectors/card.tsx +++ b/x-pack/plugins/cases/public/components/connectors/card.tsx @@ -77,5 +77,6 @@ const ConnectorCardDisplay: React.FC = ({ ); }; +ConnectorCardDisplay.displayName = 'ConnectorCardDisplay'; export const ConnectorCard = memo(ConnectorCardDisplay); diff --git a/x-pack/plugins/cases/public/components/connectors/case/alert_fields.tsx b/x-pack/plugins/cases/public/components/connectors/case/alert_fields.tsx index 7cd9b5f6a367cd..d6708657dd08f6 100644 --- a/x-pack/plugins/cases/public/components/connectors/case/alert_fields.tsx +++ b/x-pack/plugins/cases/public/components/connectors/case/alert_fields.tsx @@ -103,6 +103,7 @@ const CaseParamsFields: React.FunctionComponent ); }; +CaseParamsFields.displayName = 'CaseParamsFields'; // eslint-disable-next-line import/no-default-export export { CaseParamsFields as default }; diff --git a/x-pack/plugins/cases/public/components/connectors/case/cases_dropdown.tsx b/x-pack/plugins/cases/public/components/connectors/case/cases_dropdown.tsx index 3f3c7d4931192e..c26fa04df6843e 100644 --- a/x-pack/plugins/cases/public/components/connectors/case/cases_dropdown.tsx +++ b/x-pack/plugins/cases/public/components/connectors/case/cases_dropdown.tsx @@ -69,5 +69,6 @@ const CasesDropdownComponent: React.FC = ({ ); }; +CasesDropdownComponent.displayName = 'CasesDropdown'; export const CasesDropdown = memo(CasesDropdownComponent); diff --git a/x-pack/plugins/cases/public/components/connectors/case/existing_case.tsx b/x-pack/plugins/cases/public/components/connectors/case/existing_case.tsx index 33366e11f556a2..7472bc6b6047e5 100644 --- a/x-pack/plugins/cases/public/components/connectors/case/existing_case.tsx +++ b/x-pack/plugins/cases/public/components/connectors/case/existing_case.tsx @@ -77,5 +77,6 @@ const ExistingCaseComponent: React.FC = ({ onCaseChanged, sel ); }; +ExistingCaseComponent.displayName = 'ExistingCase'; export const ExistingCase = memo(ExistingCaseComponent); diff --git a/x-pack/plugins/cases/public/components/connectors/deprecated_callout.tsx b/x-pack/plugins/cases/public/components/connectors/deprecated_callout.tsx index 195b2deb84d6e8..60ae867fab8b4e 100644 --- a/x-pack/plugins/cases/public/components/connectors/deprecated_callout.tsx +++ b/x-pack/plugins/cases/public/components/connectors/deprecated_callout.tsx @@ -37,5 +37,6 @@ const DeprecatedCalloutComponent: React.FC = ({ type = 'warning' }) => ( {DEPRECATED_CONNECTOR_WARNING_DESC} ); +DeprecatedCalloutComponent.displayName = 'DeprecatedCallout'; export const DeprecatedCallout = React.memo(DeprecatedCalloutComponent); diff --git a/x-pack/plugins/cases/public/components/connectors/fields_form.tsx b/x-pack/plugins/cases/public/components/connectors/fields_form.tsx index 56c56436c08c75..60eb20fe861dae 100644 --- a/x-pack/plugins/cases/public/components/connectors/fields_form.tsx +++ b/x-pack/plugins/cases/public/components/connectors/fields_form.tsx @@ -51,5 +51,6 @@ const ConnectorFieldsFormComponent: React.FC = ({ connector, isEdit, onCh ); }; +ConnectorFieldsFormComponent.displayName = 'ConnectorFieldsForm'; export const ConnectorFieldsForm = memo(ConnectorFieldsFormComponent); diff --git a/x-pack/plugins/cases/public/components/connectors/jira/case_fields.tsx b/x-pack/plugins/cases/public/components/connectors/jira/case_fields.tsx index b9326a08330cd8..1fe02a8483ed39 100644 --- a/x-pack/plugins/cases/public/components/connectors/jira/case_fields.tsx +++ b/x-pack/plugins/cases/public/components/connectors/jira/case_fields.tsx @@ -209,6 +209,7 @@ const JiraFieldsComponent: React.FunctionComponent ); }; +JiraFieldsComponent.displayName = 'JiraFields'; // eslint-disable-next-line import/no-default-export export { JiraFieldsComponent as default }; diff --git a/x-pack/plugins/cases/public/components/connectors/jira/search_issues.tsx b/x-pack/plugins/cases/public/components/connectors/jira/search_issues.tsx index a9ed87fa813462..53c25db0a72b6c 100644 --- a/x-pack/plugins/cases/public/components/connectors/jira/search_issues.tsx +++ b/x-pack/plugins/cases/public/components/connectors/jira/search_issues.tsx @@ -92,5 +92,6 @@ const SearchIssuesComponent: React.FC = ({ selectedValue, actionConnector /> ); }; +SearchIssuesComponent.displayName = 'SearchIssues'; export const SearchIssues = memo(SearchIssuesComponent); diff --git a/x-pack/plugins/cases/public/components/connectors/swimlane/case_fields.tsx b/x-pack/plugins/cases/public/components/connectors/swimlane/case_fields.tsx index a7e584f7c22e23..3ca1d6b3ec6740 100644 --- a/x-pack/plugins/cases/public/components/connectors/swimlane/case_fields.tsx +++ b/x-pack/plugins/cases/public/components/connectors/swimlane/case_fields.tsx @@ -43,6 +43,7 @@ const SwimlaneComponent: React.FunctionComponent ); }; +SwimlaneComponent.displayName = 'Swimlane'; // eslint-disable-next-line import/no-default-export export { SwimlaneComponent as default }; diff --git a/x-pack/plugins/cases/public/components/create/connector.tsx b/x-pack/plugins/cases/public/components/create/connector.tsx index aa0eb024a3b0df..47cc3ea91a8681 100644 --- a/x-pack/plugins/cases/public/components/create/connector.tsx +++ b/x-pack/plugins/cases/public/components/create/connector.tsx @@ -64,6 +64,7 @@ const ConnectorFields = ({ /> ); }; +ConnectorFields.displayName = 'ConnectorFields'; const ConnectorComponent: React.FC = ({ connectors, diff --git a/x-pack/plugins/cases/public/components/create/owner_selector.tsx b/x-pack/plugins/cases/public/components/create/owner_selector.tsx index 251681506d516b..eaa5382260d212 100644 --- a/x-pack/plugins/cases/public/components/create/owner_selector.tsx +++ b/x-pack/plugins/cases/public/components/create/owner_selector.tsx @@ -101,6 +101,7 @@ const OwnerSelector = ({ ); }; +OwnerSelector.displayName = 'OwnerSelector'; const CaseOwnerSelector: React.FC = ({ availableOwners, isLoading }) => { return ( diff --git a/x-pack/plugins/cases/public/components/create/submit_button.tsx b/x-pack/plugins/cases/public/components/create/submit_button.tsx index b5e58517e6ec14..9f984b236ca690 100644 --- a/x-pack/plugins/cases/public/components/create/submit_button.tsx +++ b/x-pack/plugins/cases/public/components/create/submit_button.tsx @@ -27,5 +27,6 @@ const SubmitCaseButtonComponent: React.FC = () => { ); }; +SubmitCaseButtonComponent.displayName = 'SubmitCaseButton'; export const SubmitCaseButton = memo(SubmitCaseButtonComponent); diff --git a/x-pack/plugins/cases/public/components/formatted_date/index.tsx b/x-pack/plugins/cases/public/components/formatted_date/index.tsx index c2868557717945..0fff8431fac449 100644 --- a/x-pack/plugins/cases/public/components/formatted_date/index.tsx +++ b/x-pack/plugins/cases/public/components/formatted_date/index.tsx @@ -142,6 +142,7 @@ export const FormattedRelativePreferenceDate = ({ value }: { value?: string | nu ); }; +FormattedRelativePreferenceDate.displayName = 'FormattedRelativePreferenceDate'; /** * Renders a preceding label according to under/over one hour diff --git a/x-pack/plugins/cases/public/components/header_page/__snapshots__/editable_title.test.tsx.snap b/x-pack/plugins/cases/public/components/header_page/__snapshots__/editable_title.test.tsx.snap index 1348e26ebdf6d2..86d752f84a8b38 100644 --- a/x-pack/plugins/cases/public/components/header_page/__snapshots__/editable_title.test.tsx.snap +++ b/x-pack/plugins/cases/public/components/header_page/__snapshots__/editable_title.test.tsx.snap @@ -9,7 +9,7 @@ exports[`EditableTitle it renders 1`] = ` - diff --git a/x-pack/plugins/cases/public/components/header_page/__snapshots__/index.test.tsx.snap b/x-pack/plugins/cases/public/components/header_page/__snapshots__/index.test.tsx.snap index a100f5e4f93b48..17517b1d05f197 100644 --- a/x-pack/plugins/cases/public/components/header_page/__snapshots__/index.test.tsx.snap +++ b/x-pack/plugins/cases/public/components/header_page/__snapshots__/index.test.tsx.snap @@ -8,7 +8,7 @@ exports[`HeaderPage it renders 1`] = ` alignItems="center" > - - diff --git a/x-pack/plugins/cases/public/components/header_page/editable_title.tsx b/x-pack/plugins/cases/public/components/header_page/editable_title.tsx index 43b210b5a5afbd..674a31122d9837 100644 --- a/x-pack/plugins/cases/public/components/header_page/editable_title.tsx +++ b/x-pack/plugins/cases/public/components/header_page/editable_title.tsx @@ -134,5 +134,6 @@ const EditableTitleComponent: React.FC = ({ ); }; +EditableTitleComponent.displayName = 'EditableTitle'; export const EditableTitle = React.memo(EditableTitleComponent); diff --git a/x-pack/plugins/cases/public/components/header_page/index.tsx b/x-pack/plugins/cases/public/components/header_page/index.tsx index 073e18cd7d728f..3afcd15bfa817f 100644 --- a/x-pack/plugins/cases/public/components/header_page/index.tsx +++ b/x-pack/plugins/cases/public/components/header_page/index.tsx @@ -127,5 +127,6 @@ const HeaderPageComponent: React.FC = ({ ); }; +HeaderPageComponent.displayName = 'HeaderPage'; export const HeaderPage = React.memo(HeaderPageComponent); diff --git a/x-pack/plugins/cases/public/components/header_page/title.tsx b/x-pack/plugins/cases/public/components/header_page/title.tsx index 18b10c4f7bbcb4..9ccf13b8d83a93 100644 --- a/x-pack/plugins/cases/public/components/header_page/title.tsx +++ b/x-pack/plugins/cases/public/components/header_page/title.tsx @@ -52,5 +52,6 @@ const TitleComponent: React.FC = ({ title, badgeOptions }) => ( ); +TitleComponent.displayName = 'Title'; export const Title = React.memo(TitleComponent); diff --git a/x-pack/plugins/cases/public/components/markdown_editor/markdown_link.tsx b/x-pack/plugins/cases/public/components/markdown_editor/markdown_link.tsx index 7cc8a07c8c04e5..c42ef90648bc9b 100644 --- a/x-pack/plugins/cases/public/components/markdown_editor/markdown_link.tsx +++ b/x-pack/plugins/cases/public/components/markdown_editor/markdown_link.tsx @@ -31,5 +31,6 @@ const MarkdownLinkComponent: React.FC = ({ ); +MarkdownLinkComponent.displayName = 'MarkdownLink'; export const MarkdownLink = memo(MarkdownLinkComponent); diff --git a/x-pack/plugins/cases/public/components/markdown_editor/plugins/lens/plugin.tsx b/x-pack/plugins/cases/public/components/markdown_editor/plugins/lens/plugin.tsx index 0d3a62d3127016..5179aed6518b5e 100644 --- a/x-pack/plugins/cases/public/components/markdown_editor/plugins/lens/plugin.tsx +++ b/x-pack/plugins/cases/public/components/markdown_editor/plugins/lens/plugin.tsx @@ -375,6 +375,7 @@ const LensEditorComponent: LensEuiMarkdownEditorUiPlugin['editor'] = ({ ); }; +LensEditorComponent.displayName = 'LensEditor'; export const LensEditor = React.memo(LensEditorComponent); diff --git a/x-pack/plugins/cases/public/components/markdown_editor/plugins/lens/processor.tsx b/x-pack/plugins/cases/public/components/markdown_editor/plugins/lens/processor.tsx index 9e39cc5cb82185..1ca3f53291eb03 100644 --- a/x-pack/plugins/cases/public/components/markdown_editor/plugins/lens/processor.tsx +++ b/x-pack/plugins/cases/public/components/markdown_editor/plugins/lens/processor.tsx @@ -55,5 +55,6 @@ const LensMarkDownRendererComponent: React.FC = ({ ); }; +LensMarkDownRendererComponent.displayName = 'LensMarkDownRenderer'; export const LensMarkDownRenderer = React.memo(LensMarkDownRendererComponent); diff --git a/x-pack/plugins/cases/public/components/markdown_editor/renderer.tsx b/x-pack/plugins/cases/public/components/markdown_editor/renderer.tsx index b0f167628496b2..e0265a2884b971 100644 --- a/x-pack/plugins/cases/public/components/markdown_editor/renderer.tsx +++ b/x-pack/plugins/cases/public/components/markdown_editor/renderer.tsx @@ -46,5 +46,6 @@ const MarkdownRendererComponent: React.FC = ({ children, disableLinks }) ); }; +MarkdownRendererComponent.displayName = 'MarkdownRenderer'; export const MarkdownRenderer = memo(MarkdownRendererComponent); diff --git a/x-pack/plugins/cases/public/components/recent_cases/recent_cases.tsx b/x-pack/plugins/cases/public/components/recent_cases/recent_cases.tsx index 794984c08d79c2..0f9111e5acd1dd 100644 --- a/x-pack/plugins/cases/public/components/recent_cases/recent_cases.tsx +++ b/x-pack/plugins/cases/public/components/recent_cases/recent_cases.tsx @@ -91,3 +91,4 @@ export const RecentCasesComp = ({ filterOptions, maxCasesToShow }: RecentCasesPr ); }; +RecentCasesComp.displayName = 'RecentCasesComp'; diff --git a/x-pack/plugins/cases/public/components/status/button.tsx b/x-pack/plugins/cases/public/components/status/button.tsx index c9dcd509c10029..34eb5d62c77903 100644 --- a/x-pack/plugins/cases/public/components/status/button.tsx +++ b/x-pack/plugins/cases/public/components/status/button.tsx @@ -42,4 +42,5 @@ const StatusActionButtonComponent: React.FC = ({ status, onStatusChanged, ); }; +StatusActionButtonComponent.displayName = 'StatusActionButton'; export const StatusActionButton = memo(StatusActionButtonComponent); diff --git a/x-pack/plugins/cases/public/components/status/status.tsx b/x-pack/plugins/cases/public/components/status/status.tsx index 47c30a77612642..ad9add5d3fffdf 100644 --- a/x-pack/plugins/cases/public/components/status/status.tsx +++ b/x-pack/plugins/cases/public/components/status/status.tsx @@ -46,5 +46,6 @@ const StatusComponent: React.FC = ({ ); }; +StatusComponent.displayName = 'Status'; export const Status = memo(StatusComponent); diff --git a/x-pack/plugins/cases/public/components/tag_list/tags.tsx b/x-pack/plugins/cases/public/components/tag_list/tags.tsx index f3b05972a24a95..ec8a84de1aa884 100644 --- a/x-pack/plugins/cases/public/components/tag_list/tags.tsx +++ b/x-pack/plugins/cases/public/components/tag_list/tags.tsx @@ -30,5 +30,6 @@ const TagsComponent: React.FC = ({ tags, color = 'default', gutterSiz )} ); +TagsComponent.displayName = 'Tags'; export const Tags = memo(TagsComponent); diff --git a/x-pack/plugins/cases/public/components/truncated_text/index.tsx b/x-pack/plugins/cases/public/components/truncated_text/index.tsx index 3cf7f8322d797e..7d663dc989c967 100644 --- a/x-pack/plugins/cases/public/components/truncated_text/index.tsx +++ b/x-pack/plugins/cases/public/components/truncated_text/index.tsx @@ -26,5 +26,6 @@ interface Props { const TruncatedTextComponent: React.FC = ({ text }) => { return {text}; }; +TruncatedTextComponent.displayName = 'TruncatedText'; export const TruncatedText = React.memo(TruncatedTextComponent); diff --git a/x-pack/plugins/cases/public/components/use_create_case_modal/create_case_modal.tsx b/x-pack/plugins/cases/public/components/use_create_case_modal/create_case_modal.tsx index f3badc94e5468e..6c844a660b8013 100644 --- a/x-pack/plugins/cases/public/components/use_create_case_modal/create_case_modal.tsx +++ b/x-pack/plugins/cases/public/components/use_create_case_modal/create_case_modal.tsx @@ -40,6 +40,7 @@ const CreateModalComponent: React.FC = ({ ) : null; +CreateModalComponent.displayName = 'CreateModal'; export const CreateCaseModal = memo(CreateModalComponent); diff --git a/x-pack/plugins/cases/public/components/use_push_to_service/callout/callout.tsx b/x-pack/plugins/cases/public/components/use_push_to_service/callout/callout.tsx index 4c27d8ce7f87b0..a6acf692be10e6 100644 --- a/x-pack/plugins/cases/public/components/use_push_to_service/callout/callout.tsx +++ b/x-pack/plugins/cases/public/components/use_push_to_service/callout/callout.tsx @@ -68,5 +68,6 @@ const CallOutComponent = ({ ) : null; }; +CallOutComponent.displayName = 'CallOut'; export const CallOut = memo(CallOutComponent); diff --git a/x-pack/plugins/cases/public/components/use_push_to_service/callout/index.tsx b/x-pack/plugins/cases/public/components/use_push_to_service/callout/index.tsx index 40c61175153c0a..fb9145d2a941a5 100644 --- a/x-pack/plugins/cases/public/components/use_push_to_service/callout/index.tsx +++ b/x-pack/plugins/cases/public/components/use_push_to_service/callout/index.tsx @@ -89,5 +89,6 @@ const CaseCallOutComponent = ({ ); }; +CaseCallOutComponent.displayName = 'CaseCallOut'; export const CaseCallOut = memo(CaseCallOutComponent); diff --git a/x-pack/plugins/cases/public/components/user_actions/avatar.tsx b/x-pack/plugins/cases/public/components/user_actions/avatar.tsx index da43a122f38686..a8cfb7a3b2acf2 100644 --- a/x-pack/plugins/cases/public/components/user_actions/avatar.tsx +++ b/x-pack/plugins/cases/public/components/user_actions/avatar.tsx @@ -20,5 +20,6 @@ const UserActionAvatarComponent = ({ username, fullName, size = 'm' }: UserActio const avatarName = fullName && fullName.length > 0 ? fullName : username ?? i18n.UNKNOWN; return ; }; +UserActionAvatarComponent.displayName = 'UserActionAvatar'; export const UserActionAvatar = memo(UserActionAvatarComponent); diff --git a/x-pack/plugins/cases/public/components/user_actions/avatar_username.tsx b/x-pack/plugins/cases/public/components/user_actions/avatar_username.tsx index 581ebb7272d347..1a724838b52072 100644 --- a/x-pack/plugins/cases/public/components/user_actions/avatar_username.tsx +++ b/x-pack/plugins/cases/public/components/user_actions/avatar_username.tsx @@ -34,5 +34,6 @@ const UserActionUsernameWithAvatarComponent = ({ ); +UserActionUsernameWithAvatarComponent.displayName = 'UserActionUsernameWithAvatar'; export const UserActionUsernameWithAvatar = memo(UserActionUsernameWithAvatarComponent); diff --git a/x-pack/plugins/cases/public/components/user_actions/comment/alert_event.tsx b/x-pack/plugins/cases/public/components/user_actions/comment/alert_event.tsx index b4b4b3b75fe7e9..03e4c9b56d0c62 100644 --- a/x-pack/plugins/cases/public/components/user_actions/comment/alert_event.tsx +++ b/x-pack/plugins/cases/public/components/user_actions/comment/alert_event.tsx @@ -63,5 +63,6 @@ const AlertCommentEventComponent: React.FC = ({ ); }; +AlertCommentEventComponent.displayName = 'AlertCommentEvent'; export const AlertCommentEvent = memo(AlertCommentEventComponent); diff --git a/x-pack/plugins/cases/public/components/user_actions/comment/host_isolation_event.tsx b/x-pack/plugins/cases/public/components/user_actions/comment/host_isolation_event.tsx index 531323e548dd1c..e08c2f85e8c318 100644 --- a/x-pack/plugins/cases/public/components/user_actions/comment/host_isolation_event.tsx +++ b/x-pack/plugins/cases/public/components/user_actions/comment/host_isolation_event.tsx @@ -52,5 +52,6 @@ const HostIsolationCommentEventComponent: React.FC = ({ ); }; +HostIsolationCommentEventComponent.displayName = 'HostIsolationCommentEvent'; export const HostIsolationCommentEvent = memo(HostIsolationCommentEventComponent); diff --git a/x-pack/plugins/cases/public/components/user_actions/comment/show_alert.tsx b/x-pack/plugins/cases/public/components/user_actions/comment/show_alert.tsx index dd874b029dc9c3..5506cbd5d7d00c 100644 --- a/x-pack/plugins/cases/public/components/user_actions/comment/show_alert.tsx +++ b/x-pack/plugins/cases/public/components/user_actions/comment/show_alert.tsx @@ -38,5 +38,6 @@ const UserActionShowAlertComponent = ({ ); }; +UserActionShowAlertComponent.displayName = 'UserActionShowAlert'; export const UserActionShowAlert = memo(UserActionShowAlertComponent); diff --git a/x-pack/plugins/cases/public/components/user_actions/content_toolbar.tsx b/x-pack/plugins/cases/public/components/user_actions/content_toolbar.tsx index dee1a25c3b79c9..0a1f02b4aaebf0 100644 --- a/x-pack/plugins/cases/public/components/user_actions/content_toolbar.tsx +++ b/x-pack/plugins/cases/public/components/user_actions/content_toolbar.tsx @@ -50,5 +50,6 @@ const UserActionContentToolbarComponent = ({ ); +UserActionContentToolbarComponent.displayName = 'UserActionContentToolbar'; export const UserActionContentToolbar = memo(UserActionContentToolbarComponent); diff --git a/x-pack/plugins/cases/public/components/user_actions/copy_link.tsx b/x-pack/plugins/cases/public/components/user_actions/copy_link.tsx index 54c9b36c539628..3a74b2024db3e5 100644 --- a/x-pack/plugins/cases/public/components/user_actions/copy_link.tsx +++ b/x-pack/plugins/cases/public/components/user_actions/copy_link.tsx @@ -36,5 +36,6 @@ const UserActionCopyLinkComponent = ({ id: commentId }: UserActionCopyLinkProps) ); }; +UserActionCopyLinkComponent.displayName = 'UserActionCopyLink'; export const UserActionCopyLink = memo(UserActionCopyLinkComponent); diff --git a/x-pack/plugins/cases/public/components/user_actions/move_to_reference.tsx b/x-pack/plugins/cases/public/components/user_actions/move_to_reference.tsx index 42f6031ba1a6e9..34647d7ce6b999 100644 --- a/x-pack/plugins/cases/public/components/user_actions/move_to_reference.tsx +++ b/x-pack/plugins/cases/public/components/user_actions/move_to_reference.tsx @@ -34,5 +34,6 @@ const UserActionMoveToReferenceComponent = ({ ); }; +UserActionMoveToReferenceComponent.displayName = 'UserActionMoveToReference'; export const UserActionMoveToReference = memo(UserActionMoveToReferenceComponent); diff --git a/x-pack/plugins/cases/public/components/user_actions/property_actions.tsx b/x-pack/plugins/cases/public/components/user_actions/property_actions.tsx index 8f89c3b4208011..86e1ac0e1f4811 100644 --- a/x-pack/plugins/cases/public/components/user_actions/property_actions.tsx +++ b/x-pack/plugins/cases/public/components/user_actions/property_actions.tsx @@ -69,5 +69,6 @@ const UserActionPropertyActionsComponent = ({ ); }; +UserActionPropertyActionsComponent.displayName = 'UserActionPropertyActions'; export const UserActionPropertyActions = memo(UserActionPropertyActionsComponent); diff --git a/x-pack/plugins/cases/public/components/user_actions/timestamp.tsx b/x-pack/plugins/cases/public/components/user_actions/timestamp.tsx index 98e25fe265dbb4..a8c38657d1ee8f 100644 --- a/x-pack/plugins/cases/public/components/user_actions/timestamp.tsx +++ b/x-pack/plugins/cases/public/components/user_actions/timestamp.tsx @@ -41,5 +41,6 @@ const UserActionTimestampComponent = ({ createdAt, updatedAt }: UserActionAvatar )} ); +UserActionTimestampComponent.displayName = 'UserActionTimestamp'; export const UserActionTimestamp = memo(UserActionTimestampComponent); diff --git a/x-pack/plugins/cases/public/components/user_actions/username.tsx b/x-pack/plugins/cases/public/components/user_actions/username.tsx index 78309eb56d6207..52604d1374951a 100644 --- a/x-pack/plugins/cases/public/components/user_actions/username.tsx +++ b/x-pack/plugins/cases/public/components/user_actions/username.tsx @@ -28,5 +28,6 @@ const UserActionUsernameComponent = ({ username, fullName }: UserActionUsernameP ); }; +UserActionUsernameComponent.displayName = 'UserActionUsername'; export const UserActionUsername = memo(UserActionUsernameComponent); From 022a9efa5e8d63fdec62118efe284d7af4540ed3 Mon Sep 17 00:00:00 2001 From: Dzmitry Lemechko Date: Thu, 20 Jan 2022 20:28:09 +0100 Subject: [PATCH 092/108] Save github PR list in csv (#123276) * save PR list for release testing in csv * use paginate to simplify code * fix * Update src/dev/github/get_prs_cli.ts Co-authored-by: Spencer * review fix * update example with OR logic * fix optional flags check Co-authored-by: Spencer Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- scripts/download_pr_list.js | 10 +++ src/dev/github/download_pr_list_cli.ts | 79 ++++++++++++++++++++++ src/dev/github/example.json | 12 ++++ src/dev/github/search_and_save_pr_list.ts | 82 +++++++++++++++++++++++ 4 files changed, 183 insertions(+) create mode 100644 scripts/download_pr_list.js create mode 100644 src/dev/github/download_pr_list_cli.ts create mode 100644 src/dev/github/example.json create mode 100644 src/dev/github/search_and_save_pr_list.ts diff --git a/scripts/download_pr_list.js b/scripts/download_pr_list.js new file mode 100644 index 00000000000000..d0ee65d95d2d3d --- /dev/null +++ b/scripts/download_pr_list.js @@ -0,0 +1,10 @@ +/* + * 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. + */ + +require('../src/setup_node_env'); +require('../src/dev/github/download_pr_list_cli').downloadPullRequests(); diff --git a/src/dev/github/download_pr_list_cli.ts b/src/dev/github/download_pr_list_cli.ts new file mode 100644 index 00000000000000..fed7bc8b4f086b --- /dev/null +++ b/src/dev/github/download_pr_list_cli.ts @@ -0,0 +1,79 @@ +/* + * 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. + */ + +import { run, createFlagError, Flags } from '@kbn/dev-utils'; +import fs from 'fs'; +import Path from 'path'; +import { savePrsToCsv } from './search_and_save_pr_list'; + +function getLabelsPath(flags: Flags) { + if (typeof flags.path !== 'string') { + throw createFlagError('please provide a single --path flag'); + } + + if (!fs.existsSync(Path.resolve(flags.path))) { + throw createFlagError('please provide an existing json file with --path flag'); + } + + return Path.resolve(flags.path); +} + +export async function downloadPullRequests() { + run( + async ({ log, flags }) => { + const githubToken = process.env.GITHUB_TOKEN; + + if (!githubToken) { + throw new Error('GITHUB_TOKEN was not provided.'); + } + + const labelsPath = getLabelsPath(flags); + + if (typeof flags.dest !== 'string') { + throw createFlagError('please provide csv path in --dest flag'); + } + + const query = flags.query || undefined; + if (query !== undefined && typeof query !== 'string') { + throw createFlagError('please provide valid string in --query flag'); + } + + const mergedSince = flags['merged-since'] || undefined; + if ( + mergedSince !== undefined && + (typeof mergedSince !== 'string' || !/\d{4}-\d{2}-\d{2}/.test(mergedSince)) + ) { + throw createFlagError( + `please provide a past date in 'yyyy-mm-dd' format in --merged-since flag` + ); + } + + fs.mkdirSync(flags.dest, { recursive: true }); + const filename = Path.resolve( + flags.dest, + `kibana_prs_${new Date().toISOString().split('T').join('-')}.csv` + ); + await savePrsToCsv(log, githubToken, labelsPath, filename, query, mergedSince); + }, + { + description: ` + Create a csv file with PRs to be tests for upcoming release, + require GITHUB_TOKEN variable to be set in advance + `, + flags: { + string: ['path', 'dest', 'query', 'merged-since'], + help: ` + --path Required, path to json file with labels to operate on, see src/dev/example.json + --dest Required, generated csv file location + --query Optional, overrides default query + --merged-since Optional, start date in 'yyyy-mm-dd' format + `, + }, + } + ); +} diff --git a/src/dev/github/example.json b/src/dev/github/example.json new file mode 100644 index 00000000000000..34a74eefb37853 --- /dev/null +++ b/src/dev/github/example.json @@ -0,0 +1,12 @@ +{ + "include": [ + "v8.0.0", + "\"Team:ResponseOps\",\"Feature:Canvas\"" + ], + "exclude": [ + "failed-test", + "Feature:Unit Testing", + "Feature:Functional Testing", + "release_note:skip" + ] +} \ No newline at end of file diff --git a/src/dev/github/search_and_save_pr_list.ts b/src/dev/github/search_and_save_pr_list.ts new file mode 100644 index 00000000000000..1c6dbc6c99746d --- /dev/null +++ b/src/dev/github/search_and_save_pr_list.ts @@ -0,0 +1,82 @@ +/* + * 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. + */ + +import { ToolingLog } from '@kbn/dev-utils'; +import { Octokit } from '@octokit/rest'; +import fs from 'fs'; + +interface Labels { + include: string[]; + exclude: string[]; +} + +interface PR { + title: string; + url: string; + releaseLabel: string; +} + +export async function savePrsToCsv( + log: ToolingLog, + githubToken: string, + labelsPath: string, + filename: string, + query: string | undefined, + mergedSince: string | undefined +) { + const repo = `repo:"elastic/kibana"`; + const defaultQuery = 'is:pull-request+is:merged+sort:updated-desc'; + const perPage = 100; + const searchApiLimit = 1000; + + let q = repo + '+' + (query ?? defaultQuery) + (mergedSince ? `+merged:>=${mergedSince}` : ''); + + const rawData = fs.readFileSync(labelsPath, 'utf8'); + const labels = JSON.parse(rawData) as Labels; + + labels.include.map((label) => (q += `+label:${label}`)); + labels.exclude.map((label) => (q += ` -label:"${label}"`)); + + log.debug(`Github query: ${q}`); + + const octokit = new Octokit({ + auth: githubToken, + }); + const items: PR[] = await octokit.paginate( + 'GET /search/issues', + { q, per_page: perPage }, + (response) => + response.data.map((item: Octokit.SearchIssuesAndPullRequestsResponseItemsItem) => { + return { + title: item.title, + url: item.html_url, + releaseLabel: item.labels + .filter((label) => label.name.trim().startsWith('release_note')) + .map((label) => label.name) + .join(','), + } as PR; + }) + ); + + // https://docs.github.com/en/rest/reference/search + if (items.length >= searchApiLimit) { + log.warning( + `Search API limit is 1000 results per search, try to adjust the query. Saving first 1000 PRs` + ); + } else { + log.info(`Found ${items.length} PRs`); + } + + let csv = ''; + for (const i of items) { + csv += `${i.title}\t${i.url}\t${i.releaseLabel}\r\n`; + } + + fs.writeFileSync(filename, csv); + log.info(`Saved to ${filename}`); +} From 6ae646722b2f93044477264a927b27705967a4ab Mon Sep 17 00:00:00 2001 From: Michael Dokolin Date: Thu, 20 Jan 2022 20:46:52 +0100 Subject: [PATCH 093/108] [Expressions] Add support of comments (#122457) * Add comments support to the expressions grammar * Add typings to the interpreter parser * Add expressions comments highlighting * Update canvas to preserve original expression formatting * Update documentation to cover comments --- .../canvas-expression-lifecycle.asciidoc | 2 + docs/developer/plugin-list.asciidoc | 3 + .../kbn-interpreter/grammar/grammar.peggy | 22 ++- packages/kbn-interpreter/src/common/index.ts | 22 ++- .../kbn-interpreter/src/common/lib/ast.ts | 159 ------------------ .../kbn-interpreter/src/common/lib/ast/ast.ts | 64 +++++++ .../src/common/lib/ast/compare.ts | 85 ++++++++++ .../from_expression.test.js} | 4 +- .../src/common/lib/ast/from_expression.ts | 18 ++ .../src/common/lib/ast/index.ts | 12 ++ .../src/common/lib/ast/patch.ts | 47 ++++++ .../lib/ast/safe_element_from_expression.ts | 26 +++ .../to_expression.test.js} | 109 +++++++++++- .../src/common/lib/ast/to_expression.ts | 145 ++++++++++++++++ .../src/common/lib/grammar.d.ts | 11 ++ .../kbn-interpreter/src/common/lib/parse.ts | 27 +++ src/plugins/expressions/README.asciidoc | 6 +- src/plugins/expressions/common/ast/types.ts | 8 +- .../expression_input/autocomplete.ts | 76 ++------- .../components/expression_input/language.ts | 9 + .../hooks/use_canvas_filters.ts | 4 +- x-pack/plugins/canvas/public/lib/filter.ts | 8 +- .../canvas/public/lib/filter_adapters.test.ts | 4 +- .../canvas/public/lib/filter_adapters.ts | 6 +- .../server/collectors/collector_helpers.ts | 16 +- .../saved_objects/workpad_references.ts | 7 +- .../editor_frame/expression_helpers.ts | 4 +- .../definitions/calculations/utils.ts | 6 +- .../migrations/saved_object_migrations.ts | 6 +- 29 files changed, 644 insertions(+), 272 deletions(-) delete mode 100644 packages/kbn-interpreter/src/common/lib/ast.ts create mode 100644 packages/kbn-interpreter/src/common/lib/ast/ast.ts create mode 100644 packages/kbn-interpreter/src/common/lib/ast/compare.ts rename packages/kbn-interpreter/src/common/lib/{ast.from_expression.test.js => ast/from_expression.test.js} (98%) create mode 100644 packages/kbn-interpreter/src/common/lib/ast/from_expression.ts create mode 100644 packages/kbn-interpreter/src/common/lib/ast/index.ts create mode 100644 packages/kbn-interpreter/src/common/lib/ast/patch.ts create mode 100644 packages/kbn-interpreter/src/common/lib/ast/safe_element_from_expression.ts rename packages/kbn-interpreter/src/common/lib/{ast.to_expression.test.js => ast/to_expression.test.js} (84%) create mode 100644 packages/kbn-interpreter/src/common/lib/ast/to_expression.ts create mode 100644 packages/kbn-interpreter/src/common/lib/grammar.d.ts create mode 100644 packages/kbn-interpreter/src/common/lib/parse.ts diff --git a/docs/canvas/canvas-expression-lifecycle.asciidoc b/docs/canvas/canvas-expression-lifecycle.asciidoc index 17903408dff0e7..a20181c4b38086 100644 --- a/docs/canvas/canvas-expression-lifecycle.asciidoc +++ b/docs/canvas/canvas-expression-lifecycle.asciidoc @@ -14,6 +14,7 @@ To use demo dataset available in Canvas to produce a table, run the following ex [source,text] ---- +/* Simple demo table */ filters | demodata | table @@ -24,6 +25,7 @@ This expression starts out with the <> function, which prov The filtered <> becomes the _context_ of the next function, <>, which creates a table visualization from this data set. The <> function isn’t strictly required, but by being explicit, you have the option of providing arguments to control things like the font used in the table. The output of the <> function becomes the _context_ of the <> function. Like the <>, the <> function isn’t required either, but it allows access to other arguments, such as styling the border of the element or injecting custom CSS. +It is possible to add comments to the expression by starting them with a `//` sequence or by using `/*` and `*/` to enclose multi-line comments. [[canvas-function-arguments]] === Function arguments diff --git a/docs/developer/plugin-list.asciidoc b/docs/developer/plugin-list.asciidoc index 5a6773156bfbac..fa7613049f9d6c 100644 --- a/docs/developer/plugin-list.asciidoc +++ b/docs/developer/plugin-list.asciidoc @@ -140,6 +140,9 @@ All the arguments to expression functions need to be serializable, as well as in Expression functions should try to stay 'pure'. This makes functions easy to reuse and also make it possible to serialize the whole chain as well as output at every step of execution. +It is possible to add comments to expressions by starting them with a `//` sequence +or by using `/*` and `*/` to enclose multi-line comments. + Expressions power visualizations in Dashboard and Lens, as well as, every *element* in Canvas is backed by an expression. diff --git a/packages/kbn-interpreter/grammar/grammar.peggy b/packages/kbn-interpreter/grammar/grammar.peggy index e8a2988d2b4f67..e67e310c9f4d12 100644 --- a/packages/kbn-interpreter/grammar/grammar.peggy +++ b/packages/kbn-interpreter/grammar/grammar.peggy @@ -23,7 +23,7 @@ start = expression expression - = space? first:function? rest:('|' space? fn:function { return fn; })* { + = blank? first:function? rest:('|' blank? fn:function { return fn; })* { return addMeta({ type: 'expression', chain: first ? [first].concat(rest) : [] @@ -44,7 +44,7 @@ function "function" /* ----- Arguments ----- */ argument_assignment - = name:identifier space? '=' space? value:argument { + = name:identifier blank? '=' blank? value:argument { return { name, value }; } / value:argument { @@ -58,7 +58,7 @@ argument } arg_list - = args:(space arg:argument_assignment { return arg; })* space? { + = args:(blank arg:argument_assignment { return arg; })* blank? { return args.reduce((accumulator, { name, value }) => ({ ...accumulator, [name]: (accumulator[name] || []).concat(value) @@ -82,7 +82,7 @@ phrase unquoted_string_or_number // Make sure we're not matching the beginning of a search - = string:unquoted+ { // this also matches nulls, booleans, and numbers + = !comment string:unquoted+ { // this also matches nulls, booleans, and numbers var result = string.join(''); // Sort of hacky, but PEG doesn't have backtracking so // a null/boolean/number rule is hard to read, and performs worse @@ -93,8 +93,20 @@ unquoted_string_or_number return Number(result); } +blank + = (space / comment)+ + space - = [\ \t\r\n]+ + = [\ \t\r\n] + +comment + = inline_comment / multiline_comment + +inline_comment + = "//" [^\n]* + +multiline_comment + = "/*" (!"*/" .)* "*/"? unquoted = "\\" sequence:([\"'(){}<>\[\]$`|=\ \t\n\r] / "\\") { return sequence; } diff --git a/packages/kbn-interpreter/src/common/index.ts b/packages/kbn-interpreter/src/common/index.ts index 982de97cf881bf..52753286d72214 100644 --- a/packages/kbn-interpreter/src/common/index.ts +++ b/packages/kbn-interpreter/src/common/index.ts @@ -6,14 +6,26 @@ * Side Public License, v 1. */ -export type { Ast, ExpressionFunctionAST } from './lib/ast'; -export { fromExpression, toExpression, safeElementFromExpression } from './lib/ast'; +export type { + Ast, + AstArgument, + AstFunction, + AstNode, + AstWithMeta, + AstArgumentWithMeta, + AstFunctionWithMeta, +} from './lib/ast'; +export { + fromExpression, + isAst, + isAstWithMeta, + toExpression, + safeElementFromExpression, +} from './lib/ast'; export { Fn } from './lib/fn'; export { getType } from './lib/get_type'; export { castProvider } from './lib/cast'; -// @ts-expect-error -// @internal -export { parse } from '../../grammar'; +export { parse } from './lib/parse'; export { getByAlias } from './lib/get_by_alias'; export { Registry } from './lib/registry'; export { addRegistries, register, registryFactory } from './registries'; diff --git a/packages/kbn-interpreter/src/common/lib/ast.ts b/packages/kbn-interpreter/src/common/lib/ast.ts deleted file mode 100644 index 791c94809f35c4..00000000000000 --- a/packages/kbn-interpreter/src/common/lib/ast.ts +++ /dev/null @@ -1,159 +0,0 @@ -/* - * 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. - */ - -import { getType } from './get_type'; -// @ts-expect-error -import { parse } from '../../../grammar'; - -export type ExpressionArgAST = string | boolean | number | Ast; - -export interface ExpressionFunctionAST { - type: 'function'; - function: string; - arguments: { - [key: string]: ExpressionArgAST[]; - }; -} - -export interface Ast { - /** @internal */ - function: any; - /** @internal */ - arguments: any; - type: 'expression'; - chain: ExpressionFunctionAST[]; - /** @internal */ - replace(regExp: RegExp, s: string): string; -} - -function getArgumentString(arg: Ast, argKey: string | undefined, level = 0) { - const type = getType(arg); - - // eslint-disable-next-line @typescript-eslint/no-shadow - function maybeArgKey(argKey: string | null | undefined, argString: string) { - return argKey == null || argKey === '_' ? argString : `${argKey}=${argString}`; - } - - if (type === 'string') { - // correctly (re)escape double quotes - const escapedArg = arg.replace(/[\\"]/g, '\\$&'); // $& means the whole matched string - return maybeArgKey(argKey, `"${escapedArg}"`); - } - - if (type === 'boolean' || type === 'null' || type === 'number') { - // use values directly - return maybeArgKey(argKey, `${arg}`); - } - - if (type === 'expression') { - // build subexpressions - return maybeArgKey(argKey, `{${getExpression(arg.chain, level + 1)}}`); - } - - // unknown type, throw with type value - throw new Error(`Invalid argument type in AST: ${type}`); -} - -function getExpressionArgs(block: Ast, level = 0) { - const args = block.arguments; - const hasValidArgs = typeof args === 'object' && args != null && !Array.isArray(args); - - if (!hasValidArgs) throw new Error('Arguments can only be an object'); - - const argKeys = Object.keys(args); - const MAX_LINE_LENGTH = 80; // length before wrapping arguments - return argKeys.map((argKey) => - args[argKey].reduce((acc: any, arg: any) => { - const argString = getArgumentString(arg, argKey, level); - const lineLength = acc.split('\n').pop().length; - - // if arg values are too long, move it to the next line - if (level === 0 && lineLength + argString.length > MAX_LINE_LENGTH) { - return `${acc}\n ${argString}`; - } - - // append arg values to existing arg values - if (lineLength > 0) return `${acc} ${argString}`; - - // start the accumulator with the first arg value - return argString; - }, '') - ); -} - -function fnWithArgs(fnName: any, args: any[]) { - if (!args || args.length === 0) return fnName; - return `${fnName} ${args.join(' ')}`; -} - -function getExpression(chain: any[], level = 0) { - if (!chain) throw new Error('Expressions must contain a chain'); - - // break new functions onto new lines if we're not in a nested/sub-expression - const separator = level > 0 ? ' | ' : '\n| '; - - return chain - .map((chainObj) => { - const type = getType(chainObj); - - if (type === 'function') { - const fn = chainObj.function; - if (!fn || fn.length === 0) throw new Error('Functions must have a function name'); - - const expArgs = getExpressionArgs(chainObj, level); - - return fnWithArgs(fn, expArgs); - } - }, []) - .join(separator); -} - -export function fromExpression(expression: string, type = 'expression'): Ast { - try { - return parse(String(expression), { startRule: type }); - } catch (e) { - throw new Error(`Unable to parse expression: ${e.message}`); - } -} - -// TODO: OMG This is so bad, we need to talk about the right way to handle bad expressions since some are element based and others not -export function safeElementFromExpression(expression: string) { - try { - return fromExpression(expression); - } catch (e) { - return fromExpression( - `markdown -"## Crud. -Canvas could not parse this element's expression. I am so sorry this error isn't more useful. I promise it will be soon. - -Thanks for understanding, -#### Management -"` - ); - } -} - -// TODO: Respect the user's existing formatting -export function toExpression(astObj: Ast, type = 'expression'): string { - if (type === 'argument') { - // @ts-ignore - return getArgumentString(astObj); - } - - const validType = ['expression', 'function'].includes(getType(astObj)); - if (!validType) throw new Error('Expression must be an expression or argument function'); - - if (getType(astObj) === 'expression') { - if (!Array.isArray(astObj.chain)) throw new Error('Expressions must contain a chain'); - - return getExpression(astObj.chain); - } - - const expArgs = getExpressionArgs(astObj); - return fnWithArgs(astObj.function, expArgs); -} diff --git a/packages/kbn-interpreter/src/common/lib/ast/ast.ts b/packages/kbn-interpreter/src/common/lib/ast/ast.ts new file mode 100644 index 00000000000000..f0ea42cc039e4e --- /dev/null +++ b/packages/kbn-interpreter/src/common/lib/ast/ast.ts @@ -0,0 +1,64 @@ +/* + * 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. + */ + +export type AstNode = Ast | AstFunction | AstArgument; + +// eslint-disable-next-line @typescript-eslint/consistent-type-definitions +export type Ast = { + type: 'expression'; + chain: AstFunction[]; +}; + +// eslint-disable-next-line @typescript-eslint/consistent-type-definitions +export type AstFunction = { + type: 'function'; + function: string; + arguments: Record; +}; + +export type AstArgument = string | boolean | number | Ast; + +interface WithMeta { + start: number; + end: number; + text: string; + node: T; +} + +type Replace = Pick> & R; + +type WrapAstArgumentWithMeta = T extends Ast ? AstWithMeta : WithMeta; +export type AstArgumentWithMeta = WrapAstArgumentWithMeta; + +export type AstFunctionWithMeta = WithMeta< + Replace< + AstFunction, + { + arguments: { + [key: string]: AstArgumentWithMeta[]; + }; + } + > +>; + +export type AstWithMeta = WithMeta< + Replace< + Ast, + { + chain: AstFunctionWithMeta[]; + } + > +>; + +export function isAstWithMeta(value: any): value is AstWithMeta { + return typeof value?.node === 'object'; +} + +export function isAst(value: any): value is Ast { + return typeof value === 'object' && value?.type === 'expression'; +} diff --git a/packages/kbn-interpreter/src/common/lib/ast/compare.ts b/packages/kbn-interpreter/src/common/lib/ast/compare.ts new file mode 100644 index 00000000000000..e9a9772dba2274 --- /dev/null +++ b/packages/kbn-interpreter/src/common/lib/ast/compare.ts @@ -0,0 +1,85 @@ +/* + * 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. + */ + +import { forEach, xor, zip } from 'lodash'; +import { parse } from '../parse'; +import type { + Ast, + AstArgument, + AstArgumentWithMeta, + AstWithMeta, + AstFunction, + AstFunctionWithMeta, +} from './ast'; +import { isAst, isAstWithMeta } from './ast'; + +export interface ValueChange { + type: 'value'; + source: AstArgumentWithMeta; + target: AstArgument; +} + +export type Change = ValueChange; + +export function isValueChange(value: any): value is ValueChange { + return value?.type === 'value'; +} + +export function compare(expression: string, ast: Ast): Change[] { + const astWithMeta = parse(expression, { addMeta: true }); + const queue = [[astWithMeta, ast]] as Array<[typeof astWithMeta, typeof ast]>; + const changes = [] as Change[]; + + function compareExpression(source: AstWithMeta, target: Ast) { + zip(source.node.chain, target.chain).forEach(([fnWithMeta, fn]) => { + if (!fnWithMeta || !fn || fnWithMeta?.node.function !== fn?.function) { + throw Error('Expression changes are not supported.'); + } + + compareFunction(fnWithMeta, fn); + }); + } + + function compareFunction(source: AstFunctionWithMeta, target: AstFunction) { + if (xor(Object.keys(source.node.arguments), Object.keys(target.arguments)).length) { + throw Error('Function changes are not supported.'); + } + + forEach(source.node.arguments, (valuesWithMeta, argument) => { + const values = target.arguments[argument]; + + compareArgument(valuesWithMeta, values); + }); + } + + function compareArgument(source: AstArgumentWithMeta[], target: AstArgument[]) { + if (source.length !== target.length) { + throw Error('Arguments changes are not supported.'); + } + + zip(source, target).forEach(([valueWithMeta, value]) => compareValue(valueWithMeta!, value!)); + } + + function compareValue(source: AstArgumentWithMeta, target: AstArgument) { + if (isAstWithMeta(source) && isAst(target)) { + compareExpression(source, target); + + return; + } + + if (source.node !== target) { + changes.push({ type: 'value', source, target }); + } + } + + while (queue.length) { + compareExpression(...queue.shift()!); + } + + return changes; +} diff --git a/packages/kbn-interpreter/src/common/lib/ast.from_expression.test.js b/packages/kbn-interpreter/src/common/lib/ast/from_expression.test.js similarity index 98% rename from packages/kbn-interpreter/src/common/lib/ast.from_expression.test.js rename to packages/kbn-interpreter/src/common/lib/ast/from_expression.test.js index 11a25f6250cd6b..24a652e29bb091 100644 --- a/packages/kbn-interpreter/src/common/lib/ast.from_expression.test.js +++ b/packages/kbn-interpreter/src/common/lib/ast/from_expression.test.js @@ -7,9 +7,9 @@ */ import { fromExpression } from '@kbn/interpreter'; -import { getType } from './get_type'; +import { getType } from '../get_type'; -describe('ast fromExpression', () => { +describe('fromExpression', () => { describe('invalid expression', () => { it('throws with invalid expression', () => { const check = () => fromExpression('wat!'); diff --git a/packages/kbn-interpreter/src/common/lib/ast/from_expression.ts b/packages/kbn-interpreter/src/common/lib/ast/from_expression.ts new file mode 100644 index 00000000000000..859afd994f7449 --- /dev/null +++ b/packages/kbn-interpreter/src/common/lib/ast/from_expression.ts @@ -0,0 +1,18 @@ +/* + * 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. + */ + +import type { Ast } from './ast'; +import { parse } from '../parse'; + +export function fromExpression(expression: string, type = 'expression'): Ast { + try { + return parse(String(expression), { startRule: type }); + } catch (e) { + throw new Error(`Unable to parse expression: ${e.message}`); + } +} diff --git a/packages/kbn-interpreter/src/common/lib/ast/index.ts b/packages/kbn-interpreter/src/common/lib/ast/index.ts new file mode 100644 index 00000000000000..0889a21af21a80 --- /dev/null +++ b/packages/kbn-interpreter/src/common/lib/ast/index.ts @@ -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 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. + */ + +export * from './ast'; +export * from './from_expression'; +export * from './safe_element_from_expression'; +export * from './to_expression'; diff --git a/packages/kbn-interpreter/src/common/lib/ast/patch.ts b/packages/kbn-interpreter/src/common/lib/ast/patch.ts new file mode 100644 index 00000000000000..1dc6ef2cff6ad8 --- /dev/null +++ b/packages/kbn-interpreter/src/common/lib/ast/patch.ts @@ -0,0 +1,47 @@ +/* + * 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. + */ + +import type { Ast } from './ast'; +import { isAstWithMeta } from './ast'; +import type { Change, ValueChange } from './compare'; +import { compare, isValueChange } from './compare'; +import { toExpression } from './to_expression'; + +export function patch(expression: string, ast: Ast): string { + let result = ''; + let position = 0; + + function apply(change: Change) { + if (isValueChange(change)) { + return void patchValue(change); + } + + throw new Error('Cannot apply patch for the change.'); + } + + function patchValue(change: ValueChange) { + if (isAstWithMeta(change.source)) { + throw new Error('Patching sub-expressions is not supported.'); + } + + result += `${expression.substring(position, change.source.start)}${toExpression( + change.target, + 'argument' + )}`; + + position = change.source.end; + } + + compare(expression, ast) + .sort(({ source: source1 }, { source: source2 }) => source1.start - source2.start) + .forEach(apply); + + result += expression.substring(position); + + return result; +} diff --git a/packages/kbn-interpreter/src/common/lib/ast/safe_element_from_expression.ts b/packages/kbn-interpreter/src/common/lib/ast/safe_element_from_expression.ts new file mode 100644 index 00000000000000..3685847989c8f5 --- /dev/null +++ b/packages/kbn-interpreter/src/common/lib/ast/safe_element_from_expression.ts @@ -0,0 +1,26 @@ +/* + * 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. + */ + +import { fromExpression } from './from_expression'; + +// TODO: OMG This is so bad, we need to talk about the right way to handle bad expressions since some are element based and others not +export function safeElementFromExpression(expression: string) { + try { + return fromExpression(expression); + } catch (e) { + return fromExpression( + `markdown +"## Crud. +Canvas could not parse this element's expression. I am so sorry this error isn't more useful. I promise it will be soon. + +Thanks for understanding, +#### Management +"` + ); + } +} diff --git a/packages/kbn-interpreter/src/common/lib/ast.to_expression.test.js b/packages/kbn-interpreter/src/common/lib/ast/to_expression.test.js similarity index 84% rename from packages/kbn-interpreter/src/common/lib/ast.to_expression.test.js rename to packages/kbn-interpreter/src/common/lib/ast/to_expression.test.js index 14b75ab557f010..18e6b8fe88cf16 100644 --- a/packages/kbn-interpreter/src/common/lib/ast.to_expression.test.js +++ b/packages/kbn-interpreter/src/common/lib/ast/to_expression.test.js @@ -7,8 +7,9 @@ */ import { toExpression } from '@kbn/interpreter'; +import { cloneDeep, set, unset } from 'lodash'; -describe('ast toExpression', () => { +describe('toExpression', () => { describe('single expression', () => { it('throws if no type included', () => { const errMsg = 'Objects must have a type property'; @@ -616,4 +617,110 @@ describe('ast toExpression', () => { expect(expression).toBe('both named="example" another="item" "one" "two" "three"'); }); }); + + describe('patch expression', () => { + const expression = 'f1 a=1 a=2 b=1 b={f2 c=1 c=2 | f3 d=1 d=2} | f4 e=1 e=2'; + const ast = { + type: 'expression', + chain: [ + { + type: 'function', + function: 'f1', + arguments: { + a: [1, 2], + b: [ + 1, + { + type: 'expression', + chain: [ + { + type: 'function', + function: 'f2', + arguments: { c: ['a', 'b'] }, + }, + { + type: 'function', + function: 'f3', + arguments: { d: [1, 2] }, + }, + ], + }, + ], + }, + }, + { + type: 'function', + function: 'f4', + arguments: { + e: [1, 2], + }, + }, + ], + }; + + it.each([ + [ + expression, + 'f1 a="updated" a=2 b=1 b={f2 c="a" c="b" | f3 d=1 d=2} | f4 e=1 e=2', + set(cloneDeep(ast), 'chain.0.arguments.a.0', 'updated'), + ], + [ + expression, + 'f1 a=1 a=2 b=1 b={f2 c="updated" c="b" | f3 d=1 d=2} | f4 e=1 e=2', + set(cloneDeep(ast), 'chain.0.arguments.b.1.chain.0.arguments.c.0', 'updated'), + ], + [ + expression, + 'f1 a={updated} a=2 b=1 b={f2 c="a" c="b" | f3 d=1 d=2} | f4 e=1 e=2', + set(cloneDeep(ast), 'chain.0.arguments.a.0', { + type: 'expression', + chain: [ + { + type: 'function', + function: 'updated', + arguments: {}, + }, + ], + }), + ], + [ + '/* comment */ f1 a /* comment */ =1', + '/* comment */ f1 a /* comment */ =2', + { + type: 'expression', + chain: [ + { + type: 'function', + function: 'f1', + arguments: { + a: [2], + }, + }, + ], + }, + ], + ])('should patch "%s" to become "%s"', (source, expected, ast) => { + expect(toExpression(ast, { source })).toBe(expected); + }); + + it.each([ + [ + expression, + set(cloneDeep(ast), 'chain.2', { + type: 'function', + function: 'f5', + arguments: {}, + }), + ], + [expression, unset(cloneDeep(ast), 'chain.1')], + [expression, set(cloneDeep(ast), 'chain.0.function', 'updated')], + [expression, set(cloneDeep(ast), 'chain.0.arguments.c', [1])], + [expression, unset(cloneDeep(ast), 'chain.0.arguments.b')], + [expression, unset(cloneDeep(ast), 'chain.0.arguments.b.1')], + [expression, set(cloneDeep(ast), 'chain.0.arguments.b.2', 3)], + [expression, set(cloneDeep(ast), 'chain.0.arguments.b.1', 2)], + ])('should fail on patching expression', (source, ast) => { + expect(() => toExpression(ast, { source })).toThrowError(); + }); + }); }); diff --git a/packages/kbn-interpreter/src/common/lib/ast/to_expression.ts b/packages/kbn-interpreter/src/common/lib/ast/to_expression.ts new file mode 100644 index 00000000000000..fb656470ff8eea --- /dev/null +++ b/packages/kbn-interpreter/src/common/lib/ast/to_expression.ts @@ -0,0 +1,145 @@ +/* + * 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. + */ + +import { getType } from '../get_type'; +import type { Ast, AstArgument, AstFunction, AstNode } from './ast'; +import { isAst } from './ast'; +import { patch } from './patch'; + +interface Options { + /** + * Node type. + */ + type?: 'argument' | 'expression' | 'function'; + + /** + * Original expression to apply the new AST to. + * At the moment, only arguments values changes are supported. + */ + source?: string; +} + +function getArgumentString(arg: AstArgument, argKey?: string, level = 0): string { + const type = getType(arg); + + // eslint-disable-next-line @typescript-eslint/no-shadow + function maybeArgKey(argKey: string | null | undefined, argString: string) { + return argKey == null || argKey === '_' ? argString : `${argKey}=${argString}`; + } + + if (type === 'string') { + // correctly (re)escape double quotes + const escapedArg = (arg as string).replace(/[\\"]/g, '\\$&'); // $& means the whole matched string + return maybeArgKey(argKey, `"${escapedArg}"`); + } + + if (type === 'boolean' || type === 'null' || type === 'number') { + // use values directly + return maybeArgKey(argKey, `${arg}`); + } + + if (type === 'expression') { + // build subexpressions + return maybeArgKey(argKey, `{${getExpression((arg as Ast).chain, level + 1)}}`); + } + + // unknown type, throw with type value + throw new Error(`Invalid argument type in AST: ${type}`); +} + +function getExpressionArgs({ arguments: args }: AstFunction, level = 0) { + if (args == null || typeof args !== 'object' || Array.isArray(args)) { + throw new Error('Arguments can only be an object'); + } + + const argKeys = Object.keys(args); + const MAX_LINE_LENGTH = 80; // length before wrapping arguments + return argKeys.map((argKey) => + args[argKey].reduce((acc: string, arg) => { + const argString = getArgumentString(arg, argKey, level); + const lineLength = acc.split('\n').pop()!.length; + + // if arg values are too long, move it to the next line + if (level === 0 && lineLength + argString.length > MAX_LINE_LENGTH) { + return `${acc}\n ${argString}`; + } + + // append arg values to existing arg values + if (lineLength > 0) { + return `${acc} ${argString}`; + } + + // start the accumulator with the first arg value + return argString; + }, '') + ); +} + +function fnWithArgs(fnName: string, args: unknown[]) { + return `${fnName} ${args?.join(' ') ?? ''}`.trim(); +} + +function getExpression(chain: AstFunction[], level = 0) { + if (!chain) { + throw new Error('Expressions must contain a chain'); + } + + // break new functions onto new lines if we're not in a nested/sub-expression + const separator = level > 0 ? ' | ' : '\n| '; + + return chain + .map((item) => { + const type = getType(item); + + if (type !== 'function') { + return; + } + + const { function: fn } = item; + if (!fn) { + throw new Error('Functions must have a function name'); + } + + const expressionArgs = getExpressionArgs(item, level); + + return fnWithArgs(fn, expressionArgs); + }) + .join(separator); +} + +export function toExpression(ast: AstNode, options: string | Options = 'expression'): string { + const { type, source } = typeof options === 'string' ? ({ type: options } as Options) : options; + + if (source && isAst(ast)) { + return patch(source, ast); + } + + if (type === 'argument') { + return getArgumentString(ast as AstArgument); + } + + const nodeType = getType(ast); + + if (nodeType === 'expression') { + const { chain } = ast as Ast; + if (!Array.isArray(chain)) { + throw new Error('Expressions must contain a chain'); + } + + return getExpression(chain); + } + + if (nodeType === 'function') { + const { function: fn } = ast as AstFunction; + const args = getExpressionArgs(ast as AstFunction); + + return fnWithArgs(fn, args); + } + + throw new Error('Expression must be an expression or argument function'); +} diff --git a/packages/kbn-interpreter/src/common/lib/grammar.d.ts b/packages/kbn-interpreter/src/common/lib/grammar.d.ts new file mode 100644 index 00000000000000..e1dde5d1907e90 --- /dev/null +++ b/packages/kbn-interpreter/src/common/lib/grammar.d.ts @@ -0,0 +1,11 @@ +/* + * 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 '*/grammar' { + export const parse: import('./parse').Parse; +} diff --git a/packages/kbn-interpreter/src/common/lib/parse.ts b/packages/kbn-interpreter/src/common/lib/parse.ts new file mode 100644 index 00000000000000..7570eec40c03f5 --- /dev/null +++ b/packages/kbn-interpreter/src/common/lib/parse.ts @@ -0,0 +1,27 @@ +/* + * 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. + */ + +import type { Ast, AstWithMeta } from './ast'; +import { parse } from '../../../grammar'; + +interface Options { + startRule?: string; +} + +interface OptionsWithMeta extends Options { + addMeta: true; +} + +export interface Parse { + (input: string, options?: Options): Ast; + (input: string, options: OptionsWithMeta): AstWithMeta; +} + +const typedParse = parse; + +export { typedParse as parse }; diff --git a/src/plugins/expressions/README.asciidoc b/src/plugins/expressions/README.asciidoc index a1462fd635d92f..569c06c7e61bbb 100644 --- a/src/plugins/expressions/README.asciidoc +++ b/src/plugins/expressions/README.asciidoc @@ -10,6 +10,9 @@ All the arguments to expression functions need to be serializable, as well as in Expression functions should try to stay 'pure'. This makes functions easy to reuse and also make it possible to serialize the whole chain as well as output at every step of execution. +It is possible to add comments to expressions by starting them with a `//` sequence +or by using `/*` and `*/` to enclose multi-line comments. + Expressions power visualizations in Dashboard and Lens, as well as, every *element* in Canvas is backed by an expression. @@ -30,7 +33,8 @@ filters query="SELECT COUNT(timestamp) as total_errors FROM kibana_sample_data_logs WHERE tags LIKE '%warning%' OR tags LIKE '%error%'" -| math "total_errors" +| math "total_errors" // take "total_errors" column +/* Represent as a number over a label */ | metric "TOTAL ISSUES" metricFont={font family="'Open Sans', Helvetica, Arial, sans-serif" size=48 align="left" color="#FFFFFF" weight="normal" underline=false italic=false} labelFont={font family="'Open Sans', Helvetica, Arial, sans-serif" size=30 align="left" color="#FFFFFF" weight="lighter" underline=false italic=false} diff --git a/src/plugins/expressions/common/ast/types.ts b/src/plugins/expressions/common/ast/types.ts index 8f376ac547d266..c1324245f8314e 100644 --- a/src/plugins/expressions/common/ast/types.ts +++ b/src/plugins/expressions/common/ast/types.ts @@ -6,6 +6,7 @@ * Side Public License, v 1. */ +import type { Ast, AstFunction } from '@kbn/interpreter'; import { ExpressionValue, ExpressionValueError } from '../expression_types'; export type ExpressionAstNode = @@ -13,14 +14,11 @@ export type ExpressionAstNode = | ExpressionAstFunction | ExpressionAstArgument; -export type ExpressionAstExpression = { - type: 'expression'; +export type ExpressionAstExpression = Omit & { chain: ExpressionAstFunction[]; }; -export type ExpressionAstFunction = { - type: 'function'; - function: string; +export type ExpressionAstFunction = Omit & { arguments: Record; /** diff --git a/src/plugins/presentation_util/public/components/expression_input/autocomplete.ts b/src/plugins/presentation_util/public/components/expression_input/autocomplete.ts index b2d486f435a479..96d991719a63bb 100644 --- a/src/plugins/presentation_util/public/components/expression_input/autocomplete.ts +++ b/src/plugins/presentation_util/public/components/expression_input/autocomplete.ts @@ -7,12 +7,10 @@ */ import { uniq } from 'lodash'; -// @ts-expect-error untyped library +import type { AstWithMeta, AstArgumentWithMeta } from '@kbn/interpreter'; +import { isAstWithMeta } from '@kbn/interpreter'; import { parse } from '@kbn/interpreter'; import { - ExpressionAstExpression, - ExpressionAstFunction, - ExpressionAstArgument, ExpressionFunction, ExpressionFunctionParameter, getByAlias, @@ -40,7 +38,7 @@ interface ValueSuggestion extends BaseSuggestion { } interface FnArgAtPosition { - ast: ExpressionASTWithMeta; + ast: AstWithMeta; fnIndex: number; argName?: string; @@ -57,45 +55,6 @@ interface FnArgAtPosition { contextFn?: string | null; } -// If you parse an expression with the "addMeta" option it completely -// changes the type of returned object. The following types -// enhance the existing AST types with the appropriate meta information -interface ASTMetaInformation { - start: number; - end: number; - text: string; - node: T; -} - -// Wraps ExpressionArg with meta or replace ExpressionAstExpression with ExpressionASTWithMeta -type WrapExpressionArgWithMeta = T extends ExpressionAstExpression - ? ExpressionASTWithMeta - : ASTMetaInformation; - -type ExpressionArgASTWithMeta = WrapExpressionArgWithMeta; - -type Modify = Pick> & R; - -// Wrap ExpressionFunctionAST with meta and modify arguments to be wrapped with meta -type ExpressionFunctionASTWithMeta = Modify< - ExpressionAstFunction, - { - arguments: { - [key: string]: ExpressionArgASTWithMeta[]; - }; - } ->; - -// Wrap ExpressionFunctionAST with meta and modify chain to be wrapped with meta -type ExpressionASTWithMeta = ASTMetaInformation< - Modify< - ExpressionAstExpression, - { - chain: Array>; - } - > ->; - export interface FunctionSuggestion extends BaseSuggestion { type: 'function'; fnDef: ExpressionFunction; @@ -103,13 +62,6 @@ export interface FunctionSuggestion extends BaseSuggestion { export type AutocompleteSuggestion = FunctionSuggestion | ArgSuggestion | ValueSuggestion; -// Typeguard for checking if ExpressionArg is a new expression -function isExpression( - maybeExpression: ExpressionArgASTWithMeta -): maybeExpression is ExpressionASTWithMeta { - return typeof maybeExpression.node === 'object'; -} - /** * Generates the AST with the given expression and then returns the function and argument definitions * at the given position in the expression, if there are any. @@ -120,9 +72,9 @@ export function getFnArgDefAtPosition( position: number ) { try { - const ast: ExpressionASTWithMeta = parse(expression, { + const ast: AstWithMeta = parse(expression, { addMeta: true, - }) as ExpressionASTWithMeta; + }) as AstWithMeta; const { ast: newAst, fnIndex, argName, argStart, argEnd } = getFnArgAtPosition(ast, position); const fn = newAst.node.chain[fnIndex].node; @@ -153,7 +105,7 @@ export function getAutocompleteSuggestions( ): AutocompleteSuggestion[] { const text = expression.substr(0, position) + MARKER + expression.substr(position); try { - const ast = parse(text, { addMeta: true }) as ExpressionASTWithMeta; + const ast = parse(text, { addMeta: true }) as AstWithMeta; const { ast: newAst, fnIndex, @@ -206,7 +158,7 @@ export function getAutocompleteSuggestions( The context function for the first expression in the chain is `math`, since it's the parent's previous item. The context function for `formatnumber` is the return of `math "divide(value, 2)"`. */ -function getFnArgAtPosition(ast: ExpressionASTWithMeta, position: number): FnArgAtPosition { +function getFnArgAtPosition(ast: AstWithMeta, position: number): FnArgAtPosition { const fnIndex = ast.node.chain.findIndex((fn) => fn.start <= position && position <= fn.end); const fn = ast.node.chain[fnIndex]; for (const [argName, argValues] of Object.entries(fn.node.arguments)) { @@ -222,7 +174,7 @@ function getFnArgAtPosition(ast: ExpressionASTWithMeta, position: number): FnArg // If the arg value is an expression, expand our start and end position // to include the opening and closing braces - if (value.node !== null && isExpression(value)) { + if (value.node !== null && isAstWithMeta(value)) { argStart--; argEnd++; } @@ -233,7 +185,7 @@ function getFnArgAtPosition(ast: ExpressionASTWithMeta, position: number): FnArg // argument name (`font=` for example), recurse within the expression if ( value.node !== null && - isExpression(value) && + isAstWithMeta(value) && (argName === '_' || !(argStart <= position && position <= argStart + argName.length + 1)) ) { const result = getFnArgAtPosition(value, position); @@ -265,7 +217,7 @@ function getFnArgAtPosition(ast: ExpressionASTWithMeta, position: number): FnArg function getFnNameSuggestions( specs: ExpressionFunction[], - ast: ExpressionASTWithMeta, + ast: AstWithMeta, fnIndex: number ): FunctionSuggestion[] { // Filter the list of functions by the text at the marker @@ -299,7 +251,7 @@ function getFnNameSuggestions( function getSubFnNameSuggestions( specs: ExpressionFunction[], - ast: ExpressionASTWithMeta, + ast: AstWithMeta, fnIndex: number, parentFn: string, parentFnArgName: string, @@ -391,7 +343,7 @@ function getScore( function getArgNameSuggestions( specs: ExpressionFunction[], - ast: ExpressionASTWithMeta, + ast: AstWithMeta, fnIndex: number, argName: string, argIndex: number @@ -407,7 +359,7 @@ function getArgNameSuggestions( const { start, end } = fn.arguments[argName][argIndex]; // Filter the list of args by those which aren't already present (unless they allow multi) - const argEntries = Object.entries(fn.arguments).map<[string, ExpressionArgASTWithMeta[]]>( + const argEntries = Object.entries(fn.arguments).map<[string, AstArgumentWithMeta[]]>( ([name, values]) => { return [name, values.filter((value) => !value.text.includes(MARKER))]; } @@ -442,7 +394,7 @@ function getArgNameSuggestions( function getArgValueSuggestions( specs: ExpressionFunction[], - ast: ExpressionASTWithMeta, + ast: AstWithMeta, fnIndex: number, argName: string, argIndex: number diff --git a/src/plugins/presentation_util/public/components/expression_input/language.ts b/src/plugins/presentation_util/public/components/expression_input/language.ts index a481e5afed24ed..6dc3c252ebb03f 100644 --- a/src/plugins/presentation_util/public/components/expression_input/language.ts +++ b/src/plugins/presentation_util/public/components/expression_input/language.ts @@ -72,6 +72,9 @@ const expressionsLanguage: ExpressionsLanguage = { [/'/, 'string', '@string_single'], [/@symbols/, 'delimiter'], + + [/\/\*/, 'comment', '@multiline_comment'], + [/\/\/.*$/, 'comment'], ], string_double: [ @@ -93,6 +96,12 @@ const expressionsLanguage: ExpressionsLanguage = { [/\}/, 'delimiter.bracket', '@pop'], { include: 'common' }, ], + + multiline_comment: [ + [/[^\/*]+/, 'comment'], + ['\\*/', 'comment', '@pop'], + [/[\/*]/, 'comment'], + ], }, }; diff --git a/x-pack/plugins/canvas/public/components/workpad_filters/hooks/use_canvas_filters.ts b/x-pack/plugins/canvas/public/components/workpad_filters/hooks/use_canvas_filters.ts index 21bcc89304b3c8..bdccc8040c5def 100644 --- a/x-pack/plugins/canvas/public/components/workpad_filters/hooks/use_canvas_filters.ts +++ b/x-pack/plugins/canvas/public/components/workpad_filters/hooks/use_canvas_filters.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { ExpressionFunctionAST, fromExpression } from '@kbn/interpreter'; +import { AstFunction, fromExpression } from '@kbn/interpreter'; import { shallowEqual, useSelector } from 'react-redux'; import { State } from '../../../../types'; import { getFiltersByFilterExpressions } from '../../../lib/filter'; @@ -14,7 +14,7 @@ import { useFiltersService } from '../../../services'; const extractExpressionAST = (filters: string[]) => fromExpression(filters.join(' | ')); -export function useCanvasFilters(filterExprsToGroupBy: ExpressionFunctionAST[] = []) { +export function useCanvasFilters(filterExprsToGroupBy: AstFunction[] = []) { const filtersService = useFiltersService(); const filterExpressions = useSelector( (state: State) => filtersService.getFilters(state), diff --git a/x-pack/plugins/canvas/public/lib/filter.ts b/x-pack/plugins/canvas/public/lib/filter.ts index 2554ae11220eb7..dceb7f15b17170 100644 --- a/x-pack/plugins/canvas/public/lib/filter.ts +++ b/x-pack/plugins/canvas/public/lib/filter.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { Ast, ExpressionFunctionAST, fromExpression, toExpression } from '@kbn/interpreter'; +import { Ast, AstFunction, fromExpression, toExpression } from '@kbn/interpreter'; import { flowRight, get, groupBy } from 'lodash'; import { Filter as FilterType, @@ -63,7 +63,7 @@ export const groupFiltersBy = (filters: FilterType[], groupByField: FilterField) })); }; -const excludeFiltersByGroups = (filters: Ast[], filterExprAst: ExpressionFunctionAST) => { +const excludeFiltersByGroups = (filters: Ast[], filterExprAst: AstFunction) => { const groupsToExclude = filterExprAst.arguments.group ?? []; const removeUngrouped = filterExprAst.arguments.ungrouped?.[0] ?? false; return filters.filter((filter) => { @@ -85,7 +85,7 @@ const excludeFiltersByGroups = (filters: Ast[], filterExprAst: ExpressionFunctio const includeFiltersByGroups = ( filters: Ast[], - filterExprAst: ExpressionFunctionAST, + filterExprAst: AstFunction, ignoreUngroupedIfGroups: boolean = false ) => { const groupsToInclude = filterExprAst.arguments.group ?? []; @@ -109,7 +109,7 @@ const includeFiltersByGroups = ( export const getFiltersByFilterExpressions = ( filters: string[], - filterExprsAsts: ExpressionFunctionAST[] + filterExprsAsts: AstFunction[] ) => { const filtersAst = filters.map((filter) => fromExpression(filter)); const matchedFiltersAst = filterExprsAsts.reduce((includedFilters, filter) => { diff --git a/x-pack/plugins/canvas/public/lib/filter_adapters.test.ts b/x-pack/plugins/canvas/public/lib/filter_adapters.test.ts index e035e30e307f08..33e675a6b9d980 100644 --- a/x-pack/plugins/canvas/public/lib/filter_adapters.test.ts +++ b/x-pack/plugins/canvas/public/lib/filter_adapters.test.ts @@ -5,11 +5,11 @@ * 2.0. */ -import { ExpressionFunctionAST } from '@kbn/interpreter'; +import { AstFunction } from '@kbn/interpreter'; import { adaptCanvasFilter } from './filter_adapters'; describe('adaptCanvasFilter', () => { - const filterAST: ExpressionFunctionAST = { + const filterAST: AstFunction = { type: 'function', function: 'exactly', arguments: { diff --git a/x-pack/plugins/canvas/public/lib/filter_adapters.ts b/x-pack/plugins/canvas/public/lib/filter_adapters.ts index 67bdf13d199994..ed303a83d5e5d6 100644 --- a/x-pack/plugins/canvas/public/lib/filter_adapters.ts +++ b/x-pack/plugins/canvas/public/lib/filter_adapters.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { ExpressionFunctionAST } from '@kbn/interpreter'; +import type { AstFunction } from '@kbn/interpreter'; import { identity } from 'lodash'; import { ExpressionAstArgument, Filter, FilterType } from '../../types'; @@ -23,7 +23,7 @@ const argToValue = ( const convertFunctionToFilterType = (func: string) => functionToFilter[func] ?? FilterType.exactly; -const collectArgs = (args: ExpressionFunctionAST['arguments']) => { +const collectArgs = (args: AstFunction['arguments']) => { const argsKeys = Object.keys(args); if (!argsKeys.length) { @@ -36,7 +36,7 @@ const collectArgs = (args: ExpressionFunctionAST['arguments']) => { ); }; -export function adaptCanvasFilter(filter: ExpressionFunctionAST): Filter { +export function adaptCanvasFilter(filter: AstFunction): Filter { const { function: type, arguments: args } = filter; const { column, filterGroup, value: valueArg, type: typeArg, ...rest } = args ?? {}; return { diff --git a/x-pack/plugins/canvas/server/collectors/collector_helpers.ts b/x-pack/plugins/canvas/server/collectors/collector_helpers.ts index 2a1dbdfe437baa..aa88d910098a59 100644 --- a/x-pack/plugins/canvas/server/collectors/collector_helpers.ts +++ b/x-pack/plugins/canvas/server/collectors/collector_helpers.ts @@ -10,19 +10,13 @@ * @param cb: callback to do something with a function that has been found */ -import { - ExpressionAstExpression, - ExpressionAstNode, -} from '../../../../../src/plugins/expressions/common'; - -function isExpression( - maybeExpression: ExpressionAstNode -): maybeExpression is ExpressionAstExpression { - return typeof maybeExpression === 'object' && maybeExpression.type === 'expression'; -} +import { isAst } from '@kbn/interpreter'; +import { ExpressionAstNode } from '../../../../../src/plugins/expressions/common'; export function collectFns(ast: ExpressionAstNode, cb: (functionName: string) => void) { - if (!isExpression(ast)) return; + if (!isAst(ast)) { + return; + } ast.chain.forEach(({ function: cFunction, arguments: cArguments }) => { cb(cFunction); diff --git a/x-pack/plugins/canvas/server/saved_objects/workpad_references.ts b/x-pack/plugins/canvas/server/saved_objects/workpad_references.ts index 806f08b17651cb..6d76dc61bd96b1 100644 --- a/x-pack/plugins/canvas/server/saved_objects/workpad_references.ts +++ b/x-pack/plugins/canvas/server/saved_objects/workpad_references.ts @@ -31,7 +31,10 @@ export const extractReferences = ( })) ); - return { ...element, expression: toExpression(extract.state) }; + return { + ...element, + expression: toExpression(extract.state, { source: element.expression }), + }; }); return { ...page, elements }; @@ -59,7 +62,7 @@ export const injectReferences = ( referencesForElement ); - return { ...element, expression: toExpression(injectedAst) }; + return { ...element, expression: toExpression(injectedAst, { source: element.expression }) }; }); return { ...page, elements }; diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/expression_helpers.ts b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/expression_helpers.ts index a8d58e51691f91..600341931f575e 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/expression_helpers.ts +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/expression_helpers.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { Ast, fromExpression, ExpressionFunctionAST } from '@kbn/interpreter'; +import { Ast, AstFunction, fromExpression } from '@kbn/interpreter'; import { DatasourceStates } from '../../state_management'; import { Visualization, DatasourcePublicAPI, DatasourceMap } from '../../types'; @@ -35,7 +35,7 @@ export function prependDatasourceExpression( ([layerId, expr]) => [layerId, typeof expr === 'string' ? fromExpression(expr) : expr] ); - const datafetchExpression: ExpressionFunctionAST = { + const datafetchExpression: AstFunction = { type: 'function', function: 'lens_merge_tables', arguments: { diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/calculations/utils.ts b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/calculations/utils.ts index cec6294f7f3145..5bae2f5a1865f4 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/calculations/utils.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/calculations/utils.ts @@ -6,7 +6,7 @@ */ import { i18n } from '@kbn/i18n'; -import type { ExpressionFunctionAST } from '@kbn/interpreter'; +import type { AstFunction } from '@kbn/interpreter'; import memoizeOne from 'memoize-one'; import { LayerType, layerTypes } from '../../../../../common'; import type { TimeScaleUnit } from '../../../../../common/expressions'; @@ -143,7 +143,7 @@ export function dateBasedOperationToExpression( columnId: string, functionName: string, additionalArgs: Record = {} -): ExpressionFunctionAST[] { +): AstFunction[] { const currentColumn = layer.columns[columnId] as unknown as ReferenceBasedIndexPatternColumn; const buckets = layer.columnOrder.filter((colId) => layer.columns[colId].isBucketed); const dateColumnIndex = buckets.findIndex( @@ -174,7 +174,7 @@ export function optionallHistogramBasedOperationToExpression( columnId: string, functionName: string, additionalArgs: Record = {} -): ExpressionFunctionAST[] { +): AstFunction[] { const currentColumn = layer.columns[columnId] as unknown as ReferenceBasedIndexPatternColumn; const buckets = layer.columnOrder.filter((colId) => layer.columns[colId].isBucketed); const nonHistogramColumns = buckets.filter( diff --git a/x-pack/plugins/lens/server/migrations/saved_object_migrations.ts b/x-pack/plugins/lens/server/migrations/saved_object_migrations.ts index 596ddf12ae7c3f..fc1718c1df2fa8 100644 --- a/x-pack/plugins/lens/server/migrations/saved_object_migrations.ts +++ b/x-pack/plugins/lens/server/migrations/saved_object_migrations.ts @@ -6,7 +6,7 @@ */ import { cloneDeep, mergeWith } from 'lodash'; -import { fromExpression, toExpression, Ast, ExpressionFunctionAST } from '@kbn/interpreter'; +import { fromExpression, toExpression, Ast, AstFunction } from '@kbn/interpreter'; import { SavedObjectMigrationMap, SavedObjectMigrationFn, @@ -141,7 +141,7 @@ const removeLensAutoDate: SavedObjectMigrationFn { + const newChain: AstFunction[] = ast.chain.map((topNode) => { if (topNode.function !== 'lens_merge_tables') { return topNode; } @@ -202,7 +202,7 @@ const addTimeFieldToEsaggs: SavedObjectMigrationFn { + const newChain: AstFunction[] = ast.chain.map((topNode) => { if (topNode.function !== 'lens_merge_tables') { return topNode; } From 35f721db9bef5ffd0d2787a9da83a568c9c598ca Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Thu, 20 Jan 2022 20:00:10 +0000 Subject: [PATCH 094/108] skip flaky suite (#123495) --- .../endpoint/validators/base_validator.test.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/server/lists_integration/endpoint/validators/base_validator.test.ts b/x-pack/plugins/security_solution/server/lists_integration/endpoint/validators/base_validator.test.ts index 728e3b8559ed32..9d19ed4178a2ae 100644 --- a/x-pack/plugins/security_solution/server/lists_integration/endpoint/validators/base_validator.test.ts +++ b/x-pack/plugins/security_solution/server/lists_integration/endpoint/validators/base_validator.test.ts @@ -21,7 +21,8 @@ import { GLOBAL_ARTIFACT_TAG, } from '../../../../common/endpoint/service/artifacts'; -describe('When using Artifacts Exceptions BaseValidator', () => { +// FLAKY: https://github.com/elastic/kibana/issues/123495 +describe.skip('When using Artifacts Exceptions BaseValidator', () => { let endpointAppContextServices: EndpointAppContextService; let kibanaRequest: ReturnType; let exceptionLikeItem: ExceptionItemLikeOptions; From 67706ca03312c657f3baeb6bc58ae79f8f776a9d Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Thu, 20 Jan 2022 20:03:25 +0000 Subject: [PATCH 095/108] skip flaky suite (#123498) --- .../apis/endpoint_artifacts.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/test/security_solution_endpoint_api_int/apis/endpoint_artifacts.ts b/x-pack/test/security_solution_endpoint_api_int/apis/endpoint_artifacts.ts index 58f6fbf58ccb5b..1e6646b4fbb245 100644 --- a/x-pack/test/security_solution_endpoint_api_int/apis/endpoint_artifacts.ts +++ b/x-pack/test/security_solution_endpoint_api_int/apis/endpoint_artifacts.ts @@ -210,7 +210,8 @@ export default function ({ getService }: FtrProviderContext) { } }); - describe('and user DOES NOT have authorization to manage endpoint security', () => { + // FLAKY: https://github.com/elastic/kibana/issues/123498 + describe.skip('and user DOES NOT have authorization to manage endpoint security', () => { for (const trustedAppApiCall of trustedAppApiCalls) { it(`should error on [${trustedAppApiCall.method}]`, async () => { await supertestWithoutAuth[trustedAppApiCall.method](trustedAppApiCall.path) From 7740a5db127ff321bc0e364d8314b9fe2cbcfd22 Mon Sep 17 00:00:00 2001 From: Brian Seeders Date: Thu, 20 Jan 2022 15:08:14 -0500 Subject: [PATCH 096/108] Revert "skip flaky suite (#123498)" This reverts commit 67706ca03312c657f3baeb6bc58ae79f8f776a9d. --- .../apis/endpoint_artifacts.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/x-pack/test/security_solution_endpoint_api_int/apis/endpoint_artifacts.ts b/x-pack/test/security_solution_endpoint_api_int/apis/endpoint_artifacts.ts index 1e6646b4fbb245..58f6fbf58ccb5b 100644 --- a/x-pack/test/security_solution_endpoint_api_int/apis/endpoint_artifacts.ts +++ b/x-pack/test/security_solution_endpoint_api_int/apis/endpoint_artifacts.ts @@ -210,8 +210,7 @@ export default function ({ getService }: FtrProviderContext) { } }); - // FLAKY: https://github.com/elastic/kibana/issues/123498 - describe.skip('and user DOES NOT have authorization to manage endpoint security', () => { + describe('and user DOES NOT have authorization to manage endpoint security', () => { for (const trustedAppApiCall of trustedAppApiCalls) { it(`should error on [${trustedAppApiCall.method}]`, async () => { await supertestWithoutAuth[trustedAppApiCall.method](trustedAppApiCall.path) From ba0833f42b89a0b62bccd1d8c04bf9c799f32258 Mon Sep 17 00:00:00 2001 From: Georgii Gorbachev Date: Fri, 21 Jan 2022 00:17:26 +0300 Subject: [PATCH 097/108] [Security Solution][Detections] Rule execution logging overhaul (#121644) **Epic:** https://github.com/elastic/kibana/issues/118324 **Tickets:** https://github.com/elastic/kibana/issues/119603, https://github.com/elastic/kibana/issues/119597, https://github.com/elastic/kibana/issues/91265, https://github.com/elastic/kibana/issues/118511 ## Summary The legacy rule execution logging implementation is replaced by a new one that introduces a new model for execution-related data, a new saved object and a new, cleaner interface and implementation. - [x] The legacy data model is deleted (`IRuleStatusResponseAttributes`, `IRuleStatusSOAttributes`) - [x] The legacy `siem-detection-engine-rule-status` saved object type is deleted and marked as deleted in `src/core` - [x] A new data model is introduced (`x-pack/plugins/security_solution/common/detection_engine/schemas/common/rule_monitoring.ts`). This data model doesn't contain a mixture of successful and failed statuses, which should simplify client-side code (e.g. the code of Rule Management and Monitoring tables, as well as Rule Details page). - [x] A new `siem-detection-engine-rule-execution-info` saved object is introduced (`x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/rule_execution_info/saved_object.ts`). - [x] This SO has 1:1 association with the rule SO, so every rule can have 0 or 1 execution info associated with it. This SO is used in order to 1) update the last execution status and metrics and 2) fetch execution data for N rules more efficiently comparing to the legacy SO. - [x] The logic of creating or updating this SOs is based on the "upsert" approach (planned in https://github.com/elastic/kibana/issues/118511). It does not fetch the SO by rule id before updating it anymore. - [x] Rule execution logging logic is rewritten (see `x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log`). The previous rule execution log client is split into two objects: `IRuleExecutionLogClient` for using it from route handlers, and `IRuleExecutionLogger` for writing logs from rule executors. - [x] `IRuleExecutionLogger` instance is scoped to the currently executing rule and space id. There's no need to pass rule id, name, type etc to `.logStatusChange()` every time. - [x] Rule executors and related functions are updated. - [x] API routes are updated, including the rule preview route which uses a special "spy" implementation of `IRuleExecutionLogger`. A rule returned from an API endpoint now has optional `execution_summary` field of type `RuleExecutionSummary`. - [x] UI is updated to use the new data model of `RuleExecutionSummary`: - [x] Rule Management and Monitoring tables - [x] Rule Details page - [x] A new API route is introduced for fetching rule execution events: `/internal/detection_engine/rules/{ruleId}/execution/events`. It is used for rendering the Failure History tab (last 5 failures) and is intended to be used in the coming UI of Rule Execution Log on the Details page. - [x] Rule Details page and Failure History tab are updated to use the new data models and API routes. - [x] I used `react-query` for fetching execution events - [x] See `x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rule_execution_events.tsx` - [x] The lib is updated to the latest version - [x] Tests and fixed and updated according to all the changes - [x] Components related to rule execution statuses are all moved to `x-pack/plugins/security_solution/public/detections/components/rules/rule_execution_status`. - [x] I left a lot of `// TODO: https://github.com/elastic/kibana/pull/121644` comments in the code which I'm planning to address and remove in a follow-up PR. Lots of clean up work is needed, but I'd like to unblock the work on Rule Execution Log UI. ## In the next episodes - Address and remove `// TODO: https://github.com/elastic/kibana/pull/121644` comments in the code - Make sure that SO id generation for `siem-detection-engine-rule-execution-info` is safe and future-proof. Sync with the Core team. If there are risks, we will need to choose between risks and performance (reading the SO before updating it). It would be easy to submit a fix if needed. - Add APM integration. Use `withSecuritySpan` in methods of `rule_execution_log` citizens. - Add comments to the code and README. - Add test coverage. - Etc... ### Checklist Delete any items that are not applicable to this PR. - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [ ] Any UI touched in this PR is usable by keyboard only (learn more about [keyboard accessibility](https://webaim.org/techniques/keyboard/)) - [ ] Any UI touched in this PR does not create any new axe failures (run axe in browser: [FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/), [Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US)) - [x] If a plugin configuration key changed, check if it needs to be allowlisted in the cloud and added to the [docker list](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker) - [ ] This renders correctly on smaller devices using a responsive layout. (You can test this [in your browser](https://www.browserstack.com/guide/responsive-testing-on-local-server)) - [ ] This was checked for [cross-browser compatibility](https://www.elastic.co/support/matrix#matrix_browsers) ### For maintainers - [x] This was checked for breaking API changes and was [labeled appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) --- package.json | 2 +- .../transform_data_to_ndjson/index.test.ts | 4 - ...grations_state_action_machine.test.ts.snap | 30 +++ .../migrations/core/unused_types.ts | 2 + .../type_registrations.test.ts | 1 + .../reporting_example/public/application.tsx | 2 +- .../security_solution/common/constants.ts | 6 +- .../detection_engine/schemas/common/index.ts} | 9 +- .../schemas/common/rule_monitoring.ts | 84 +++++++ .../schemas/common/schemas.ts | 37 --- .../request/find_rule_statuses_schema.ts | 28 --- .../get_rule_execution_events_request.ts | 18 ++ .../schemas/request/rule_schemas.ts | 23 +- .../get_rule_execution_events_response.ts | 17 ++ .../schemas/response/index.ts | 1 + .../schemas/response/rules_schema.mocks.ts | 15 +- .../schemas/response/rules_schema.ts | 16 +- .../common/detection_engine/utils.ts | 21 +- .../rules/rule_execution_status/index.tsx | 13 ++ .../rule_status.tsx} | 26 ++- .../rule_status_badge.test.tsx} | 11 +- .../rule_status_badge.tsx} | 23 +- .../rule_status_failed_callout.test.tsx | 57 +++++ .../rule_status_failed_callout.tsx | 81 +++++++ .../translations.ts | 14 ++ .../rule_execution_status/utils.test.tsx | 16 ++ .../utils.ts} | 19 +- .../detection_engine/rules/__mocks__/api.ts | 84 +++---- .../detection_engine/rules/api.test.ts | 45 ++-- .../containers/detection_engine/rules/api.ts | 55 +++-- .../detection_engine/rules/index.ts | 2 +- .../detection_engine/rules/types.ts | 36 +-- .../rules/use_rule_execution_events.test.tsx | 57 +++++ .../rules/use_rule_execution_events.tsx | 31 +++ .../rules/use_rule_status.test.tsx | 85 ------- .../rules/use_rule_status.tsx | 67 ------ .../detection_engine/rules/all/columns.tsx | 51 ++-- .../rules/details/failure_history.test.tsx | 88 ------- .../rules/details/failure_history.tsx | 78 +++---- .../rules/details/index.test.tsx | 10 - .../detection_engine/rules/details/index.tsx | 87 +++---- .../details/status_failed_callout.test.tsx | 26 --- .../rules/details/status_failed_callout.tsx | 43 ---- .../rules/details/translations.ts | 14 -- .../security_solution/server/config.mock.ts | 4 - .../security_solution/server/config.ts | 14 -- .../plugins/security_solution/server/index.ts | 3 +- .../routes/__mocks__/request_context.ts | 4 +- .../routes/__mocks__/request_responses.ts | 145 ++++++------ .../routes/__mocks__/utils.ts | 7 +- .../rules/add_prepackaged_rules_route.test.ts | 25 +- .../rules/add_prepackaged_rules_route.ts | 9 +- .../rules/create_rules_bulk_route.test.ts | 17 +- .../routes/rules/create_rules_bulk_route.ts | 10 +- .../routes/rules/create_rules_route.test.ts | 25 +- .../routes/rules/create_rules_route.ts | 20 +- .../rules/delete_rules_bulk_route.test.ts | 7 - .../routes/rules/delete_rules_bulk_route.ts | 23 +- .../routes/rules/delete_rules_route.test.ts | 12 - .../routes/rules/delete_rules_route.ts | 19 +- .../routes/rules/export_rules_route.ts | 6 +- .../find_rule_status_internal_route.test.ts | 119 ---------- .../rules/find_rule_status_internal_route.ts | 85 ------- .../routes/rules/find_rules_route.test.ts | 19 +- .../routes/rules/find_rules_route.ts | 19 +- ...get_prepackaged_rules_status_route.test.ts | 11 +- .../get_prepackaged_rules_status_route.ts | 8 +- .../get_rule_execution_events_route.test.ts | 53 +++++ .../rules/get_rule_execution_events_route.ts | 58 +++++ .../routes/rules/import_rules_route.ts | 2 - .../rules/patch_rules_bulk_route.test.ts | 11 +- .../routes/rules/patch_rules_bulk_route.ts | 22 +- .../routes/rules/patch_rules_route.test.ts | 20 +- .../routes/rules/patch_rules_route.ts | 19 +- .../rules/perform_bulk_action_route.test.ts | 7 - .../routes/rules/perform_bulk_action_route.ts | 10 +- .../routes/rules/preview_rules_route.ts | 45 ++-- .../routes/rules/read_rules_route.test.ts | 17 +- .../routes/rules/read_rules_route.ts | 18 +- .../rules/update_rules_bulk_route.test.ts | 19 +- .../routes/rules/update_rules_bulk_route.ts | 24 +- .../routes/rules/update_rules_route.test.ts | 26 +-- .../routes/rules/update_rules_route.ts | 22 +- .../detection_engine/routes/rules/utils.ts | 47 ++-- .../rules/utils/get_current_rule_statuses.ts | 64 ----- .../rules/utils/import_rules_utils.test.ts | 8 - .../routes/rules/utils/import_rules_utils.ts | 4 - .../routes/rules/validate.test.ts | 28 ++- .../detection_engine/routes/rules/validate.ts | 68 +++--- .../lib/detection_engine/routes/utils.test.ts | 165 +------------ .../lib/detection_engine/routes/utils.ts | 68 +----- .../__mocks__/rule_execution_log_client.ts | 34 ++- .../event_log_adapter/event_log_adapter.ts | 126 ---------- .../event_log_adapter/event_log_client.ts | 221 ------------------ .../rule_execution_log/index.ts | 14 +- .../merge_rule_execution_summary.ts | 43 ++++ .../constants.ts | 4 +- .../rule_execution_events/events_reader.ts | 86 +++++++ .../rule_execution_events/events_writer.ts | 126 ++++++++++ .../register_event_log_provider.ts | 0 .../rule_execution_info/saved_object.ts | 77 ++++++ .../saved_objects_client.ts | 177 ++++++++++++++ .../saved_objects_utils.ts | 36 +++ .../rule_execution_log_client.ts | 131 ----------- .../rule_execution_log_client/client.ts | 47 ++++ .../client_interface.ts | 45 ++++ .../rule_execution_log_client/decorator.ts | 64 +++++ .../rule_execution_log_factory.ts | 58 +++++ .../rule_execution_logger/logger.ts | 145 ++++++++++++ .../rule_execution_logger/logger_interface.ts | 48 ++++ .../rule_status_saved_objects_client.ts | 139 ----------- .../saved_objects_adapter.ts | 191 --------------- .../rule_execution_log/types.ts | 120 ---------- .../rule_execution_log/utils/logging.ts | 24 ++ .../rule_execution_log/utils/normalization.ts | 26 ++- .../rule_types/__mocks__/threshold.ts | 5 +- .../create_security_rule_type_wrapper.ts | 77 +++--- .../query/create_query_alert_type.test.ts | 4 +- .../lib/detection_engine/rule_types/types.ts | 4 +- .../rules/delete_rules.test.ts | 10 +- .../detection_engine/rules/delete_rules.ts | 8 +- .../rules/get_export_by_object_ids.test.ts | 7 +- .../rules/get_export_by_object_ids.ts | 2 +- .../legacy_rule_status/legacy_migrations.ts | 110 --------- ...egacy_rule_status_saved_object_mappings.ts | 74 ------ .../rules/legacy_rule_status/legacy_utils.ts | 17 -- .../lib/detection_engine/rules/types.ts | 69 +----- .../rules/update_prepacked_rules.test.ts | 6 +- .../rules/update_prepacked_rules.ts | 6 - .../rules/update_rules.mock.ts | 3 - .../schemas/rule_converters.ts | 39 +--- ...s.sh => delete_all_rule_execution_data.sh} | 20 +- .../detection_engine/scripts/hard_reset.sh | 9 +- .../signals/__mocks__/es_results.ts | 38 --- .../signals/build_signal.test.ts | 9 - .../preview_rule_execution_log_client.ts | 78 ------- .../preview/preview_rule_execution_logger.ts | 52 +++++ .../detection_engine/signals/utils.test.ts | 79 ++++--- .../lib/detection_engine/signals/utils.ts | 61 ++--- .../security_solution/server/plugin.ts | 6 +- .../server/request_context_factory.ts | 19 +- .../security_solution/server/routes/index.ts | 8 +- .../security_solution/server/saved_objects.ts | 7 +- .../plugins/security_solution/server/types.ts | 2 +- .../translations/translations/ja-JP.json | 2 - .../translations/translations/zh-CN.json | 2 - .../tests/check_privileges.ts | 8 +- .../security_and_spaces/tests/create_rules.ts | 13 +- .../tests/create_threat_matching.ts | 8 +- .../tests/generating_signals.ts | 5 +- .../security_and_spaces/tests/migrations.ts | 89 ------- .../detection_engine_api_integration/utils.ts | 30 ++- .../security_solution/migrations/data.json | 63 ----- .../migrations/mappings.json | 38 --- yarn.lock | 8 +- 155 files changed, 2386 insertions(+), 3562 deletions(-) rename x-pack/plugins/security_solution/{public/detections/components/rules/rule_status/helpers.test.tsx => common/detection_engine/schemas/common/index.ts} (54%) create mode 100644 x-pack/plugins/security_solution/common/detection_engine/schemas/common/rule_monitoring.ts delete mode 100644 x-pack/plugins/security_solution/common/detection_engine/schemas/request/find_rule_statuses_schema.ts create mode 100644 x-pack/plugins/security_solution/common/detection_engine/schemas/request/get_rule_execution_events_request.ts create mode 100644 x-pack/plugins/security_solution/common/detection_engine/schemas/response/get_rule_execution_events_response.ts create mode 100644 x-pack/plugins/security_solution/public/detections/components/rules/rule_execution_status/index.tsx rename x-pack/plugins/security_solution/public/detections/components/rules/{rule_status/index.tsx => rule_execution_status/rule_status.tsx} (62%) rename x-pack/plugins/security_solution/public/detections/components/rules/{rule_execution_status_badge/index.test.tsx => rule_execution_status/rule_status_badge.test.tsx} (61%) rename x-pack/plugins/security_solution/public/detections/components/rules/{rule_execution_status_badge/index.tsx => rule_execution_status/rule_status_badge.tsx} (53%) create mode 100644 x-pack/plugins/security_solution/public/detections/components/rules/rule_execution_status/rule_status_failed_callout.test.tsx create mode 100644 x-pack/plugins/security_solution/public/detections/components/rules/rule_execution_status/rule_status_failed_callout.tsx rename x-pack/plugins/security_solution/public/detections/components/rules/{rule_status => rule_execution_status}/translations.ts (71%) create mode 100644 x-pack/plugins/security_solution/public/detections/components/rules/rule_execution_status/utils.test.tsx rename x-pack/plugins/security_solution/public/detections/components/rules/{rule_status/helpers.ts => rule_execution_status/utils.ts} (55%) create mode 100644 x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rule_execution_events.test.tsx create mode 100644 x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rule_execution_events.tsx delete mode 100644 x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rule_status.test.tsx delete mode 100644 x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rule_status.tsx delete mode 100644 x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/failure_history.test.tsx delete mode 100644 x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/status_failed_callout.test.tsx delete mode 100644 x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/status_failed_callout.tsx delete mode 100644 x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/find_rule_status_internal_route.test.ts delete mode 100644 x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/find_rule_status_internal_route.ts create mode 100644 x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/get_rule_execution_events_route.test.ts create mode 100644 x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/get_rule_execution_events_route.ts delete mode 100644 x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils/get_current_rule_statuses.ts delete mode 100644 x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/event_log_adapter/event_log_adapter.ts delete mode 100644 x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/event_log_adapter/event_log_client.ts create mode 100644 x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/merge_rule_execution_summary.ts rename x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/{event_log_adapter => rule_execution_events}/constants.ts (90%) create mode 100644 x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/rule_execution_events/events_reader.ts create mode 100644 x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/rule_execution_events/events_writer.ts rename x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/{event_log_adapter => rule_execution_events}/register_event_log_provider.ts (100%) create mode 100644 x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/rule_execution_info/saved_object.ts create mode 100644 x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/rule_execution_info/saved_objects_client.ts create mode 100644 x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/rule_execution_info/saved_objects_utils.ts delete mode 100644 x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/rule_execution_log_client.ts create mode 100644 x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/rule_execution_log_client/client.ts create mode 100644 x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/rule_execution_log_client/client_interface.ts create mode 100644 x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/rule_execution_log_client/decorator.ts create mode 100644 x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/rule_execution_log_factory.ts create mode 100644 x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/rule_execution_logger/logger.ts create mode 100644 x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/rule_execution_logger/logger_interface.ts delete mode 100644 x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/saved_objects_adapter/rule_status_saved_objects_client.ts delete mode 100644 x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/saved_objects_adapter/saved_objects_adapter.ts delete mode 100644 x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/types.ts create mode 100644 x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/utils/logging.ts delete mode 100644 x-pack/plugins/security_solution/server/lib/detection_engine/rules/legacy_rule_status/legacy_migrations.ts delete mode 100644 x-pack/plugins/security_solution/server/lib/detection_engine/rules/legacy_rule_status/legacy_rule_status_saved_object_mappings.ts delete mode 100644 x-pack/plugins/security_solution/server/lib/detection_engine/rules/legacy_rule_status/legacy_utils.ts rename x-pack/plugins/security_solution/server/lib/detection_engine/scripts/{delete_all_statuses.sh => delete_all_rule_execution_data.sh} (52%) delete mode 100644 x-pack/plugins/security_solution/server/lib/detection_engine/signals/preview/preview_rule_execution_log_client.ts create mode 100644 x-pack/plugins/security_solution/server/lib/detection_engine/signals/preview/preview_rule_execution_logger.ts diff --git a/package.json b/package.json index 429d1ea67e73f2..0bd1b5c9e5b552 100644 --- a/package.json +++ b/package.json @@ -340,7 +340,7 @@ "react-moment-proptypes": "^1.7.0", "react-monaco-editor": "^0.41.2", "react-popper-tooltip": "^2.10.1", - "react-query": "^3.28.0", + "react-query": "^3.34.0", "react-redux": "^7.2.0", "react-resizable": "^1.7.5", "react-resize-detector": "^4.2.0", diff --git a/packages/kbn-securitysolution-utils/src/transform_data_to_ndjson/index.test.ts b/packages/kbn-securitysolution-utils/src/transform_data_to_ndjson/index.test.ts index b10626357f5b10..bb4fc47ce0370d 100644 --- a/packages/kbn-securitysolution-utils/src/transform_data_to_ndjson/index.test.ts +++ b/packages/kbn-securitysolution-utils/src/transform_data_to_ndjson/index.test.ts @@ -32,10 +32,6 @@ const getRulesSchemaMock = (anchorDate: string = ANCHOR_DATE) => ({ type: 'query', threat: [], version: 1, - status: 'succeeded', - status_date: '2020-02-22T16:47:50.047Z', - last_success_at: '2020-02-22T16:47:50.047Z', - last_success_message: 'succeeded', output_index: '.siem-signals-default', max_signals: 100, risk_score: 55, diff --git a/src/core/server/saved_objects/migrations/__snapshots__/migrations_state_action_machine.test.ts.snap b/src/core/server/saved_objects/migrations/__snapshots__/migrations_state_action_machine.test.ts.snap index 760a83fa65cf1f..0ad6f18104685f 100644 --- a/src/core/server/saved_objects/migrations/__snapshots__/migrations_state_action_machine.test.ts.snap +++ b/src/core/server/saved_objects/migrations/__snapshots__/migrations_state_action_machine.test.ts.snap @@ -119,6 +119,11 @@ Object { "type": "server", }, }, + Object { + "term": Object { + "type": "siem-detection-engine-rule-status", + }, + }, Object { "term": Object { "type": "timelion-sheet", @@ -275,6 +280,11 @@ Object { "type": "server", }, }, + Object { + "term": Object { + "type": "siem-detection-engine-rule-status", + }, + }, Object { "term": Object { "type": "timelion-sheet", @@ -435,6 +445,11 @@ Object { "type": "server", }, }, + Object { + "term": Object { + "type": "siem-detection-engine-rule-status", + }, + }, Object { "term": Object { "type": "timelion-sheet", @@ -599,6 +614,11 @@ Object { "type": "server", }, }, + Object { + "term": Object { + "type": "siem-detection-engine-rule-status", + }, + }, Object { "term": Object { "type": "timelion-sheet", @@ -800,6 +820,11 @@ Object { "type": "server", }, }, + Object { + "term": Object { + "type": "siem-detection-engine-rule-status", + }, + }, Object { "term": Object { "type": "timelion-sheet", @@ -967,6 +992,11 @@ Object { "type": "server", }, }, + Object { + "term": Object { + "type": "siem-detection-engine-rule-status", + }, + }, Object { "term": Object { "type": "timelion-sheet", diff --git a/src/core/server/saved_objects/migrations/core/unused_types.ts b/src/core/server/saved_objects/migrations/core/unused_types.ts index ddcadc09502f43..fd4b8a09600d7f 100644 --- a/src/core/server/saved_objects/migrations/core/unused_types.ts +++ b/src/core/server/saved_objects/migrations/core/unused_types.ts @@ -29,6 +29,8 @@ export const REMOVED_TYPES: string[] = [ 'tsvb-validation-telemetry', // replaced by osquery-manager-usage-metric 'osquery-usage-metric', + // Was removed in 8.1 https://github.com/elastic/kibana/issues/91265 + 'siem-detection-engine-rule-status', // Was removed in 7.16 'timelion-sheet', ].sort(); diff --git a/src/core/server/saved_objects/migrations/integration_tests/type_registrations.test.ts b/src/core/server/saved_objects/migrations/integration_tests/type_registrations.test.ts index 4ff66151db925b..962d32b44eb324 100644 --- a/src/core/server/saved_objects/migrations/integration_tests/type_registrations.test.ts +++ b/src/core/server/saved_objects/migrations/integration_tests/type_registrations.test.ts @@ -84,6 +84,7 @@ const previouslyRegisteredTypes = [ 'security-solution-signals-migration', 'server', 'siem-detection-engine-rule-actions', + 'siem-detection-engine-rule-execution-info', 'siem-detection-engine-rule-status', 'siem-ui-timeline', 'siem-ui-timeline-note', diff --git a/x-pack/examples/reporting_example/public/application.tsx b/x-pack/examples/reporting_example/public/application.tsx index 9b044ac801773c..c1e18b13ebe5ef 100644 --- a/x-pack/examples/reporting_example/public/application.tsx +++ b/x-pack/examples/reporting_example/public/application.tsx @@ -9,7 +9,7 @@ import React from 'react'; import ReactDOM from 'react-dom'; import { Router, Route, Switch } from 'react-router-dom'; import { AppMountParameters, CoreStart } from '../../../../src/core/public'; -import { KibanaThemeProvider } from '../../../../../kibana/src/plugins/kibana_react/public'; +import { KibanaThemeProvider } from '../../../../src/plugins/kibana_react/public'; import { CaptureTest } from './containers/capture_test'; import { Main } from './containers/main'; import { ApplicationContextProvider } from './application_context'; diff --git a/x-pack/plugins/security_solution/common/constants.ts b/x-pack/plugins/security_solution/common/constants.ts index 7514edea6247ff..6e408bfb0822a9 100644 --- a/x-pack/plugins/security_solution/common/constants.ts +++ b/x-pack/plugins/security_solution/common/constants.ts @@ -264,8 +264,10 @@ export const DETECTION_ENGINE_RULES_PREVIEW = `${DETECTION_ENGINE_RULES_URL}/pre * Internal detection engine routes */ export const INTERNAL_DETECTION_ENGINE_URL = '/internal/detection_engine' as const; -export const INTERNAL_DETECTION_ENGINE_RULE_STATUS_URL = - `${INTERNAL_DETECTION_ENGINE_URL}/rules/_find_status` as const; +export const DETECTION_ENGINE_RULE_EXECUTION_EVENTS_URL = + `${INTERNAL_DETECTION_ENGINE_URL}/rules/{ruleId}/execution/events` as const; +export const detectionEngineRuleExecutionEventsUrl = (ruleId: string) => + `${INTERNAL_DETECTION_ENGINE_URL}/rules/${ruleId}/execution/events` as const; export const TIMELINE_RESOLVE_URL = '/api/timeline/resolve' as const; export const TIMELINE_URL = '/api/timeline' as const; diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/rule_status/helpers.test.tsx b/x-pack/plugins/security_solution/common/detection_engine/schemas/common/index.ts similarity index 54% rename from x-pack/plugins/security_solution/public/detections/components/rules/rule_status/helpers.test.tsx rename to x-pack/plugins/security_solution/common/detection_engine/schemas/common/index.ts index bfc972d75fcc33..4ef5d6178d5a54 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/rule_status/helpers.test.tsx +++ b/x-pack/plugins/security_solution/common/detection_engine/schemas/common/index.ts @@ -5,10 +5,5 @@ * 2.0. */ -import { getStatusColor } from './helpers'; - -describe('rule_status helpers', () => { - it('getStatusColor returns subdued if null was provided', () => { - expect(getStatusColor(null)).toBe('subdued'); - }); -}); +export * from './rule_monitoring'; +export * from './schemas'; diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/common/rule_monitoring.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/common/rule_monitoring.ts new file mode 100644 index 00000000000000..afc6fad33a4bd7 --- /dev/null +++ b/x-pack/plugins/security_solution/common/detection_engine/schemas/common/rule_monitoring.ts @@ -0,0 +1,84 @@ +/* + * 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 * as t from 'io-ts'; +import { enumeration, IsoDateString, PositiveInteger } from '@kbn/securitysolution-io-ts-types'; + +// ------------------------------------------------------------------------------------------------- +// Rule execution status + +/** + * Custom execution status of Security rules that is different from the status + * used in the Alerting Framework. We merge our custom status with the + * Framework's status to determine the resulting status of a rule. + */ +export enum RuleExecutionStatus { + 'succeeded' = 'succeeded', + 'failed' = 'failed', + 'going to run' = 'going to run', + 'partial failure' = 'partial failure', + /** + * @deprecated 'partial failure' status should be used instead + */ + 'warning' = 'warning', +} + +export const ruleExecutionStatus = enumeration('RuleExecutionStatus', RuleExecutionStatus); + +export const ruleExecutionStatusOrder = PositiveInteger; +export type RuleExecutionStatusOrder = t.TypeOf; + +export const ruleExecutionStatusOrderByStatus: Record< + RuleExecutionStatus, + RuleExecutionStatusOrder +> = { + [RuleExecutionStatus.succeeded]: 0, + [RuleExecutionStatus['going to run']]: 10, + [RuleExecutionStatus.warning]: 20, + [RuleExecutionStatus['partial failure']]: 20, + [RuleExecutionStatus.failed]: 30, +}; + +// ------------------------------------------------------------------------------------------------- +// Rule execution metrics + +export const durationMetric = PositiveInteger; +export type DurationMetric = t.TypeOf; + +export const ruleExecutionMetrics = t.partial({ + total_search_duration_ms: durationMetric, + total_indexing_duration_ms: durationMetric, + execution_gap_duration_s: durationMetric, +}); + +export type RuleExecutionMetrics = t.TypeOf; + +// ------------------------------------------------------------------------------------------------- +// Rule execution summary + +export const ruleExecutionSummary = t.type({ + last_execution: t.type({ + date: IsoDateString, + status: ruleExecutionStatus, + status_order: ruleExecutionStatusOrder, + message: t.string, + metrics: ruleExecutionMetrics, + }), +}); + +export type RuleExecutionSummary = t.TypeOf; + +// ------------------------------------------------------------------------------------------------- +// Rule execution events + +export const ruleExecutionEvent = t.type({ + date: IsoDateString, + status: ruleExecutionStatus, + message: t.string, +}); + +export type RuleExecutionEvent = t.TypeOf; diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/common/schemas.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/common/schemas.ts index 7e4a4fd1295bd8..f063d14822c84b 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/common/schemas.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/schemas/common/schemas.ts @@ -193,19 +193,6 @@ export const status = t.keyof({ }); export type Status = t.TypeOf; -export enum RuleExecutionStatus { - 'succeeded' = 'succeeded', - 'failed' = 'failed', - 'going to run' = 'going to run', - 'partial failure' = 'partial failure', - /** - * @deprecated 'partial failure' status should be used instead - */ - 'warning' = 'warning', -} - -export const ruleExecutionStatus = enumeration('RuleExecutionStatus', RuleExecutionStatus); - export const conflicts = t.keyof({ abort: null, proceed: null }); export type Conflicts = t.TypeOf; @@ -332,30 +319,6 @@ export type UpdatedByOrNull = t.TypeOf; export const createdByOrNull = t.union([created_by, t.null]); export type CreatedByOrNull = t.TypeOf; -export const last_success_at = IsoDateString; -export type LastSuccessAt = t.TypeOf; - -export const last_success_message = t.string; -export type LastSuccessMessage = t.TypeOf; - -export const last_failure_at = IsoDateString; -export type LastFailureAt = t.TypeOf; - -export const last_failure_message = t.string; -export type LastFailureMessage = t.TypeOf; - -export const last_gap = t.string; -export type LastGap = t.TypeOf; - -export const bulk_create_time_durations = t.array(t.string); -export type BulkCreateTimeDurations = t.TypeOf; - -export const search_after_time_durations = t.array(t.string); -export type SearchAfterTimeDurations = t.TypeOf; - -export const status_date = IsoDateString; -export type StatusDate = t.TypeOf; - export const rules_installed = PositiveInteger; export const rules_updated = PositiveInteger; export const status_code = PositiveInteger; diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/find_rule_statuses_schema.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/find_rule_statuses_schema.ts deleted file mode 100644 index d489ad562f3043..00000000000000 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/find_rule_statuses_schema.ts +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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 * as t from 'io-ts'; - -export const findRulesStatusesSchema = t.exact( - t.type({ - ids: t.array(t.string), - }) -); - -export type FindRulesStatusesSchema = t.TypeOf; - -export type FindRulesStatusesSchemaDecoded = FindRulesStatusesSchema; - -export const findRuleStatusSchema = t.exact( - t.type({ - ruleId: t.string, - }) -); - -export type FindRuleStatusSchema = t.TypeOf; - -export type FindRuleStatusSchemaDecoded = FindRuleStatusSchema; diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/get_rule_execution_events_request.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/get_rule_execution_events_request.ts new file mode 100644 index 00000000000000..5e0e63ae7330dc --- /dev/null +++ b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/get_rule_execution_events_request.ts @@ -0,0 +1,18 @@ +/* + * 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 * as t from 'io-ts'; + +export const GetRuleExecutionEventsRequestParams = t.exact( + t.type({ + ruleId: t.string, + }) +); + +export type GetRuleExecutionEventsRequestParams = t.TypeOf< + typeof GetRuleExecutionEventsRequestParams +>; diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/rule_schemas.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/rule_schemas.ts index 64f6c9c32d4cbf..78ac7d6f1bbef8 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/request/rule_schemas.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/schemas/request/rule_schemas.ts @@ -64,17 +64,9 @@ import { updated_by, created_at, created_by, - ruleExecutionStatus, - status_date, - last_success_at, - last_success_message, - last_failure_at, - last_failure_message, namespace, - last_gap, - bulk_create_time_durations, - search_after_time_durations, -} from '../common/schemas'; + ruleExecutionSummary, +} from '../common'; export const createSchema = < Required extends t.Props, @@ -419,16 +411,9 @@ const responseRequiredFields = { created_at, created_by, }; + const responseOptionalFields = { - status: ruleExecutionStatus, - status_date, - last_success_at, - last_success_message, - last_failure_at, - last_failure_message, - last_gap, - bulk_create_time_durations, - search_after_time_durations, + execution_summary: ruleExecutionSummary, }; export const fullResponseSchema = t.intersection([ diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/response/get_rule_execution_events_response.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/response/get_rule_execution_events_response.ts new file mode 100644 index 00000000000000..9a732a46cbaba8 --- /dev/null +++ b/x-pack/plugins/security_solution/common/detection_engine/schemas/response/get_rule_execution_events_response.ts @@ -0,0 +1,17 @@ +/* + * 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 * as t from 'io-ts'; +import { ruleExecutionEvent } from '../common'; + +export const GetRuleExecutionEventsResponse = t.exact( + t.type({ + events: t.array(ruleExecutionEvent), + }) +); + +export type GetRuleExecutionEventsResponse = t.TypeOf; diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/response/index.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/response/index.ts index fa8ebaf597f47f..c30ea389fad767 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/response/index.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/schemas/response/index.ts @@ -6,6 +6,7 @@ */ export * from './error_schema'; +export * from './get_rule_execution_events_response'; export * from './import_rules_schema'; export * from './prepackaged_rules_schema'; export * from './prepackaged_rules_status_schema'; diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/response/rules_schema.mocks.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/response/rules_schema.mocks.ts index 5bbad750d997d6..5b25a1273ac379 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/response/rules_schema.mocks.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/schemas/response/rules_schema.mocks.ts @@ -6,7 +6,6 @@ */ import { DEFAULT_INDICATOR_SOURCE_PATH } from '../../../constants'; -import { RuleExecutionStatus } from '../common/schemas'; import { getListArrayMock } from '../types/lists.mock'; import { RulesSchema } from './rules_schema'; @@ -61,10 +60,6 @@ export const getRulesSchemaMock = (anchorDate: string = ANCHOR_DATE): RulesSchem type: 'query', threat: [], version: 1, - status: RuleExecutionStatus.succeeded, - status_date: '2020-02-22T16:47:50.047Z', - last_success_at: '2020-02-22T16:47:50.047Z', - last_success_message: 'succeeded', output_index: '.siem-signals-default', max_signals: 100, risk_score: 55, @@ -73,6 +68,16 @@ export const getRulesSchemaMock = (anchorDate: string = ANCHOR_DATE): RulesSchem rule_id: 'query-rule-id', interval: '5m', exceptions_list: getListArrayMock(), + // TODO: https://github.com/elastic/kibana/pull/121644 clean up + // execution_summary: { + // last_execution: { + // date: '2020-02-22T16:47:50.047Z', + // status: RuleExecutionStatus.succeeded, + // status_order: 0, + // message: 'succeeded', + // metrics: {}, + // }, + // }, }); export const getRulesMlSchemaMock = (anchorDate: string = ANCHOR_DATE): RulesSchema => { diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/response/rules_schema.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/response/rules_schema.ts index ac9329c3870f1a..1a6c86854f6ec0 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/response/rules_schema.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/schemas/response/rules_schema.ts @@ -62,12 +62,6 @@ import { timeline_id, timeline_title, threshold, - ruleExecutionStatus, - status_date, - last_success_at, - last_success_message, - last_failure_at, - last_failure_message, filters, meta, outcome, @@ -78,7 +72,8 @@ import { rule_name_override, timestamp_override, namespace, -} from '../common/schemas'; + ruleExecutionSummary, +} from '../common'; import { typeAndTimelineOnlySchema, TypeAndTimelineOnly } from './type_timeline_only_schema'; @@ -167,13 +162,7 @@ export const partialRulesSchema = t.partial({ license, throttle, rule_name_override, - status: ruleExecutionStatus, - status_date, timestamp_override, - last_success_at, - last_success_message, - last_failure_at, - last_failure_message, filters, meta, outcome, @@ -182,6 +171,7 @@ export const partialRulesSchema = t.partial({ namespace, note, uuid: id, // Move to 'required' post-migration + execution_summary: ruleExecutionSummary, }); /** diff --git a/x-pack/plugins/security_solution/common/detection_engine/utils.ts b/x-pack/plugins/security_solution/common/detection_engine/utils.ts index 8c6c3fdd961a8a..de5a05edc2f8a6 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/utils.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/utils.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { isEmpty, capitalize } from 'lodash'; +import { isEmpty } from 'lodash'; import type { EntriesArray, @@ -16,7 +16,7 @@ import type { import { Type } from '@kbn/securitysolution-io-ts-alerting-types'; import { hasLargeValueList } from '@kbn/securitysolution-list-utils'; -import { RuleExecutionStatus, Threshold, ThresholdNormalized } from './schemas/common/schemas'; +import { Threshold, ThresholdNormalized } from './schemas/common'; export const hasLargeValueItem = ( exceptionItems: Array @@ -64,20 +64,3 @@ export const normalizeThresholdObject = (threshold: Threshold): ThresholdNormali export const normalizeMachineLearningJobIds = (value: string | string[]): string[] => Array.isArray(value) ? value : [value]; - -export const getRuleStatusText = ( - value: RuleExecutionStatus | null | undefined -): RuleExecutionStatus | null => - value === RuleExecutionStatus['partial failure'] - ? RuleExecutionStatus.warning - : value != null - ? value - : null; - -export const getCapitalizedRuleStatusText = ( - value: RuleExecutionStatus | null | undefined -): string | null => { - const status = getRuleStatusText(value); - - return status != null ? capitalize(status) : null; -}; diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/rule_execution_status/index.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/rule_execution_status/index.tsx new file mode 100644 index 00000000000000..9178f154404fb7 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detections/components/rules/rule_execution_status/index.tsx @@ -0,0 +1,13 @@ +/* + * 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 * from './rule_status'; +export * from './rule_status_badge'; +export * from './rule_status_failed_callout'; + +// TODO: https://github.com/elastic/kibana/pull/121644 clean up +export * as ruleStatusI18n from './translations'; diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/rule_status/index.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/rule_execution_status/rule_status.tsx similarity index 62% rename from x-pack/plugins/security_solution/public/detections/components/rules/rule_status/index.tsx rename to x-pack/plugins/security_solution/public/detections/components/rules/rule_execution_status/rule_status.tsx index 5273cdd6d42712..026a81c3726f56 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/rule_status/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/rule_execution_status/rule_status.tsx @@ -5,38 +5,41 @@ * 2.0. */ +import React from 'react'; import { EuiFlexItem, EuiHealth, EuiText } from '@elastic/eui'; -import React, { memo } from 'react'; + +import { RuleExecutionStatus } from '../../../../../common/detection_engine/schemas/common'; import { FormattedDate } from '../../../../common/components/formatted_date'; import { getEmptyTagValue } from '../../../../common/components/empty_value'; -import { getStatusColor } from './helpers'; +import { getStatusColor, normalizeRuleExecutionStatus } from './utils'; import * as i18n from './translations'; -import { RuleExecutionStatus } from '../../../../../common/detection_engine/schemas/common/schemas'; interface RuleStatusProps { - children: React.ReactNode | null | undefined; - statusDate: string | null | undefined; status: RuleExecutionStatus | null | undefined; + date: string | null | undefined; + children: React.ReactNode | null | undefined; } -const RuleStatusComponent: React.FC = ({ children, statusDate, status }) => { +const RuleStatusComponent: React.FC = ({ status, date, children }) => { + const normalizedStatus = normalizeRuleExecutionStatus(status); + const statusColor = getStatusColor(normalizedStatus); return ( <> - + - {status ?? getEmptyTagValue()} + {normalizedStatus ?? getEmptyTagValue()} - {statusDate != null && status != null && ( + {date != null && normalizedStatus != null && ( <> <>{i18n.STATUS_AT} - + )} @@ -45,4 +48,5 @@ const RuleStatusComponent: React.FC = ({ children, statusDate, ); }; -export const RuleStatus = memo(RuleStatusComponent); +export const RuleStatus = React.memo(RuleStatusComponent); +RuleStatus.displayName = 'RuleStatus'; diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/rule_execution_status_badge/index.test.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/rule_execution_status/rule_status_badge.test.tsx similarity index 61% rename from x-pack/plugins/security_solution/public/detections/components/rules/rule_execution_status_badge/index.test.tsx rename to x-pack/plugins/security_solution/public/detections/components/rules/rule_execution_status/rule_status_badge.test.tsx index d57bfcb329a775..52a6c723fcbd6a 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/rule_execution_status_badge/index.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/rule_execution_status/rule_status_badge.test.tsx @@ -8,13 +8,12 @@ import React from 'react'; import { render, screen } from '@testing-library/react'; -import { RuleExecutionStatusBadge } from '.'; +import { RuleExecutionStatus } from '../../../../../common/detection_engine/schemas/common'; +import { RuleStatusBadge } from './rule_status_badge'; -import { RuleExecutionStatus } from '../../../../../common/detection_engine/schemas/common/schemas'; - -describe('Component RuleExecutionStatus', () => { - it('should render component correctly with capitalized status text', () => { - render(); +describe('RuleStatusBadge', () => { + it('renders capitalized status text', () => { + render(); expect(screen.getByText('Succeeded')).toBeInTheDocument(); }); diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/rule_execution_status_badge/index.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/rule_execution_status/rule_status_badge.tsx similarity index 53% rename from x-pack/plugins/security_solution/public/detections/components/rules/rule_execution_status_badge/index.tsx rename to x-pack/plugins/security_solution/public/detections/components/rules/rule_execution_status/rule_status_badge.tsx index 9203480716e48d..48e744172b6ae0 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/rule_execution_status_badge/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/rule_execution_status/rule_status_badge.tsx @@ -9,12 +9,11 @@ import React from 'react'; import { getEmptyTagValue } from '../../../../common/components/empty_value'; import { HealthTruncateText } from '../../../../common/components/health_truncate_text'; -import { getStatusColor } from '../rule_status/helpers'; +import { getCapitalizedRuleStatusText, getStatusColor } from './utils'; -import { getCapitalizedRuleStatusText } from '../../../../../common/detection_engine/utils'; -import type { RuleExecutionStatus } from '../../../../../common/detection_engine/schemas/common/schemas'; +import type { RuleExecutionStatus } from '../../../../../common/detection_engine/schemas/common'; -interface RuleExecutionStatusBadgeProps { +interface RuleStatusBadgeProps { status: RuleExecutionStatus | null | undefined; } @@ -22,19 +21,19 @@ interface RuleExecutionStatusBadgeProps { * Shows rule execution status * @param status - rule execution status */ -const RuleExecutionStatusBadgeComponent = ({ status }: RuleExecutionStatusBadgeProps) => { - const displayStatus = getCapitalizedRuleStatusText(status); +const RuleStatusBadgeComponent = ({ status }: RuleStatusBadgeProps) => { + const statusText = getCapitalizedRuleStatusText(status); + const statusColor = getStatusColor(status ?? null); return ( - {displayStatus ?? getEmptyTagValue()} + {statusText ?? getEmptyTagValue()} ); }; -export const RuleExecutionStatusBadge = React.memo(RuleExecutionStatusBadgeComponent); - -RuleExecutionStatusBadge.displayName = 'RuleExecutionStatusBadge'; +export const RuleStatusBadge = React.memo(RuleStatusBadgeComponent); +RuleStatusBadge.displayName = 'RuleStatusBadge'; diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/rule_execution_status/rule_status_failed_callout.test.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/rule_execution_status/rule_status_failed_callout.test.tsx new file mode 100644 index 00000000000000..562d0f4df98721 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detections/components/rules/rule_execution_status/rule_status_failed_callout.test.tsx @@ -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 React from 'react'; +import { shallow } from 'enzyme'; + +import { RuleExecutionStatus } from '../../../../../common/detection_engine/schemas/common'; +import { RuleStatusFailedCallOut } from './rule_status_failed_callout'; + +// TODO: https://github.com/elastic/kibana/pull/121644 clean up +// - switch to react testing library +// - test actual content being rendered +describe('RuleStatusFailedCallOut', () => { + describe('Visibility conditions', () => { + const renderWith = (status: RuleExecutionStatus | null | undefined) => + shallow(); + + it('is hidden if status is undefined', () => { + const wrapper = renderWith(undefined); + expect(wrapper.find('EuiCallOut')).toHaveLength(0); + }); + + it('is hidden if status is null', () => { + const wrapper = renderWith(null); + expect(wrapper.find('EuiCallOut')).toHaveLength(0); + }); + + it('is hidden if status is "going to run"', () => { + const wrapper = renderWith(RuleExecutionStatus['going to run']); + expect(wrapper.find('EuiCallOut')).toHaveLength(0); + }); + + it('is hidden if status is "succeeded"', () => { + const wrapper = renderWith(RuleExecutionStatus.succeeded); + expect(wrapper.find('EuiCallOut')).toHaveLength(0); + }); + + it('is visible if status is "warning"', () => { + const wrapper = renderWith(RuleExecutionStatus.warning); + expect(wrapper.find('EuiCallOut')).toHaveLength(1); + }); + + it('is visible if status is "partial failure"', () => { + const wrapper = renderWith(RuleExecutionStatus['partial failure']); + expect(wrapper.find('EuiCallOut')).toHaveLength(1); + }); + + it('is visible if status is "failed"', () => { + const wrapper = renderWith(RuleExecutionStatus.failed); + expect(wrapper.find('EuiCallOut')).toHaveLength(1); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/rule_execution_status/rule_status_failed_callout.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/rule_execution_status/rule_status_failed_callout.tsx new file mode 100644 index 00000000000000..474ce6ac0ffe09 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detections/components/rules/rule_execution_status/rule_status_failed_callout.tsx @@ -0,0 +1,81 @@ +/* + * 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 React from 'react'; + +import { EuiCallOut, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import { FormattedDate } from '../../../../common/components/formatted_date'; + +import { RuleExecutionStatus } from '../../../../../common/detection_engine/schemas/common'; +import { normalizeRuleExecutionStatus } from './utils'; + +import * as i18n from './translations'; + +interface RuleStatusFailedCallOutProps { + date: string; + message: string; + status?: RuleExecutionStatus | null; +} + +const RuleStatusFailedCallOutComponent: React.FC = ({ + date, + message, + status, +}) => { + // TODO: https://github.com/elastic/kibana/pull/121644 clean up + const props = getPropsByStatus(status); + if (!props) { + // we will not show this callout for this status + return null; + } + + return ( + + {props.title} + + + + + } + color={props.color} + iconType="alert" + > +

{message}

+
+ ); +}; + +export const RuleStatusFailedCallOut = React.memo(RuleStatusFailedCallOutComponent); +RuleStatusFailedCallOut.displayName = 'RuleStatusFailedCallOut'; + +// ------------------------------------------------------------------------------------------------- +// Helpers + +interface HelperProps { + color: 'danger' | 'warning'; + title: string; +} + +const getPropsByStatus = (status: RuleExecutionStatus | null | undefined): HelperProps | null => { + const normalizedStatus = normalizeRuleExecutionStatus(status); + switch (normalizedStatus) { + case RuleExecutionStatus.failed: + return { + color: 'danger', + title: i18n.ERROR_CALLOUT_TITLE, + }; + case RuleExecutionStatus.warning: + return { + color: 'warning', + title: i18n.PARTIAL_FAILURE_CALLOUT_TITLE, + }; + default: + return null; + } +}; diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/rule_status/translations.ts b/x-pack/plugins/security_solution/public/detections/components/rules/rule_execution_status/translations.ts similarity index 71% rename from x-pack/plugins/security_solution/public/detections/components/rules/rule_status/translations.ts rename to x-pack/plugins/security_solution/public/detections/components/rules/rule_execution_status/translations.ts index b4c5475f9ed840..e2a1e566813a3a 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/rule_status/translations.ts +++ b/x-pack/plugins/security_solution/public/detections/components/rules/rule_execution_status/translations.ts @@ -34,3 +34,17 @@ export const REFRESH = i18n.translate( defaultMessage: 'Refresh', } ); + +export const ERROR_CALLOUT_TITLE = i18n.translate( + 'xpack.securitySolution.detectionEngine.ruleStatus.errorCalloutTitle', + { + defaultMessage: 'Rule failure at', + } +); + +export const PARTIAL_FAILURE_CALLOUT_TITLE = i18n.translate( + 'xpack.securitySolution.detectionEngine.ruleStatus.partialErrorCalloutTitle', + { + defaultMessage: 'Warning at', + } +); diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/rule_execution_status/utils.test.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/rule_execution_status/utils.test.tsx new file mode 100644 index 00000000000000..d2bbe11bafabe9 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detections/components/rules/rule_execution_status/utils.test.tsx @@ -0,0 +1,16 @@ +/* + * 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 { getStatusColor } from './utils'; + +describe('Rule execution status utils', () => { + describe('getStatusColor', () => { + it('returns "subdued" if null was provided', () => { + expect(getStatusColor(null)).toBe('subdued'); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/rule_status/helpers.ts b/x-pack/plugins/security_solution/public/detections/components/rules/rule_execution_status/utils.ts similarity index 55% rename from x-pack/plugins/security_solution/public/detections/components/rules/rule_status/helpers.ts rename to x-pack/plugins/security_solution/public/detections/components/rules/rule_execution_status/utils.ts index 13381b350761ba..5f68f6634fff74 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/rule_status/helpers.ts +++ b/x-pack/plugins/security_solution/public/detections/components/rules/rule_execution_status/utils.ts @@ -5,7 +5,24 @@ * 2.0. */ -import { RuleExecutionStatus } from '../../../../../common/detection_engine/schemas/common/schemas'; +import { capitalize } from 'lodash'; +import { RuleExecutionStatus } from '../../../../../common/detection_engine/schemas/common'; + +export const normalizeRuleExecutionStatus = ( + value: RuleExecutionStatus | null | undefined +): RuleExecutionStatus | null => + value === RuleExecutionStatus['partial failure'] + ? RuleExecutionStatus.warning + : value != null + ? value + : null; + +export const getCapitalizedRuleStatusText = ( + value: RuleExecutionStatus | null | undefined +): string | null => { + const status = normalizeRuleExecutionStatus(value); + return status != null ? capitalize(status) : null; +}; export const getStatusColor = (status: RuleExecutionStatus | string | null) => status == null diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/__mocks__/api.ts b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/__mocks__/api.ts index 90e972ef90f5b1..6f01001b3f957d 100644 --- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/__mocks__/api.ts +++ b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/__mocks__/api.ts @@ -5,22 +5,26 @@ * 2.0. */ +import { RuleExecutionStatus } from '../../../../../../common/detection_engine/schemas/common'; +import { + GetRuleExecutionEventsResponse, + RulesSchema, +} from '../../../../../../common/detection_engine/schemas/response'; + +import { getRulesSchemaMock } from '../../../../../../common/detection_engine/schemas/response/rules_schema.mocks'; +import { savedRuleMock, rulesMock } from '../mock'; + import { PatchRuleProps, CreateRulesProps, UpdateRulesProps, PrePackagedRulesStatusResponse, BasicFetchProps, - RuleStatusResponse, Rule, FetchRuleProps, FetchRulesResponse, FetchRulesProps, } from '../types'; -import { savedRuleMock, rulesMock } from '../mock'; -import { getRulesSchemaMock } from '../../../../../../common/detection_engine/schemas/response/rules_schema.mocks'; -import { RulesSchema } from '../../../../../../common/detection_engine/schemas/response'; -import { RuleExecutionStatus } from '../../../../../../common/detection_engine/schemas/common/schemas'; export const updateRule = async ({ rule, signal }: UpdateRulesProps): Promise => Promise.resolve(getRulesSchemaMock()); @@ -49,58 +53,6 @@ export const getPrePackagedRulesStatus = async ({ export const createPrepackagedRules = async ({ signal }: BasicFetchProps): Promise => Promise.resolve(true); -export const getRuleStatusById = async ({ - id, - signal, -}: { - id: string; - signal: AbortSignal; -}): Promise => - Promise.resolve({ - myOwnRuleID: { - current_status: { - alert_id: 'alertId', - status_date: 'mm/dd/yyyyTHH:MM:sssz', - status: RuleExecutionStatus.succeeded, - last_failure_at: null, - last_success_at: 'mm/dd/yyyyTHH:MM:sssz', - last_failure_message: null, - last_success_message: 'it is a success', - gap: null, - bulk_create_time_durations: ['2235.01'], - search_after_time_durations: ['616.97'], - last_look_back_date: '2020-03-19T00:32:07.996Z', // NOTE: This is no longer used on the UI, but left here in case users are using it within the API - }, - failures: [], - }, - }); - -export const getRulesStatusByIds = async ({ - ids, - signal, -}: { - ids: string[]; - signal: AbortSignal; -}): Promise => - Promise.resolve({ - '12345678987654321': { - current_status: { - alert_id: 'alertId', - status_date: 'mm/dd/yyyyTHH:MM:sssz', - status: RuleExecutionStatus.succeeded, - last_failure_at: null, - last_success_at: 'mm/dd/yyyyTHH:MM:sssz', - last_failure_message: null, - last_success_message: 'it is a success', - gap: null, - bulk_create_time_durations: ['2235.01'], - search_after_time_durations: ['616.97'], - last_look_back_date: '2020-03-19T00:32:07.996Z', // NOTE: This is no longer used on the UI, but left here in case users are using it within the API - }, - failures: [], - }, - }); - export const fetchRuleById = jest.fn( async ({ id, signal }: FetchRuleProps): Promise => savedRuleMock ); @@ -122,5 +74,23 @@ export const fetchRules = async ({ signal, }: FetchRulesProps): Promise => Promise.resolve(rulesMock); +export const fetchRuleExecutionEvents = async ({ + ruleId, + signal, +}: { + ruleId: string; + signal?: AbortSignal; +}): Promise => { + return Promise.resolve({ + events: [ + { + date: '2021-12-29T10:42:59.996Z', + status: RuleExecutionStatus.succeeded, + message: 'Rule executed successfully', + }, + ], + }); +}; + export const fetchTags = async ({ signal }: { signal: AbortSignal }): Promise => Promise.resolve(['elastic', 'love', 'quality', 'code']); diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/api.test.ts b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/api.test.ts index ef9120aa829e34..3591d49b66b405 100644 --- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/api.test.ts +++ b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/api.test.ts @@ -18,7 +18,7 @@ import { createPrepackagedRules, importRules, exportRules, - getRuleStatusById, + fetchRuleExecutionEvents, fetchTags, getPrePackagedRulesStatus, previewRule, @@ -655,39 +655,32 @@ describe('Detections Rules API', () => { }); }); - describe('getRuleStatusById', () => { - const statusMock = { - myRule: { - current_status: { - alert_id: 'alertId', - status_date: 'mm/dd/yyyyTHH:MM:sssz', - status: 'succeeded', - last_failure_at: null, - last_success_at: 'mm/dd/yyyyTHH:MM:sssz', - last_failure_message: null, - last_success_message: 'it is a success', - }, - failures: [], - }, + // TODO: https://github.com/elastic/kibana/pull/121644 clean up + describe('fetchRuleExecutionEvents', () => { + const responseMock = { + dummy: 'response', }; beforeEach(() => { fetchMock.mockClear(); - fetchMock.mockResolvedValue(statusMock); + fetchMock.mockResolvedValue(responseMock); }); - test('check parameter url, query', async () => { - await getRuleStatusById({ id: 'mySuperRuleId', signal: abortCtrl.signal }); - expect(fetchMock).toHaveBeenCalledWith('/internal/detection_engine/rules/_find_status', { - body: '{"ruleId":"mySuperRuleId"}', - method: 'POST', - signal: abortCtrl.signal, - }); + test('calls API with correct parameters', async () => { + await fetchRuleExecutionEvents({ ruleId: '42', signal: abortCtrl.signal }); + + expect(fetchMock).toHaveBeenCalledWith( + '/internal/detection_engine/rules/42/execution/events', + { + method: 'GET', + signal: abortCtrl.signal, + } + ); }); - test('happy path', async () => { - const ruleResp = await getRuleStatusById({ id: 'mySuperRuleId', signal: abortCtrl.signal }); - expect(ruleResp).toEqual(statusMock); + test('returns API response as is', async () => { + const response = await fetchRuleExecutionEvents({ ruleId: '42', signal: abortCtrl.signal }); + expect(response).toEqual(responseMock); }); }); diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/api.ts b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/api.ts index 6444969e123ad4..6ff9b2a2884523 100644 --- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/api.ts +++ b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/api.ts @@ -6,11 +6,8 @@ */ import { camelCase } from 'lodash'; -import { - FullResponseSchema, - PreviewResponse, -} from '../../../../../common/detection_engine/schemas/request'; -import { HttpStart } from '../../../../../../../../src/core/public'; +import { HttpStart } from 'src/core/public'; + import { DETECTION_ENGINE_RULES_URL, DETECTION_ENGINE_PREPACKAGED_URL, @@ -18,8 +15,18 @@ import { DETECTION_ENGINE_TAGS_URL, DETECTION_ENGINE_RULES_BULK_ACTION, DETECTION_ENGINE_RULES_PREVIEW, - INTERNAL_DETECTION_ENGINE_RULE_STATUS_URL, + detectionEngineRuleExecutionEventsUrl, } from '../../../../../common/constants'; +import { BulkAction } from '../../../../../common/detection_engine/schemas/common'; +import { + FullResponseSchema, + PreviewResponse, +} from '../../../../../common/detection_engine/schemas/request'; +import { + RulesSchema, + GetRuleExecutionEventsResponse, +} from '../../../../../common/detection_engine/schemas/response'; + import { UpdateRulesProps, CreateRulesProps, @@ -33,7 +40,6 @@ import { BasicFetchProps, ImportDataProps, ExportDocumentsProps, - RuleStatusResponse, ImportDataResponse, PrePackagedRulesStatusResponse, BulkRuleResponse, @@ -44,9 +50,7 @@ import { } from './types'; import { KibanaServices } from '../../../../common/lib/kibana'; import * as i18n from '../../../pages/detection_engine/rules/translations'; -import { RulesSchema } from '../../../../../common/detection_engine/schemas/response'; import { convertRulesFilterToKQL } from './utils'; -import { BulkAction } from '../../../../../common/detection_engine/schemas/common/schemas'; /** * Create provided Rule @@ -241,15 +245,7 @@ export const duplicateRules = async ({ rules }: DuplicateRulesProps): Promise => - KibanaServices.get().http.fetch(INTERNAL_DETECTION_ENGINE_RULE_STATUS_URL, { - method: 'POST', - body: JSON.stringify({ ruleId: id }), + ruleId: string; + signal?: AbortSignal; +}): Promise => { + const url = detectionEngineRuleExecutionEventsUrl(ruleId); + return KibanaServices.get().http.fetch(url, { + method: 'GET', signal, }); +}; /** * Fetch all unique Tags used by Rules diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/index.ts b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/index.ts index 8128eb045f759d..435a1e6ef073bd 100644 --- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/index.ts +++ b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/index.ts @@ -12,4 +12,4 @@ export * from './types'; export * from './use_rule'; export * from './rules_table'; export * from './use_pre_packaged_rules'; -export * from './use_rule_status'; +export * from './use_rule_execution_events'; diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/types.ts b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/types.ts index 2507d5a9596b62..9aecab3d06a021 100644 --- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/types.ts +++ b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/types.ts @@ -30,9 +30,8 @@ import { timestamp_override, threshold, BulkAction, - ruleExecutionStatus, - RuleExecutionStatus, -} from '../../../../../common/detection_engine/schemas/common/schemas'; + ruleExecutionSummary, +} from '../../../../../common/detection_engine/schemas/common'; import { CreateRulesSchema, PatchRulesSchema, @@ -122,21 +121,12 @@ export const RuleSchema = t.intersection([ index: t.array(t.string), language: t.string, license, - last_failure_at: t.string, - last_failure_message: t.string, - last_success_message: t.string, - last_success_at: t.string, - last_gap: t.string, - bulk_create_time_durations: t.array(t.string), - search_after_time_durations: t.array(t.string), meta: MetaRule, machine_learning_job_id: t.array(t.string), output_index: t.string, query: t.string, rule_name_override, saved_id: t.string, - status: ruleExecutionStatus, - status_date: t.string, threshold, threat_query, threat_filters, @@ -151,6 +141,8 @@ export const RuleSchema = t.intersection([ exceptions_list: listArray, uuid: t.string, version: t.number, + // TODO: https://github.com/elastic/kibana/pull/121644 clean up + execution_summary: ruleExecutionSummary, }), ]); @@ -291,26 +283,6 @@ export interface ExportDocumentsProps { signal?: AbortSignal; } -export interface RuleStatus { - current_status: RuleInfoStatus; - failures: RuleInfoStatus[]; -} -export interface RuleInfoStatus { - alert_id: string; - status_date: string; - status: RuleExecutionStatus | null; - last_failure_at: string | null; - last_success_at: string | null; - last_failure_message: string | null; - last_success_message: string | null; - last_look_back_date: string | null | undefined; // NOTE: This is no longer used on the UI, but left here in case users are using it within the API - gap: string | null | undefined; - bulk_create_time_durations: string[] | null | undefined; - search_after_time_durations: string[] | null | undefined; -} - -export type RuleStatusResponse = Record; - export interface PrePackagedRulesStatusResponse { rules_custom_installed: number; rules_installed: number; diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rule_execution_events.test.tsx b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rule_execution_events.test.tsx new file mode 100644 index 00000000000000..2036c79d3f80c2 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rule_execution_events.test.tsx @@ -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 React from 'react'; +import { QueryClient, QueryClientProvider } from 'react-query'; +import { renderHook, cleanup } from '@testing-library/react-hooks'; + +import { RuleExecutionStatus } from '../../../../../common/detection_engine/schemas/common'; +import { useAppToastsMock } from '../../../../common/hooks/use_app_toasts.mock'; +import { useAppToasts } from '../../../../common/hooks/use_app_toasts'; +import { useRuleExecutionEvents } from './use_rule_execution_events'; + +import * as api from './api'; + +jest.mock('./api'); +jest.mock('../../../../common/hooks/use_app_toasts'); + +// TODO: https://github.com/elastic/kibana/pull/121644 clean up +describe('useRuleExecutionEvents', () => { + (useAppToasts as jest.Mock).mockReturnValue(useAppToastsMock.create()); + + beforeEach(() => { + jest.clearAllMocks(); + }); + + afterEach(async () => { + cleanup(); + }); + + it('fetches data from the API (via fetchRuleExecutionEvents)', async () => { + const fetchRuleExecutionEvents = jest.spyOn(api, 'fetchRuleExecutionEvents'); + const queryClient = new QueryClient(); + const wrapper: React.FC = ({ children }) => ( + {children} + ); + + const { result, waitFor } = renderHook(() => useRuleExecutionEvents('some rule ID'), { + wrapper, + }); + + await waitFor(() => result.current.isSuccess); + + expect(fetchRuleExecutionEvents).toHaveBeenCalledTimes(1); + expect(result.current.isLoading).toEqual(false); + expect(result.current.data).toEqual([ + { + date: '2021-12-29T10:42:59.996Z', + status: RuleExecutionStatus.succeeded, + message: 'Rule executed successfully', + }, + ]); + }); +}); diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rule_execution_events.tsx b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rule_execution_events.tsx new file mode 100644 index 00000000000000..8cbb9cb3e9ceb9 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rule_execution_events.tsx @@ -0,0 +1,31 @@ +/* + * 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 { useQuery } from 'react-query'; +import { useAppToasts } from '../../../../common/hooks/use_app_toasts'; +import { fetchRuleExecutionEvents } from './api'; +import * as i18n from './translations'; + +// TODO: https://github.com/elastic/kibana/pull/121644 clean up +export const useRuleExecutionEvents = (ruleId: string) => { + const { addError } = useAppToasts(); + + return useQuery( + 'ruleExecutionEvents', + async ({ signal }) => { + const response = await fetchRuleExecutionEvents({ ruleId, signal }); + return response.events; + }, + { + onError: (e) => { + // TODO: Should it be responsible for showing toasts? + // TODO: Change the title + addError(e, { title: i18n.RULE_AND_TIMELINE_FETCH_FAILURE }); + }, + } + ); +}; diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rule_status.test.tsx b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rule_status.test.tsx deleted file mode 100644 index 73b05f94153e6c..00000000000000 --- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rule_status.test.tsx +++ /dev/null @@ -1,85 +0,0 @@ -/* - * 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 { renderHook, act, cleanup } from '@testing-library/react-hooks'; -import { useRuleStatus, ReturnRuleStatus } from './use_rule_status'; -import * as api from './api'; -import { useAppToastsMock } from '../../../../common/hooks/use_app_toasts.mock'; -import { useAppToasts } from '../../../../common/hooks/use_app_toasts'; - -jest.mock('./api'); -jest.mock('../../../../common/hooks/use_app_toasts'); - -describe('useRuleStatus', () => { - (useAppToasts as jest.Mock).mockReturnValue(useAppToastsMock.create()); - - beforeEach(() => { - jest.clearAllMocks(); - }); - - afterEach(async () => { - cleanup(); - }); - - describe('useRuleStatus', () => { - test('init', async () => { - await act(async () => { - const { result, waitForNextUpdate } = renderHook(() => - useRuleStatus('myOwnRuleID') - ); - await waitForNextUpdate(); - expect(result.current).toEqual([true, null, null]); - }); - }); - - test('fetch rule status', async () => { - await act(async () => { - const { result, waitForNextUpdate } = renderHook(() => - useRuleStatus('myOwnRuleID') - ); - await waitForNextUpdate(); - await waitForNextUpdate(); - expect(result.current).toEqual([ - false, - { - current_status: { - alert_id: 'alertId', - last_failure_at: null, - last_failure_message: null, - last_success_at: 'mm/dd/yyyyTHH:MM:sssz', - last_success_message: 'it is a success', - status: 'succeeded', - status_date: 'mm/dd/yyyyTHH:MM:sssz', - gap: null, - bulk_create_time_durations: ['2235.01'], - search_after_time_durations: ['616.97'], - last_look_back_date: '2020-03-19T00:32:07.996Z', // NOTE: This is no longer used on the UI, but left here in case users are using it within the API - }, - failures: [], - }, - result.current[2], - ]); - }); - }); - - test('re-fetch rule status', async () => { - const spyOngetRuleStatusById = jest.spyOn(api, 'getRuleStatusById'); - await act(async () => { - const { result, waitForNextUpdate } = renderHook(() => - useRuleStatus('myOwnRuleID') - ); - await waitForNextUpdate(); - await waitForNextUpdate(); - if (result.current[2]) { - result.current[2]('myOwnRuleID'); - } - await waitForNextUpdate(); - expect(spyOngetRuleStatusById).toHaveBeenCalledTimes(2); - }); - }); - }); -}); diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rule_status.tsx b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rule_status.tsx deleted file mode 100644 index 815ed261c490fa..00000000000000 --- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rule_status.tsx +++ /dev/null @@ -1,67 +0,0 @@ -/* - * 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 { useEffect, useRef, useState } from 'react'; -import { isNotFoundError } from '@kbn/securitysolution-t-grid'; -import { useAppToasts } from '../../../../common/hooks/use_app_toasts'; - -import { getRuleStatusById } from './api'; -import * as i18n from './translations'; -import { RuleStatus } from './types'; - -type Func = (ruleId: string) => void; -export type ReturnRuleStatus = [boolean, RuleStatus | null, Func | null]; - -/** - * Hook for using to get a Rule from the Detection Engine API - * - * @param id desired Rule ID's (not rule_id) - * - */ -export const useRuleStatus = (id: string | undefined | null): ReturnRuleStatus => { - const [ruleStatus, setRuleStatus] = useState(null); - const fetchRuleStatus = useRef(null); - const [loading, setLoading] = useState(true); - const { addError } = useAppToasts(); - - useEffect(() => { - let isSubscribed = true; - const abortCtrl = new AbortController(); - - const fetchData = async (idToFetch: string) => { - try { - setLoading(true); - const ruleStatusResponse = await getRuleStatusById({ - id: idToFetch, - signal: abortCtrl.signal, - }); - - if (isSubscribed) { - setRuleStatus(ruleStatusResponse[id ?? '']); - } - } catch (error) { - if (isSubscribed && !isNotFoundError(error)) { - setRuleStatus(null); - addError(error, { title: i18n.RULE_AND_TIMELINE_FETCH_FAILURE }); - } - } - if (isSubscribed) { - setLoading(false); - } - }; - if (id != null) { - fetchData(id); - } - fetchRuleStatus.current = fetchData; - return () => { - isSubscribed = false; - abortCtrl.abort(); - }; - }, [id, addError]); - - return [loading, ruleStatus, fetchRuleStatus.current]; -}; diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/columns.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/columns.tsx index f1771e6f44dddd..d03e61334b728d 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/columns.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/columns.tsx @@ -5,6 +5,7 @@ * 2.0. */ +import React, { Dispatch } from 'react'; import { EuiBasicTableColumn, EuiTableActionsColumnType, @@ -14,9 +15,11 @@ import { EuiBadge, } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; -import { sum } from 'lodash'; -import React, { Dispatch } from 'react'; +import { + RuleExecutionSummary, + DurationMetric, +} from '../../../../../../common/detection_engine/schemas/common'; import { isMlRule } from '../../../../../../common/machine_learning/helpers'; import { Rule } from '../../../../containers/detection_engine/rules'; import { getEmptyTagValue } from '../../../../../common/components/empty_value'; @@ -26,7 +29,7 @@ import { ActionToaster } from '../../../../../common/components/toasters'; import { PopoverItems } from '../../../../../common/components/popover_items'; import { RuleSwitch } from '../../../../components/rules/rule_switch'; import { SeverityBadge } from '../../../../components/rules/severity_badge'; -import { RuleExecutionStatusBadge } from '../../../../components/rules/rule_execution_status_badge'; +import { RuleStatusBadge } from '../../../../components/rules/rule_execution_status'; import * as i18n from '../translations'; import { deleteRulesAction, @@ -271,9 +274,9 @@ export const getRulesColumns = (columnsProps: GetColumnsProps): TableColumn[] => truncateText: true, }, { - field: 'status_date', + field: 'execution_summary.last_execution.date', name: i18n.COLUMN_LAST_COMPLETE_RUN, - render: (value: Rule['status_date']) => { + render: (value: RuleExecutionSummary['last_execution']['date'] | undefined) => { return value == null ? ( getEmptyTagValue() ) : ( @@ -289,9 +292,11 @@ export const getRulesColumns = (columnsProps: GetColumnsProps): TableColumn[] => truncateText: true, }, { - field: 'status', + field: 'execution_summary.last_execution.status', name: i18n.COLUMN_LAST_RESPONSE, - render: (value: Rule['status']) => , + render: (value: RuleExecutionSummary['last_execution']['status'] | undefined) => ( + + ), width: '16%', truncateText: true, }, @@ -340,39 +345,39 @@ export const getMonitoringColumns = (columnsProps: GetColumnsProps): TableColumn { ...getColumnRuleName(columnsProps), width: '28%' }, getColumnTags(), { - field: 'bulk_create_time_durations', + field: 'execution_summary.last_execution.metrics.total_indexing_duration_ms', name: ( ), - render: (value: Rule['bulk_create_time_durations'] | undefined) => ( - - {value?.length ? sum(value.map(Number)).toFixed() : getEmptyTagValue()} + render: (value: DurationMetric | undefined) => ( + + {value != null ? value.toFixed() : getEmptyTagValue()} ), width: '16%', truncateText: true, }, { - field: 'search_after_time_durations', + field: 'execution_summary.last_execution.metrics.total_search_duration_ms', name: ( ), - render: (value: Rule['search_after_time_durations'] | undefined) => ( - - {value?.length ? sum(value.map(Number)).toFixed() : getEmptyTagValue()} + render: (value: DurationMetric | undefined) => ( + + {value != null ? value.toFixed() : getEmptyTagValue()} ), width: '14%', truncateText: true, }, { - field: 'last_gap', + field: 'execution_summary.last_execution.metrics.execution_gap_duration_s', name: ( ), - render: (value: Rule['last_gap'] | undefined) => ( + render: (value: DurationMetric | undefined) => ( - {value ?? getEmptyTagValue()} + {value != null ? value.toFixed() : getEmptyTagValue()} ), width: '14%', truncateText: true, }, { - field: 'status', + field: 'execution_summary.last_execution.status', name: i18n.COLUMN_LAST_RESPONSE, - render: (value: Rule['status'] | undefined) => , + render: (value: RuleExecutionSummary['last_execution']['status'] | undefined) => ( + + ), width: '12%', truncateText: true, }, { - field: 'status_date', + field: 'execution_summary.last_execution.date', name: i18n.COLUMN_LAST_COMPLETE_RUN, - render: (value: Rule['status_date'] | undefined) => { + render: (value: RuleExecutionSummary['last_execution']['date'] | undefined) => { return value == null ? ( getEmptyTagValue() ) : ( diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/failure_history.test.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/failure_history.test.tsx deleted file mode 100644 index c91aade50cbaea..00000000000000 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/failure_history.test.tsx +++ /dev/null @@ -1,88 +0,0 @@ -/* - * 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 React from 'react'; -import { shallow, mount } from 'enzyme'; -import { - TestProviders, - createSecuritySolutionStorageMock, - kibanaObservable, - mockGlobalState, - SUB_PLUGINS_REDUCER, -} from '../../../../../common/mock'; -import { FailureHistory } from './failure_history'; -import { useRuleStatus } from '../../../../containers/detection_engine/rules'; -jest.mock('../../../../containers/detection_engine/rules'); - -import { waitFor } from '@testing-library/react'; - -import '../../../../../common/mock/match_media'; - -import { createStore, State } from '../../../../../common/store'; -import { mockHistory, Router } from '../../../../../common/mock/router'; - -const state: State = { - ...mockGlobalState, -}; -const { storage } = createSecuritySolutionStorageMock(); -const store = createStore(state, SUB_PLUGINS_REDUCER, kibanaObservable, storage); - -describe('RuleDetailsPageComponent', () => { - beforeAll(() => { - (useRuleStatus as jest.Mock).mockReturnValue([ - false, - { - status: 'succeeded', - last_failure_at: new Date().toISOString(), - last_failure_message: 'my fake failure message', - failures: [ - { - alert_id: 'myfakeid', - status_date: new Date().toISOString(), - status: 'failed', - last_failure_at: new Date().toISOString(), - last_success_at: new Date().toISOString(), - last_failure_message: 'my fake failure message', - last_look_back_date: new Date().toISOString(), // NOTE: This is no longer used on the UI, but left here in case users are using it within the API - }, - ], - }, - ]); - }); - - it('renders reported rule failures correctly', async () => { - const wrapper = mount( - - - - - - ); - - await waitFor(() => { - expect(wrapper.find('EuiBasicTable')).toHaveLength(1); - // ensure the expected error message is displayed in the table - expect(wrapper.find('EuiTableRowCell').at(2).find('div').at(1).text()).toEqual( - 'my fake failure message' - ); - }); - }); -}); - -describe('FailureHistory', () => { - beforeAll(() => { - (useRuleStatus as jest.Mock).mockReturnValue([false, null]); - }); - - it('renders correctly with no statuses', () => { - const wrapper = shallow(, { - wrappingComponent: TestProviders, - }); - - expect(wrapper.find('EuiBasicTable')).toHaveLength(1); - }); -}); diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/failure_history.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/failure_history.tsx index 5289e34b100466..62992d5d189c1b 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/failure_history.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/failure_history.tsx @@ -5,6 +5,7 @@ * 2.0. */ +import React from 'react'; import { EuiBasicTable, EuiPanel, @@ -12,25 +13,48 @@ import { EuiHealth, EuiBasicTableColumn, } from '@elastic/eui'; -import React, { memo } from 'react'; -import { useRuleStatus, RuleInfoStatus } from '../../../../containers/detection_engine/rules'; +import { RuleExecutionEvent } from '../../../../../../common/detection_engine/schemas/common'; +import { useRuleExecutionEvents } from '../../../../containers/detection_engine/rules'; import { HeaderSection } from '../../../../../common/components/header_section'; import * as i18n from './translations'; import { FormattedDate } from '../../../../../common/components/formatted_date'; +// TODO: https://github.com/elastic/kibana/pull/121644 clean up +const columns: Array> = [ + { + name: i18n.COLUMN_STATUS_TYPE, + render: () => {i18n.TYPE_FAILED}, + truncateText: false, + width: '16%', + }, + { + field: 'date', + name: i18n.COLUMN_FAILED_AT, + render: (value: string) => , + sortable: false, + truncateText: false, + width: '24%', + }, + { + field: 'message', + name: i18n.COLUMN_FAILED_MSG, + render: (value: string) => <>{value}, + sortable: false, + truncateText: false, + width: '60%', + }, +]; + interface FailureHistoryProps { - id?: string | null; + ruleId: string; } -const renderStatus = () => {i18n.TYPE_FAILED}; -const renderLastFailureAt = (value: string) => ( - -); -const renderLastFailureMessage = (value: string) => <>{value}; +const FailureHistoryComponent: React.FC = ({ ruleId }) => { + const events = useRuleExecutionEvents(ruleId); + const loading = events.isLoading; + const items = events.data ?? []; -const FailureHistoryComponent: React.FC = ({ id }) => { - const [loading, ruleStatus] = useRuleStatus(id); if (loading) { return ( @@ -39,43 +63,19 @@ const FailureHistoryComponent: React.FC = ({ id }) => { ); } - const columns: Array> = [ - { - name: i18n.COLUMN_STATUS_TYPE, - render: renderStatus, - truncateText: false, - width: '16%', - }, - { - field: 'last_failure_at', - name: i18n.COLUMN_FAILED_AT, - render: renderLastFailureAt, - sortable: false, - truncateText: false, - width: '24%', - }, - { - field: 'last_failure_message', - name: i18n.COLUMN_FAILED_MSG, - render: renderLastFailureMessage, - sortable: false, - truncateText: false, - width: '60%', - }, - ]; + return ( rs.last_failure_at != null) : [] - } - sorting={{ sort: { field: 'status_date', direction: 'desc' } }} + sorting={{ sort: { field: 'date', direction: 'desc' } }} /> ); }; -export const FailureHistory = memo(FailureHistoryComponent); +export const FailureHistory = React.memo(FailureHistoryComponent); +FailureHistory.displayName = 'FailureHistory'; diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/index.test.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/index.test.tsx index 11529d2f4c6c57..21666ae3ad3d1e 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/index.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/index.test.tsx @@ -20,7 +20,6 @@ import { import { RuleDetailsPage } from './index'; import { createStore, State } from '../../../../../common/store'; import { useUserData } from '../../../../components/user_info'; -import { useRuleStatus } from '../../../../containers/detection_engine/rules'; import { useRuleWithFallback } from '../../../../containers/detection_engine/rules/use_rule_with_fallback'; import { useSourcererDataView } from '../../../../../common/containers/sourcerer'; @@ -131,15 +130,6 @@ describe('RuleDetailsPageComponent', () => { indicesExist: true, indexPattern: {}, }); - (useRuleStatus as jest.Mock).mockReturnValue([ - false, - { - status: 'succeeded', - last_failure_at: new Date().toISOString(), - last_failure_message: 'my fake failure message', - failures: [], - }, - ]); (useRuleWithFallback as jest.Mock).mockReturnValue({ error: null, loading: false, diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/index.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/index.tsx index 03d43e3969c10e..7039a2eeb496aa 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/index.tsx @@ -27,7 +27,6 @@ import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react' import { useParams } from 'react-router-dom'; import { connect, ConnectedProps, useDispatch } from 'react-redux'; import styled from 'styled-components'; -import deepEqual from 'fast-deep-equal'; import { ExceptionListTypeEnum, ExceptionListIdentifiers, @@ -52,7 +51,7 @@ import { } from '../../../../../common/components/link_to/redirect_to_detection_engine'; import { SiemSearchBar } from '../../../../../common/components/search_bar'; import { SecuritySolutionPageWrapper } from '../../../../../common/components/page_wrapper'; -import { Rule, useRuleStatus, RuleInfoStatus } from '../../../../containers/detection_engine/rules'; +import { Rule } from '../../../../containers/detection_engine/rules'; import { useListsConfig } from '../../../../containers/detection_engine/lists/use_lists_config'; import { SpyRoute } from '../../../../../common/utils/route/spy_routes'; import { StepAboutRuleToggleDetails } from '../../../../components/rules/step_about_rule_details'; @@ -75,9 +74,6 @@ import { useGlobalTime } from '../../../../../common/containers/use_global_time' import { inputsSelectors } from '../../../../../common/store/inputs'; import { setAbsoluteRangeDatePicker } from '../../../../../common/store/inputs/actions'; import { RuleActionsOverflow } from '../../../../components/rules/rule_actions_overflow'; -import { RuleStatusFailedCallOut } from './status_failed_callout'; -import { FailureHistory } from './failure_history'; -import { RuleStatus } from '../../../../components/rules//rule_status'; import { useMlCapabilities } from '../../../../../common/components/ml/hooks/use_ml_capabilities'; import { hasMlAdminPermissions } from '../../../../../../common/machine_learning/has_ml_admin_permissions'; import { hasMlLicense } from '../../../../../../common/machine_learning/has_ml_license'; @@ -109,12 +105,17 @@ import { isBoolean, } from '../../../../../common/utils/privileges'; +import { + RuleStatus, + RuleStatusFailedCallOut, + ruleStatusI18n, +} from '../../../../components/rules/rule_execution_status'; +import { FailureHistory } from './failure_history'; + import * as detectionI18n from '../../translations'; import * as ruleI18n from '../translations'; -import * as statusI18n from '../../../../components/rules/rule_status/translations'; import * as i18n from './translations'; import { NeedAdminForUpdateRulesCallOut } from '../../../../components/callouts/need_admin_for_update_callout'; -import { getRuleStatusText } from '../../../../../../common/detection_engine/utils'; import { MissingPrivilegesCallOut } from '../../../../components/callouts/missing_privileges_callout'; import { useRuleWithFallback } from '../../../../containers/detection_engine/rules/use_rule_with_fallback'; import { BadgeOptions } from '../../../../../common/components/header_page/types'; @@ -224,15 +225,6 @@ const RuleDetailsPageComponent: React.FC = ({ isExistingRule, } = useRuleWithFallback(ruleId); const { pollForSignalIndex } = useSignalHelpers(); - const [loadingStatus, ruleStatus, fetchRuleStatus] = useRuleStatus(ruleId); - const [currentStatus, setCurrentStatus] = useState( - ruleStatus?.current_status ?? null - ); - useEffect(() => { - if (!deepEqual(currentStatus, ruleStatus?.current_status)) { - setCurrentStatus(ruleStatus?.current_status ?? null); - } - }, [currentStatus, ruleStatus, setCurrentStatus]); const [rule, setRule] = useState(null); const isLoading = ruleLoading && rule == null; // This is used to re-trigger api rule status when user de/activate rule @@ -466,27 +458,25 @@ const RuleDetailsPageComponent: React.FC = ({ : DEFAULT_INDEX_PATTERN), [rule?.index, uebaEnabled] ); - const handleRefresh = useCallback(() => { - if (fetchRuleStatus != null && ruleId != null) { - fetchRuleStatus(ruleId); - } - }, [fetchRuleStatus, ruleId]); + const lastExecution = rule?.execution_summary?.last_execution; + const lastExecutionStatus = lastExecution?.status; + const lastExecutionDate = lastExecution?.date ?? ''; + const lastExecutionMessage = lastExecution?.message ?? ''; + + // TODO: https://github.com/elastic/kibana/pull/121644 clean up const ruleStatusInfo = useMemo(() => { - return loadingStatus ? ( + return ruleLoading ? ( ) : ( <> - + = ({ ); - }, [isExistingRule, currentStatus, loadingStatus, handleRefresh]); + }, [lastExecutionStatus, lastExecutionDate, ruleLoading, isExistingRule, refreshRule]); + // TODO: https://github.com/elastic/kibana/pull/121644 clean up const ruleError = useMemo(() => { - if (loadingStatus) { + if (ruleLoading) { return ( ); - } else if ( - currentStatus?.status === 'failed' && - (ruleDetailTab === RuleDetailTabs.alerts || ruleDetailTab === RuleDetailTabs.failures) && - currentStatus?.last_failure_at != null - ) { - return ( - - ); - } else if ( - (currentStatus?.status === 'warning' || currentStatus?.status === 'partial failure') && - (ruleDetailTab === RuleDetailTabs.alerts || ruleDetailTab === RuleDetailTabs.failures) && - currentStatus?.last_success_at != null - ) { - return ( - - ); } - return null; - }, [ruleDetailTab, currentStatus, loadingStatus]); + + return ( + + ); + }, [lastExecutionStatus, lastExecutionDate, lastExecutionMessage, ruleLoading]); const updateDateRangeCallback = useCallback( ({ x }) => { @@ -704,7 +679,7 @@ const RuleDetailsPageComponent: React.FC = ({ <> - {statusI18n.STATUS} + {ruleStatusI18n.STATUS} {':'} {ruleStatusInfo} @@ -859,7 +834,7 @@ const RuleDetailsPageComponent: React.FC = ({ onRuleChange={refreshRule} /> )} - {ruleDetailTab === RuleDetailTabs.failures && } + {ruleDetailTab === RuleDetailTabs.failures && } diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/status_failed_callout.test.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/status_failed_callout.test.tsx deleted file mode 100644 index 2a5c5cff30f2d4..00000000000000 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/status_failed_callout.test.tsx +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 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 React from 'react'; -import { shallow } from 'enzyme'; - -import { RuleStatusFailedCallOut } from './status_failed_callout'; - -describe('RuleStatusFailedCallOut', () => { - it('renders correctly', () => { - const wrapper = shallow(); - - expect(wrapper.find('EuiCallOut')).toHaveLength(1); - }); - it('renders correctly with optional params', () => { - const wrapper = shallow( - - ); - - expect(wrapper.find('EuiCallOut')).toHaveLength(1); - }); -}); diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/status_failed_callout.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/status_failed_callout.tsx deleted file mode 100644 index 103cbb7a1674c4..00000000000000 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/status_failed_callout.tsx +++ /dev/null @@ -1,43 +0,0 @@ -/* - * 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 { EuiCallOut, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; -import React, { memo } from 'react'; - -import { FormattedDate } from '../../../../../common/components/formatted_date'; -import * as i18n from './translations'; - -interface RuleStatusFailedCallOutComponentProps { - date: string; - message: string; - color?: 'danger' | 'primary' | 'success' | 'warning'; -} - -const RuleStatusFailedCallOutComponent: React.FC = ({ - date, - message, - color, -}) => ( - - - {color === 'warning' ? i18n.PARTIAL_FAILURE_CALLOUT_TITLE : i18n.ERROR_CALLOUT_TITLE} - - - - - - } - color={color ? color : 'danger'} - iconType="alert" - > -

{message}

- -); - -export const RuleStatusFailedCallOut = memo(RuleStatusFailedCallOutComponent); diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/translations.ts b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/translations.ts index a83647f8a97813..2ea37ccfd343bd 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/translations.ts +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/translations.ts @@ -42,20 +42,6 @@ export const UNKNOWN = i18n.translate( } ); -export const ERROR_CALLOUT_TITLE = i18n.translate( - 'xpack.securitySolution.detectionEngine.ruleDetails.errorCalloutTitle', - { - defaultMessage: 'Rule failure at', - } -); - -export const PARTIAL_FAILURE_CALLOUT_TITLE = i18n.translate( - 'xpack.securitySolution.detectionEngine.ruleDetails.partialErrorCalloutTitle', - { - defaultMessage: 'Warning at', - } -); - export const FAILURE_HISTORY_TAB = i18n.translate( 'xpack.securitySolution.detectionEngine.ruleDetails.failureHistoryTab', { diff --git a/x-pack/plugins/security_solution/server/config.mock.ts b/x-pack/plugins/security_solution/server/config.mock.ts index 9325f2f57bdd63..bc83a721cbf58d 100644 --- a/x-pack/plugins/security_solution/server/config.mock.ts +++ b/x-pack/plugins/security_solution/server/config.mock.ts @@ -11,7 +11,6 @@ import { parseExperimentalConfigValue, } from '../common/experimental_features'; import { ConfigType } from './config'; -import { UnderlyingLogClient } from './lib/detection_engine/rule_execution_log/types'; export const createMockConfig = (): ConfigType => { const enableExperimental: string[] = []; @@ -28,9 +27,6 @@ export const createMockConfig = (): ConfigType => { alertIgnoreFields: [], prebuiltRulesFromFileSystem: true, prebuiltRulesFromSavedObjects: false, - ruleExecutionLog: { - underlyingClient: UnderlyingLogClient.savedObjects, - }, experimentalFeatures: parseExperimentalConfigValue(enableExperimental), }; diff --git a/x-pack/plugins/security_solution/server/config.ts b/x-pack/plugins/security_solution/server/config.ts index b76edf3b508001..d7e8547fd50ef9 100644 --- a/x-pack/plugins/security_solution/server/config.ts +++ b/x-pack/plugins/security_solution/server/config.ts @@ -14,7 +14,6 @@ import { isValidExperimentalValue, parseExperimentalConfigValue, } from '../common/experimental_features'; -import { UnderlyingLogClient } from './lib/detection_engine/rule_execution_log/types'; const allowedExperimentalValues = getExperimentalAllowedValues(); @@ -105,19 +104,6 @@ export const configSchema = schema.object({ }, }), - /** - * Rule Execution Log Configuration - */ - ruleExecutionLog: schema.object({ - underlyingClient: schema.oneOf( - [ - schema.literal(UnderlyingLogClient.eventLog), - schema.literal(UnderlyingLogClient.savedObjects), - ], - { defaultValue: UnderlyingLogClient.eventLog } - ), - }), - /** * Artifacts Configuration */ diff --git a/x-pack/plugins/security_solution/server/index.ts b/x-pack/plugins/security_solution/server/index.ts index 777bc27a068669..f3ce6e458fe7da 100644 --- a/x-pack/plugins/security_solution/server/index.ts +++ b/x-pack/plugins/security_solution/server/index.ts @@ -20,7 +20,7 @@ export const config: PluginConfigDescriptor = { enableExperimental: true, }, schema: configSchema, - deprecations: ({ renameFromRoot }) => [ + deprecations: ({ renameFromRoot, unused }) => [ renameFromRoot('xpack.siem.enabled', 'xpack.securitySolution.enabled', { level: 'critical' }), renameFromRoot( 'xpack.siem.maxRuleImportExportSize', @@ -47,6 +47,7 @@ export const config: PluginConfigDescriptor = { `xpack.securitySolution.${SIGNALS_INDEX_KEY}`, { level: 'critical' } ), + unused('ruleExecutionLog.underlyingClient', { level: 'warning' }), ], }; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/request_context.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/request_context.ts index db05f13702a811..df1a263e1b2c10 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/request_context.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/request_context.ts @@ -22,7 +22,7 @@ import { ruleRegistryMocks } from '../../../../../../rule_registry/server/mocks' import { siemMock } from '../../../../mocks'; import { createMockConfig } from '../../../../config.mock'; -import { ruleExecutionLogClientMock } from '../../rule_execution_log/__mocks__/rule_execution_log_client'; +import { ruleExecutionLogMock } from '../../rule_execution_log/__mocks__/rule_execution_log_client'; import { requestMock } from './request'; import { internalFrameworkRequest } from '../../../framework'; @@ -56,7 +56,7 @@ export const createMockClients = () => { config: createMockConfig(), appClient: siemMock.createClient(), - ruleExecutionLogClient: ruleExecutionLogClientMock.create(), + ruleExecutionLogClient: ruleExecutionLogMock.client.create(), }; }; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/request_responses.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/request_responses.ts index d186c88e8458ed..9118df4fc413f6 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/request_responses.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/request_responses.ts @@ -23,9 +23,9 @@ import { DETECTION_ENGINE_SIGNALS_FINALIZE_MIGRATION_URL, DETECTION_ENGINE_SIGNALS_MIGRATION_STATUS_URL, DETECTION_ENGINE_RULES_BULK_ACTION, - INTERNAL_DETECTION_ENGINE_RULE_STATUS_URL, + DETECTION_ENGINE_RULE_EXECUTION_EVENTS_URL, } from '../../../../../common/constants'; -import { RuleAlertType, HapiReadableStream, IRuleStatusSOAttributes } from '../../rules/types'; +import { RuleAlertType, HapiReadableStream } from '../../rules/types'; import { requestMock } from './request'; import { QuerySignalsSchemaDecoded } from '../../../../../common/detection_engine/schemas/request/query_signals_index_schema'; import { SetSignalsStatusSchemaDecoded } from '../../../../../common/detection_engine/schemas/request/set_signal_status_schema'; @@ -40,10 +40,14 @@ import { getPerformBulkActionSchemaMock, getPerformBulkActionEditSchemaMock, } from '../../../../../common/detection_engine/schemas/request/perform_bulk_action_schema.mock'; -import { RuleExecutionStatus } from '../../../../../common/detection_engine/schemas/common/schemas'; -import { GetCurrentStatusBulkResult } from '../../rule_execution_log/types'; +import { + RuleExecutionEvent, + RuleExecutionStatus, + RuleExecutionSummary, +} from '../../../../../common/detection_engine/schemas/common'; // eslint-disable-next-line no-restricted-imports import type { LegacyRuleNotificationAlertType } from '../../notifications/legacy_types'; +import { RuleExecutionSummariesByRuleId } from '../../rule_execution_log'; export const typicalSetStatusSignalByIdsPayload = (): SetSignalsStatusSchemaDecoded => ({ signal_ids: ['somefakeid1', 'somefakeid2'], @@ -231,11 +235,13 @@ export const getFindResultWithMultiHits = ({ }; }; -export const internalRuleStatusRequest = () => +export const getRuleExecutionEventsRequest = () => requestMock.create({ - method: 'post', - path: INTERNAL_DETECTION_ENGINE_RULE_STATUS_URL, - body: { ruleId: '04128c15-0d1b-4716-a4c5-46997ac7f3bd' }, + method: 'get', + path: DETECTION_ENGINE_RULE_EXECUTION_EVENTS_URL, + params: { + ruleId: '04128c15-0d1b-4716-a4c5-46997ac7f3bd', + }, }); export const getImportRulesRequest = (hapiStream?: HapiReadableStream) => @@ -473,74 +479,79 @@ export const getMockPrivilegesResult = () => ({ application: {}, }); -export const getEmptySavedObjectsResponse = - (): SavedObjectsFindResponse => ({ - page: 1, - per_page: 1, - total: 0, - saved_objects: [], - }); - -export const getRuleExecutionStatusSucceeded = (): IRuleStatusSOAttributes => ({ - statusDate: '2020-02-18T15:26:49.783Z', - status: RuleExecutionStatus.succeeded, - lastFailureAt: undefined, - lastSuccessAt: '2020-02-18T15:26:49.783Z', - lastFailureMessage: undefined, - lastSuccessMessage: 'succeeded', - lastLookBackDate: new Date('2020-02-18T15:14:58.806Z').toISOString(), - gap: '500.32', - searchAfterTimeDurations: ['200.00'], - bulkCreateTimeDurations: ['800.43'], -}); - -export const getRuleExecutionStatusFailed = (): IRuleStatusSOAttributes => ({ - statusDate: '2020-02-18T15:15:58.806Z', - status: RuleExecutionStatus.failed, - lastFailureAt: '2020-02-18T15:15:58.806Z', - lastSuccessAt: '2020-02-13T20:31:59.855Z', - lastFailureMessage: - 'Signal rule name: "Query with a rule id Number 1", id: "1ea5a820-4da1-4e82-92a1-2b43a7bece08", rule_id: "query-rule-id-1" has a time gap of 5 days (412682928ms), and could be missing signals within that time. Consider increasing your look behind time or adding more Kibana instances.', - lastSuccessMessage: 'succeeded', - lastLookBackDate: new Date('2020-02-18T15:14:58.806Z').toISOString(), - gap: '500.32', - searchAfterTimeDurations: ['200.00'], - bulkCreateTimeDurations: ['800.43'], +export const getEmptySavedObjectsResponse = (): SavedObjectsFindResponse => ({ + page: 1, + per_page: 1, + total: 0, + saved_objects: [], }); -export const getRuleExecutionStatuses = (): IRuleStatusSOAttributes[] => [ - getRuleExecutionStatusSucceeded(), - getRuleExecutionStatusFailed(), -]; - -export const getFindBulkResultStatus = (): GetCurrentStatusBulkResult => ({ - '04128c15-0d1b-4716-a4c5-46997ac7f3bd': { - statusDate: '2020-02-18T15:26:49.783Z', +// TODO: https://github.com/elastic/kibana/pull/121644 clean up +export const getRuleExecutionSummarySucceeded = (): RuleExecutionSummary => ({ + last_execution: { + date: '2020-02-18T15:26:49.783Z', status: RuleExecutionStatus.succeeded, - lastFailureAt: undefined, - lastSuccessAt: '2020-02-18T15:26:49.783Z', - lastFailureMessage: undefined, - lastSuccessMessage: 'succeeded', - lastLookBackDate: new Date('2020-02-18T15:14:58.806Z').toISOString(), - gap: '500.32', - searchAfterTimeDurations: ['200.00'], - bulkCreateTimeDurations: ['800.43'], + status_order: 0, + message: 'succeeded', + metrics: { + total_search_duration_ms: 200, + total_indexing_duration_ms: 800, + execution_gap_duration_s: 500, + }, }, - '1ea5a820-4da1-4e82-92a1-2b43a7bece08': { - statusDate: '2020-02-18T15:15:58.806Z', +}); + +// TODO: https://github.com/elastic/kibana/pull/121644 clean up +export const getRuleExecutionSummaryFailed = (): RuleExecutionSummary => ({ + last_execution: { + date: '2020-02-18T15:15:58.806Z', status: RuleExecutionStatus.failed, - lastFailureAt: '2020-02-18T15:15:58.806Z', - lastSuccessAt: '2020-02-13T20:31:59.855Z', - lastFailureMessage: + status_order: 30, + message: 'Signal rule name: "Query with a rule id Number 1", id: "1ea5a820-4da1-4e82-92a1-2b43a7bece08", rule_id: "query-rule-id-1" has a time gap of 5 days (412682928ms), and could be missing signals within that time. Consider increasing your look behind time or adding more Kibana instances.', - lastSuccessMessage: 'succeeded', - lastLookBackDate: new Date('2020-02-18T15:14:58.806Z').toISOString(), - gap: '500.32', - searchAfterTimeDurations: ['200.00'], - bulkCreateTimeDurations: ['800.43'], + metrics: { + total_search_duration_ms: 200, + total_indexing_duration_ms: 800, + execution_gap_duration_s: 500, + }, }, }); +// TODO: https://github.com/elastic/kibana/pull/121644 clean up +export const getRuleExecutionSummaries = (): RuleExecutionSummariesByRuleId => ({ + '04128c15-0d1b-4716-a4c5-46997ac7f3bd': getRuleExecutionSummarySucceeded(), + '1ea5a820-4da1-4e82-92a1-2b43a7bece08': getRuleExecutionSummaryFailed(), +}); + +// TODO: https://github.com/elastic/kibana/pull/121644 clean up +export const getLastFailures = (): RuleExecutionEvent[] => [ + { + date: '2021-12-28T10:30:00.806Z', + status: RuleExecutionStatus.failed, + message: 'Rule failed', + }, + { + date: '2021-12-28T10:25:00.806Z', + status: RuleExecutionStatus.failed, + message: 'Rule failed', + }, + { + date: '2021-12-28T10:20:00.806Z', + status: RuleExecutionStatus.failed, + message: 'Rule failed', + }, + { + date: '2021-12-28T10:15:00.806Z', + status: RuleExecutionStatus.failed, + message: 'Rule failed', + }, + { + date: '2021-12-28T10:10:00.806Z', + status: RuleExecutionStatus.failed, + message: 'Rule failed', + }, +]; + export const getBasicEmptySearchResponse = (): estypes.SearchResponse => ({ took: 1, timed_out: false, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/utils.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/utils.ts index 0dcecf3fe37895..2622493a51dc18 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/utils.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/utils.ts @@ -58,10 +58,6 @@ export const getOutputRuleAlertForRest = (): Omit< rule_name_override: undefined, saved_id: undefined, language: 'kuery', - last_failure_at: undefined, - last_failure_message: undefined, - last_success_at: undefined, - last_success_message: undefined, license: 'Elastic License', max_signals: 10000, name: 'Detect Root/Admin Users', @@ -70,8 +66,6 @@ export const getOutputRuleAlertForRest = (): Omit< references: ['http://example.com', 'https://example.com'], severity: 'high', severity_mapping: [], - status: undefined, - status_date: undefined, updated_by: 'elastic', tags: [], throttle: 'no_actions', @@ -95,4 +89,5 @@ export const getOutputRuleAlertForRest = (): Omit< type: 'query', note: '# Investigative notes', version: 1, + execution_summary: undefined, }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/add_prepackaged_rules_route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/add_prepackaged_rules_route.test.ts index 3ec8cb733aa287..119f7a0b07db5c 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/add_prepackaged_rules_route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/add_prepackaged_rules_route.test.ts @@ -104,35 +104,12 @@ describe('add_prepackaged_rules_route', () => { }); describe('status codes', () => { - test('returns 200 when creating with a valid actionClient and rulesClient', async () => { + test('returns 200', async () => { const request = addPrepackagedRulesRequest(); const response = await server.inject(request, context); expect(response.status).toEqual(200); }); - - test('returns 404 if rulesClient is not available on the route', async () => { - context.alerting.getRulesClient = jest.fn(); - const request = addPrepackagedRulesRequest(); - const response = await server.inject(request, context); - - expect(response.status).toEqual(404); - expect(response.body).toEqual({ - message: 'Not Found', - status_code: 404, - }); - }); - - test('returns 404 if siem client is unavailable', async () => { - const { securitySolution, ...contextWithoutSecuritySolution } = context; - const response = await server.inject( - addPrepackagedRulesRequest(), - // @ts-expect-error - contextWithoutSecuritySolution - ); - expect(response.status).toEqual(404); - expect(response.body).toEqual({ message: 'Not Found', status_code: 404 }); - }); }); describe('responses', () => { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/add_prepackaged_rules_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/add_prepackaged_rules_route.ts index 50766af669ce79..691548c0a9efd0 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/add_prepackaged_rules_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/add_prepackaged_rules_route.ts @@ -54,12 +54,7 @@ export const addPrepackedRulesRoute = (router: SecuritySolutionPluginRouter) => const siemResponse = buildSiemResponse(response); try { - const rulesClient = context.alerting?.getRulesClient(); - const siemClient = context.securitySolution?.getAppClient(); - - if (!siemClient || !rulesClient) { - return siemResponse.error({ statusCode: 404 }); - } + const rulesClient = context.alerting.getRulesClient(); const validated = await createPrepackagedRules( context.securitySolution, @@ -98,7 +93,6 @@ export const createPrepackagedRules = async ( const siemClient = context.getAppClient(); const exceptionsListClient = context.getExceptionListClient() ?? exceptionsClient; const ruleAssetsClient = ruleAssetSavedObjectsClientFactory(savedObjectsClient); - const ruleStatusClient = context.getExecutionLogClient(); const { maxTimelineImportExportSize, @@ -154,7 +148,6 @@ export const createPrepackagedRules = async ( rulesClient, savedObjectsClient, context.getSpaceId(), - ruleStatusClient, rulesToUpdate, signalsIndex, ruleRegistryEnabled diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rules_bulk_route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rules_bulk_route.test.ts index 6dc303d5a266b5..68a3ec0733b60f 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rules_bulk_route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rules_bulk_route.test.ts @@ -51,25 +51,10 @@ describe.each([ }); describe('status codes', () => { - test('returns 200 when creating a single rule with a valid actionClient and alertClient', async () => { + test('returns 200', async () => { const response = await server.inject(getReadBulkRequest(), context); expect(response.status).toEqual(200); }); - - test('returns 404 if alertClient is not available on the route', async () => { - context.alerting.getRulesClient = jest.fn(); - const response = await server.inject(getReadBulkRequest(), context); - expect(response.status).toEqual(404); - expect(response.body).toEqual({ message: 'Not Found', status_code: 404 }); - }); - - test('returns 404 if siem client is unavailable', async () => { - const { securitySolution, ...contextWithoutSecuritySolution } = context; - // @ts-expect-error - const response = await server.inject(getReadBulkRequest(), contextWithoutSecuritySolution); - expect(response.status).toEqual(404); - expect(response.body).toEqual({ message: 'Not Found', status_code: 404 }); - }); }); describe('unhappy paths', () => { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rules_bulk_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rules_bulk_route.ts index 1db9cca2ca2d86..a5a982a6d78c6f 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rules_bulk_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rules_bulk_route.ts @@ -43,14 +43,10 @@ export const createRulesBulkRoute = ( }, async (context, request, response) => { const siemResponse = buildSiemResponse(response); - const rulesClient = context.alerting?.getRulesClient(); + const rulesClient = context.alerting.getRulesClient(); const esClient = context.core.elasticsearch.client; const savedObjectsClient = context.core.savedObjects.client; - const siemClient = context.securitySolution?.getAppClient(); - - if (!siemClient || !rulesClient) { - return siemResponse.error({ statusCode: 404 }); - } + const siemClient = context.securitySolution.getAppClient(); const mlAuthz = buildMlAuthz({ license: context.licensing.license, @@ -119,7 +115,7 @@ export const createRulesBulkRoute = ( return transformValidateBulkError( internalRule.params.ruleId, createdRule, - undefined, + null, isRuleRegistryEnabled ); } catch (err) { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rules_route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rules_route.test.ts index a9f5938abb921d..449456a12a69c6 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rules_route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rules_route.test.ts @@ -10,7 +10,7 @@ import { getEmptyFindResult, getAlertMock, getCreateRequest, - getRuleExecutionStatusSucceeded, + getRuleExecutionSummarySucceeded, getFindResultWithSingleHit, createMlRuleRequest, getBasicEmptySearchResponse, @@ -43,8 +43,8 @@ describe.each([ clients.rulesClient.create.mockResolvedValue( getAlertMock(isRuleRegistryEnabled, getQueryRuleParams()) ); // creation succeeds - clients.ruleExecutionLogClient.getCurrentStatus.mockResolvedValue( - getRuleExecutionStatusSucceeded() + clients.ruleExecutionLogClient.getExecutionSummary.mockResolvedValue( + getRuleExecutionSummarySucceeded() ); context.core.elasticsearch.client.asCurrentUser.search.mockResolvedValue( @@ -53,27 +53,12 @@ describe.each([ createRulesRoute(server.router, ml, isRuleRegistryEnabled); }); - describe('status codes with actionClient and alertClient', () => { - test('returns 200 when creating a single rule with a valid actionClient and alertClient', async () => { + describe('status codes', () => { + test('returns 200 with a rule created via RulesClient', async () => { const response = await server.inject(getCreateRequest(), context); expect(response.status).toEqual(200); }); - test('returns 404 if alertClient is not available on the route', async () => { - context.alerting.getRulesClient = jest.fn(); - const response = await server.inject(getCreateRequest(), context); - expect(response.status).toEqual(404); - expect(response.body).toEqual({ message: 'Not Found', status_code: 404 }); - }); - - test('returns 404 if siem client is unavailable', async () => { - const { securitySolution, ...contextWithoutSecuritySolution } = context; - // @ts-expect-error - const response = await server.inject(getCreateRequest(), contextWithoutSecuritySolution); - expect(response.status).toEqual(404); - expect(response.body).toEqual({ message: 'Not Found', status_code: 404 }); - }); - test('returns 200 if license is not platinum', async () => { (context.licensing.license.hasAtLeast as jest.Mock).mockReturnValue(false); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rules_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rules_route.ts index 71d453809d0fa5..6a87b780f8e759 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rules_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rules_route.ts @@ -44,15 +44,13 @@ export const createRulesRoute = ( if (validationErrors.length) { return siemResponse.error({ statusCode: 400, body: validationErrors }); } + try { - const rulesClient = context.alerting?.getRulesClient(); + const rulesClient = context.alerting.getRulesClient(); + const ruleExecutionLogClient = context.securitySolution.getExecutionLogClient(); const esClient = context.core.elasticsearch.client; const savedObjectsClient = context.core.savedObjects.client; - const siemClient = context.securitySolution?.getAppClient(); - - if (!siemClient || !rulesClient) { - return siemResponse.error({ statusCode: 404 }); - } + const siemClient = context.securitySolution.getAppClient(); if (request.body.rule_id != null) { const rule = await readRules({ @@ -106,13 +104,13 @@ export const createRulesRoute = ( await rulesClient.muteAll({ id: createdRule.id }); } - const ruleStatus = await context.securitySolution.getExecutionLogClient().getCurrentStatus({ - ruleId: createdRule.id, - spaceId: context.securitySolution.getSpaceId(), - }); + const ruleExecutionSummary = await ruleExecutionLogClient.getExecutionSummary( + createdRule.id + ); + const [validated, errors] = newTransformValidate( createdRule, - ruleStatus, + ruleExecutionSummary, isRuleRegistryEnabled ); if (errors != null) { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/delete_rules_bulk_route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/delete_rules_bulk_route.test.ts index 49580fc09ca63f..4ac4822c412fa4 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/delete_rules_bulk_route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/delete_rules_bulk_route.test.ts @@ -82,13 +82,6 @@ describe.each([ ]) ); }); - - test('returns 404 if alertClient is not available on the route', async () => { - context.alerting.getRulesClient = jest.fn(); - const response = await server.inject(getDeleteBulkRequest(), context); - expect(response.status).toEqual(404); - expect(response.body).toEqual({ message: 'Not Found', status_code: 404 }); - }); }); describe('request validation', () => { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/delete_rules_bulk_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/delete_rules_bulk_route.ts index 149227084ace06..ac8c0fce984b56 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/delete_rules_bulk_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/delete_rules_bulk_route.ts @@ -53,14 +53,8 @@ export const deleteRulesBulkRoute = ( }; const handler: Handler = async (context, request, response) => { const siemResponse = buildSiemResponse(response); - - const rulesClient = context.alerting?.getRulesClient(); - - if (!rulesClient) { - return siemResponse.error({ statusCode: 404 }); - } - - const ruleStatusClient = context.securitySolution.getExecutionLogClient(); + const rulesClient = context.alerting.getRulesClient(); + const ruleExecutionLogClient = context.securitySolution.getExecutionLogClient(); const savedObjectsClient = context.core.savedObjects.client; const rules = await Promise.all( @@ -87,19 +81,20 @@ export const deleteRulesBulkRoute = ( return getIdBulkError({ id, ruleId }); } - const ruleStatus = await ruleStatusClient.getCurrentStatus({ - ruleId: migratedRule.id, - spaceId: context.securitySolution.getSpaceId(), - }); + const ruleExecutionSummary = await ruleExecutionLogClient.getExecutionSummary( + migratedRule.id + ); + await deleteRules({ ruleId: migratedRule.id, rulesClient, - ruleStatusClient, + ruleExecutionLogClient, }); + return transformValidateBulkError( idOrRuleIdOrUnknown, migratedRule, - ruleStatus, + ruleExecutionSummary, isRuleRegistryEnabled ); } catch (err) { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/delete_rules_route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/delete_rules_route.test.ts index 9c126a177eeb59..b18e330eab5a4c 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/delete_rules_route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/delete_rules_route.test.ts @@ -12,7 +12,6 @@ import { getDeleteRequest, getFindResultWithSingleHit, getDeleteRequestById, - getRuleExecutionStatusSucceeded, getEmptySavedObjectsResponse, } from '../__mocks__/request_responses'; import { requestContextMock, serverMock, requestMock } from '../__mocks__'; @@ -32,9 +31,6 @@ describe.each([ clients.rulesClient.find.mockResolvedValue(getFindResultWithSingleHit(isRuleRegistryEnabled)); clients.savedObjectsClient.find.mockResolvedValue(getEmptySavedObjectsResponse()); - clients.ruleExecutionLogClient.getCurrentStatus.mockResolvedValue( - getRuleExecutionStatusSucceeded() - ); deleteRulesRoute(server.router, isRuleRegistryEnabled); }); @@ -66,14 +62,6 @@ describe.each([ }); }); - test('returns 404 if alertClient is not available on the route', async () => { - context.alerting.getRulesClient = jest.fn(); - const response = await server.inject(getDeleteRequest(), context); - - expect(response.status).toEqual(404); - expect(response.body).toEqual({ message: 'Not Found', status_code: 404 }); - }); - test('catches error if deletion throws error', async () => { clients.rulesClient.delete.mockImplementation(async () => { throw new Error('Test error'); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/delete_rules_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/delete_rules_route.ts index 3bb7778e5bc5ee..376fa3f5694883 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/delete_rules_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/delete_rules_route.ts @@ -47,13 +47,10 @@ export const deleteRulesRoute = ( try { const { id, rule_id: ruleId } = request.query; - const rulesClient = context.alerting?.getRulesClient(); + const rulesClient = context.alerting.getRulesClient(); + const ruleExecutionLogClient = context.securitySolution.getExecutionLogClient(); const savedObjectsClient = context.core.savedObjects.client; - if (!rulesClient) { - return siemResponse.error({ statusCode: 404 }); - } - const ruleStatusClient = context.securitySolution.getExecutionLogClient(); const rule = await readRules({ isRuleRegistryEnabled, rulesClient, id, ruleId }); const migratedRule = await legacyMigrate({ rulesClient, @@ -69,17 +66,17 @@ export const deleteRulesRoute = ( }); } - const currentStatus = await ruleStatusClient.getCurrentStatus({ - ruleId: migratedRule.id, - spaceId: context.securitySolution.getSpaceId(), - }); + const ruleExecutionSummary = await ruleExecutionLogClient.getExecutionSummary( + migratedRule.id + ); await deleteRules({ ruleId: migratedRule.id, rulesClient, - ruleStatusClient, + ruleExecutionLogClient, }); - const transformed = transform(migratedRule, currentStatus, isRuleRegistryEnabled); + + const transformed = transform(migratedRule, ruleExecutionSummary, isRuleRegistryEnabled); if (transformed == null) { return siemResponse.error({ statusCode: 500, body: 'failed to transform alert' }); } else { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/export_rules_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/export_rules_route.ts index 277590820850be..84b37cd023036d 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/export_rules_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/export_rules_route.ts @@ -45,14 +45,10 @@ export const exportRulesRoute = ( }, async (context, request, response) => { const siemResponse = buildSiemResponse(response); - const rulesClient = context.alerting?.getRulesClient(); + const rulesClient = context.alerting.getRulesClient(); const exceptionsClient = context.lists?.getExceptionListClient(); const savedObjectsClient = context.core.savedObjects.client; - if (!rulesClient) { - return siemResponse.error({ statusCode: 404 }); - } - try { const exportSizeLimit = config.maxRuleImportExportSize; if (request.body?.objects != null && request.body.objects.length > exportSizeLimit) { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/find_rule_status_internal_route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/find_rule_status_internal_route.test.ts deleted file mode 100644 index 69f36422aafc55..00000000000000 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/find_rule_status_internal_route.test.ts +++ /dev/null @@ -1,119 +0,0 @@ -/* - * 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 { INTERNAL_DETECTION_ENGINE_RULE_STATUS_URL } from '../../../../../common/constants'; -import { - internalRuleStatusRequest, - getAlertMock, - getRuleExecutionStatusSucceeded, - getRuleExecutionStatusFailed, - resolveAlertMock, -} from '../__mocks__/request_responses'; -import { serverMock, requestContextMock, requestMock } from '../__mocks__'; -import { findRuleStatusInternalRoute } from './find_rule_status_internal_route'; -import { RuleStatusResponse } from '../../rules/types'; -import { AlertExecutionStatusErrorReasons } from '../../../../../../alerting/common'; -import { getQueryRuleParams } from '../../schemas/rule_schemas.mock'; - -describe.each([ - ['Legacy', false], - ['RAC', true], -])(`${INTERNAL_DETECTION_ENGINE_RULE_STATUS_URL} - %s`, (_, isRuleRegistryEnabled) => { - let server: ReturnType; - let { clients, context } = requestContextMock.createTools(); - - beforeEach(async () => { - server = serverMock.create(); - ({ clients, context } = requestContextMock.createTools()); - - clients.ruleExecutionLogClient.getCurrentStatus.mockResolvedValue( - getRuleExecutionStatusSucceeded() - ); - clients.ruleExecutionLogClient.getLastFailures.mockResolvedValue([ - getRuleExecutionStatusFailed(), - ]); - clients.rulesClient.get.mockResolvedValue( - getAlertMock(isRuleRegistryEnabled, getQueryRuleParams()) - ); - clients.rulesClient.resolve.mockResolvedValue( - resolveAlertMock(isRuleRegistryEnabled, getQueryRuleParams()) - ); - - findRuleStatusInternalRoute(server.router); - }); - - describe('status codes with actionClient and alertClient', () => { - test('returns 200 when finding a single rule status with a valid rulesClient', async () => { - const response = await server.inject(internalRuleStatusRequest(), context); - expect(response.status).toEqual(200); - }); - - test('returns 404 if alertClient is not available on the route', async () => { - context.alerting.getRulesClient = jest.fn(); - const response = await server.inject(internalRuleStatusRequest(), context); - expect(response.status).toEqual(404); - expect(response.body).toEqual({ message: 'Not Found', status_code: 404 }); - }); - - test('catch error when status search throws error', async () => { - clients.ruleExecutionLogClient.getCurrentStatus.mockImplementation(async () => { - throw new Error('Test error'); - }); - const response = await server.inject(internalRuleStatusRequest(), context); - expect(response.status).toEqual(500); - expect(response.body).toEqual({ - message: 'Test error', - status_code: 500, - }); - }); - - test('returns success if rule status client writes an error status', async () => { - // 0. task manager tried to run the rule but couldn't, so the alerting framework - // wrote an error to the executionStatus. - const failingExecutionRule = resolveAlertMock(isRuleRegistryEnabled, getQueryRuleParams()); - failingExecutionRule.executionStatus = { - status: 'error', - lastExecutionDate: failingExecutionRule.executionStatus.lastExecutionDate, - error: { - reason: AlertExecutionStatusErrorReasons.Read, - message: 'oops', - }, - }; - - // 1. getFailingRules api found a rule where the executionStatus was 'error' - clients.rulesClient.resolve.mockResolvedValue({ - ...failingExecutionRule, - }); - - const request = internalRuleStatusRequest(); - const { ruleId } = request.body; - - const response = await server.inject(request, context); - const responseBody: RuleStatusResponse = response.body; - const ruleStatus = responseBody[ruleId].current_status; - - expect(response.status).toEqual(200); - expect(ruleStatus?.status).toEqual('failed'); - expect(ruleStatus?.last_failure_message).toEqual('Reason: read Message: oops'); - }); - }); - - describe('request validation', () => { - test('disallows singular id query param', async () => { - const request = requestMock.create({ - method: 'post', - path: INTERNAL_DETECTION_ENGINE_RULE_STATUS_URL, - body: { id: ['someId'] }, - }); - const result = server.validate(request); - - expect(result.badRequest).toHaveBeenCalledWith( - 'Invalid value "undefined" supplied to "ruleId"' - ); - }); - }); -}); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/find_rule_status_internal_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/find_rule_status_internal_route.ts deleted file mode 100644 index 6d9b371a9370c8..00000000000000 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/find_rule_status_internal_route.ts +++ /dev/null @@ -1,85 +0,0 @@ -/* - * 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 { transformError } from '@kbn/securitysolution-es-utils'; -import { buildRouteValidation } from '../../../../utils/build_validation/route_validation'; -import type { SecuritySolutionPluginRouter } from '../../../../types'; -import { INTERNAL_DETECTION_ENGINE_RULE_STATUS_URL } from '../../../../../common/constants'; -import { buildSiemResponse, mergeStatuses, getFailingRules } from '../utils'; -import { - findRuleStatusSchema, - FindRuleStatusSchemaDecoded, -} from '../../../../../common/detection_engine/schemas/request/find_rule_statuses_schema'; -import { mergeAlertWithSidecarStatus } from '../../schemas/rule_converters'; - -/** - * Returns the current execution status and metrics + last five failed statuses of a given rule. - * Accepts a rule id. - * - * NOTE: This endpoint is a raw implementation of an endpoint for reading rule execution - * status and logs for a given rule (e.g. for use on the Rule Details page). It will be reworked. - * See the plan in https://github.com/elastic/kibana/pull/115574 - * - * @param router - * @returns RuleStatusResponse containing data only for the given rule (normally it contains data for N rules). - */ -export const findRuleStatusInternalRoute = (router: SecuritySolutionPluginRouter) => { - router.post( - { - path: INTERNAL_DETECTION_ENGINE_RULE_STATUS_URL, - validate: { - body: buildRouteValidation( - findRuleStatusSchema - ), - }, - options: { - tags: ['access:securitySolution'], - }, - }, - async (context, request, response) => { - const { ruleId } = request.body; - - const siemResponse = buildSiemResponse(response); - const rulesClient = context.alerting?.getRulesClient(); - - if (!rulesClient) { - return siemResponse.error({ statusCode: 404 }); - } - - try { - const ruleStatusClient = context.securitySolution.getExecutionLogClient(); - const spaceId = context.securitySolution.getSpaceId(); - - const [currentStatus, lastFailures, failingRules] = await Promise.all([ - ruleStatusClient.getCurrentStatus({ ruleId, spaceId }), - ruleStatusClient.getLastFailures({ ruleId, spaceId }), - getFailingRules([ruleId], rulesClient), - ]); - - const failingRule = failingRules[ruleId]; - let statuses = {}; - - if (currentStatus != null) { - const finalCurrentStatus = - failingRule != null - ? mergeAlertWithSidecarStatus(failingRule, currentStatus) - : currentStatus; - - statuses = mergeStatuses(ruleId, [finalCurrentStatus, ...lastFailures], statuses); - } - - return response.ok({ body: statuses }); - } catch (err) { - const error = transformError(err); - return siemResponse.error({ - body: error.message, - statusCode: error.statusCode, - }); - } - } - ); -}; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/find_rules_route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/find_rules_route.test.ts index 9f151d1db9292a..75698436417c04 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/find_rules_route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/find_rules_route.test.ts @@ -11,10 +11,10 @@ import { getQueryRuleParams } from '../../schemas/rule_schemas.mock'; import { requestContextMock, requestMock, serverMock } from '../__mocks__'; import { getAlertMock, - getFindBulkResultStatus, getFindRequest, - getEmptySavedObjectsResponse, getFindResultWithSingleHit, + getEmptySavedObjectsResponse, + getRuleExecutionSummaries, } from '../__mocks__/request_responses'; import { findRulesRoute } from './find_rules_route'; @@ -36,26 +36,19 @@ describe.each([ getAlertMock(isRuleRegistryEnabled, getQueryRuleParams()) ); clients.savedObjectsClient.find.mockResolvedValue(getEmptySavedObjectsResponse()); - clients.ruleExecutionLogClient.getCurrentStatusBulk.mockResolvedValue( - getFindBulkResultStatus() + clients.ruleExecutionLogClient.getExecutionSummariesBulk.mockResolvedValue( + getRuleExecutionSummaries() ); findRulesRoute(server.router, logger, isRuleRegistryEnabled); }); - describe('status codes with actionClient and alertClient', () => { - test('returns 200 when finding a single rule with a valid actionClient and alertClient', async () => { + describe('status codes', () => { + test('returns 200', async () => { const response = await server.inject(getFindRequest(), context); expect(response.status).toEqual(200); }); - test('returns 404 if alertClient is not available on the route', async () => { - context.alerting.getRulesClient = jest.fn(); - const response = await server.inject(getFindRequest(), context); - expect(response.status).toEqual(404); - expect(response.body).toEqual({ message: 'Not Found', status_code: 404 }); - }); - test('catches error if search throws error', async () => { clients.rulesClient.find.mockImplementation(async () => { throw new Error('Test error'); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/find_rules_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/find_rules_route.ts index 859f84241ae383..1fd6565e77edaf 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/find_rules_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/find_rules_route.ts @@ -18,7 +18,6 @@ import { findRules } from '../../rules/find_rules'; import { buildSiemResponse } from '../utils'; import { buildRouteValidation } from '../../../../utils/build_validation/route_validation'; import { transformFindAlerts } from './utils'; -import { getCurrentRuleStatuses } from './utils/get_current_rule_statuses'; // eslint-disable-next-line no-restricted-imports import { legacyGetBulkRuleActionsSavedObject } from '../../rule_actions/legacy_get_bulk_rule_actions_saved_object'; @@ -42,6 +41,7 @@ export const findRulesRoute = ( }, async (context, request, response) => { const siemResponse = buildSiemResponse(response); + const validationErrors = findRuleValidateTypeDependents(request.query); if (validationErrors.length) { return siemResponse.error({ statusCode: 400, body: validationErrors }); @@ -49,14 +49,10 @@ export const findRulesRoute = ( try { const { query } = request; - const rulesClient = context.alerting?.getRulesClient(); + const rulesClient = context.alerting.getRulesClient(); + const ruleExecutionLogClient = context.securitySolution.getExecutionLogClient(); const savedObjectsClient = context.core.savedObjects.client; - if (!rulesClient) { - return siemResponse.error({ statusCode: 404 }); - } - - const execLogClient = context.securitySolution.getExecutionLogClient(); const rules = await findRules({ isRuleRegistryEnabled, rulesClient, @@ -67,14 +63,15 @@ export const findRulesRoute = ( filter: query.filter, fields: query.fields, }); + const ruleIds = rules.data.map((rule) => rule.id); - const spaceId = context.securitySolution.getSpaceId(); - const [currentStatusesByRuleId, ruleActions] = await Promise.all([ - getCurrentRuleStatuses({ ruleIds, execLogClient, spaceId, logger }), + const [ruleExecutionSummaries, ruleActions] = await Promise.all([ + ruleExecutionLogClient.getExecutionSummariesBulk(ruleIds), legacyGetBulkRuleActionsSavedObject({ alertIds: ruleIds, savedObjectsClient, logger }), ]); - const transformed = transformFindAlerts(rules, currentStatusesByRuleId, ruleActions); + + const transformed = transformFindAlerts(rules, ruleExecutionSummaries, ruleActions); if (transformed == null) { return siemResponse.error({ statusCode: 500, body: 'Internal error transforming' }); } else { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/get_prepackaged_rules_status_route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/get_prepackaged_rules_status_route.test.ts index e97744a5fe5a89..3d3d80284aaac6 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/get_prepackaged_rules_status_route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/get_prepackaged_rules_status_route.test.ts @@ -93,19 +93,12 @@ describe.each([ ); }); - describe('status codes with actionClient and alertClient', () => { - test('returns 200 when creating a with a valid actionClient and alertClient', async () => { + describe('status codes', () => { + test('returns 200', async () => { const response = await server.inject(getPrepackagedRulesStatusRequest(), context); expect(response.status).toEqual(200); }); - test('returns 404 if alertClient is not available on the route', async () => { - context.alerting.getRulesClient = jest.fn(); - const response = await server.inject(getPrepackagedRulesStatusRequest(), context); - expect(response.status).toEqual(404); - expect(response.body).toEqual({ message: 'Not Found', status_code: 404 }); - }); - test('catch error when finding rules throws error', async () => { clients.rulesClient.find.mockImplementation(async () => { throw new Error('Test error'); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/get_prepackaged_rules_status_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/get_prepackaged_rules_status_route.ts index a18507eea4977e..4fcf1bd992c6a8 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/get_prepackaged_rules_status_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/get_prepackaged_rules_status_route.ts @@ -44,15 +44,11 @@ export const getPrepackagedRulesStatusRoute = ( }, }, async (context, request, response) => { - const savedObjectsClient = context.core.savedObjects.client; const siemResponse = buildSiemResponse(response); - const rulesClient = context.alerting?.getRulesClient(); + const savedObjectsClient = context.core.savedObjects.client; + const rulesClient = context.alerting.getRulesClient(); const ruleAssetsClient = ruleAssetSavedObjectsClientFactory(savedObjectsClient); - if (!rulesClient) { - return siemResponse.error({ statusCode: 404 }); - } - try { const latestPrepackagedRules = await getLatestPrepackagedRules( ruleAssetsClient, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/get_rule_execution_events_route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/get_rule_execution_events_route.test.ts new file mode 100644 index 00000000000000..ff4b3ccf812bdd --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/get_rule_execution_events_route.test.ts @@ -0,0 +1,53 @@ +/* + * 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 { serverMock, requestContextMock } from '../__mocks__'; +import { getRuleExecutionEventsRequest, getLastFailures } from '../__mocks__/request_responses'; +import { getRuleExecutionEventsRoute } from './get_rule_execution_events_route'; + +// TODO: https://github.com/elastic/kibana/pull/121644 clean up +describe('getRuleExecutionEventsRoute', () => { + let server: ReturnType; + let { clients, context } = requestContextMock.createTools(); + + beforeEach(async () => { + server = serverMock.create(); + ({ clients, context } = requestContextMock.createTools()); + + getRuleExecutionEventsRoute(server.router); + }); + + describe('success', () => { + it('returns 200 with found rule execution events', async () => { + const lastFailures = getLastFailures(); + clients.ruleExecutionLogClient.getLastFailures.mockResolvedValue(lastFailures); + + const response = await server.inject(getRuleExecutionEventsRequest(), context); + + expect(response.status).toEqual(200); + expect(response.body).toEqual({ + events: lastFailures, + }); + }); + }); + + describe('errors', () => { + it('returns 500 when rule execution log client throws an exception', async () => { + clients.ruleExecutionLogClient.getLastFailures.mockImplementation(async () => { + throw new Error('Test error'); + }); + + const response = await server.inject(getRuleExecutionEventsRequest(), context); + + expect(response.status).toEqual(500); + expect(response.body).toEqual({ + message: 'Test error', + status_code: 500, + }); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/get_rule_execution_events_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/get_rule_execution_events_route.ts new file mode 100644 index 00000000000000..e449b5b21a298e --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/get_rule_execution_events_route.ts @@ -0,0 +1,58 @@ +/* + * 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 { transformError } from '@kbn/securitysolution-es-utils'; +import { buildRouteValidation } from '../../../../utils/build_validation/route_validation'; +import { buildSiemResponse } from '../utils'; +import type { SecuritySolutionPluginRouter } from '../../../../types'; + +import { DETECTION_ENGINE_RULE_EXECUTION_EVENTS_URL } from '../../../../../common/constants'; +import { GetRuleExecutionEventsRequestParams } from '../../../../../common/detection_engine/schemas/request/get_rule_execution_events_request'; +import { GetRuleExecutionEventsResponse } from '../../../../../common/detection_engine/schemas/response/get_rule_execution_events_response'; + +// TODO: https://github.com/elastic/kibana/pull/121644 clean up +/** + * Returns execution events of a given rule (e.g. status changes) from Event Log. + * Accepts rule's saved object ID (`rule.id`). + * + * NOTE: This endpoint is under construction. It will be extended and finalized. + * https://github.com/elastic/kibana/issues/119598 + */ +export const getRuleExecutionEventsRoute = (router: SecuritySolutionPluginRouter) => { + router.get( + { + path: DETECTION_ENGINE_RULE_EXECUTION_EVENTS_URL, + validate: { + params: buildRouteValidation(GetRuleExecutionEventsRequestParams), + }, + options: { + tags: ['access:securitySolution'], + }, + }, + async (context, request, response) => { + const { ruleId } = request.params; + const siemResponse = buildSiemResponse(response); + + try { + const executionLog = context.securitySolution.getExecutionLogClient(); + const executionEvents = await executionLog.getLastFailures(ruleId); + + const responseBody: GetRuleExecutionEventsResponse = { + events: executionEvents, + }; + + return response.ok({ body: responseBody }); + } catch (err) { + const error = transformError(err); + return siemResponse.error({ + body: error.message, + statusCode: error.statusCode, + }); + } + } + ); +}; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/import_rules_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/import_rules_route.ts index 630e7907d4f55e..3cb8ff029a68a5 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/import_rules_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/import_rules_route.ts @@ -92,7 +92,6 @@ export const importRulesRoute = ( savedObjectsClient, }); - const ruleStatusClient = context.securitySolution.getExecutionLogClient(); const { filename } = (request.body.file as HapiReadableStream).hapi; const fileExtension = extname(filename).toLowerCase(); if (fileExtension !== '.ndjson') { @@ -158,7 +157,6 @@ export const importRulesRoute = ( mlAuthz, overwriteRules: request.query.overwrite, rulesClient, - ruleStatusClient, savedObjectsClient, exceptionsClient, isRuleRegistryEnabled, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/patch_rules_bulk_route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/patch_rules_bulk_route.test.ts index d0d5937eab2d70..6b3fa7ad83c68b 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/patch_rules_bulk_route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/patch_rules_bulk_route.test.ts @@ -43,8 +43,8 @@ describe.each([ patchRulesBulkRoute(server.router, ml, isRuleRegistryEnabled); }); - describe('status codes with actionClient and alertClient', () => { - test('returns 200 when updating a single rule with a valid actionClient and alertClient', async () => { + describe('status codes', () => { + test('returns 200', async () => { const response = await server.inject(getPatchBulkRequest(), context); expect(response.status).toEqual(200); }); @@ -88,13 +88,6 @@ describe.each([ ); }); - test('returns 404 if alertClient is not available on the route', async () => { - context.alerting.getRulesClient = jest.fn(); - const response = await server.inject(getPatchBulkRequest(), context); - expect(response.status).toEqual(404); - expect(response.body).toEqual({ message: 'Not Found', status_code: 404 }); - }); - it('rejects patching a rule to ML if mlAuthz fails', async () => { (buildMlAuthz as jest.Mock).mockReturnValueOnce({ validateRuleType: jest diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/patch_rules_bulk_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/patch_rules_bulk_route.ts index 1a79d12ae1b189..f30ba4665aeb05 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/patch_rules_bulk_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/patch_rules_bulk_route.ts @@ -46,14 +46,10 @@ export const patchRulesBulkRoute = ( async (context, request, response) => { const siemResponse = buildSiemResponse(response); - const rulesClient = context.alerting?.getRulesClient(); - const ruleStatusClient = context.securitySolution.getExecutionLogClient(); + const rulesClient = context.alerting.getRulesClient(); + const ruleExecutionLogClient = context.securitySolution.getExecutionLogClient(); const savedObjectsClient = context.core.savedObjects.client; - if (!rulesClient) { - return siemResponse.error({ statusCode: 404 }); - } - const mlAuthz = buildMlAuthz({ license: context.licensing.license, ml, @@ -193,11 +189,15 @@ export const patchRulesBulkRoute = ( exceptionsList, }); if (rule != null && rule.enabled != null && rule.name != null) { - const ruleStatus = await ruleStatusClient.getCurrentStatus({ - ruleId: rule.id, - spaceId: context.securitySolution.getSpaceId(), - }); - return transformValidateBulkError(rule.id, rule, ruleStatus, isRuleRegistryEnabled); + const ruleExecutionSummary = await ruleExecutionLogClient.getExecutionSummary( + rule.id + ); + return transformValidateBulkError( + rule.id, + rule, + ruleExecutionSummary, + isRuleRegistryEnabled + ); } else { return getIdBulkError({ id, ruleId }); } diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/patch_rules_route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/patch_rules_route.test.ts index fe8e4470a61cfc..594c91f561204d 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/patch_rules_route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/patch_rules_route.test.ts @@ -10,7 +10,7 @@ import { mlServicesMock, mlAuthzMock as mockMlAuthzFactory } from '../../../mach import { buildMlAuthz } from '../../../machine_learning/authz'; import { getEmptyFindResult, - getRuleExecutionStatusSucceeded, + getRuleExecutionSummarySucceeded, getAlertMock, getPatchRequest, getFindResultWithSingleHit, @@ -49,18 +49,19 @@ describe.each([ clients.savedObjectsClient.create.mockResolvedValue({ type: 'my-type', id: 'e0b86950-4e9f-11ea-bdbd-07b56aa159b3', - attributes: getRuleExecutionStatusSucceeded(), + // TODO: https://github.com/elastic/kibana/pull/121644 clean up + attributes: getRuleExecutionSummarySucceeded(), references: [], }); // successful transform - clients.ruleExecutionLogClient.getCurrentStatus.mockResolvedValue( - getRuleExecutionStatusSucceeded() + clients.ruleExecutionLogClient.getExecutionSummary.mockResolvedValue( + getRuleExecutionSummarySucceeded() ); patchRulesRoute(server.router, ml, isRuleRegistryEnabled); }); - describe('status codes with actionClient and alertClient', () => { - test('returns 200 when updating a single rule with a valid actionClient and alertClient', async () => { + describe('status codes', () => { + test('returns 200', async () => { const response = await server.inject(getPatchRequest(), context); expect(response.status).toEqual(200); }); @@ -75,13 +76,6 @@ describe.each([ }); }); - test('returns 404 if alertClient is not available on the route', async () => { - context.alerting.getRulesClient = jest.fn(); - const response = await server.inject(getPatchRequest(), context); - expect(response.status).toEqual(404); - expect(response.body).toEqual({ message: 'Not Found', status_code: 404 }); - }); - test('returns error if requesting a non-rule', async () => { clients.rulesClient.find.mockResolvedValue(nonRuleFindResult(isRuleRegistryEnabled)); const response = await server.inject(getPatchRequest(), context); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/patch_rules_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/patch_rules_route.ts index 6d11fc5851625d..f75fcbc4dea287 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/patch_rules_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/patch_rules_route.ts @@ -106,14 +106,10 @@ export const patchRulesRoute = ( const actions: RuleAlertAction[] = actionsRest as RuleAlertAction[]; const filters: PartialFilter[] | undefined = filtersRest as PartialFilter[]; - const rulesClient = context.alerting?.getRulesClient(); - const ruleStatusClient = context.securitySolution.getExecutionLogClient(); + const rulesClient = context.alerting.getRulesClient(); + const ruleExecutionLogClient = context.securitySolution.getExecutionLogClient(); const savedObjectsClient = context.core.savedObjects.client; - if (!rulesClient) { - return siemResponse.error({ statusCode: 404 }); - } - const mlAuthz = buildMlAuthz({ license: context.licensing.license, ml, @@ -194,12 +190,13 @@ export const patchRulesRoute = ( exceptionsList, }); if (rule != null && rule.enabled != null && rule.name != null) { - const ruleStatus = await ruleStatusClient.getCurrentStatus({ - ruleId: rule.id, - spaceId: context.securitySolution.getSpaceId(), - }); + const ruleExecutionSummary = await ruleExecutionLogClient.getExecutionSummary(rule.id); - const [validated, errors] = transformValidate(rule, ruleStatus, isRuleRegistryEnabled); + const [validated, errors] = transformValidate( + rule, + ruleExecutionSummary, + isRuleRegistryEnabled + ); if (errors != null) { return siemResponse.error({ statusCode: 500, body: errors }); } else { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/perform_bulk_action_route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/perform_bulk_action_route.test.ts index c99760b72b56b4..4019e519e9db49 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/perform_bulk_action_route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/perform_bulk_action_route.test.ts @@ -71,13 +71,6 @@ describe.each([ status_code: 400, }); }); - - it('returns 404 if alertClient is not available on the route', async () => { - context.alerting.getRulesClient = jest.fn(); - const response = await server.inject(getBulkActionRequest(), context); - expect(response.status).toEqual(404); - expect(response.body).toEqual({ message: 'Not Found', status_code: 404 }); - }); }); describe('rules execution failures', () => { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/perform_bulk_action_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/perform_bulk_action_route.ts index f263cd7b9cec1c..6e9d9d0e02d527 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/perform_bulk_action_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/perform_bulk_action_route.ts @@ -158,10 +158,10 @@ export const performBulkActionRoute = ( request.events.completed$.subscribe(() => abortController.abort()); try { - const rulesClient = context.alerting?.getRulesClient(); + const rulesClient = context.alerting.getRulesClient(); + const ruleExecutionLogClient = context.securitySolution.getExecutionLogClient(); const exceptionsClient = context.lists?.getExceptionListClient(); const savedObjectsClient = context.core.savedObjects.client; - const ruleStatusClient = context.securitySolution.getExecutionLogClient(); const mlAuthz = buildMlAuthz({ license: context.licensing.license, @@ -170,10 +170,6 @@ export const performBulkActionRoute = ( savedObjectsClient, }); - if (!rulesClient) { - return siemResponse.error({ statusCode: 404 }); - } - const rules = await findRules({ isRuleRegistryEnabled, rulesClient, @@ -232,7 +228,7 @@ export const performBulkActionRoute = ( await deleteRules({ ruleId: rule.id, rulesClient, - ruleStatusClient, + ruleExecutionLogClient, }); }, abortController.signal diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/preview_rules_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/preview_rules_route.ts index b93125d614f123..204c67bf6cf5ac 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/preview_rules_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/preview_rules_route.ts @@ -11,7 +11,7 @@ import { IRuleDataClient } from '../../../../../../rule_registry/server'; import { buildSiemResponse } from '../utils'; import { convertCreateAPIToInternalSchema } from '../../schemas/rule_converters'; import { RuleParams } from '../../schemas/rule_schemas'; -import { createWarningsAndErrors } from '../../signals/preview/preview_rule_execution_log_client'; +import { createPreviewRuleExecutionLogger } from '../../signals/preview/preview_rule_execution_logger'; import { parseInterval } from '../../signals/utils'; import { buildMlAuthz } from '../../../machine_learning/authz'; import { throwHttpError } from '../../../machine_learning/validation'; @@ -24,7 +24,7 @@ import { previewRulesSchema, RulePreviewLogs, } from '../../../../../common/detection_engine/schemas/request'; -import { RuleExecutionStatus } from '../../../../../common/detection_engine/schemas/common/schemas'; +import { RuleExecutionStatus } from '../../../../../common/detection_engine/schemas/common'; import { AlertInstanceContext, @@ -75,10 +75,7 @@ export const previewRulesRoute = async ( } try { const savedObjectsClient = context.core.savedObjects.client; - const siemClient = context.securitySolution?.getAppClient(); - if (!siemClient) { - return siemResponse.error({ statusCode: 404 }); - } + const siemClient = context.securitySolution.getAppClient(); let invocationCount = request.body.invocationCount; if ( @@ -115,14 +112,14 @@ export const previewRulesRoute = async ( const spaceId = siemClient.getSpaceId(); const previewId = uuid.v4(); const username = security?.authc.getCurrentUser(request)?.username; - const { previewRuleExecutionLogClient, warningsAndErrorsStore } = createWarningsAndErrors(); + const previewRuleExecutionLogger = createPreviewRuleExecutionLogger(); const runState: Record = {}; const logs: RulePreviewLogs[] = []; const previewRuleTypeWrapper = createSecurityRuleTypeWrapper({ ...securityRuleTypeOptions, ruleDataClient: previewRuleDataClient, - ruleExecutionLogClientOverride: previewRuleExecutionLogClient, + ruleExecutionLoggerFactory: previewRuleExecutionLogger.factory, }); const runExecutors = async < @@ -194,21 +191,25 @@ export const previewRulesRoute = async ( })) as TState; // Save and reset error and warning logs - const currentLogs = { - errors: warningsAndErrorsStore - .filter((item) => item.newStatus === RuleExecutionStatus.failed) - .map((item) => item.message ?? 'Unkown Error'), - warnings: warningsAndErrorsStore - .filter( - (item) => - item.newStatus === RuleExecutionStatus['partial failure'] || - item.newStatus === RuleExecutionStatus.warning - ) - .map((item) => item.message ?? 'Unknown Warning'), + const errors = previewRuleExecutionLogger.logged.statusChanges + .filter((item) => item.newStatus === RuleExecutionStatus.failed) + .map((item) => item.message ?? 'Unkown Error'); + + const warnings = previewRuleExecutionLogger.logged.statusChanges + .filter( + (item) => + item.newStatus === RuleExecutionStatus['partial failure'] || + item.newStatus === RuleExecutionStatus.warning + ) + .map((item) => item.message ?? 'Unknown Warning'); + + logs.push({ + errors, + warnings, startedAt: startedAt.toDate().toISOString(), - }; - logs.push(currentLogs); - previewRuleExecutionLogClient.clearWarningsAndErrorsStore(); + }); + + previewRuleExecutionLogger.clearLogs(); previousStartedAt = startedAt.toDate(); startedAt.add(parseInterval(internalRule.schedule.interval)); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/read_rules_route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/read_rules_route.test.ts index 4264ca9961bd47..d462141a8fade3 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/read_rules_route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/read_rules_route.test.ts @@ -16,7 +16,7 @@ import { getFindResultWithSingleHit, nonRuleFindResult, getEmptySavedObjectsResponse, - getRuleExecutionStatusSucceeded, + getRuleExecutionSummarySucceeded, resolveAlertMock, } from '../__mocks__/request_responses'; import { requestMock, requestContextMock, serverMock } from '../__mocks__'; @@ -38,8 +38,8 @@ describe.each([ clients.rulesClient.find.mockResolvedValue(getFindResultWithSingleHit(isRuleRegistryEnabled)); // rule exists clients.savedObjectsClient.find.mockResolvedValue(getEmptySavedObjectsResponse()); // successful transform - clients.ruleExecutionLogClient.getCurrentStatus.mockResolvedValue( - getRuleExecutionStatusSucceeded() + clients.ruleExecutionLogClient.getExecutionSummary.mockResolvedValue( + getRuleExecutionSummarySucceeded() ); clients.rulesClient.resolve.mockResolvedValue({ @@ -51,8 +51,8 @@ describe.each([ readRulesRoute(server.router, logger, isRuleRegistryEnabled); }); - describe('status codes with actionClient and alertClient', () => { - test('returns 200 when reading a single rule with a valid actionClient and alertClient', async () => { + describe('status codes', () => { + test('returns 200', async () => { const response = await server.inject(getReadRequest(), context); expect(response.status).toEqual(200); }); @@ -88,13 +88,6 @@ describe.each([ expect(response.body.alias_target_id).toEqual('myaliastargetid'); }); - test('returns 404 if alertClient is not available on the route', async () => { - context.alerting.getRulesClient = jest.fn(); - const response = await server.inject(getReadRequest(), context); - expect(response.status).toEqual(404); - expect(response.body).toEqual({ message: 'Not Found', status_code: 404 }); - }); - test('returns error if requesting a non-rule', async () => { clients.rulesClient.find.mockResolvedValue(nonRuleFindResult(isRuleRegistryEnabled)); const response = await server.inject(getReadRequest(), context); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/read_rules_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/read_rules_route.ts index 7193387088d841..d327c53089cf67 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/read_rules_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/read_rules_route.ts @@ -48,15 +48,11 @@ export const readRulesRoute = ( const { id, rule_id: ruleId } = request.query; - const rulesClient = context.alerting?.getRulesClient(); - try { - if (!rulesClient) { - return siemResponse.error({ statusCode: 404 }); - } - - const ruleStatusClient = context.securitySolution.getExecutionLogClient(); + const rulesClient = context.alerting.getRulesClient(); + const ruleExecutionLogClient = context.securitySolution.getExecutionLogClient(); const savedObjectsClient = context.core.savedObjects.client; + const rule = await readRules({ id, isRuleRegistryEnabled, @@ -69,14 +65,12 @@ export const readRulesRoute = ( ruleAlertId: rule.id, logger, }); - const currentStatus = await ruleStatusClient.getCurrentStatus({ - ruleId: rule.id, - spaceId: context.securitySolution.getSpaceId(), - }); + + const ruleExecutionSummary = await ruleExecutionLogClient.getExecutionSummary(rule.id); const transformed = transform( rule, - currentStatus, + ruleExecutionSummary, isRuleRegistryEnabled, legacyRuleActions ); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_bulk_route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_bulk_route.test.ts index 22e8f6543eb7c2..88c15f99ed6f7c 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_bulk_route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_bulk_route.test.ts @@ -46,8 +46,8 @@ describe.each([ updateRulesBulkRoute(server.router, ml, isRuleRegistryEnabled); }); - describe('status codes with actionClient and alertClient', () => { - test('returns 200 when updating a single rule with a valid actionClient and alertClient', async () => { + describe('status codes', () => { + test('returns 200', async () => { const response = await server.inject(getUpdateBulkRequest(), context); expect(response.status).toEqual(200); }); @@ -66,21 +66,6 @@ describe.each([ expect(response.body).toEqual(expected); }); - test('returns 404 if alertClient is not available on the route', async () => { - context.alerting.getRulesClient = jest.fn(); - const response = await server.inject(getUpdateBulkRequest(), context); - expect(response.status).toEqual(404); - expect(response.body).toEqual({ message: 'Not Found', status_code: 404 }); - }); - - it('returns 404 if siem client is unavailable', async () => { - const { securitySolution, ...contextWithoutSecuritySolution } = context; - // @ts-expect-error - const response = await server.inject(getUpdateBulkRequest(), contextWithoutSecuritySolution); - expect(response.status).toEqual(404); - expect(response.body).toEqual({ message: 'Not Found', status_code: 404 }); - }); - test('returns an error if update throws', async () => { clients.rulesClient.update.mockImplementation(() => { throw new Error('Test error'); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_bulk_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_bulk_route.ts index e3a125e50bfe9e..e560474b8a6543 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_bulk_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_bulk_route.ts @@ -40,13 +40,10 @@ export const updateRulesBulkRoute = ( async (context, request, response) => { const siemResponse = buildSiemResponse(response); - const rulesClient = context.alerting?.getRulesClient(); + const rulesClient = context.alerting.getRulesClient(); + const ruleExecutionLogClient = context.securitySolution.getExecutionLogClient(); const savedObjectsClient = context.core.savedObjects.client; - const siemClient = context.securitySolution?.getAppClient(); - - if (!siemClient || !rulesClient) { - return siemResponse.error({ statusCode: 404 }); - } + const siemClient = context.securitySolution.getAppClient(); const mlAuthz = buildMlAuthz({ license: context.licensing.license, @@ -55,7 +52,6 @@ export const updateRulesBulkRoute = ( savedObjectsClient, }); - const ruleStatusClient = context.securitySolution.getExecutionLogClient(); const rules = await Promise.all( request.body.map(async (payloadRule) => { const idOrRuleIdOrUnknown = payloadRule.id ?? payloadRule.rule_id ?? '(unknown id)'; @@ -91,11 +87,15 @@ export const updateRulesBulkRoute = ( ruleUpdate: payloadRule, }); if (rule != null) { - const ruleStatus = await ruleStatusClient.getCurrentStatus({ - ruleId: rule.id, - spaceId: context.securitySolution.getSpaceId(), - }); - return transformValidateBulkError(rule.id, rule, ruleStatus, isRuleRegistryEnabled); + const ruleExecutionSummary = await ruleExecutionLogClient.getExecutionSummary( + rule.id + ); + return transformValidateBulkError( + rule.id, + rule, + ruleExecutionSummary, + isRuleRegistryEnabled + ); } else { return getIdBulkError({ id: payloadRule.id, ruleId: payloadRule.rule_id }); } diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_route.test.ts index 131015880053c2..0c1e685a0dad3a 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_route.test.ts @@ -12,7 +12,7 @@ import { getAlertMock, getUpdateRequest, getFindResultWithSingleHit, - getRuleExecutionStatusSucceeded, + getRuleExecutionSummarySucceeded, nonRuleFindResult, typicalMlRulePayload, } from '../__mocks__/request_responses'; @@ -44,16 +44,16 @@ describe.each([ clients.rulesClient.update.mockResolvedValue( getAlertMock(isRuleRegistryEnabled, getQueryRuleParams()) ); // successful update - clients.ruleExecutionLogClient.getCurrentStatus.mockResolvedValue( - getRuleExecutionStatusSucceeded() + clients.ruleExecutionLogClient.getExecutionSummary.mockResolvedValue( + getRuleExecutionSummarySucceeded() ); clients.appClient.getSignalsIndex.mockReturnValue('.siem-signals-test-index'); updateRulesRoute(server.router, ml, isRuleRegistryEnabled); }); - describe('status codes with actionClient and alertClient', () => { - test('returns 200 when updating a single rule with a valid actionClient and alertClient', async () => { + describe('status codes', () => { + test('returns 200', async () => { const response = await server.inject(getUpdateRequest(), context); expect(response.status).toEqual(200); }); @@ -69,22 +69,6 @@ describe.each([ }); }); - test('returns 404 if alertClient is not available on the route', async () => { - context.alerting.getRulesClient = jest.fn(); - const response = await server.inject(getUpdateRequest(), context); - - expect(response.status).toEqual(404); - expect(response.body).toEqual({ message: 'Not Found', status_code: 404 }); - }); - - it('returns 404 if siem client is unavailable', async () => { - const { securitySolution, ...contextWithoutSecuritySolution } = context; - // @ts-expect-error - const response = await server.inject(getUpdateRequest(), contextWithoutSecuritySolution); - expect(response.status).toEqual(404); - expect(response.body).toEqual({ message: 'Not Found', status_code: 404 }); - }); - test('returns error when updating non-rule', async () => { clients.rulesClient.find.mockResolvedValue(nonRuleFindResult(isRuleRegistryEnabled)); const response = await server.inject(getUpdateRequest(), context); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_route.ts index f8bb60eb5f77f7..49dcdea0f183cd 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_route.ts @@ -44,13 +44,9 @@ export const updateRulesRoute = ( return siemResponse.error({ statusCode: 400, body: validationErrors }); } try { - const rulesClient = context.alerting?.getRulesClient(); + const rulesClient = context.alerting.getRulesClient(); const savedObjectsClient = context.core.savedObjects.client; - const siemClient = context.securitySolution?.getAppClient(); - - if (!siemClient || !rulesClient) { - return siemResponse.error({ statusCode: 404 }); - } + const siemClient = context.securitySolution.getAppClient(); const mlAuthz = buildMlAuthz({ license: context.licensing.license, @@ -60,8 +56,6 @@ export const updateRulesRoute = ( }); throwHttpError(await mlAuthz.validateRuleType(request.body.type)); - const ruleStatusClient = context.securitySolution.getExecutionLogClient(); - const existingRule = await readRules({ isRuleRegistryEnabled, rulesClient, @@ -82,11 +76,13 @@ export const updateRulesRoute = ( }); if (rule != null) { - const ruleStatus = await ruleStatusClient.getCurrentStatus({ - ruleId: rule.id, - spaceId: context.securitySolution.getSpaceId(), - }); - const [validated, errors] = transformValidate(rule, ruleStatus, isRuleRegistryEnabled); + const ruleExecutionLogClient = context.securitySolution.getExecutionLogClient(); + const ruleExecutionSummary = await ruleExecutionLogClient.getExecutionSummary(rule.id); + const [validated, errors] = transformValidate( + rule, + ruleExecutionSummary, + isRuleRegistryEnabled + ); if (errors != null) { return siemResponse.error({ statusCode: 500, body: errors }); } else { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils.ts index 8819b068fd5d78..7e9f03cf828a8d 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils.ts @@ -11,24 +11,21 @@ import { Action } from '@kbn/securitysolution-io-ts-alerting-types'; import { SavedObjectsClientContract } from 'kibana/server'; import pMap from 'p-map'; +import { RuleExecutionSummary } from '../../../../../common/detection_engine/schemas/common'; import { RulesSchema } from '../../../../../common/detection_engine/schemas/response/rules_schema'; import { ImportRulesSchemaDecoded } from '../../../../../common/detection_engine/schemas/request/import_rules_schema'; import { CreateRulesBulkSchema } from '../../../../../common/detection_engine/schemas/request/create_rules_bulk_schema'; import { PartialAlert, FindResult } from '../../../../../../alerting/server'; import { ActionsClient } from '../../../../../../actions/server'; import { INTERNAL_IDENTIFIER } from '../../../../../common/constants'; -import { - RuleAlertType, - isAlertType, - isRuleStatusSavedObjectAttributes, - IRuleStatusSOAttributes, -} from '../../rules/types'; +import { RuleAlertType, isAlertType } from '../../rules/types'; import { createBulkErrorObject, BulkError, OutputError } from '../utils'; import { internalRuleToAPIResponse } from '../../schemas/rule_converters'; import { RuleParams } from '../../schemas/rule_schemas'; import { SanitizedAlert } from '../../../../../../alerting/common'; // eslint-disable-next-line no-restricted-imports import { LegacyRulesActionsSavedObject } from '../../rule_actions/legacy_get_rule_actions_saved_object'; +import { RuleExecutionSummariesByRuleId } from '../../rule_execution_log'; type PromiseFromStreams = ImportRulesSchemaDecoded | Error; const MAX_CONCURRENT_SEARCHES = 10; @@ -99,23 +96,23 @@ export const transformTags = (tags: string[]): string[] => { // Transforms the data but will remove any null or undefined it encounters and not include // those on the export export const transformAlertToRule = ( - alert: SanitizedAlert, - ruleStatus?: IRuleStatusSOAttributes, + rule: SanitizedAlert, + ruleExecutionSummary?: RuleExecutionSummary | null, legacyRuleActions?: LegacyRulesActionsSavedObject | null ): Partial => { - return internalRuleToAPIResponse(alert, ruleStatus, legacyRuleActions); + return internalRuleToAPIResponse(rule, ruleExecutionSummary, legacyRuleActions); }; export const transformAlertsToRules = ( - alerts: RuleAlertType[], + rules: RuleAlertType[], legacyRuleActions: Record ): Array> => { - return alerts.map((alert) => transformAlertToRule(alert, undefined, legacyRuleActions[alert.id])); + return rules.map((rule) => transformAlertToRule(rule, null, legacyRuleActions[rule.id])); }; export const transformFindAlerts = ( - findResults: FindResult, - currentStatusesByRuleId: { [key: string]: IRuleStatusSOAttributes | undefined }, + ruleFindResults: FindResult, + ruleExecutionSummariesByRuleId: RuleExecutionSummariesByRuleId, legacyRuleActions: Record ): { page: number; @@ -124,28 +121,24 @@ export const transformFindAlerts = ( data: Array>; } | null => { return { - page: findResults.page, - perPage: findResults.perPage, - total: findResults.total, - data: findResults.data.map((alert) => { - const status = currentStatusesByRuleId[alert.id]; - return internalRuleToAPIResponse(alert, status, legacyRuleActions[alert.id]); + page: ruleFindResults.page, + perPage: ruleFindResults.perPage, + total: ruleFindResults.total, + data: ruleFindResults.data.map((rule) => { + const executionSummary = ruleExecutionSummariesByRuleId[rule.id]; + return internalRuleToAPIResponse(rule, executionSummary, legacyRuleActions[rule.id]); }), }; }; export const transform = ( - alert: PartialAlert, - ruleStatus?: IRuleStatusSOAttributes, + rule: PartialAlert, + ruleExecutionSummary?: RuleExecutionSummary | null, isRuleRegistryEnabled?: boolean, legacyRuleActions?: LegacyRulesActionsSavedObject | null ): Partial | null => { - if (isAlertType(isRuleRegistryEnabled ?? false, alert)) { - return transformAlertToRule( - alert, - isRuleStatusSavedObjectAttributes(ruleStatus) ? ruleStatus : undefined, - legacyRuleActions - ); + if (isAlertType(isRuleRegistryEnabled ?? false, rule)) { + return transformAlertToRule(rule, ruleExecutionSummary, legacyRuleActions); } return null; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils/get_current_rule_statuses.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils/get_current_rule_statuses.ts deleted file mode 100644 index 4622805e11db66..00000000000000 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils/get_current_rule_statuses.ts +++ /dev/null @@ -1,64 +0,0 @@ -/* - * 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 { chunk } from 'lodash'; -import { Logger } from 'src/core/server'; -import { initPromisePool } from '../../../../../utils/promise_pool'; -import { GetCurrentStatusBulkResult, IRuleExecutionLogClient } from '../../../rule_execution_log'; - -const RULES_PER_CHUNK = 1000; - -interface GetCurrentRuleStatusesArgs { - ruleIds: string[]; - execLogClient: IRuleExecutionLogClient; - spaceId: string; - logger: Logger; -} - -/** - * Get the most recent execution status for each of the given rule IDs. - * This method splits work into chunks so not to owerwhelm Elasticsearch - * when fetching statuses for a big number of rules. - * - * @param ruleIds Rule IDs to fetch statuses for - * @param execLogClient RuleExecutionLogClient - * @param spaceId Current Space ID - * @param logger Logger - * @returns A dict with rule IDs as keys and rule statuses as values - * - * @throws AggregateError if any of the rule status requests fail - */ -export async function getCurrentRuleStatuses({ - ruleIds, - execLogClient, - spaceId, - logger, -}: GetCurrentRuleStatusesArgs): Promise { - const { results, errors } = await initPromisePool({ - concurrency: 1, - items: chunk(ruleIds, RULES_PER_CHUNK), - executor: (ruleIdsChunk) => - execLogClient - .getCurrentStatusBulk({ - ruleIds: ruleIdsChunk, - spaceId, - }) - .catch((error) => { - logger.error( - `Error fetching rule status: ${error instanceof Error ? error.message : String(error)}` - ); - throw error; - }), - }); - - if (errors.length) { - throw new AggregateError(errors, 'Error fetching rule statuses'); - } - - // Merge all rule statuses into a single dict - return Object.assign({}, ...results); -} diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils/import_rules_utils.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils/import_rules_utils.test.ts index c8aad35fa62d54..8d78592dc7fc46 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils/import_rules_utils.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils/import_rules_utils.test.ts @@ -45,7 +45,6 @@ describe('importRules', () => { isRuleRegistryEnabled: true, savedObjectsClient: context.core.savedObjects.client, rulesClient: context.alerting.getRulesClient(), - ruleStatusClient: context.securitySolution.getExecutionLogClient(), exceptionsClient: context.lists?.getExceptionListClient(), spaceId: 'default', signalsIndex: '.signals-index', @@ -64,7 +63,6 @@ describe('importRules', () => { isRuleRegistryEnabled: true, savedObjectsClient: context.core.savedObjects.client, rulesClient: context.alerting.getRulesClient(), - ruleStatusClient: context.securitySolution.getExecutionLogClient(), exceptionsClient: context.lists?.getExceptionListClient(), spaceId: 'default', signalsIndex: '.signals-index', @@ -98,7 +96,6 @@ describe('importRules', () => { isRuleRegistryEnabled: true, savedObjectsClient: context.core.savedObjects.client, rulesClient: context.alerting.getRulesClient(), - ruleStatusClient: context.securitySolution.getExecutionLogClient(), exceptionsClient: context.lists?.getExceptionListClient(), spaceId: 'default', signalsIndex: '.signals-index', @@ -128,7 +125,6 @@ describe('importRules', () => { isRuleRegistryEnabled: true, savedObjectsClient: context.core.savedObjects.client, rulesClient: context.alerting.getRulesClient(), - ruleStatusClient: context.securitySolution.getExecutionLogClient(), exceptionsClient: context.lists?.getExceptionListClient(), spaceId: 'default', signalsIndex: '.signals-index', @@ -163,7 +159,6 @@ describe('importRules', () => { isRuleRegistryEnabled: true, savedObjectsClient: context.core.savedObjects.client, rulesClient: context.alerting.getRulesClient(), - ruleStatusClient: context.securitySolution.getExecutionLogClient(), exceptionsClient: context.lists?.getExceptionListClient(), spaceId: 'default', signalsIndex: '.signals-index', @@ -193,7 +188,6 @@ describe('importRules', () => { isRuleRegistryEnabled: true, savedObjectsClient: context.core.savedObjects.client, rulesClient: context.alerting.getRulesClient(), - ruleStatusClient: context.securitySolution.getExecutionLogClient(), exceptionsClient: context.lists?.getExceptionListClient(), spaceId: 'default', signalsIndex: '.signals-index', @@ -231,7 +225,6 @@ describe('importRules', () => { isRuleRegistryEnabled: true, savedObjectsClient: context.core.savedObjects.client, rulesClient: context.alerting.getRulesClient(), - ruleStatusClient: context.securitySolution.getExecutionLogClient(), exceptionsClient: context.lists?.getExceptionListClient(), spaceId: 'default', signalsIndex: '.signals-index', @@ -268,7 +261,6 @@ describe('importRules', () => { isRuleRegistryEnabled: true, savedObjectsClient: context.core.savedObjects.client, rulesClient: context.alerting.getRulesClient(), - ruleStatusClient: context.securitySolution.getExecutionLogClient(), exceptionsClient: context.lists?.getExceptionListClient(), spaceId: 'default', signalsIndex: '.signals-index', diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils/import_rules_utils.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils/import_rules_utils.ts index 3f0adaf58a2fd2..121e54c7688569 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils/import_rules_utils.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils/import_rules_utils.ts @@ -23,7 +23,6 @@ import { ImportRulesSchemaDecoded } from '../../../../../../common/detection_eng import { MlAuthz } from '../../../../machine_learning/authz'; import { throwHttpError } from '../../../../machine_learning/validation'; import { RulesClient } from '../../../../../../../../plugins/alerting/server'; -import { IRuleExecutionLogClient } from '../../../rule_execution_log'; import { ExceptionListClient } from '../../../../../../../../plugins/lists/server'; import { checkRuleExceptionReferences } from './check_rule_exception_references'; @@ -45,7 +44,6 @@ export interface RuleExceptionsPromiseFromStreams { * @param isRuleRegistryEnabled {boolean} - feature flag that should be * removed as this is now on and no going back * @param rulesClient {object} - * @param ruleStatusClient {object} * @param savedObjectsClient {object} * @param exceptionsClient {object} * @param spaceId {string} - space being used during import @@ -61,7 +59,6 @@ export const importRules = async ({ overwriteRules, isRuleRegistryEnabled, rulesClient, - ruleStatusClient, savedObjectsClient, exceptionsClient, spaceId, @@ -74,7 +71,6 @@ export const importRules = async ({ overwriteRules: boolean; isRuleRegistryEnabled: boolean; rulesClient: RulesClient; - ruleStatusClient: IRuleExecutionLogClient; savedObjectsClient: SavedObjectsClientContract; exceptionsClient: ExceptionListClient | undefined; spaceId: string; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/validate.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/validate.test.ts index 032988bcca8be1..4d8f64193e6ec3 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/validate.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/validate.test.ts @@ -8,11 +8,10 @@ import { transformValidate, transformValidateBulkError } from './validate'; import { BulkError } from '../utils'; import { RulesSchema } from '../../../../../common/detection_engine/schemas/response'; -import { getAlertMock, getRuleExecutionStatusSucceeded } from '../__mocks__/request_responses'; +import { getAlertMock, getRuleExecutionSummarySucceeded } from '../__mocks__/request_responses'; import { getListArrayMock } from '../../../../../common/detection_engine/schemas/types/lists.mock'; import { getThreatMock } from '../../../../../common/detection_engine/schemas/types/threat.mock'; import { getQueryRuleParams } from '../../schemas/rule_schemas.mock'; -import { RuleExecutionStatus } from '../../../../../common/detection_engine/schemas/common/schemas'; export const ruleOutput = (): RulesSchema => ({ actions: [], @@ -73,7 +72,7 @@ describe.each([ describe('transformValidate', () => { test('it should do a validation correctly of a partial alert', () => { const ruleAlert = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams()); - const [validated, errors] = transformValidate(ruleAlert, undefined, isRuleRegistryEnabled); + const [validated, errors] = transformValidate(ruleAlert, null, isRuleRegistryEnabled); expect(validated).toEqual(ruleOutput()); expect(errors).toEqual(null); }); @@ -82,7 +81,7 @@ describe.each([ const ruleAlert = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams()); // @ts-expect-error delete ruleAlert.name; - const [validated, errors] = transformValidate(ruleAlert, undefined, isRuleRegistryEnabled); + const [validated, errors] = transformValidate(ruleAlert, null, isRuleRegistryEnabled); expect(validated).toEqual(null); expect(errors).toEqual('Invalid value "undefined" supplied to "name"'); }); @@ -94,7 +93,7 @@ describe.each([ const validatedOrError = transformValidateBulkError( 'rule-1', ruleAlert, - undefined, + null, isRuleRegistryEnabled ); expect(validatedOrError).toEqual(ruleOutput()); @@ -107,7 +106,7 @@ describe.each([ const validatedOrError = transformValidateBulkError( 'rule-1', ruleAlert, - undefined, + null, isRuleRegistryEnabled ); const expected: BulkError = { @@ -120,25 +119,24 @@ describe.each([ expect(validatedOrError).toEqual(expected); }); + // TODO: https://github.com/elastic/kibana/pull/121644 clean up test('it should do a validation correctly of a rule id with ruleStatus passed in', () => { - const ruleStatus = getRuleExecutionStatusSucceeded(); - const ruleAlert = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams()); + const rule = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams()); + const ruleExecutionSumary = getRuleExecutionSummarySucceeded(); const validatedOrError = transformValidateBulkError( 'rule-1', - ruleAlert, - ruleStatus, + rule, + ruleExecutionSumary, isRuleRegistryEnabled ); const expected: RulesSchema = { ...ruleOutput(), - status: RuleExecutionStatus.succeeded, - status_date: '2020-02-18T15:26:49.783Z', - last_success_at: '2020-02-18T15:26:49.783Z', - last_success_message: 'succeeded', + execution_summary: ruleExecutionSumary, }; expect(validatedOrError).toEqual(expected); }); + // TODO: https://github.com/elastic/kibana/pull/121644 clean up test('it should return error object if "alert" is not expected alert type', () => { const ruleAlert = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams()); // @ts-expect-error @@ -146,7 +144,7 @@ describe.each([ const validatedOrError = transformValidateBulkError( 'rule-1', ruleAlert, - undefined, + null, isRuleRegistryEnabled ); const expected: BulkError = { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/validate.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/validate.ts index d4bb020cfb6728..54a1b3521f2b19 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/validate.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/validate.ts @@ -6,6 +6,8 @@ */ import { validateNonExact } from '@kbn/securitysolution-io-ts-utils'; + +import { RuleExecutionSummary } from '../../../../../common/detection_engine/schemas/common'; import { FullResponseSchema, fullResponseSchema, @@ -15,11 +17,7 @@ import { rulesSchema, } from '../../../../../common/detection_engine/schemas/response/rules_schema'; import { PartialAlert } from '../../../../../../alerting/server'; -import { - isAlertType, - IRuleStatusSOAttributes, - isRuleStatusSavedObjectAttributes, -} from '../../rules/types'; +import { isAlertType } from '../../rules/types'; import { createBulkErrorObject, BulkError } from '../utils'; import { transform, transformAlertToRule } from './utils'; import { RuleParams } from '../../schemas/rule_schemas'; @@ -27,12 +25,17 @@ import { RuleParams } from '../../schemas/rule_schemas'; import { LegacyRulesActionsSavedObject } from '../../rule_actions/legacy_get_rule_actions_saved_object'; export const transformValidate = ( - alert: PartialAlert, - ruleStatus?: IRuleStatusSOAttributes, + rule: PartialAlert, + ruleExecutionSummary: RuleExecutionSummary | null, isRuleRegistryEnabled?: boolean, legacyRuleActions?: LegacyRulesActionsSavedObject | null ): [RulesSchema | null, string | null] => { - const transformed = transform(alert, ruleStatus, isRuleRegistryEnabled, legacyRuleActions); + const transformed = transform( + rule, + ruleExecutionSummary, + isRuleRegistryEnabled, + legacyRuleActions + ); if (transformed == null) { return [null, 'Internal error transforming']; } else { @@ -41,12 +44,17 @@ export const transformValidate = ( }; export const newTransformValidate = ( - alert: PartialAlert, - ruleStatus?: IRuleStatusSOAttributes, + rule: PartialAlert, + ruleExecutionSummary: RuleExecutionSummary | null, isRuleRegistryEnabled?: boolean, legacyRuleActions?: LegacyRulesActionsSavedObject | null ): [FullResponseSchema | null, string | null] => { - const transformed = transform(alert, ruleStatus, isRuleRegistryEnabled, legacyRuleActions); + const transformed = transform( + rule, + ruleExecutionSummary, + isRuleRegistryEnabled, + legacyRuleActions + ); if (transformed == null) { return [null, 'Internal error transforming']; } else { @@ -56,35 +64,21 @@ export const newTransformValidate = ( export const transformValidateBulkError = ( ruleId: string, - alert: PartialAlert, - ruleStatus?: IRuleStatusSOAttributes, + rule: PartialAlert, + ruleExecutionSummary: RuleExecutionSummary | null, isRuleRegistryEnabled?: boolean ): RulesSchema | BulkError => { - if (isAlertType(isRuleRegistryEnabled ?? false, alert)) { - if (ruleStatus && isRuleStatusSavedObjectAttributes(ruleStatus)) { - const transformed = transformAlertToRule(alert, ruleStatus); - const [validated, errors] = validateNonExact(transformed, rulesSchema); - if (errors != null || validated == null) { - return createBulkErrorObject({ - ruleId, - statusCode: 500, - message: errors ?? 'Internal error transforming', - }); - } else { - return validated; - } + if (isAlertType(isRuleRegistryEnabled ?? false, rule)) { + const transformed = transformAlertToRule(rule, ruleExecutionSummary); + const [validated, errors] = validateNonExact(transformed, rulesSchema); + if (errors != null || validated == null) { + return createBulkErrorObject({ + ruleId, + statusCode: 500, + message: errors ?? 'Internal error transforming', + }); } else { - const transformed = transformAlertToRule(alert); - const [validated, errors] = validateNonExact(transformed, rulesSchema); - if (errors != null || validated == null) { - return createBulkErrorObject({ - ruleId, - statusCode: 500, - message: errors ?? 'Internal error transforming', - }); - } else { - return validated; - } + return validated; } } else { return createBulkErrorObject({ diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/utils.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/utils.test.ts index eee28c0b04149b..4e614b5fc83811 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/utils.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/utils.test.ts @@ -5,29 +5,11 @@ * 2.0. */ -import { SavedObjectsFindResponse } from 'kibana/server'; - -import { rulesClientMock } from '../../../../../alerting/server/mocks'; -import { IRuleStatusSOAttributes } from '../rules/types'; import { BadRequestError } from '@kbn/securitysolution-es-utils'; -import { - transformBulkError, - BulkError, - convertToSnakeCase, - SiemResponseFactory, - mergeStatuses, - getFailingRules, -} from './utils'; +import { transformBulkError, BulkError, convertToSnakeCase, SiemResponseFactory } from './utils'; import { responseMock } from './__mocks__'; -import { exampleRuleStatus } from '../signals/__mocks__/es_results'; -import { resolveAlertMock } from './__mocks__/request_responses'; -import { AlertExecutionStatusErrorReasons } from '../../../../../alerting/common'; -import { getQueryRuleParams } from '../schemas/rule_schemas.mock'; -import { RuleExecutionStatus } from '../../../../common/detection_engine/schemas/common/schemas'; import { CustomHttpRequestError } from '../../../utils/custom_http_request_error'; -let rulesClient: ReturnType; - describe.each([ ['Legacy', false], ['RAC', true], @@ -91,18 +73,19 @@ describe.each([ expect(convertToSnakeCase(values)).toEqual({}); }); it('returns null when passed in undefined', () => { + interface Foo { + bar: Record; + } + // Array accessors can result in undefined but // this is not represented in typescript for some reason, // https://github.com/Microsoft/TypeScript/issues/11122 - const values: SavedObjectsFindResponse = { - page: 0, - per_page: 5, - total: 0, - saved_objects: [], - }; - expect( - convertToSnakeCase(values.saved_objects[0]?.attributes) // this is undefined, but it says it's not - ).toEqual(null); + const array: Foo[] = []; + + // This is undefined, but it says it's not + const undefinedValue = array[0]?.bar; + + expect(convertToSnakeCase(undefinedValue)).toEqual(null); }); }); @@ -132,130 +115,4 @@ describe.each([ ); }); }); - - describe('mergeStatuses', () => { - it('merges statuses and converts from camelCase saved object to snake_case HTTP response', () => { - const statusOne = exampleRuleStatus(); - statusOne.attributes.status = RuleExecutionStatus.failed; - const statusTwo = exampleRuleStatus(); - statusTwo.attributes.status = RuleExecutionStatus.failed; - const currentStatus = exampleRuleStatus(); - const foundRules = [currentStatus.attributes, statusOne.attributes, statusTwo.attributes]; - const res = mergeStatuses(currentStatus.references[0].id, foundRules, { - 'myfakealertid-8cfac': { - current_status: { - status_date: '2020-03-27T22:55:59.517Z', - status: RuleExecutionStatus.succeeded, - last_failure_at: null, - last_success_at: '2020-03-27T22:55:59.517Z', - last_failure_message: null, - last_success_message: 'succeeded', - gap: null, - bulk_create_time_durations: [], - search_after_time_durations: [], - last_look_back_date: null, // NOTE: This is no longer used on the UI, but left here in case users are using it within the API - }, - failures: [], - }, - }); - expect(res).toEqual({ - 'myfakealertid-8cfac': { - current_status: { - status_date: '2020-03-27T22:55:59.517Z', - status: 'succeeded', - last_failure_at: null, - last_success_at: '2020-03-27T22:55:59.517Z', - last_failure_message: null, - last_success_message: 'succeeded', - gap: null, - bulk_create_time_durations: [], - search_after_time_durations: [], - last_look_back_date: null, // NOTE: This is no longer used on the UI, but left here in case users are using it within the API - }, - failures: [], - }, - 'f4b8e31d-cf93-4bde-a265-298bde885cd7': { - current_status: { - status_date: '2020-03-27T22:55:59.517Z', - status: 'succeeded', - last_failure_at: null, - last_success_at: '2020-03-27T22:55:59.517Z', - last_failure_message: null, - last_success_message: 'succeeded', - gap: null, - bulk_create_time_durations: [], - search_after_time_durations: [], - last_look_back_date: null, // NOTE: This is no longer used on the UI, but left here in case users are using it within the API - }, - failures: [ - { - status_date: '2020-03-27T22:55:59.517Z', - status: 'failed', - last_failure_at: null, - last_success_at: '2020-03-27T22:55:59.517Z', - last_failure_message: null, - last_success_message: 'succeeded', - gap: null, - bulk_create_time_durations: [], - search_after_time_durations: [], - last_look_back_date: null, // NOTE: This is no longer used on the UI, but left here in case users are using it within the API - }, - { - status_date: '2020-03-27T22:55:59.517Z', - status: 'failed', - last_failure_at: null, - last_success_at: '2020-03-27T22:55:59.517Z', - last_failure_message: null, - last_success_message: 'succeeded', - gap: null, - bulk_create_time_durations: [], - search_after_time_durations: [], - last_look_back_date: null, // NOTE: This is no longer used on the UI, but left here in case users are using it within the API - }, - ], - }, - }); - }); - }); - - describe('getFailingRules', () => { - beforeEach(() => { - rulesClient = rulesClientMock.create(); - }); - it('getFailingRules finds no failing rules', async () => { - rulesClient.resolve.mockResolvedValue( - resolveAlertMock(isRuleRegistryEnabled, getQueryRuleParams()) - ); - const res = await getFailingRules(['my-fake-id'], rulesClient); - expect(res).toEqual({}); - }); - it('getFailingRules finds a failing rule', async () => { - const foundRule = resolveAlertMock(isRuleRegistryEnabled, getQueryRuleParams()); - foundRule.executionStatus = { - status: 'error', - lastExecutionDate: foundRule.executionStatus.lastExecutionDate, - error: { - reason: AlertExecutionStatusErrorReasons.Read, - message: 'oops', - }, - }; - rulesClient.resolve.mockResolvedValue(foundRule); - const res = await getFailingRules([foundRule.id], rulesClient); - expect(res).toEqual({ [foundRule.id]: foundRule }); - }); - it('getFailingRules throws an error', async () => { - rulesClient.resolve.mockImplementation(() => { - throw new Error('my test error'); - }); - let error; - try { - await getFailingRules(['my-fake-id'], rulesClient); - } catch (exc) { - error = exc; - } - expect(error.message).toEqual( - 'Failed to get executionStatus with RulesClient: my test error' - ); - }); - }); }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/utils.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/utils.ts index a6e977207b8381..66418e6f8db246 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/utils.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/utils.ts @@ -7,17 +7,13 @@ import { has, snakeCase } from 'lodash/fp'; import { BadRequestError } from '@kbn/securitysolution-es-utils'; -import { SanitizedAlert } from '../../../../../alerting/common'; import { RouteValidationFunction, KibanaResponseFactory, CustomHttpResponseOptions, -} from '../../../../../../../src/core/server'; -import { RulesClient } from '../../../../../alerting/server'; -import { RuleStatusResponse, IRuleStatusSOAttributes } from '../rules/types'; +} from 'kibana/server'; -import { RuleParams } from '../schemas/rule_schemas'; import { CustomHttpRequestError } from '../../../utils/custom_http_request_error'; export interface OutputError { @@ -198,65 +194,3 @@ export const convertToSnakeCase = >( return { ...acc, [newKey]: obj[item] }; }, {}); }; - -/** - * - * @param id rule id - * @param currentStatusAndFailures array of rule statuses where the 0th status is the current status and 1-5 positions are the historical failures - * @param acc accumulated rule id : statuses - */ -export const mergeStatuses = ( - id: string, - currentStatusAndFailures: IRuleStatusSOAttributes[], - acc: RuleStatusResponse -): RuleStatusResponse => { - if (currentStatusAndFailures.length === 0) { - return { - ...acc, - }; - } - const convertedCurrentStatus = convertToSnakeCase( - currentStatusAndFailures[0] - ); - return { - ...acc, - [id]: { - current_status: convertedCurrentStatus, - failures: currentStatusAndFailures - .slice(1) - .map((errorItem) => convertToSnakeCase(errorItem)), - }, - } as RuleStatusResponse; -}; - -export type GetFailingRulesResult = Record>; - -export const getFailingRules = async ( - ids: string[], - rulesClient: RulesClient -): Promise => { - try { - const errorRules = await Promise.all( - ids.map(async (id) => - rulesClient.resolve({ - id, - }) - ) - ); - return errorRules - .filter((rule) => rule.executionStatus.status === 'error') - .reduce((acc, failingRule) => { - return { - [failingRule.id]: { - ...failingRule, - }, - ...acc, - }; - }, {}); - } catch (exc) { - if (exc instanceof CustomHttpRequestError) { - throw exc; - } - throw new Error(`Failed to get executionStatus with RulesClient: ${(exc as Error).message}`); - } -}; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/__mocks__/rule_execution_log_client.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/__mocks__/rule_execution_log_client.ts index c01d6afa951907..22a41f356c226e 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/__mocks__/rule_execution_log_client.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/__mocks__/rule_execution_log_client.ts @@ -5,23 +5,35 @@ * 2.0. */ -import { IRuleExecutionLogClient } from '../types'; +import { IRuleExecutionLogClient } from '../rule_execution_log_client/client_interface'; +import { + IRuleExecutionLogger, + RuleExecutionContext, +} from '../rule_execution_logger/logger_interface'; -export const ruleExecutionLogClientMock = { +const ruleExecutionLogClientMock = { create: (): jest.Mocked => ({ - find: jest.fn(), - findBulk: jest.fn(), - + getExecutionSummariesBulk: jest.fn(), + getExecutionSummary: jest.fn(), + clearExecutionSummary: jest.fn(), getLastFailures: jest.fn(), - getCurrentStatus: jest.fn(), - getCurrentStatusBulk: jest.fn(), + }), +}; - deleteCurrentStatus: jest.fn(), +const ruleExecutionLoggerMock = { + create: (context: Partial = {}): jest.Mocked => ({ + context: { + ruleId: context.ruleId ?? 'some rule id', + ruleName: context.ruleName ?? 'Some rule', + ruleType: context.ruleType ?? 'some rule type', + spaceId: context.spaceId ?? 'some space id', + }, logStatusChange: jest.fn(), }), }; -export const RuleExecutionLogClient = jest - .fn, []>() - .mockImplementation(ruleExecutionLogClientMock.create); +export const ruleExecutionLogMock = { + client: ruleExecutionLogClientMock, + logger: ruleExecutionLoggerMock, +}; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/event_log_adapter/event_log_adapter.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/event_log_adapter/event_log_adapter.ts deleted file mode 100644 index d88f4119b691fa..00000000000000 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/event_log_adapter/event_log_adapter.ts +++ /dev/null @@ -1,126 +0,0 @@ -/* - * 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 { sum } from 'lodash'; -import { SavedObjectsClientContract } from '../../../../../../../../src/core/server'; -import { IEventLogClient, IEventLogService } from '../../../../../../event_log/server'; -import { RuleExecutionStatus } from '../../../../../common/detection_engine/schemas/common/schemas'; -import { IRuleStatusSOAttributes } from '../../rules/types'; -import { SavedObjectsAdapter } from '../saved_objects_adapter/saved_objects_adapter'; -import { - FindBulkExecutionLogArgs, - FindExecutionLogArgs, - GetCurrentStatusArgs, - GetCurrentStatusBulkArgs, - GetCurrentStatusBulkResult, - GetLastFailuresArgs, - IRuleExecutionLogClient, - LogExecutionMetricsArgs, - LogStatusChangeArgs, -} from '../types'; -import { EventLogClient } from './event_log_client'; - -const MAX_LAST_FAILURES = 5; - -export class EventLogAdapter implements IRuleExecutionLogClient { - private eventLogClient: EventLogClient; - /** - * @deprecated Saved objects adapter is used during the transition period while the event log doesn't support all features needed to implement the execution log. - * We use savedObjectsAdapter to write/read the latest rule execution status and eventLogClient to read/write historical execution data. - * We can remove savedObjectsAdapter as soon as the event log supports all methods that we need (find, findBulk). - */ - private savedObjectsAdapter: IRuleExecutionLogClient; - - constructor( - eventLogService: IEventLogService, - eventLogClient: IEventLogClient | undefined, - savedObjectsClient: SavedObjectsClientContract - ) { - this.eventLogClient = new EventLogClient(eventLogService, eventLogClient); - this.savedObjectsAdapter = new SavedObjectsAdapter(savedObjectsClient); - } - - /** @deprecated */ - public async find(args: FindExecutionLogArgs) { - return this.savedObjectsAdapter.find(args); - } - - /** @deprecated */ - public async findBulk(args: FindBulkExecutionLogArgs) { - return this.savedObjectsAdapter.findBulk(args); - } - - public getLastFailures(args: GetLastFailuresArgs): Promise { - const { ruleId } = args; - return this.eventLogClient.getLastStatusChanges({ - ruleId, - count: MAX_LAST_FAILURES, - includeStatuses: [RuleExecutionStatus.failed], - }); - } - - public getCurrentStatus( - args: GetCurrentStatusArgs - ): Promise { - return this.savedObjectsAdapter.getCurrentStatus(args); - } - - public getCurrentStatusBulk(args: GetCurrentStatusBulkArgs): Promise { - return this.savedObjectsAdapter.getCurrentStatusBulk(args); - } - - public async deleteCurrentStatus(ruleId: string): Promise { - await this.savedObjectsAdapter.deleteCurrentStatus(ruleId); - - // EventLog execution events are immutable, nothing to do here - } - - public async logStatusChange(args: LogStatusChangeArgs): Promise { - await Promise.all([ - this.logStatusChangeToSavedObjects(args), - this.logStatusChangeToEventLog(args), - ]); - } - - private async logStatusChangeToSavedObjects(args: LogStatusChangeArgs): Promise { - await this.savedObjectsAdapter.logStatusChange(args); - } - - private async logStatusChangeToEventLog(args: LogStatusChangeArgs): Promise { - if (args.metrics) { - this.logExecutionMetrics({ - ruleId: args.ruleId, - ruleName: args.ruleName, - ruleType: args.ruleType, - spaceId: args.spaceId, - metrics: args.metrics, - }); - } - - this.eventLogClient.logStatusChange(args); - } - - private logExecutionMetrics(args: LogExecutionMetricsArgs): void { - const { ruleId, spaceId, ruleType, ruleName, metrics } = args; - - this.eventLogClient.logExecutionMetrics({ - ruleId, - ruleName, - ruleType, - spaceId, - metrics: { - executionGapDuration: metrics.executionGap?.asSeconds(), - totalIndexingDuration: metrics.indexingDurations - ? sum(metrics.indexingDurations.map(Number)) - : undefined, - totalSearchDuration: metrics.searchDurations - ? sum(metrics.searchDurations.map(Number)) - : undefined, - }, - }); - } -} diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/event_log_adapter/event_log_client.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/event_log_adapter/event_log_client.ts deleted file mode 100644 index 6ce9d3d1c26ee0..00000000000000 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/event_log_adapter/event_log_client.ts +++ /dev/null @@ -1,221 +0,0 @@ -/* - * 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 { SavedObjectsUtils } from '../../../../../../../../src/core/server'; -import { - IEventLogClient, - IEventLogger, - IEventLogService, - SAVED_OBJECT_REL_PRIMARY, -} from '../../../../../../event_log/server'; -import { RuleExecutionStatus } from '../../../../../common/detection_engine/schemas/common/schemas'; -import { invariant } from '../../../../../common/utils/invariant'; -import { IRuleStatusSOAttributes } from '../../rules/types'; -import { LogStatusChangeArgs } from '../types'; -import { - RuleExecutionLogAction, - RULE_EXECUTION_LOG_PROVIDER, - ALERT_SAVED_OBJECT_TYPE, -} from './constants'; - -const spaceIdToNamespace = SavedObjectsUtils.namespaceStringToId; - -const now = () => new Date().toISOString(); - -const statusSeverityDict: Record = { - [RuleExecutionStatus.succeeded]: 0, - [RuleExecutionStatus['going to run']]: 10, - [RuleExecutionStatus.warning]: 20, - [RuleExecutionStatus['partial failure']]: 20, - [RuleExecutionStatus.failed]: 30, -}; - -interface LogExecutionMetricsArgs { - ruleId: string; - ruleName: string; - ruleType: string; - spaceId: string; - metrics: EventLogExecutionMetrics; -} - -interface EventLogExecutionMetrics { - totalSearchDuration?: number; - totalIndexingDuration?: number; - executionGapDuration?: number; -} - -interface GetLastStatusChangesArgs { - ruleId: string; - count: number; - includeStatuses?: RuleExecutionStatus[]; -} - -interface IExecLogEventLogClient { - getLastStatusChanges(args: GetLastStatusChangesArgs): Promise; - logStatusChange: (args: LogStatusChangeArgs) => void; - logExecutionMetrics: (args: LogExecutionMetricsArgs) => void; -} - -export class EventLogClient implements IExecLogEventLogClient { - private readonly eventLogClient: IEventLogClient | undefined; - private readonly eventLogger: IEventLogger; - private sequence = 0; - - constructor(eventLogService: IEventLogService, eventLogClient: IEventLogClient | undefined) { - this.eventLogClient = eventLogClient; - this.eventLogger = eventLogService.getLogger({ - event: { provider: RULE_EXECUTION_LOG_PROVIDER }, - }); - } - - public async getLastStatusChanges( - args: GetLastStatusChangesArgs - ): Promise { - if (!this.eventLogClient) { - throw new Error('Querying Event Log from a rule executor is not supported at this moment'); - } - - const soType = ALERT_SAVED_OBJECT_TYPE; - const soIds = [args.ruleId]; - const count = args.count; - const includeStatuses = (args.includeStatuses ?? []).map((status) => `"${status}"`); - - const filterBy: string[] = [ - `event.provider: ${RULE_EXECUTION_LOG_PROVIDER}`, - 'event.kind: event', - `event.action: ${RuleExecutionLogAction['status-change']}`, - includeStatuses.length > 0 - ? `kibana.alert.rule.execution.status:${includeStatuses.join(' ')}` - : '', - ]; - - const kqlFilter = filterBy - .filter(Boolean) - .map((item) => `(${item})`) - .join(' and '); - - const findResult = await this.eventLogClient.findEventsBySavedObjectIds(soType, soIds, { - page: 1, - per_page: count, - sort_field: '@timestamp', - sort_order: 'desc', - filter: kqlFilter, - }); - - return findResult.data.map((event) => { - invariant(event, 'Event not found'); - invariant(event['@timestamp'], 'Required "@timestamp" field is not found'); - - const statusDate = event['@timestamp']; - const status = event.kibana?.alert?.rule?.execution?.status as - | RuleExecutionStatus - | undefined; - const isStatusFailed = status === RuleExecutionStatus.failed; - const message = event.message ?? ''; - - return { - statusDate, - status, - lastFailureAt: isStatusFailed ? statusDate : undefined, - lastFailureMessage: isStatusFailed ? message : undefined, - lastSuccessAt: !isStatusFailed ? statusDate : undefined, - lastSuccessMessage: !isStatusFailed ? message : undefined, - lastLookBackDate: undefined, - gap: undefined, - bulkCreateTimeDurations: undefined, - searchAfterTimeDurations: undefined, - }; - }); - } - - public logExecutionMetrics({ - ruleId, - ruleName, - ruleType, - metrics, - spaceId, - }: LogExecutionMetricsArgs) { - this.eventLogger.logEvent({ - '@timestamp': now(), - rule: { - id: ruleId, - name: ruleName, - category: ruleType, - }, - event: { - kind: 'metric', - action: RuleExecutionLogAction['execution-metrics'], - sequence: this.sequence++, - }, - kibana: { - alert: { - rule: { - execution: { - metrics: { - execution_gap_duration_s: metrics.executionGapDuration, - total_search_duration_ms: metrics.totalSearchDuration, - total_indexing_duration_ms: metrics.totalIndexingDuration, - }, - }, - }, - }, - space_ids: [spaceId], - saved_objects: [ - { - rel: SAVED_OBJECT_REL_PRIMARY, - type: ALERT_SAVED_OBJECT_TYPE, - id: ruleId, - namespace: spaceIdToNamespace(spaceId), - }, - ], - }, - }); - } - - public logStatusChange({ - ruleId, - ruleName, - ruleType, - newStatus, - message, - spaceId, - }: LogStatusChangeArgs) { - this.eventLogger.logEvent({ - '@timestamp': now(), - message, - rule: { - id: ruleId, - name: ruleName, - category: ruleType, - }, - event: { - kind: 'event', - action: RuleExecutionLogAction['status-change'], - sequence: this.sequence++, - }, - kibana: { - alert: { - rule: { - execution: { - status: newStatus, - status_order: statusSeverityDict[newStatus], - }, - }, - }, - space_ids: [spaceId], - saved_objects: [ - { - rel: SAVED_OBJECT_REL_PRIMARY, - type: ALERT_SAVED_OBJECT_TYPE, - id: ruleId, - namespace: spaceIdToNamespace(spaceId), - }, - ], - }, - }); - } -} diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/index.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/index.ts index 5c7d9a875056af..cecb8cf70a96d3 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/index.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/index.ts @@ -5,6 +5,16 @@ * 2.0. */ -export * from './rule_execution_log_client'; -export * from './types'; +export { ruleExecutionInfoType } from './rule_execution_info/saved_object'; +export type { + RuleExecutionInfoSavedObject, + RuleExecutionInfoAttributes, +} from './rule_execution_info/saved_object'; + +export * from './rule_execution_log_client/client_interface'; +export * from './rule_execution_logger/logger_interface'; +export * from './rule_execution_log_factory'; + +export { registerEventLogProvider } from './rule_execution_events/register_event_log_provider'; +export { mergeRuleExecutionSummary } from './merge_rule_execution_summary'; export * from './utils/normalization'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/merge_rule_execution_summary.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/merge_rule_execution_summary.ts new file mode 100644 index 00000000000000..e1b7a008ead073 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/merge_rule_execution_summary.ts @@ -0,0 +1,43 @@ +/* + * 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 { + RuleExecutionStatus, + ruleExecutionStatusOrderByStatus, + RuleExecutionSummary, +} from '../../../../common/detection_engine/schemas/common'; +import { RuleAlertType } from '../rules/types'; + +export const mergeRuleExecutionSummary = ( + rule: RuleAlertType, + ruleExecutionSummary: RuleExecutionSummary | null +): RuleExecutionSummary | null => { + if (ruleExecutionSummary == null) { + return null; + } + + const frameworkStatus = rule.executionStatus; + const customStatus = ruleExecutionSummary.last_execution; + + if ( + frameworkStatus.status === 'error' && + new Date(frameworkStatus.lastExecutionDate) > new Date(customStatus.date) + ) { + return { + ...ruleExecutionSummary, + last_execution: { + date: frameworkStatus.lastExecutionDate.toISOString(), + status: RuleExecutionStatus.failed, + status_order: ruleExecutionStatusOrderByStatus[RuleExecutionStatus.failed], + message: `Reason: ${frameworkStatus.error?.reason} Message: ${frameworkStatus.error?.message}`, + metrics: customStatus.metrics, + }, + }; + } + + return ruleExecutionSummary; +}; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/event_log_adapter/constants.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/rule_execution_events/constants.ts similarity index 90% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/event_log_adapter/constants.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/rule_execution_events/constants.ts index 55624b56e39a0e..08bafa92ac02ab 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/event_log_adapter/constants.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/rule_execution_events/constants.ts @@ -5,9 +5,9 @@ * 2.0. */ -export const RULE_EXECUTION_LOG_PROVIDER = 'securitySolution.ruleExecution'; +export const RULE_SAVED_OBJECT_TYPE = 'alert'; -export const ALERT_SAVED_OBJECT_TYPE = 'alert'; +export const RULE_EXECUTION_LOG_PROVIDER = 'securitySolution.ruleExecution'; export enum RuleExecutionLogAction { 'status-change' = 'status-change', diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/rule_execution_events/events_reader.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/rule_execution_events/events_reader.ts new file mode 100644 index 00000000000000..35c6775f03c05d --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/rule_execution_events/events_reader.ts @@ -0,0 +1,86 @@ +/* + * 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 { Logger } from 'src/core/server'; +import { IEventLogClient } from '../../../../../../event_log/server'; + +import { + RuleExecutionEvent, + RuleExecutionStatus, +} from '../../../../../common/detection_engine/schemas/common'; +import { invariant } from '../../../../../common/utils/invariant'; +import { + RULE_SAVED_OBJECT_TYPE, + RULE_EXECUTION_LOG_PROVIDER, + RuleExecutionLogAction, +} from './constants'; + +export interface IRuleExecutionEventsReader { + getLastStatusChanges(args: GetLastStatusChangesArgs): Promise; +} + +export interface GetLastStatusChangesArgs { + ruleId: string; + count: number; + includeStatuses?: RuleExecutionStatus[]; +} + +export const createRuleExecutionEventsReader = ( + eventLogClient: IEventLogClient, + logger: Logger +): IRuleExecutionEventsReader => { + return { + async getLastStatusChanges(args) { + const soType = RULE_SAVED_OBJECT_TYPE; + const soIds = [args.ruleId]; + const count = args.count; + const includeStatuses = (args.includeStatuses ?? []).map((status) => `"${status}"`); + + const filterBy: string[] = [ + `event.provider: ${RULE_EXECUTION_LOG_PROVIDER}`, + 'event.kind: event', + `event.action: ${RuleExecutionLogAction['status-change']}`, + includeStatuses.length > 0 + ? `kibana.alert.rule.execution.status:${includeStatuses.join(' ')}` + : '', + ]; + + const kqlFilter = filterBy + .filter(Boolean) + .map((item) => `(${item})`) + .join(' and '); + + const findResult = await eventLogClient.findEventsBySavedObjectIds(soType, soIds, { + page: 1, + per_page: count, + sort_field: '@timestamp', + sort_order: 'desc', + filter: kqlFilter, + }); + + return findResult.data.map((event) => { + invariant(event, 'Event not found'); + invariant(event['@timestamp'], 'Required "@timestamp" field is not found'); + invariant( + event.kibana?.alert?.rule?.execution?.status, + 'Required "kibana.alert.rule.execution.status" field is not found' + ); + + const date = event['@timestamp']; + const status = event.kibana?.alert?.rule?.execution?.status as RuleExecutionStatus; + const message = event.message ?? ''; + const result: RuleExecutionEvent = { + date, + status, + message, + }; + + return result; + }); + }, + }; +}; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/rule_execution_events/events_writer.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/rule_execution_events/events_writer.ts new file mode 100644 index 00000000000000..dad30e9cb5d88c --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/rule_execution_events/events_writer.ts @@ -0,0 +1,126 @@ +/* + * 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 { SavedObjectsUtils } from '../../../../../../../../src/core/server'; +import { IEventLogService, SAVED_OBJECT_REL_PRIMARY } from '../../../../../../event_log/server'; +import { + RuleExecutionStatus, + ruleExecutionStatusOrderByStatus, + RuleExecutionMetrics, +} from '../../../../../common/detection_engine/schemas/common'; +import { + RULE_SAVED_OBJECT_TYPE, + RULE_EXECUTION_LOG_PROVIDER, + RuleExecutionLogAction, +} from './constants'; + +export interface IRuleExecutionEventsWriter { + logStatusChange(args: StatusChangeArgs): void; + logExecutionMetrics(args: ExecutionMetricsArgs): void; +} + +export interface BaseArgs { + ruleId: string; + ruleName: string; + ruleType: string; + spaceId: string; +} + +export interface StatusChangeArgs extends BaseArgs { + newStatus: RuleExecutionStatus; + message?: string; +} + +export interface ExecutionMetricsArgs extends BaseArgs { + metrics: RuleExecutionMetrics; +} + +export const createRuleExecutionEventsWriter = ( + eventLogService: IEventLogService +): IRuleExecutionEventsWriter => { + const eventLogger = eventLogService.getLogger({ + event: { provider: RULE_EXECUTION_LOG_PROVIDER }, + }); + + let sequence = 0; + + return { + logStatusChange({ ruleId, ruleName, ruleType, spaceId, newStatus, message }) { + eventLogger.logEvent({ + '@timestamp': nowISO(), + message, + rule: { + id: ruleId, + name: ruleName, + category: ruleType, + }, + event: { + kind: 'event', + action: RuleExecutionLogAction['status-change'], + sequence: sequence++, + }, + kibana: { + alert: { + rule: { + execution: { + status: newStatus, + status_order: ruleExecutionStatusOrderByStatus[newStatus], + }, + }, + }, + space_ids: [spaceId], + saved_objects: [ + { + rel: SAVED_OBJECT_REL_PRIMARY, + type: RULE_SAVED_OBJECT_TYPE, + id: ruleId, + namespace: spaceIdToNamespace(spaceId), + }, + ], + }, + }); + }, + + logExecutionMetrics({ ruleId, ruleName, ruleType, spaceId, metrics }) { + eventLogger.logEvent({ + '@timestamp': nowISO(), + rule: { + id: ruleId, + name: ruleName, + category: ruleType, + }, + event: { + kind: 'metric', + action: RuleExecutionLogAction['execution-metrics'], + sequence: sequence++, + }, + kibana: { + alert: { + rule: { + execution: { + metrics, + }, + }, + }, + space_ids: [spaceId], + saved_objects: [ + { + rel: SAVED_OBJECT_REL_PRIMARY, + type: RULE_SAVED_OBJECT_TYPE, + id: ruleId, + namespace: spaceIdToNamespace(spaceId), + }, + ], + }, + }); + }, + }; +}; + +const nowISO = () => new Date().toISOString(); + +const spaceIdToNamespace = SavedObjectsUtils.namespaceStringToId; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/event_log_adapter/register_event_log_provider.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/rule_execution_events/register_event_log_provider.ts similarity index 100% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/event_log_adapter/register_event_log_provider.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/rule_execution_events/register_event_log_provider.ts diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/rule_execution_info/saved_object.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/rule_execution_info/saved_object.ts new file mode 100644 index 00000000000000..8a763d59e1a9fa --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/rule_execution_info/saved_object.ts @@ -0,0 +1,77 @@ +/* + * 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 { SavedObject, SavedObjectsType } from 'src/core/server'; +import { + RuleExecutionMetrics, + RuleExecutionStatus, + RuleExecutionStatusOrder, +} from '../../../../../common/detection_engine/schemas/common'; + +export const RULE_EXECUTION_INFO_TYPE = 'siem-detection-engine-rule-execution-info'; + +/** + * This side-car SO stores information about rule executions (like last status and metrics). + * Eventually we're going to replace it with data stored in the rule itself: + * https://github.com/elastic/kibana/issues/112193 + */ +export type RuleExecutionInfoSavedObject = SavedObject; + +export interface RuleExecutionInfoAttributes { + last_execution: { + date: string; + status: RuleExecutionStatus; + status_order: RuleExecutionStatusOrder; + message: string; + metrics: RuleExecutionMetrics; + }; +} + +const ruleExecutionInfoMappings: SavedObjectsType['mappings'] = { + properties: { + last_execution: { + type: 'object', + properties: { + date: { + type: 'date', + }, + status: { + type: 'keyword', + ignore_above: 1024, + }, + status_order: { + type: 'long', + }, + message: { + type: 'text', + }, + metrics: { + type: 'object', + properties: { + total_search_duration_ms: { + type: 'long', + }, + total_indexing_duration_ms: { + type: 'long', + }, + execution_gap_duration_s: { + type: 'long', + }, + }, + }, + }, + }, + }, +}; + +export const ruleExecutionInfoType: SavedObjectsType = { + name: RULE_EXECUTION_INFO_TYPE, + mappings: ruleExecutionInfoMappings, + hidden: false, + namespaceType: 'multiple-isolated', + convertToMultiNamespaceTypeVersion: '8.0.0', +}; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/rule_execution_info/saved_objects_client.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/rule_execution_info/saved_objects_client.ts new file mode 100644 index 00000000000000..77bc6c45efd454 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/rule_execution_info/saved_objects_client.ts @@ -0,0 +1,177 @@ +/* + * 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 { + Logger, + SavedObjectsClientContract, + SavedObjectsErrorHelpers, +} from '../../../../../../../../src/core/server'; + +import { + RuleExecutionInfoSavedObject, + RuleExecutionInfoAttributes, + RULE_EXECUTION_INFO_TYPE, +} from './saved_object'; +import { + getRuleExecutionInfoId, + getRuleExecutionInfoReferences, + extractRuleIdFromReferences, +} from './saved_objects_utils'; + +import { ExtMeta } from '../utils/logging'; +import { truncateList } from '../utils/normalization'; + +export interface IRuleExecutionInfoSavedObjectsClient { + createOrUpdate( + ruleId: string, + attributes: RuleExecutionInfoAttributes + ): Promise; + + delete(ruleId: string): Promise; + + getOneByRuleId(ruleId: string): Promise; + + getManyByRuleIds(ruleIds: string[]): Promise; +} + +export type RuleExecutionInfoSavedObjectsByRuleId = Record< + string, + RuleExecutionInfoSavedObject | null +>; + +export const createRuleExecutionInfoSavedObjectsClient = ( + soClient: SavedObjectsClientContract, + logger: Logger +): IRuleExecutionInfoSavedObjectsClient => { + return { + async createOrUpdate(ruleId, attributes) { + try { + const id = getRuleExecutionInfoId(ruleId); + const references = getRuleExecutionInfoReferences(ruleId); + + return await soClient.create( + RULE_EXECUTION_INFO_TYPE, + attributes, + { + id, + references, + overwrite: true, + } + ); + } catch (e) { + const logMessage = 'Error creating/updating rule execution info saved object'; + const logAttributes = `rule id: "${ruleId}"`; + const logReason = e instanceof Error ? e.message : String(e); + const logMeta: ExtMeta = { + rule: { id: ruleId }, + }; + + logger.error(`${logMessage}; ${logAttributes}; ${logReason}`, logMeta); + throw e; + } + }, + + async delete(ruleId) { + try { + const id = getRuleExecutionInfoId(ruleId); + await soClient.delete(RULE_EXECUTION_INFO_TYPE, id); + } catch (e) { + if (SavedObjectsErrorHelpers.isNotFoundError(e)) { + return; + } + + const logMessage = 'Error deleting rule execution info saved object'; + const logAttributes = `rule id: "${ruleId}"`; + const logReason = e instanceof Error ? e.message : String(e); + const logMeta: ExtMeta = { + rule: { id: ruleId }, + }; + + logger.error(`${logMessage}; ${logAttributes}; ${logReason}`, logMeta); + throw e; + } + }, + + async getOneByRuleId(ruleId) { + try { + const id = getRuleExecutionInfoId(ruleId); + return await soClient.get(RULE_EXECUTION_INFO_TYPE, id); + } catch (e) { + if (SavedObjectsErrorHelpers.isNotFoundError(e)) { + return null; + } + + const logMessage = 'Error fetching rule execution info saved object'; + const logAttributes = `rule id: "${ruleId}"`; + const logReason = e instanceof Error ? e.message : String(e); + const logMeta: ExtMeta = { + rule: { id: ruleId }, + }; + + logger.error(`${logMessage}; ${logAttributes}; ${logReason}`, logMeta); + throw e; + } + }, + + async getManyByRuleIds(ruleIds) { + try { + const ids = ruleIds + .map((id) => getRuleExecutionInfoId(id)) + .map((id) => ({ id, type: RULE_EXECUTION_INFO_TYPE })); + + const response = await soClient.bulkGet(ids); + const result = prepopulateRuleExecutionInfoSavedObjectsByRuleId(ruleIds); + + response.saved_objects.forEach((so) => { + // NOTE: We need to explicitly check that this saved object is not an error result and has references in it. + // "Saved object" may not actually contain most of its properties (despite the fact that they are required + // in its TypeScript interface), for example if it wasn't found. In this case it will look like that: + // { + // id: '64b51590-a87e-5afc-9ede-906c3f3483b7', + // type: 'siem-detection-engine-rule-execution-info', + // error: { + // statusCode: 404, + // error: 'Not Found', + // message: 'Saved object [siem-detection-engine-rule-execution-info/64b51590-a87e-5afc-9ede-906c3f3483b7] not found' + // }, + // namespaces: undefined + // } + const hasReferences = !so.error && so.references && Array.isArray(so.references); + const references = hasReferences ? so.references : []; + + const ruleId = extractRuleIdFromReferences(references); + if (ruleId) { + result[ruleId] = so; + } + + if (so.error && so.error.statusCode !== 404) { + logger.error(so.error.message); + } + }); + + return result; + } catch (e) { + const ruleIdsString = `[${truncateList(ruleIds).join(', ')}]`; + + const logMessage = 'Error bulk fetching rule execution info saved objects'; + const logAttributes = `num of rules: ${ruleIds.length}, rule ids: ${ruleIdsString}`; + const logReason = e instanceof Error ? e.message : String(e); + + logger.error(`${logMessage}; ${logAttributes}; ${logReason}`); + throw e; + } + }, + }; +}; + +const prepopulateRuleExecutionInfoSavedObjectsByRuleId = (ruleIds: string[]) => { + const result: RuleExecutionInfoSavedObjectsByRuleId = {}; + ruleIds.forEach((ruleId) => { + result[ruleId] = null; + }); + return result; +}; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/rule_execution_info/saved_objects_utils.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/rule_execution_info/saved_objects_utils.ts new file mode 100644 index 00000000000000..b0597c178b039b --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/rule_execution_info/saved_objects_utils.ts @@ -0,0 +1,36 @@ +/* + * 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 uuidv5 from 'uuid/v5'; +import { SavedObjectReference } from 'src/core/server'; +import { RULE_EXECUTION_INFO_TYPE } from './saved_object'; + +export const getRuleExecutionInfoId = (ruleId: string): string => { + // The uuidv5 namespace constant (uuidv5.DNS) is arbitrary. + return uuidv5(`${RULE_EXECUTION_INFO_TYPE}:${ruleId}`, uuidv5.DNS); +}; + +const RULE_REFERENCE_TYPE = 'alert'; +const RULE_REFERENCE_NAME = 'alert_0'; + +export const getRuleExecutionInfoReferences = (ruleId: string): SavedObjectReference[] => { + return [ + { + id: ruleId, + type: RULE_REFERENCE_TYPE, + name: RULE_REFERENCE_NAME, + }, + ]; +}; + +export const extractRuleIdFromReferences = (references: SavedObjectReference[]): string | null => { + const foundReference = references.find( + (r) => r.type === RULE_REFERENCE_TYPE && r.name === RULE_REFERENCE_NAME + ); + + return foundReference?.id || null; +}; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/rule_execution_log_client.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/rule_execution_log_client.ts deleted file mode 100644 index 3efddf4d7afb07..00000000000000 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/rule_execution_log_client.ts +++ /dev/null @@ -1,131 +0,0 @@ -/* - * 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 { Logger, SavedObjectsClientContract } from 'src/core/server'; -import { IEventLogClient, IEventLogService } from '../../../../../event_log/server'; -import { IRuleStatusSOAttributes } from '../rules/types'; -import { EventLogAdapter } from './event_log_adapter/event_log_adapter'; -import { SavedObjectsAdapter } from './saved_objects_adapter/saved_objects_adapter'; -import { - FindBulkExecutionLogArgs, - FindExecutionLogArgs, - IRuleExecutionLogClient, - LogStatusChangeArgs, - UnderlyingLogClient, - GetLastFailuresArgs, - GetCurrentStatusArgs, - GetCurrentStatusBulkArgs, - GetCurrentStatusBulkResult, - ExtMeta, -} from './types'; -import { truncateMessage } from './utils/normalization'; -import { withSecuritySpan } from '../../../utils/with_security_span'; - -interface ConstructorParams { - underlyingClient: UnderlyingLogClient; - savedObjectsClient: SavedObjectsClientContract; - eventLogService: IEventLogService; - eventLogClient?: IEventLogClient; - logger: Logger; -} - -export class RuleExecutionLogClient implements IRuleExecutionLogClient { - private readonly client: IRuleExecutionLogClient; - private readonly logger: Logger; - - constructor(params: ConstructorParams) { - const { underlyingClient, eventLogService, eventLogClient, savedObjectsClient, logger } = - params; - - switch (underlyingClient) { - case UnderlyingLogClient.savedObjects: - this.client = new SavedObjectsAdapter(savedObjectsClient); - break; - case UnderlyingLogClient.eventLog: - this.client = new EventLogAdapter(eventLogService, eventLogClient, savedObjectsClient); - break; - } - - // We write rule execution logs via a child console logger with the context - // "plugins.securitySolution.ruleExecution" - this.logger = logger.get('ruleExecution'); - } - - /** @deprecated */ - public find(args: FindExecutionLogArgs) { - return withSecuritySpan('RuleExecutionLogClient.find', () => this.client.find(args)); - } - - /** @deprecated */ - public findBulk(args: FindBulkExecutionLogArgs) { - return withSecuritySpan('RuleExecutionLogClient.findBulk', () => this.client.findBulk(args)); - } - - public getLastFailures(args: GetLastFailuresArgs): Promise { - return withSecuritySpan('RuleExecutionLogClient.getLastFailures', () => - this.client.getLastFailures(args) - ); - } - - public getCurrentStatus( - args: GetCurrentStatusArgs - ): Promise { - return withSecuritySpan('RuleExecutionLogClient.getCurrentStatus', () => - this.client.getCurrentStatus(args) - ); - } - - public getCurrentStatusBulk(args: GetCurrentStatusBulkArgs): Promise { - return withSecuritySpan('RuleExecutionLogClient.getCurrentStatusBulk', () => - this.client.getCurrentStatusBulk(args) - ); - } - - public async deleteCurrentStatus(ruleId: string): Promise { - await withSecuritySpan('RuleExecutionLogClient.deleteCurrentStatus', () => - this.client.deleteCurrentStatus(ruleId) - ); - } - - public async logStatusChange(args: LogStatusChangeArgs): Promise { - const { newStatus, message, ruleId, ruleName, ruleType, spaceId } = args; - - try { - const truncatedMessage = message ? truncateMessage(message) : message; - await withSecuritySpan( - { - name: 'RuleExecutionLogClient.logStatusChange', - labels: { new_rule_execution_status: args.newStatus }, - }, - () => - this.client.logStatusChange({ - ...args, - message: truncatedMessage, - }) - ); - } catch (e) { - const logMessage = 'Error logging rule execution status change'; - const logAttributes = `status: "${newStatus}", rule id: "${ruleId}", rule name: "${ruleName}"`; - const logReason = e instanceof Error ? `${e.stack}` : `${e}`; - const logMeta: ExtMeta = { - rule: { - id: ruleId, - name: ruleName, - type: ruleType, - execution: { - status: newStatus, - }, - }, - kibana: { - spaceId, - }, - }; - - this.logger.error(`${logMessage}; ${logAttributes}; ${logReason}`, logMeta); - } - } -} diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/rule_execution_log_client/client.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/rule_execution_log_client/client.ts new file mode 100644 index 00000000000000..e87a5d231e0b24 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/rule_execution_log_client/client.ts @@ -0,0 +1,47 @@ +/* + * 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 { mapValues } from 'lodash'; +import { Logger } from 'src/core/server'; + +import { RuleExecutionStatus } from '../../../../../common/detection_engine/schemas/common'; + +import { IRuleExecutionEventsReader } from '../rule_execution_events/events_reader'; +import { IRuleExecutionInfoSavedObjectsClient } from '../rule_execution_info/saved_objects_client'; +import { IRuleExecutionLogClient } from './client_interface'; + +const MAX_LAST_FAILURES = 5; + +export const createRuleExecutionLogClient = ( + savedObjectsClient: IRuleExecutionInfoSavedObjectsClient, + eventsReader: IRuleExecutionEventsReader, + logger: Logger +): IRuleExecutionLogClient => { + return { + async getExecutionSummariesBulk(ruleIds) { + const savedObjectsByRuleId = await savedObjectsClient.getManyByRuleIds(ruleIds); + return mapValues(savedObjectsByRuleId, (so) => so?.attributes ?? null); + }, + + async getExecutionSummary(ruleId) { + const savedObject = await savedObjectsClient.getOneByRuleId(ruleId); + return savedObject ? savedObject.attributes : null; + }, + + async clearExecutionSummary(ruleId) { + await savedObjectsClient.delete(ruleId); + }, + + getLastFailures(ruleId) { + return eventsReader.getLastStatusChanges({ + ruleId, + count: MAX_LAST_FAILURES, + includeStatuses: [RuleExecutionStatus.failed], + }); + }, + }; +}; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/rule_execution_log_client/client_interface.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/rule_execution_log_client/client_interface.ts new file mode 100644 index 00000000000000..207cae49d2ab85 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/rule_execution_log_client/client_interface.ts @@ -0,0 +1,45 @@ +/* + * 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 { + RuleExecutionEvent, + RuleExecutionSummary, +} from '../../../../../common/detection_engine/schemas/common'; + +/** + * Used from route handlers to fetch and manage various information about the rule execution: + * - execution summary of a rule containing such data as the last status and metrics + * - execution events such as recent failures and status changes + */ +export interface IRuleExecutionLogClient { + /** + * Fetches a list of current execution summaries of multiple rules. + * @param ruleIds A list of saved object ids of multiple rules (`rule.id`). + */ + getExecutionSummariesBulk(ruleIds: string[]): Promise; + + /** + * Fetches current execution summary of a given rule. + * @param ruleId Saved object id of the rule (`rule.id`). + */ + getExecutionSummary(ruleId: string): Promise; + + /** + * Deletes the current execution summary if it exists. + * @param ruleId Saved object id of the rule (`rule.id`). + */ + clearExecutionSummary(ruleId: string): Promise; + + /** + * Fetches last 5 failures (`RuleExecutionStatus.failed`) of a given rule. + * @param ruleId Saved object id of the rule (`rule.id`). + * @deprecated Will be replaced with a more flexible method for fetching execution events. + */ + getLastFailures(ruleId: string): Promise; +} + +export type RuleExecutionSummariesByRuleId = Record; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/rule_execution_log_client/decorator.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/rule_execution_log_client/decorator.ts new file mode 100644 index 00000000000000..070d42354dd68b --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/rule_execution_log_client/decorator.ts @@ -0,0 +1,64 @@ +/* + * 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 { chunk } from 'lodash'; +import { Logger } from 'src/core/server'; +import { initPromisePool } from '../../../../utils/promise_pool'; + +import { IRuleExecutionLogClient } from './client_interface'; + +const RULES_PER_CHUNK = 1000; + +export const decorateRuleExecutionLogClient = ( + client: IRuleExecutionLogClient, + logger: Logger +): IRuleExecutionLogClient => { + return { + /** + * Get the current rule execution summary for each of the given rule IDs. + * This method splits work into chunks so not to owerwhelm Elasticsearch + * when fetching statuses for a big number of rules. + * + * @param ruleIds A list of rule IDs (`rule.id`) to fetch summaries for + * @returns A dict with rule IDs as keys and execution summaries as values + * + * @throws AggregateError if any of the rule status requests fail + */ + async getExecutionSummariesBulk(ruleIds) { + const { results, errors } = await initPromisePool({ + concurrency: 1, + items: chunk(ruleIds, RULES_PER_CHUNK), + executor: (ruleIdsChunk) => + client.getExecutionSummariesBulk(ruleIdsChunk).catch((e) => { + logger.error( + `Error fetching rule execution summaries: ${e instanceof Error ? e.stack : String(e)}` + ); + throw e; + }), + }); + + if (errors.length) { + throw new AggregateError(errors, 'Error fetching rule execution summaries'); + } + + // Merge all rule statuses into a single dict + return Object.assign({}, ...results); + }, + + getExecutionSummary(ruleId) { + return client.getExecutionSummary(ruleId); + }, + + clearExecutionSummary(ruleId) { + return client.clearExecutionSummary(ruleId); + }, + + getLastFailures(ruleId) { + return client.getLastFailures(ruleId); + }, + }; +}; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/rule_execution_log_factory.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/rule_execution_log_factory.ts new file mode 100644 index 00000000000000..958d0d5f6dc34a --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/rule_execution_log_factory.ts @@ -0,0 +1,58 @@ +/* + * 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 { Logger, SavedObjectsClientContract } from 'src/core/server'; +import { IEventLogClient, IEventLogService } from '../../../../../event_log/server'; + +import { IRuleExecutionLogClient } from './rule_execution_log_client/client_interface'; +import { createRuleExecutionLogClient } from './rule_execution_log_client/client'; +import { decorateRuleExecutionLogClient } from './rule_execution_log_client/decorator'; + +import { + IRuleExecutionLogger, + RuleExecutionContext, +} from './rule_execution_logger/logger_interface'; +import { createRuleExecutionLogger } from './rule_execution_logger/logger'; + +import { createRuleExecutionEventsReader } from './rule_execution_events/events_reader'; +import { createRuleExecutionEventsWriter } from './rule_execution_events/events_writer'; +import { createRuleExecutionInfoSavedObjectsClient } from './rule_execution_info/saved_objects_client'; + +export type RuleExecutionLogClientFactory = ( + savedObjectsClient: SavedObjectsClientContract, + eventLogClient: IEventLogClient, + logger: Logger +) => IRuleExecutionLogClient; + +export const ruleExecutionLogClientFactory: RuleExecutionLogClientFactory = ( + savedObjectsClient, + eventLogClient, + logger +) => { + const soClient = createRuleExecutionInfoSavedObjectsClient(savedObjectsClient, logger); + const eventsReader = createRuleExecutionEventsReader(eventLogClient, logger); + const executionLogClient = createRuleExecutionLogClient(soClient, eventsReader, logger); + return decorateRuleExecutionLogClient(executionLogClient, logger); +}; + +export type RuleExecutionLoggerFactory = ( + savedObjectsClient: SavedObjectsClientContract, + eventLogService: IEventLogService, + logger: Logger, + context: RuleExecutionContext +) => IRuleExecutionLogger; + +export const ruleExecutionLoggerFactory: RuleExecutionLoggerFactory = ( + savedObjectsClient, + eventLogService, + logger, + context +) => { + const soClient = createRuleExecutionInfoSavedObjectsClient(savedObjectsClient, logger); + const eventsWriter = createRuleExecutionEventsWriter(eventLogService); + return createRuleExecutionLogger(soClient, eventsWriter, logger, context); +}; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/rule_execution_logger/logger.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/rule_execution_logger/logger.ts new file mode 100644 index 00000000000000..f67aae472ef604 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/rule_execution_logger/logger.ts @@ -0,0 +1,145 @@ +/* + * 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 { sum } from 'lodash'; +import { Duration } from 'moment'; +import { Logger } from 'src/core/server'; + +import { + RuleExecutionStatus, + ruleExecutionStatusOrderByStatus, + RuleExecutionMetrics, +} from '../../../../../common/detection_engine/schemas/common'; + +import { ExtMeta } from '../utils/logging'; +import { truncateValue } from '../utils/normalization'; + +import { IRuleExecutionEventsWriter } from '../rule_execution_events/events_writer'; +import { IRuleExecutionInfoSavedObjectsClient } from '../rule_execution_info/saved_objects_client'; +import { IRuleExecutionLogger, RuleExecutionContext, StatusChangeArgs } from './logger_interface'; + +export const createRuleExecutionLogger = ( + savedObjectsClient: IRuleExecutionInfoSavedObjectsClient, + eventsWriter: IRuleExecutionEventsWriter, + logger: Logger, + context: RuleExecutionContext +): IRuleExecutionLogger => { + const { ruleId, ruleName, ruleType, spaceId } = context; + + const ruleExecutionLogger: IRuleExecutionLogger = { + get context() { + return context; + }, + + async logStatusChange(args) { + try { + const normalizedArgs = normalizeStatusChangeArgs(args); + await Promise.all([ + writeStatusChangeToSavedObjects(normalizedArgs), + writeStatusChangeToEventLog(normalizedArgs), + ]); + } catch (e) { + const logMessage = 'Error logging rule execution status change'; + const logAttributes = `status: "${args.newStatus}", rule id: "${ruleId}", rule name: "${ruleName}"`; + const logReason = e instanceof Error ? e.stack ?? e.message : String(e); + const logMeta: ExtMeta = { + rule: { + id: ruleId, + name: ruleName, + type: ruleType, + execution: { + status: args.newStatus, + }, + }, + kibana: { + spaceId, + }, + }; + + logger.error(`${logMessage}; ${logAttributes}; ${logReason}`, logMeta); + } + }, + }; + + const writeStatusChangeToSavedObjects = async ( + args: NormalizedStatusChangeArgs + ): Promise => { + const { newStatus, message, metrics } = args; + + await savedObjectsClient.createOrUpdate(ruleId, { + last_execution: { + date: nowISO(), + status: newStatus, + status_order: ruleExecutionStatusOrderByStatus[newStatus], + message, + metrics: metrics ?? {}, + }, + }); + }; + + const writeStatusChangeToEventLog = (args: NormalizedStatusChangeArgs): void => { + const { newStatus, message, metrics } = args; + + if (metrics) { + eventsWriter.logExecutionMetrics({ + ruleId, + ruleName, + ruleType, + spaceId, + metrics, + }); + } + + eventsWriter.logStatusChange({ + ruleId, + ruleName, + ruleType, + spaceId, + newStatus, + message, + }); + }; + + return ruleExecutionLogger; +}; + +const nowISO = () => new Date().toISOString(); + +interface NormalizedStatusChangeArgs { + newStatus: RuleExecutionStatus; + message: string; + metrics?: RuleExecutionMetrics; +} + +const normalizeStatusChangeArgs = (args: StatusChangeArgs): NormalizedStatusChangeArgs => { + const { newStatus, message, metrics } = args; + + return { + newStatus, + message: truncateValue(message) ?? '', + metrics: metrics + ? { + total_search_duration_ms: normalizeDurations(metrics.searchDurations), + total_indexing_duration_ms: normalizeDurations(metrics.indexingDurations), + execution_gap_duration_s: normalizeGap(metrics.executionGap), + } + : undefined, + }; +}; + +const normalizeDurations = (durations?: string[]): number | undefined => { + if (durations == null) { + return undefined; + } + + const sumAsFloat = sum(durations.map(Number)); + return Math.round(sumAsFloat); +}; + +const normalizeGap = (duration?: Duration): number | undefined => { + return duration ? Math.round(duration.asSeconds()) : undefined; +}; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/rule_execution_logger/logger_interface.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/rule_execution_logger/logger_interface.ts new file mode 100644 index 00000000000000..e31c10bd9747f4 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/rule_execution_logger/logger_interface.ts @@ -0,0 +1,48 @@ +/* + * 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 { Duration } from 'moment'; +import { RuleExecutionStatus } from '../../../../../common/detection_engine/schemas/common'; + +/** + * Used from rule executors to log various information about the rule execution: + * - rule status changes + * - rule execution metrics + * - later - generic messages and any kind of info we'd need to log for rule + * monitoring or debugging purposes + */ +export interface IRuleExecutionLogger { + context: RuleExecutionContext; + + /** + * Writes information about new rule statuses and measured execution metrics: + * 1. To .kibana-* index as a custom `siem-detection-engine-rule-execution-info` saved object. + * This SO is used for fast access to last execution info of a large amount of rules. + * 2. To .kibana-event-log-* index in order to track history of rule executions. + * @param args Information about the status change event. + */ + logStatusChange(args: StatusChangeArgs): Promise; +} + +export interface RuleExecutionContext { + ruleId: string; + ruleName: string; + ruleType: string; + spaceId: string; +} + +export interface StatusChangeArgs { + newStatus: RuleExecutionStatus; + message?: string; + metrics?: MetricsArgs; +} + +export interface MetricsArgs { + searchDurations?: string[]; + indexingDurations?: string[]; + executionGap?: Duration; +} diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/saved_objects_adapter/rule_status_saved_objects_client.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/saved_objects_adapter/rule_status_saved_objects_client.ts deleted file mode 100644 index 5ec17e47a8b316..00000000000000 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/saved_objects_adapter/rule_status_saved_objects_client.ts +++ /dev/null @@ -1,139 +0,0 @@ -/* - * 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 { - SavedObject, - SavedObjectsClientContract, - SavedObjectsCreateOptions, - SavedObjectsFindOptions, - SavedObjectsFindOptionsReference, - SavedObjectsFindResult, - SavedObjectsUpdateResponse, -} from 'kibana/server'; -import { get } from 'lodash'; -import { withSecuritySpan } from '../../../../utils/with_security_span'; -// eslint-disable-next-line no-restricted-imports -import { legacyRuleStatusSavedObjectType } from '../../rules/legacy_rule_status/legacy_rule_status_saved_object_mappings'; -import { IRuleStatusSOAttributes } from '../../rules/types'; - -export interface RuleStatusSavedObjectsClient { - find: ( - options: Omit & { ruleId: string } - ) => Promise>>; - findBulk: (ids: string[], statusesPerId: number) => Promise; - create: ( - attributes: IRuleStatusSOAttributes, - options: SavedObjectsCreateOptions - ) => Promise>; - update: ( - id: string, - attributes: Partial, - options: SavedObjectsCreateOptions - ) => Promise>; - delete: (id: string) => Promise<{}>; -} - -export interface FindBulkResponse { - [key: string]: IRuleStatusSOAttributes[] | undefined; -} - -/** - * @deprecated Use RuleExecutionLogClient instead - */ -export const ruleStatusSavedObjectsClientFactory = ( - savedObjectsClient: SavedObjectsClientContract -): RuleStatusSavedObjectsClient => ({ - find: async (options) => { - return withSecuritySpan('RuleStatusSavedObjectsClient.find', async () => { - const references = { - id: options.ruleId, - type: 'alert', - }; - const result = await savedObjectsClient.find({ - ...options, - type: legacyRuleStatusSavedObjectType, - hasReference: references, - }); - return result.saved_objects; - }); - }, - findBulk: async (ids, statusesPerId) => { - if (ids.length === 0) { - return {}; - } - return withSecuritySpan('RuleStatusSavedObjectsClient.findBulk', async () => { - const references = ids.map((alertId) => ({ - id: alertId, - type: 'alert', - })); - const order: 'desc' = 'desc'; - // NOTE: Once https://github.com/elastic/kibana/issues/115153 is resolved - // ${legacyRuleStatusSavedObjectType}.statusDate will need to be updated to - // ${legacyRuleStatusSavedObjectType}.attributes.statusDate - const aggs = { - references: { - nested: { - path: `${legacyRuleStatusSavedObjectType}.references`, - }, - aggs: { - alertIds: { - terms: { - field: `${legacyRuleStatusSavedObjectType}.references.id`, - size: ids.length, - }, - aggs: { - rule_status: { - reverse_nested: {}, - aggs: { - most_recent_statuses: { - top_hits: { - sort: [ - { - [`${legacyRuleStatusSavedObjectType}.statusDate`]: { - order, - }, - }, - ], - size: statusesPerId, - }, - }, - }, - }, - }, - }, - }, - }, - }; - const results = await savedObjectsClient.find({ - hasReference: references, - aggs, - type: legacyRuleStatusSavedObjectType, - perPage: 0, - }); - const buckets = get(results, 'aggregations.references.alertIds.buckets'); - return buckets.reduce((acc: Record, bucket: unknown) => { - const key = get(bucket, 'key'); - const hits = get(bucket, 'rule_status.most_recent_statuses.hits.hits'); - // eslint-disable-next-line @typescript-eslint/no-explicit-any - acc[key] = hits.map((hit: any) => hit._source[legacyRuleStatusSavedObjectType]); - return acc; - }, {}); - }); - }, - create: (attributes, options) => - withSecuritySpan('RuleStatusSavedObjectsClient.create', () => - savedObjectsClient.create(legacyRuleStatusSavedObjectType, attributes, options) - ), - update: (id, attributes, options) => - withSecuritySpan('RuleStatusSavedObjectsClient.update', () => - savedObjectsClient.update(legacyRuleStatusSavedObjectType, id, attributes, options) - ), - delete: (id) => - withSecuritySpan('RuleStatusSavedObjectsClient.delete', () => - savedObjectsClient.delete(legacyRuleStatusSavedObjectType, id) - ), -}); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/saved_objects_adapter/saved_objects_adapter.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/saved_objects_adapter/saved_objects_adapter.ts deleted file mode 100644 index 230306c453ace1..00000000000000 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/saved_objects_adapter/saved_objects_adapter.ts +++ /dev/null @@ -1,191 +0,0 @@ -/* - * 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 { mapValues } from 'lodash'; -import { SavedObject, SavedObjectReference } from 'src/core/server'; -import { SavedObjectsClientContract } from '../../../../../../../../src/core/server'; -import { RuleExecutionStatus } from '../../../../../common/detection_engine/schemas/common/schemas'; -// eslint-disable-next-line no-restricted-imports -import { legacyGetRuleReference } from '../../rules/legacy_rule_status/legacy_utils'; -import { IRuleStatusSOAttributes } from '../../rules/types'; -import { - ExecutionMetrics, - FindBulkExecutionLogArgs, - FindExecutionLogArgs, - GetCurrentStatusArgs, - GetCurrentStatusBulkArgs, - GetCurrentStatusBulkResult, - GetLastFailuresArgs, - IRuleExecutionLogClient, - LogStatusChangeArgs, -} from '../types'; -import { - RuleStatusSavedObjectsClient, - ruleStatusSavedObjectsClientFactory, -} from './rule_status_saved_objects_client'; - -const MAX_ERRORS = 5; -// 1st is mutable status, followed by 5 most recent failures -const MAX_RULE_STATUSES = 1 + MAX_ERRORS; - -const convertMetricFields = ( - metrics: ExecutionMetrics -): Pick< - IRuleStatusSOAttributes, - 'gap' | 'searchAfterTimeDurations' | 'bulkCreateTimeDurations' -> => ({ - gap: metrics.executionGap?.humanize(), - searchAfterTimeDurations: metrics.searchDurations, - bulkCreateTimeDurations: metrics.indexingDurations, -}); - -export class SavedObjectsAdapter implements IRuleExecutionLogClient { - private ruleStatusClient: RuleStatusSavedObjectsClient; - - constructor(savedObjectsClient: SavedObjectsClientContract) { - this.ruleStatusClient = ruleStatusSavedObjectsClientFactory(savedObjectsClient); - } - - private findRuleStatusSavedObjects(ruleId: string, count: number) { - return this.ruleStatusClient.find({ - perPage: count, - sortField: 'statusDate', - sortOrder: 'desc', - ruleId, - }); - } - - /** @deprecated */ - public find({ ruleId, logsCount = 1 }: FindExecutionLogArgs) { - return this.findRuleStatusSavedObjects(ruleId, logsCount); - } - - /** @deprecated */ - public findBulk({ ruleIds, logsCount = 1 }: FindBulkExecutionLogArgs) { - return this.ruleStatusClient.findBulk(ruleIds, logsCount); - } - - public async getLastFailures(args: GetLastFailuresArgs): Promise { - const result = await this.findRuleStatusSavedObjects(args.ruleId, MAX_RULE_STATUSES); - - // The first status is always the current one followed by 5 last failures. - // We skip the current status and return only the failures. - return result.map((so) => so.attributes).slice(1); - } - - public async getCurrentStatus( - args: GetCurrentStatusArgs - ): Promise { - const result = await this.findRuleStatusSavedObjects(args.ruleId, 1); - const currentStatusSavedObject = result[0]; - return currentStatusSavedObject?.attributes; - } - - public async getCurrentStatusBulk( - args: GetCurrentStatusBulkArgs - ): Promise { - const { ruleIds } = args; - const result = await this.ruleStatusClient.findBulk(ruleIds, 1); - return mapValues(result, (attributes = []) => attributes[0]); - } - - public async deleteCurrentStatus(ruleId: string): Promise { - const statusSavedObjects = await this.findRuleStatusSavedObjects(ruleId, MAX_RULE_STATUSES); - await Promise.all(statusSavedObjects.map((so) => this.ruleStatusClient.delete(so.id))); - } - - private findRuleStatuses = async ( - ruleId: string - ): Promise>> => - this.findRuleStatusSavedObjects(ruleId, MAX_RULE_STATUSES); - - public async logStatusChange({ newStatus, ruleId, message, metrics }: LogStatusChangeArgs) { - const references: SavedObjectReference[] = [legacyGetRuleReference(ruleId)]; - const ruleStatuses = await this.findRuleStatuses(ruleId); - const [currentStatus] = ruleStatuses; - const attributes = buildRuleStatusAttributes({ - status: newStatus, - message, - metrics, - currentAttributes: currentStatus?.attributes, - }); - // Create or update current status - if (currentStatus) { - await this.ruleStatusClient.update(currentStatus.id, attributes, { references }); - } else { - await this.ruleStatusClient.create(attributes, { references }); - } - - if (newStatus === RuleExecutionStatus.failed) { - await Promise.all([ - // Persist the current failure in the last five errors list - this.ruleStatusClient.create(attributes, { references }), - // Drop oldest failures - ...ruleStatuses - .slice(MAX_RULE_STATUSES - 1) - .map((status) => this.ruleStatusClient.delete(status.id)), - ]); - } - } -} - -const defaultStatusAttributes: IRuleStatusSOAttributes = { - statusDate: '', - status: RuleExecutionStatus['going to run'], - lastFailureAt: null, - lastSuccessAt: null, - lastFailureMessage: null, - lastSuccessMessage: null, - gap: null, - bulkCreateTimeDurations: [], - searchAfterTimeDurations: [], - lastLookBackDate: null, -}; - -const buildRuleStatusAttributes = ({ - status, - message, - metrics = {}, - currentAttributes, -}: { - status: RuleExecutionStatus; - message?: string; - metrics?: ExecutionMetrics; - currentAttributes?: IRuleStatusSOAttributes; -}): IRuleStatusSOAttributes => { - const now = new Date().toISOString(); - const baseAttributes: IRuleStatusSOAttributes = { - ...defaultStatusAttributes, - ...currentAttributes, - statusDate: now, - status: - status === RuleExecutionStatus.warning ? RuleExecutionStatus['partial failure'] : status, - ...convertMetricFields(metrics), - }; - - switch (status) { - case RuleExecutionStatus.succeeded: - case RuleExecutionStatus.warning: - case RuleExecutionStatus['partial failure']: { - return { - ...baseAttributes, - lastSuccessAt: now, - lastSuccessMessage: message, - }; - } - case RuleExecutionStatus.failed: { - return { - ...baseAttributes, - lastFailureAt: now, - lastFailureMessage: message, - }; - } - case RuleExecutionStatus['going to run']: { - return baseAttributes; - } - } -}; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/types.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/types.ts deleted file mode 100644 index 1fa256b0f088c4..00000000000000 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/types.ts +++ /dev/null @@ -1,120 +0,0 @@ -/* - * 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 { Duration } from 'moment'; -import { LogMeta, SavedObjectsFindResult } from 'src/core/server'; -import { RuleExecutionStatus } from '../../../../common/detection_engine/schemas/common/schemas'; -import { IRuleStatusSOAttributes } from '../rules/types'; - -export enum UnderlyingLogClient { - 'savedObjects' = 'savedObjects', - 'eventLog' = 'eventLog', -} - -export interface IRuleExecutionLogClient { - /** @deprecated */ - find(args: FindExecutionLogArgs): Promise>>; - /** @deprecated */ - findBulk(args: FindBulkExecutionLogArgs): Promise; - - getLastFailures(args: GetLastFailuresArgs): Promise; - getCurrentStatus(args: GetCurrentStatusArgs): Promise; - getCurrentStatusBulk(args: GetCurrentStatusBulkArgs): Promise; - - deleteCurrentStatus(ruleId: string): Promise; - - logStatusChange(args: LogStatusChangeArgs): Promise; -} - -/** @deprecated */ -export interface FindExecutionLogArgs { - ruleId: string; - spaceId: string; - logsCount?: number; -} - -/** @deprecated */ -export interface FindBulkExecutionLogArgs { - ruleIds: string[]; - spaceId: string; - logsCount?: number; -} - -/** @deprecated */ -export interface FindBulkExecutionLogResponse { - [ruleId: string]: IRuleStatusSOAttributes[] | undefined; -} - -export interface GetLastFailuresArgs { - ruleId: string; - spaceId: string; -} - -export interface GetCurrentStatusArgs { - ruleId: string; - spaceId: string; -} - -export interface GetCurrentStatusBulkArgs { - ruleIds: string[]; - spaceId: string; -} - -export interface GetCurrentStatusBulkResult { - [ruleId: string]: IRuleStatusSOAttributes; -} - -export interface CreateExecutionLogArgs { - attributes: IRuleStatusSOAttributes; - spaceId: string; -} - -export interface LogStatusChangeArgs { - ruleId: string; - ruleName: string; - ruleType: string; - spaceId: string; - newStatus: RuleExecutionStatus; - message?: string; - /** - * @deprecated Use RuleExecutionLogClient.logExecutionMetrics to write metrics instead - */ - metrics?: ExecutionMetrics; -} - -export interface LogExecutionMetricsArgs { - ruleId: string; - ruleName: string; - ruleType: string; - spaceId: string; - metrics: ExecutionMetrics; -} - -export interface ExecutionMetrics { - searchDurations?: string[]; - indexingDurations?: string[]; - /** - * @deprecated lastLookBackDate is logged only by SavedObjectsAdapter and should be removed in the future - */ - lastLookBackDate?: string; - executionGap?: Duration; -} - -/** - * Custom extended log metadata that rule execution logger can attach to every log record. - */ -export type ExtMeta = LogMeta & { - rule?: LogMeta['rule'] & { - type?: string; - execution?: { - status?: RuleExecutionStatus; - }; - }; - kibana?: { - spaceId?: string; - }; -}; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/utils/logging.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/utils/logging.ts new file mode 100644 index 00000000000000..4d373f68c00bca --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/utils/logging.ts @@ -0,0 +1,24 @@ +/* + * 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 { LogMeta } from 'src/core/server'; +import { RuleExecutionStatus } from '../../../../../common/detection_engine/schemas/common'; + +/** + * Custom extended log metadata that rule execution logger can attach to every log record. + */ +export type ExtMeta = LogMeta & { + rule?: LogMeta['rule'] & { + type?: string; + execution?: { + status?: RuleExecutionStatus; + }; + }; + kibana?: { + spaceId?: string; + }; +}; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/utils/normalization.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/utils/normalization.ts index baaee9446eee3d..e24f6318111685 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/utils/normalization.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/utils/normalization.ts @@ -7,28 +7,32 @@ import { take, toString, truncate, uniq } from 'lodash'; -// When we write rule execution status updates to `siem-detection-engine-rule-status` saved objects -// or to event log, we write success and failure messages as well. Those messages are built from -// N errors collected during the "big loop" in the Detection Engine, where N can be very large. -// When N is large the resulting message strings are so large that these documents are up to 26MB. -// These large documents may cause migrations to fail because a batch of 1000 documents easily +// When we write rule execution status updates to saved objects or to event log, +// we can write warning/failure messages as well. In some cases those messages +// are built from N errors collected during the "big loop" of Detection Engine, +// where N can be a large number. When N is large the resulting message strings +// can take ~26MB of memory and make the resulting documents huge. These large +// documents may cause migrations to fail because a batch of 1000 documents can // exceed Elasticsearch's `http.max_content_length` which defaults to 100mb. -// In order to fix that, we need to truncate those messages to an adequate MAX length. +// In order to fix that, we need to truncate messages to an adequate MAX length. // https://github.com/elastic/kibana/pull/112257 -const MAX_MESSAGE_LENGTH = 10240; +const MAX_STRING_LENGTH = 10240; const MAX_LIST_LENGTH = 20; -export const truncateMessage = (value: unknown): string | undefined => { +export const truncateValue = ( + value: unknown, + maxLength = MAX_STRING_LENGTH +): string | undefined => { if (value === undefined) { return value; } const str = toString(value); - return truncate(str, { length: MAX_MESSAGE_LENGTH }); + return truncate(str, { length: maxLength }); }; -export const truncateMessageList = (list: string[]): string[] => { +export const truncateList = (list: T[], maxLength = MAX_LIST_LENGTH): T[] => { const deduplicatedList = uniq(list); - return take(deduplicatedList, MAX_LIST_LENGTH); + return take(deduplicatedList, maxLength); }; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/__mocks__/threshold.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/__mocks__/threshold.ts index 19b1405cb1433b..334add447dcbe8 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/__mocks__/threshold.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/__mocks__/threshold.ts @@ -77,6 +77,7 @@ export const mockThresholdResults = { }, }; +// TODO: https://github.com/elastic/kibana/pull/121644 clean up export const sampleThresholdAlert = { _id: 'b3ad77a4-65bd-4c4e-89cf-13c46f54bc4d', _index: 'some-index', @@ -155,10 +156,6 @@ export const sampleThresholdAlert = { type: 'query', threat: [], version: 1, - status: 'succeeded', - status_date: '2020-02-22T16:47:50.047Z', - last_success_at: '2020-02-22T16:47:50.047Z', - last_success_message: 'succeeded', max_signals: 100, language: 'kuery', rule_id: 'f88a544c-1d4e-4652-ae2a-c953b38da5d0', diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/create_security_rule_type_wrapper.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/create_security_rule_type_wrapper.ts index 50d553045b5d5a..a643f428e58e7c 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/create_security_rule_type_wrapper.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/create_security_rule_type_wrapper.ts @@ -35,8 +35,8 @@ import { import { getNotificationResultsLink } from '../notifications/utils'; import { createResultObject } from './utils'; import { bulkCreateFactory, wrapHitsFactory, wrapSequencesFactory } from './factories'; -import { RuleExecutionLogClient, truncateMessageList } from '../rule_execution_log'; -import { RuleExecutionStatus } from '../../../../common/detection_engine/schemas/common/schemas'; +import { truncateList } from '../rule_execution_log'; +import { RuleExecutionStatus } from '../../../../common/detection_engine/schemas/common'; import { scheduleThrottledNotificationActions } from '../notifications/schedule_throttle_notification_actions'; import aadFieldConversion from '../routes/index/signal_aad_mapping.json'; import { extractReferences, injectReferences } from '../signals/saved_object_references'; @@ -44,7 +44,7 @@ import { withSecuritySpan } from '../../../utils/with_security_span'; /* eslint-disable complexity */ export const createSecurityRuleTypeWrapper: CreateSecurityRuleTypeWrapper = - ({ lists, logger, config, ruleDataClient, eventLogService, ruleExecutionLogClientOverride }) => + ({ lists, logger, config, ruleDataClient, eventLogService, ruleExecutionLoggerFactory }) => (type) => { const { alertIgnoreFields: ignoreFields, alertMergeStrategy: mergeStrategy } = config; const persistenceRuleType = createPersistenceRuleTypeWrapper({ ruleDataClient, logger }); @@ -76,14 +76,17 @@ export const createSecurityRuleTypeWrapper: CreateSecurityRuleTypeWrapper = const esClient = scopedClusterClient.asCurrentUser; - const ruleStatusClient = ruleExecutionLogClientOverride - ? ruleExecutionLogClientOverride - : new RuleExecutionLogClient({ - underlyingClient: config.ruleExecutionLog.underlyingClient, - savedObjectsClient, - eventLogService, - logger, - }); + const ruleExecutionLogger = ruleExecutionLoggerFactory( + savedObjectsClient, + eventLogService, + logger, + { + ruleId: alertId, + ruleName: rule.name, + ruleType: rule.ruleTypeId, + spaceId, + } + ); const completeRule = { ruleConfig: rule, @@ -95,7 +98,6 @@ export const createSecurityRuleTypeWrapper: CreateSecurityRuleTypeWrapper = actions, name, schedule: { interval }, - ruleTypeId, } = completeRule.ruleConfig; const refresh = actions.length ? 'wait_for' : false; @@ -111,14 +113,8 @@ export const createSecurityRuleTypeWrapper: CreateSecurityRuleTypeWrapper = logger.debug(buildRuleMessage(`interval: ${interval}`)); let wroteWarningStatus = false; - const basicLogArguments = { - spaceId, - ruleId: alertId, - ruleName: name, - ruleType: ruleTypeId, - }; - await ruleStatusClient.logStatusChange({ - ...basicLogArguments, + + await ruleExecutionLogger.logStatusChange({ newStatus: RuleExecutionStatus['going to run'], }); @@ -152,11 +148,10 @@ export const createSecurityRuleTypeWrapper: CreateSecurityRuleTypeWrapper = const privileges = await checkPrivilegesFromEsClient(esClient, inputIndices); wroteWarningStatus = await hasReadIndexPrivileges({ - ...basicLogArguments, privileges, logger, buildRuleMessage, - ruleStatusClient, + ruleExecutionLogger, }); if (!wroteWarningStatus) { @@ -170,13 +165,12 @@ export const createSecurityRuleTypeWrapper: CreateSecurityRuleTypeWrapper = }) ); wroteWarningStatus = await hasTimestampFields({ - ...basicLogArguments, timestampField: hasTimestampOverride ? (timestampOverride as string) : '@timestamp', timestampFieldCapsResponse: timestampFieldCaps, inputIndices, - ruleStatusClient, + ruleExecutionLogger, logger, buildRuleMessage, }); @@ -185,10 +179,9 @@ export const createSecurityRuleTypeWrapper: CreateSecurityRuleTypeWrapper = } catch (exc) { const errorMessage = buildRuleMessage(`Check privileges failed to execute ${exc}`); logger.warn(errorMessage); - await ruleStatusClient.logStatusChange({ - ...basicLogArguments, - message: errorMessage, + await ruleExecutionLogger.logStatusChange({ newStatus: RuleExecutionStatus['partial failure'], + message: errorMessage, }); wroteWarningStatus = true; } @@ -212,8 +205,7 @@ export const createSecurityRuleTypeWrapper: CreateSecurityRuleTypeWrapper = ); logger.warn(gapMessage); hasError = true; - await ruleStatusClient.logStatusChange({ - ...basicLogArguments, + await ruleExecutionLogger.logStatusChange({ newStatus: RuleExecutionStatus.failed, message: gapMessage, metrics: { executionGap: remainingGap }, @@ -293,11 +285,8 @@ export const createSecurityRuleTypeWrapper: CreateSecurityRuleTypeWrapper = } if (result.warningMessages.length) { - const warningMessage = buildRuleMessage( - truncateMessageList(result.warningMessages).join() - ); - await ruleStatusClient.logStatusChange({ - ...basicLogArguments, + const warningMessage = buildRuleMessage(truncateList(result.warningMessages).join()); + await ruleExecutionLogger.logStatusChange({ newStatus: RuleExecutionStatus['partial failure'], message: warningMessage, }); @@ -356,14 +345,12 @@ export const createSecurityRuleTypeWrapper: CreateSecurityRuleTypeWrapper = ); if (!hasError && !wroteWarningStatus && !result.warning) { - await ruleStatusClient.logStatusChange({ - ...basicLogArguments, + await ruleExecutionLogger.logStatusChange({ newStatus: RuleExecutionStatus.succeeded, message: 'succeeded', metrics: { - indexingDurations: result.bulkCreateTimes, searchDurations: result.searchAfterTimes, - lastLookBackDate: result.lastLookbackDate?.toISOString(), + indexingDurations: result.bulkCreateTimes, }, }); } @@ -397,17 +384,15 @@ export const createSecurityRuleTypeWrapper: CreateSecurityRuleTypeWrapper = } const errorMessage = buildRuleMessage( 'Bulk Indexing of signals failed:', - truncateMessageList(result.errors).join() + truncateList(result.errors).join() ); logger.error(errorMessage); - await ruleStatusClient.logStatusChange({ - ...basicLogArguments, + await ruleExecutionLogger.logStatusChange({ newStatus: RuleExecutionStatus.failed, message: errorMessage, metrics: { - indexingDurations: result.bulkCreateTimes, searchDurations: result.searchAfterTimes, - lastLookBackDate: result.lastLookbackDate?.toISOString(), + indexingDurations: result.bulkCreateTimes, }, }); } @@ -437,14 +422,12 @@ export const createSecurityRuleTypeWrapper: CreateSecurityRuleTypeWrapper = ); logger.error(message); - await ruleStatusClient.logStatusChange({ - ...basicLogArguments, + await ruleExecutionLogger.logStatusChange({ newStatus: RuleExecutionStatus.failed, message, metrics: { - indexingDurations: result.bulkCreateTimes, searchDurations: result.searchAfterTimes, - lastLookBackDate: result.lastLookbackDate?.toISOString(), + indexingDurations: result.bulkCreateTimes, }, }); } diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/query/create_query_alert_type.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/query/create_query_alert_type.test.ts index bfa99f68b48c33..4a33dd0868aabf 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/query/create_query_alert_type.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/query/create_query_alert_type.test.ts @@ -14,6 +14,7 @@ import { createRuleTypeMocks } from '../__mocks__/rule_type'; import { createSecurityRuleTypeWrapper } from '../create_security_rule_type_wrapper'; import { createMockConfig } from '../../routes/__mocks__'; import { createMockTelemetryEventsSender } from '../../../telemetry/__mocks__'; +import { ruleExecutionLogMock } from '../../rule_execution_log/__mocks__/rule_execution_log_client'; import { sampleDocNoSortId } from '../../signals/__mocks__/es_results'; import { getQueryRuleParams } from '../../schemas/rule_schemas.mock'; @@ -29,8 +30,6 @@ jest.mock('../utils/get_list_client', () => ({ }), })); -jest.mock('../../rule_execution_log/rule_execution_log_client'); - describe('Custom Query Alerts', () => { const mocks = createRuleTypeMocks(); const { dependencies, executor, services } = mocks; @@ -41,6 +40,7 @@ describe('Custom Query Alerts', () => { config: createMockConfig(), ruleDataClient, eventLogService, + ruleExecutionLoggerFactory: () => ruleExecutionLogMock.logger.create(), }); const eventsTelemetry = createMockTelemetryEventsSender(true); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/types.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/types.ts index 17e749ec251b43..9aae815a4188a6 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/types.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/types.ts @@ -38,7 +38,7 @@ import { ExperimentalFeatures } from '../../../../common/experimental_features'; import { IEventLogService } from '../../../../../event_log/server'; import { AlertsFieldMap, RulesFieldMap } from '../../../../common/field_maps'; import { TelemetryEventsSender } from '../../telemetry/sender'; -import { IRuleExecutionLogClient } from '../rule_execution_log'; +import { RuleExecutionLoggerFactory } from '../rule_execution_log'; import { commonParamsCamelToSnake } from '../schemas/rule_converters'; export interface SecurityAlertTypeReturnValue { @@ -99,7 +99,7 @@ export interface CreateSecurityRuleTypeWrapperProps { config: ConfigType; ruleDataClient: IRuleDataClient; eventLogService: IEventLogService; - ruleExecutionLogClientOverride?: IRuleExecutionLogClient; + ruleExecutionLoggerFactory: RuleExecutionLoggerFactory; } export type CreateSecurityRuleTypeWrapper = ( diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/delete_rules.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/delete_rules.test.ts index 42d7f960beb22e..0fada9327cb3a4 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/delete_rules.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/delete_rules.test.ts @@ -6,29 +6,29 @@ */ import { rulesClientMock } from '../../../../../alerting/server/mocks'; -import { ruleExecutionLogClientMock } from '../rule_execution_log/__mocks__/rule_execution_log_client'; +import { ruleExecutionLogMock } from '../rule_execution_log/__mocks__/rule_execution_log_client'; import { deleteRules } from './delete_rules'; import { DeleteRuleOptions } from './types'; describe('deleteRules', () => { let rulesClient: ReturnType; - let ruleStatusClient: ReturnType; + let ruleExecutionLogClient: ReturnType; beforeEach(() => { rulesClient = rulesClientMock.create(); - ruleStatusClient = ruleExecutionLogClientMock.create(); + ruleExecutionLogClient = ruleExecutionLogMock.client.create(); }); it('should delete the rule along with its actions, and statuses', async () => { const options: DeleteRuleOptions = { ruleId: 'ruleId', rulesClient, - ruleStatusClient, + ruleExecutionLogClient, }; await deleteRules(options); expect(rulesClient.delete).toHaveBeenCalledWith({ id: options.ruleId }); - expect(ruleStatusClient.deleteCurrentStatus).toHaveBeenCalledWith(options.ruleId); + expect(ruleExecutionLogClient.clearExecutionSummary).toHaveBeenCalledWith(options.ruleId); }); }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/delete_rules.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/delete_rules.ts index 880132434f7cc8..cbe6f36914663e 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/delete_rules.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/delete_rules.ts @@ -7,7 +7,11 @@ import { DeleteRuleOptions } from './types'; -export const deleteRules = async ({ ruleId, rulesClient, ruleStatusClient }: DeleteRuleOptions) => { +export const deleteRules = async ({ + ruleId, + rulesClient, + ruleExecutionLogClient, +}: DeleteRuleOptions) => { await rulesClient.delete({ id: ruleId }); - await ruleStatusClient.deleteCurrentStatus(ruleId); + await ruleExecutionLogClient.clearExecutionSummary(ruleId); }; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/get_export_by_object_ids.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/get_export_by_object_ids.test.ts index 0e07ac4e56a9fc..a047100bc52629 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/get_export_by_object_ids.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/get_export_by_object_ids.test.ts @@ -187,10 +187,6 @@ describe.each([ interval: '5m', rule_id: 'rule-1', language: 'kuery', - last_failure_at: undefined, - last_failure_message: undefined, - last_success_at: undefined, - last_success_message: undefined, license: 'Elastic License', output_index: '.siem-signals', max_signals: 10000, @@ -198,8 +194,6 @@ describe.each([ risk_score_mapping: [], rule_name_override: undefined, saved_id: undefined, - status: undefined, - status_date: undefined, name: 'Detect Root/Admin Users', query: 'user.name: root or user.name: admin', references: ['http://example.com', 'https://example.com'], @@ -217,6 +211,7 @@ describe.each([ note: '# Investigative notes', version: 1, exceptions_list: getListArrayMock(), + execution_summary: undefined, }, ], }; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/get_export_by_object_ids.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/get_export_by_object_ids.ts index b8f1467cffe872..7381e2c3a1f02a 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/get_export_by_object_ids.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/get_export_by_object_ids.ts @@ -127,7 +127,7 @@ export const getRulesFromObjects = async ( ) { return { statusCode: 200, - rule: transformAlertToRule(matchingRule, undefined, legacyActions[matchingRule.id]), + rule: transformAlertToRule(matchingRule, null, legacyActions[matchingRule.id]), }; } else { return { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/legacy_rule_status/legacy_migrations.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/legacy_rule_status/legacy_migrations.ts deleted file mode 100644 index 120b8cf20b18d6..00000000000000 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/legacy_rule_status/legacy_migrations.ts +++ /dev/null @@ -1,110 +0,0 @@ -/* - * 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 { - SavedObjectMigrationFn, - SavedObjectReference, - SavedObjectSanitizedDoc, - SavedObjectUnsanitizedDoc, -} from 'kibana/server'; -import { isString } from 'lodash/fp'; -import { truncateMessage } from '../../rule_execution_log'; -import { IRuleStatusSOAttributes } from '../types'; -// eslint-disable-next-line no-restricted-imports -import { legacyGetRuleReference } from './legacy_utils'; - -export const truncateMessageFields: SavedObjectMigrationFn> = (doc) => { - const { lastFailureMessage, lastSuccessMessage, ...otherAttributes } = doc.attributes; - - return { - ...doc, - attributes: { - ...otherAttributes, - lastFailureMessage: truncateMessage(lastFailureMessage), - lastSuccessMessage: truncateMessage(lastSuccessMessage), - }, - references: doc.references ?? [], - }; -}; - -/** - * This migrates alertId within legacy `siem-detection-engine-rule-status` to saved object references on an upgrade. - * We only migrate alertId if we find these conditions: - * - alertId is a string and not null, undefined, or malformed data. - * - The existing references do not already have a alertId found within it. - * - * Some of these issues could crop up during either user manual errors of modifying things, earlier migration - * issues, etc... so we are safer to check them as possibilities - * - * @deprecated Remove this once we've fully migrated to event-log and no longer require addition status SO (8.x) - * @param doc The document having an alertId to migrate into references - * @returns The document migrated with saved object references - */ -export const legacyMigrateRuleAlertIdSOReferences = ( - doc: SavedObjectUnsanitizedDoc -): SavedObjectSanitizedDoc => { - const { alertId, ...otherAttributes } = doc.attributes; - const existingReferences = doc.references ?? []; - - // early return if alertId is not a string as expected, still removing alertId as the mapping no longer exists - if (!isString(alertId)) { - return { - ...doc, - attributes: otherAttributes, - references: existingReferences, - }; - } - - const alertReferences = legacyMigrateAlertId({ - alertId, - existingReferences, - }); - - return { - ...doc, - attributes: otherAttributes, - references: [...existingReferences, ...alertReferences], - }; -}; - -/** - * This is a helper to migrate "alertId" - * - * @deprecated Remove this once we've fully migrated to event-log and no longer require addition status SO (8.x) - * - * @param existingReferences The existing saved object references - * @param alertId The alertId to migrate - * - * @returns The savedObjectReferences migrated - */ -export const legacyMigrateAlertId = ({ - existingReferences, - alertId, -}: { - existingReferences: SavedObjectReference[]; - alertId: string; -}): SavedObjectReference[] => { - const existingReferenceFound = existingReferences.find((reference) => { - return reference.id === alertId && reference.type === 'alert'; - }); - if (existingReferenceFound) { - return []; - } else { - return [legacyGetRuleReference(alertId)]; - } -}; - -/** - * This side-car rule status SO is deprecated and is to be replaced by the RuleExecutionLog on Event-Log and - * additional fields on the Alerting Framework Rule SO. - * - * @deprecated Remove this once we've fully migrated to event-log and no longer require addition status SO (8.x) - */ -export const legacyRuleStatusSavedObjectMigration = { - '7.15.2': truncateMessageFields, - '7.16.0': legacyMigrateRuleAlertIdSOReferences, -}; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/legacy_rule_status/legacy_rule_status_saved_object_mappings.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/legacy_rule_status/legacy_rule_status_saved_object_mappings.ts deleted file mode 100644 index 298c75b8b7d514..00000000000000 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/legacy_rule_status/legacy_rule_status_saved_object_mappings.ts +++ /dev/null @@ -1,74 +0,0 @@ -/* - * 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 { SavedObjectsType } from 'kibana/server'; -// eslint-disable-next-line no-restricted-imports -import { legacyRuleStatusSavedObjectMigration } from './legacy_migrations'; - -/** - * This side-car rule status SO is deprecated and is to be replaced by the RuleExecutionLog on Event-Log and - * additional fields on the Alerting Framework Rule SO. - * - * @deprecated Remove this once we've fully migrated to event-log and no longer require addition status SO (8.x) - */ -export const legacyRuleStatusSavedObjectType = 'siem-detection-engine-rule-status'; - -/** - * This side-car rule status SO is deprecated and is to be replaced by the RuleExecutionLog on Event-Log and - * additional fields on the Alerting Framework Rule SO. - * - * @deprecated Remove this once we've fully migrated to event-log and no longer require addition status SO (8.x) - */ -export const ruleStatusSavedObjectMappings: SavedObjectsType['mappings'] = { - properties: { - status: { - type: 'keyword', - }, - statusDate: { - type: 'date', - }, - lastFailureAt: { - type: 'date', - }, - lastSuccessAt: { - type: 'date', - }, - lastFailureMessage: { - type: 'text', - }, - lastSuccessMessage: { - type: 'text', - }, - lastLookBackDate: { - type: 'date', - }, - gap: { - type: 'text', - }, - bulkCreateTimeDurations: { - type: 'float', - }, - searchAfterTimeDurations: { - type: 'float', - }, - }, -}; - -/** - * This side-car rule status SO is deprecated and is to be replaced by the RuleExecutionLog on Event-Log and - * additional fields on the Alerting Framework Rule SO. - * - * @deprecated Remove this once we've fully migrated to event-log and no longer require addition status SO (8.x) - */ -export const legacyRuleStatusType: SavedObjectsType = { - convertToMultiNamespaceTypeVersion: '8.0.0', - name: legacyRuleStatusSavedObjectType, - hidden: false, - namespaceType: 'multiple-isolated', - mappings: ruleStatusSavedObjectMappings, - migrations: legacyRuleStatusSavedObjectMigration, -}; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/legacy_rule_status/legacy_utils.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/legacy_rule_status/legacy_utils.ts deleted file mode 100644 index 62de5ce5912303..00000000000000 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/legacy_rule_status/legacy_utils.ts +++ /dev/null @@ -1,17 +0,0 @@ -/* - * 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. - */ - -/** - * Given an id this returns a legacy rule reference. - * @param id The id of the alert - * @deprecated Remove this once we've fully migrated to event-log and no longer require addition status SO (8.x) - */ -export const legacyGetRuleReference = (id: string) => ({ - id, - type: 'alert', - name: 'alert_0', -}); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/types.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/types.ts index e2ea5aefaea1a1..79406c30e15722 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/types.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/types.ts @@ -5,10 +5,9 @@ * 2.0. */ -import { get } from 'lodash/fp'; import { Readable } from 'stream'; -import { SavedObject, SavedObjectAttributes, SavedObjectsClientContract } from 'kibana/server'; +import { SavedObjectAttributes, SavedObjectsClientContract } from 'kibana/server'; import type { MachineLearningJobIdOrUndefined, From, @@ -84,12 +83,6 @@ import { QueryFilterOrUndefined, FieldsOrUndefined, SortOrderOrUndefined, - RuleExecutionStatus, - LastSuccessAt, - StatusDate, - LastSuccessMessage, - LastFailureAt, - LastFailureMessage, Author, AuthorOrUndefined, LicenseOrUndefined, @@ -98,65 +91,16 @@ import { RuleNameOverrideOrUndefined, EventCategoryOverrideOrUndefined, NamespaceOrUndefined, -} from '../../../../common/detection_engine/schemas/common/schemas'; +} from '../../../../common/detection_engine/schemas/common'; import { RulesClient, PartialAlert } from '../../../../../alerting/server'; import { SanitizedAlert } from '../../../../../alerting/common'; import { PartialFilter } from '../types'; import { RuleParams } from '../schemas/rule_schemas'; -import { IRuleExecutionLogClient } from '../rule_execution_log/types'; +import { IRuleExecutionLogClient } from '../rule_execution_log'; export type RuleAlertType = SanitizedAlert; -export interface IRuleStatusSOAttributes extends SavedObjectAttributes { - statusDate: StatusDate; - lastFailureAt: LastFailureAt | null | undefined; - lastFailureMessage: LastFailureMessage | null | undefined; - lastSuccessAt: LastSuccessAt | null | undefined; - lastSuccessMessage: LastSuccessMessage | null | undefined; - status: RuleExecutionStatus | null | undefined; - lastLookBackDate: string | null | undefined; - gap: string | null | undefined; - bulkCreateTimeDurations: string[] | null | undefined; - searchAfterTimeDurations: string[] | null | undefined; -} - -export interface IRuleStatusResponseAttributes { - status_date: StatusDate; - last_failure_at: LastFailureAt | null | undefined; - last_failure_message: LastFailureMessage | null | undefined; - last_success_at: LastSuccessAt | null | undefined; - last_success_message: LastSuccessMessage | null | undefined; - status: RuleExecutionStatus | null | undefined; - last_look_back_date: string | null | undefined; // NOTE: This is no longer used on the UI, but left here in case users are using it within the API - gap: string | null | undefined; - bulk_create_time_durations: string[] | null | undefined; - search_after_time_durations: string[] | null | undefined; -} - -export interface RuleStatusResponse { - [key: string]: { - current_status: IRuleStatusResponseAttributes | null | undefined; - failures: IRuleStatusResponseAttributes[] | null | undefined; - }; -} - -export interface IRuleStatusSavedObject { - type: string; - id: string; - attributes: Array>; - references: unknown[]; - updated_at: string; - version: string; -} - -export interface IRuleStatusFindType { - page: number; - per_page: number; - total: number; - saved_objects: IRuleStatusSavedObject[]; -} - // eslint-disable-next-line @typescript-eslint/no-explicit-any export interface IRuleAssetSOAttributes extends Record { rule_id: string | null | undefined; @@ -197,10 +141,6 @@ export const isAlertType = ( : partialAlert.alertTypeId === SIGNALS_ID; }; -export const isRuleStatusSavedObjectAttributes = (obj: unknown): obj is IRuleStatusSOAttributes => { - return get('status', obj) != null; -}; - export interface CreateRulesOptions { rulesClient: RulesClient; anomalyThreshold: AnomalyThresholdOrUndefined; @@ -267,6 +207,7 @@ export interface PatchRulesOptions extends Partial { rulesClient: RulesClient; rule: SanitizedAlert | null | undefined; } + interface PatchRulesFieldsOptions { anomalyThreshold: AnomalyThresholdOrUndefined; author: AuthorOrUndefined; @@ -328,7 +269,7 @@ export interface ReadRuleOptions { export interface DeleteRuleOptions { ruleId: Id; rulesClient: RulesClient; - ruleStatusClient: IRuleExecutionLogClient; + ruleExecutionLogClient: IRuleExecutionLogClient; } export interface FindRuleOptions { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_prepacked_rules.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_prepacked_rules.test.ts index c4cd5d4211c963..703b0a4f5aec19 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_prepacked_rules.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_prepacked_rules.test.ts @@ -11,7 +11,7 @@ import { getFindResultWithSingleHit } from '../routes/__mocks__/request_response import { updatePrepackagedRules } from './update_prepacked_rules'; import { patchRules } from './patch_rules'; import { getAddPrepackagedRulesSchemaDecodedMock } from '../../../../common/detection_engine/schemas/request/add_prepackaged_rules_schema.mock'; -import { ruleExecutionLogClientMock } from '../rule_execution_log/__mocks__/rule_execution_log_client'; + jest.mock('./patch_rules'); describe.each([ @@ -19,12 +19,10 @@ describe.each([ ['RAC', true], ])('updatePrepackagedRules - %s', (_, isRuleRegistryEnabled) => { let rulesClient: ReturnType; - let ruleStatusClient: ReturnType; let savedObjectsClient: ReturnType; beforeEach(() => { rulesClient = rulesClientMock.create(); - ruleStatusClient = ruleExecutionLogClientMock.create(); savedObjectsClient = savedObjectsClientMock.create(); }); @@ -45,7 +43,6 @@ describe.each([ rulesClient, savedObjectsClient, 'default', - ruleStatusClient, [{ ...prepackagedRule, actions }], outputIndex, isRuleRegistryEnabled @@ -77,7 +74,6 @@ describe.each([ rulesClient, savedObjectsClient, 'default', - ruleStatusClient, [{ ...prepackagedRule, ...updatedThreatParams }], 'output-index', isRuleRegistryEnabled diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_prepacked_rules.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_prepacked_rules.ts index 71ca8cf8f1dfab..f6b4508405c5eb 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_prepacked_rules.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_prepacked_rules.ts @@ -14,7 +14,6 @@ import { patchRules } from './patch_rules'; import { readRules } from './read_rules'; import { PartialFilter } from '../types'; import { RuleParams } from '../schemas/rule_schemas'; -import { IRuleExecutionLogClient } from '../rule_execution_log/types'; import { legacyMigrate } from './utils'; /** @@ -23,7 +22,6 @@ import { legacyMigrate } from './utils'; * avoid being a "noisy neighbor". * @param rulesClient Alerting client * @param spaceId Current user spaceId - * @param ruleStatusClient Rule execution log client * @param rules The rules to apply the update for * @param outputIndex The output index to apply the update to. */ @@ -31,7 +29,6 @@ export const updatePrepackagedRules = async ( rulesClient: RulesClient, savedObjectsClient: SavedObjectsClientContract, spaceId: string, - ruleStatusClient: IRuleExecutionLogClient, rules: AddPrepackagedRulesSchemaDecoded[], outputIndex: string, isRuleRegistryEnabled: boolean @@ -42,7 +39,6 @@ export const updatePrepackagedRules = async ( rulesClient, savedObjectsClient, spaceId, - ruleStatusClient, ruleChunk, outputIndex, isRuleRegistryEnabled @@ -55,7 +51,6 @@ export const updatePrepackagedRules = async ( * Creates promises of the rules and returns them. * @param rulesClient Alerting client * @param spaceId Current user spaceId - * @param ruleStatusClient Rule execution log client * @param rules The rules to apply the update for * @param outputIndex The output index to apply the update to. * @returns Promise of what was updated. @@ -64,7 +59,6 @@ export const createPromises = ( rulesClient: RulesClient, savedObjectsClient: SavedObjectsClientContract, spaceId: string, - ruleStatusClient: IRuleExecutionLogClient, rules: AddPrepackagedRulesSchemaDecoded[], outputIndex: string, isRuleRegistryEnabled: boolean diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_rules.mock.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_rules.mock.ts index b98a95ed1aabc0..c027f3b8505a96 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_rules.mock.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_rules.mock.ts @@ -11,14 +11,12 @@ import { getUpdateMachineLearningSchemaMock, getUpdateRulesSchemaMock, } from '../../../../common/detection_engine/schemas/request/rule_schemas.mock'; -import { ruleExecutionLogClientMock } from '../rule_execution_log/__mocks__/rule_execution_log_client'; import { getAlertMock } from '../routes/__mocks__/request_responses'; import { getQueryRuleParams } from '../schemas/rule_schemas.mock'; export const getUpdateRulesOptionsMock = (isRuleRegistryEnabled: boolean) => ({ spaceId: 'default', rulesClient: rulesClientMock.create(), - ruleStatusClient: ruleExecutionLogClientMock.create(), savedObjectsClient: savedObjectsClientMock.create(), defaultOutputIndex: '.siem-signals-default', existingRule: getAlertMock(isRuleRegistryEnabled, getQueryRuleParams()), @@ -30,7 +28,6 @@ export const getUpdateRulesOptionsMock = (isRuleRegistryEnabled: boolean) => ({ export const getUpdateMlRulesOptionsMock = (isRuleRegistryEnabled: boolean) => ({ spaceId: 'default', rulesClient: rulesClientMock.create(), - ruleStatusClient: ruleExecutionLogClientMock.create(), savedObjectsClient: savedObjectsClientMock.create(), defaultOutputIndex: '.siem-signals-default', existingRule: getAlertMock(isRuleRegistryEnabled, getQueryRuleParams()), diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/schemas/rule_converters.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/schemas/rule_converters.ts index 4cc73f48202ab2..fff8147da86729 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/schemas/rule_converters.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/schemas/rule_converters.ts @@ -20,6 +20,7 @@ import { BaseRuleParams, } from './rule_schemas'; import { assertUnreachable } from '../../../../common/utility_types'; +import { RuleExecutionSummary } from '../../../../common/detection_engine/schemas/common'; import { CreateRulesSchema, CreateTypeSpecific, @@ -31,9 +32,7 @@ import { addTags } from '../rules/add_tags'; import { DEFAULT_MAX_SIGNALS, SERVER_APP_ID } from '../../../../common/constants'; import { transformRuleToAlertAction } from '../../../../common/detection_engine/transform_actions'; import { ResolvedSanitizedRule, SanitizedAlert } from '../../../../../alerting/common'; -import { IRuleStatusSOAttributes } from '../rules/types'; import { transformTags } from '../routes/rules/utils'; -import { RuleExecutionStatus } from '../../../../common/detection_engine/schemas/common/schemas'; import { transformFromAlertThrottle, transformToAlertThrottle, @@ -42,6 +41,7 @@ import { } from '../rules/utils'; // eslint-disable-next-line no-restricted-imports import { LegacyRuleActions } from '../rule_actions/legacy_types'; +import { mergeRuleExecutionSummary } from '../rule_execution_log'; // These functions provide conversions from the request API schema to the internal rule schema and from the internal rule schema // to the response API schema. This provides static type-check assurances that the internal schema is in sync with the API schema for @@ -284,10 +284,10 @@ export const commonParamsCamelToSnake = (params: BaseRuleParams) => { export const internalRuleToAPIResponse = ( rule: SanitizedAlert | ResolvedSanitizedRule, - ruleStatus?: IRuleStatusSOAttributes, + ruleExecutionSummary?: RuleExecutionSummary | null, legacyRuleActions?: LegacyRuleActions | null ): FullResponseSchema => { - const mergedStatus = ruleStatus ? mergeAlertWithSidecarStatus(rule, ruleStatus) : undefined; + const mergedExecutionSummary = mergeRuleExecutionSummary(rule, ruleExecutionSummary ?? null); const isResolvedRule = (obj: unknown): obj is ResolvedSanitizedRule => (obj as ResolvedSanitizedRule).outcome != null; return { @@ -311,34 +311,7 @@ export const internalRuleToAPIResponse = ( // Actions throttle: transformFromAlertThrottle(rule, legacyRuleActions), actions: transformActions(rule.actions, legacyRuleActions), - // Rule status - status: mergedStatus?.status ?? undefined, - status_date: mergedStatus?.statusDate ?? undefined, - last_failure_at: mergedStatus?.lastFailureAt ?? undefined, - last_success_at: mergedStatus?.lastSuccessAt ?? undefined, - last_failure_message: mergedStatus?.lastFailureMessage ?? undefined, - last_success_message: mergedStatus?.lastSuccessMessage ?? undefined, - last_gap: mergedStatus?.gap ?? undefined, - bulk_create_time_durations: mergedStatus?.bulkCreateTimeDurations ?? undefined, - search_after_time_durations: mergedStatus?.searchAfterTimeDurations ?? undefined, + // Execution summary + execution_summary: mergedExecutionSummary ?? undefined, }; }; - -export const mergeAlertWithSidecarStatus = ( - alert: SanitizedAlert, - status: IRuleStatusSOAttributes -): IRuleStatusSOAttributes => { - if ( - new Date(alert.executionStatus.lastExecutionDate) > new Date(status.statusDate) && - alert.executionStatus.status === 'error' - ) { - return { - ...status, - lastFailureMessage: `Reason: ${alert.executionStatus.error?.reason} Message: ${alert.executionStatus.error?.message}`, - lastFailureAt: alert.executionStatus.lastExecutionDate.toISOString(), - statusDate: alert.executionStatus.lastExecutionDate.toISOString(), - status: RuleExecutionStatus.failed, - }; - } - return status; -}; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/delete_all_statuses.sh b/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/delete_all_rule_execution_data.sh similarity index 52% rename from x-pack/plugins/security_solution/server/lib/detection_engine/scripts/delete_all_statuses.sh rename to x-pack/plugins/security_solution/server/lib/detection_engine/scripts/delete_all_rule_execution_data.sh index de95ae56805212..82cca250f2d9b6 100755 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/delete_all_statuses.sh +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/delete_all_rule_execution_data.sh @@ -10,15 +10,31 @@ set -e ./check_env_variables.sh -# Example: ./delete_all_statuses.sh +# Deletes all data related to rule execution: +# - `siem-detection-engine-rule-execution-info` sidecar saved objects from `.kibana` index +# - fully clears `.kibana-event-log` index + +# Example: ./delete_all_rule_execution_data.sh # https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-delete-by-query.html + curl -s -k \ -H "Content-Type: application/json" \ -u ${ELASTICSEARCH_USERNAME}:${ELASTICSEARCH_PASSWORD} \ -X POST ${ELASTICSEARCH_URL}/${KIBANA_INDEX}*/_delete_by_query \ --data '{ "query": { - "exists": { "field": "siem-detection-engine-rule-status" } + "exists": { "field": "siem-detection-engine-rule-execution-info" } + } + }' \ + | jq . + +curl -s -k \ + -H "Content-Type: application/json" \ + -u ${ELASTICSEARCH_USERNAME}:${ELASTICSEARCH_PASSWORD} \ + -X POST ${ELASTICSEARCH_URL}/.kibana-event-log*/_delete_by_query \ + --data '{ + "query": { + "match_all" : {} } }' \ | jq . diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/hard_reset.sh b/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/hard_reset.sh index ab377457188aae..9a319d7ad4ce05 100755 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/hard_reset.sh +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/hard_reset.sh @@ -10,15 +10,12 @@ set -e ./check_env_variables.sh -# Clean up and remove all actions and alerts from SIEM -# within saved objects +# Clean up and remove all Detection Engine's saved objects and related data ./delete_all_actions.sh ./delete_all_alerts.sh ./delete_all_alert_tasks.sh +./delete_all_rule_execution_data.sh -# delete all the statuses from the signal index -./delete_all_statuses.sh - -# re-create the signal index +# Re-create the signal index ./delete_signal_index.sh ./post_signal_index.sh diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/__mocks__/es_results.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/__mocks__/es_results.ts index 6558c48a6af5d1..5f6ce6966fc02c 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/__mocks__/es_results.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/__mocks__/es_results.ts @@ -18,14 +18,10 @@ import type { } from '../types'; import { SavedObject } from '../../../../../../../../src/core/server'; import { loggingSystemMock } from '../../../../../../../../src/core/server/mocks'; -import { IRuleStatusSOAttributes } from '../../rules/types'; -// eslint-disable-next-line no-restricted-imports -import { legacyRuleStatusSavedObjectType } from '../../rules/legacy_rule_status/legacy_rule_status_saved_object_mappings'; import { getListArrayMock } from '../../../../../common/detection_engine/schemas/types/lists.mock'; import { RulesSchema } from '../../../../../common/detection_engine/schemas/response'; import { RuleParams } from '../../schemas/rule_schemas'; import { getThreatMock } from '../../../../../common/detection_engine/schemas/types/threat.mock'; -import { RuleExecutionStatus } from '../../../../../common/detection_engine/schemas/common/schemas'; import { ALERT_REASON, ALERT_RULE_PARAMETERS, @@ -499,10 +495,6 @@ export const sampleSignalHit = (): SignalHit => ({ type: 'query', threat: [], version: 1, - status: RuleExecutionStatus.succeeded, - status_date: '2020-02-22T16:47:50.047Z', - last_success_at: '2020-02-22T16:47:50.047Z', - last_success_message: 'succeeded', output_index: '.siem-signals-default', max_signals: 100, risk_score: 55, @@ -564,10 +556,6 @@ export const sampleThresholdSignalHit = (): SignalHit => ({ type: 'query', threat: [], version: 1, - status: RuleExecutionStatus.succeeded, - status_date: '2020-02-22T16:47:50.047Z', - last_success_at: '2020-02-22T16:47:50.047Z', - last_success_message: 'succeeded', output_index: '.siem-signals-default', max_signals: 100, risk_score: 55, @@ -879,32 +867,6 @@ export const sampleDocSearchResultsWithSortId = ( export const sampleRuleGuid = '04128c15-0d1b-4716-a4c5-46997ac7f3bd'; export const sampleIdGuid = 'e1e08ddc-5e37-49ff-a258-5393aa44435a'; -export const exampleRuleStatus: () => SavedObject = () => ({ - type: legacyRuleStatusSavedObjectType, - id: '042e6d90-7069-11ea-af8b-0f8ae4fa817e', - attributes: { - statusDate: '2020-03-27T22:55:59.517Z', - status: RuleExecutionStatus.succeeded, - lastFailureAt: null, - lastSuccessAt: '2020-03-27T22:55:59.517Z', - lastFailureMessage: null, - lastSuccessMessage: 'succeeded', - gap: null, - bulkCreateTimeDurations: [], - searchAfterTimeDurations: [], - lastLookBackDate: null, - }, - references: [ - { - id: 'f4b8e31d-cf93-4bde-a265-298bde885cd7', - type: 'alert', - name: 'alert_0', - }, - ], - updated_at: '2020-03-27T22:55:59.577Z', - version: 'WzgyMiwxXQ==', -}); - export const mockLogger = loggingSystemMock.createLogger(); export const sampleBulkErrorItem = ( diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/build_signal.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/build_signal.test.ts index e69bbd64faada7..e06e8a5cdcf766 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/build_signal.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/build_signal.test.ts @@ -20,7 +20,6 @@ import { } from '../../../../common/detection_engine/schemas/response/rules_schema.mocks'; import { getListArrayMock } from '../../../../common/detection_engine/schemas/types/lists.mock'; import { SIGNALS_TEMPLATE_VERSION } from '../routes/index/get_signals_template'; -import { RuleExecutionStatus } from '../../../../common/detection_engine/schemas/common/schemas'; describe('buildSignal', () => { beforeEach(() => { @@ -88,10 +87,6 @@ describe('buildSignal', () => { type: 'query', threat: [], version: 1, - status: RuleExecutionStatus.succeeded, - status_date: '2020-02-22T16:47:50.047Z', - last_success_at: '2020-02-22T16:47:50.047Z', - last_success_message: 'succeeded', output_index: '.siem-signals-default', max_signals: 100, risk_score: 55, @@ -177,10 +172,6 @@ describe('buildSignal', () => { type: 'query', threat: [], version: 1, - status: RuleExecutionStatus.succeeded, - status_date: '2020-02-22T16:47:50.047Z', - last_success_at: '2020-02-22T16:47:50.047Z', - last_success_message: 'succeeded', output_index: '.siem-signals-default', max_signals: 100, risk_score: 55, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/preview/preview_rule_execution_log_client.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/preview/preview_rule_execution_log_client.ts deleted file mode 100644 index 2a000b7a31968e..00000000000000 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/preview/preview_rule_execution_log_client.ts +++ /dev/null @@ -1,78 +0,0 @@ -/* - * 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 { SavedObjectsFindResult } from 'kibana/server'; -import { - IRuleExecutionLogClient, - LogStatusChangeArgs, - FindBulkExecutionLogArgs, - FindBulkExecutionLogResponse, - FindExecutionLogArgs, - GetLastFailuresArgs, - GetCurrentStatusArgs, - GetCurrentStatusBulkArgs, - GetCurrentStatusBulkResult, -} from '../../rule_execution_log'; -import { IRuleStatusSOAttributes } from '../../rules/types'; - -interface PreviewRuleExecutionLogClient extends IRuleExecutionLogClient { - clearWarningsAndErrorsStore: () => void; -} - -export const createWarningsAndErrors = () => { - const warningsAndErrorsStore: LogStatusChangeArgs[] = []; - - const previewRuleExecutionLogClient: PreviewRuleExecutionLogClient = { - find( - args: FindExecutionLogArgs - ): Promise>> { - return Promise.resolve([]); - }, - - findBulk(args: FindBulkExecutionLogArgs): Promise { - return Promise.resolve({}); - }, - - getLastFailures(args: GetLastFailuresArgs): Promise { - return Promise.resolve([]); - }, - - getCurrentStatus(args: GetCurrentStatusArgs): Promise { - return Promise.resolve({ - statusDate: new Date().toISOString(), - status: null, - lastFailureAt: null, - lastFailureMessage: null, - lastSuccessAt: null, - lastSuccessMessage: null, - lastLookBackDate: null, - gap: null, - bulkCreateTimeDurations: null, - searchAfterTimeDurations: null, - }); - }, - - getCurrentStatusBulk(args: GetCurrentStatusBulkArgs): Promise { - return Promise.resolve({}); - }, - - deleteCurrentStatus(ruleId: string): Promise { - return Promise.resolve(); - }, - - logStatusChange(args: LogStatusChangeArgs): Promise { - warningsAndErrorsStore.push(args); - return Promise.resolve(); - }, - - clearWarningsAndErrorsStore() { - warningsAndErrorsStore.length = 0; - }, - }; - - return { previewRuleExecutionLogClient, warningsAndErrorsStore }; -}; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/preview/preview_rule_execution_logger.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/preview/preview_rule_execution_logger.ts new file mode 100644 index 00000000000000..0cc6baf55ac287 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/preview/preview_rule_execution_logger.ts @@ -0,0 +1,52 @@ +/* + * 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 { + RuleExecutionLoggerFactory, + RuleExecutionContext, + StatusChangeArgs, +} from '../../rule_execution_log'; + +export interface IPreviewRuleExecutionLogger { + factory: RuleExecutionLoggerFactory; + + logged: { + statusChanges: Array; + }; + + clearLogs(): void; +} + +export const createPreviewRuleExecutionLogger = () => { + let logged: IPreviewRuleExecutionLogger['logged'] = { + statusChanges: [], + }; + + const factory: RuleExecutionLoggerFactory = ( + savedObjectsClient, + eventLogService, + logger, + context + ) => { + return { + context, + + logStatusChange(args: StatusChangeArgs): Promise { + logged.statusChanges.push({ ...context, ...args }); + return Promise.resolve(); + }, + }; + }; + + const clearLogs = (): void => { + logged = { + statusChanges: [], + }; + }; + + return { factory, logged, clearLogs }; +}; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.test.ts index b59922fbd7c9c1..c620d51a833826 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.test.ts @@ -14,6 +14,7 @@ import { alertsMock, AlertServicesMock } from '../../../../../alerting/server/mo import { listMock } from '../../../../../lists/server/mocks'; import { buildRuleMessageFactory } from './rule_messages'; import { ExceptionListClient } from '../../../../../lists/server'; +import { RuleExecutionStatus } from '../../../../common/detection_engine/schemas/common'; import { getListArrayMock } from '../../../../common/detection_engine/schemas/types/lists.mock'; import { getExceptionListItemSchemaMock } from '../../../../../lists/common/schemas/response/exception_list_item_schema.mock'; @@ -62,7 +63,7 @@ import { sampleAlertDocAADNoSortIdWithTimestamp, } from './__mocks__/es_results'; import { ShardError } from '../../types'; -import { ruleExecutionLogClientMock } from '../rule_execution_log/__mocks__/rule_execution_log_client'; +import { ruleExecutionLogMock } from '../rule_execution_log/__mocks__/rule_execution_log_client'; const buildRuleMessage = buildRuleMessageFactory({ id: 'fake id', @@ -71,8 +72,6 @@ const buildRuleMessage = buildRuleMessageFactory({ name: 'fake name', }); -const ruleStatusClient = ruleExecutionLogClientMock.create(); - describe('utils', () => { const anchor = '2020-01-01T06:06:06.666Z'; const unix = moment(anchor).valueOf(); @@ -664,26 +663,31 @@ describe('utils', () => { }, }, }; + + const ruleExecutionLogger = ruleExecutionLogMock.logger.create(); mockLogger.warn.mockClear(); + const res = await hasTimestampFields({ timestampField, - ruleName: 'myfakerulename', timestampFieldCapsResponse: timestampFieldCapsResponse as TransportResult< // eslint-disable-next-line @typescript-eslint/no-explicit-any Record >, inputIndices: ['myfa*'], - ruleStatusClient, - ruleId: 'ruleId', - ruleType: 'ruleType', - spaceId: 'default', + ruleExecutionLogger, logger: mockLogger, buildRuleMessage, }); + + expect(res).toBeTruthy(); expect(mockLogger.warn).toHaveBeenCalledWith( 'The following indices are missing the timestamp override field "event.ingested": ["myfakeindex-1","myfakeindex-2"] name: "fake name" id: "fake id" rule id: "fake rule id" signals index: "fakeindex"' ); - expect(res).toBeTruthy(); + expect(ruleExecutionLogger.logStatusChange).toHaveBeenCalledWith({ + newStatus: RuleExecutionStatus['partial failure'], + message: + 'The following indices are missing the timestamp override field "event.ingested": ["myfakeindex-1","myfakeindex-2"]', + }); }); test('returns true when missing timestamp field', async () => { @@ -710,26 +714,31 @@ describe('utils', () => { }, }, }; + + const ruleExecutionLogger = ruleExecutionLogMock.logger.create(); mockLogger.warn.mockClear(); + const res = await hasTimestampFields({ timestampField, - ruleName: 'myfakerulename', timestampFieldCapsResponse: timestampFieldCapsResponse as TransportResult< // eslint-disable-next-line @typescript-eslint/no-explicit-any Record >, inputIndices: ['myfa*'], - ruleStatusClient, - ruleId: 'ruleId', - ruleType: 'ruleType', - spaceId: 'default', + ruleExecutionLogger, logger: mockLogger, buildRuleMessage, }); + + expect(res).toBeTruthy(); expect(mockLogger.warn).toHaveBeenCalledWith( 'The following indices are missing the timestamp field "@timestamp": ["myfakeindex-1","myfakeindex-2"] name: "fake name" id: "fake id" rule id: "fake rule id" signals index: "fakeindex"' ); - expect(res).toBeTruthy(); + expect(ruleExecutionLogger.logStatusChange).toHaveBeenCalledWith({ + newStatus: RuleExecutionStatus['partial failure'], + message: + 'The following indices are missing the timestamp field "@timestamp": ["myfakeindex-1","myfakeindex-2"]', + }); }); test('returns true when missing logs-endpoint.alerts-* index and rule name is Endpoint Security', async () => { @@ -741,26 +750,33 @@ describe('utils', () => { fields: {}, }, }; + + const ruleExecutionLogger = ruleExecutionLogMock.logger.create({ + ruleName: 'Endpoint Security', + }); mockLogger.warn.mockClear(); + const res = await hasTimestampFields({ timestampField, - ruleName: 'Endpoint Security', timestampFieldCapsResponse: timestampFieldCapsResponse as TransportResult< // eslint-disable-next-line @typescript-eslint/no-explicit-any Record >, inputIndices: ['logs-endpoint.alerts-*'], - ruleStatusClient, - ruleId: 'ruleId', - ruleType: 'ruleType', - spaceId: 'default', + ruleExecutionLogger, logger: mockLogger, buildRuleMessage, }); + + expect(res).toBeTruthy(); expect(mockLogger.warn).toHaveBeenCalledWith( 'This rule is attempting to query data from Elasticsearch indices listed in the "Index pattern" section of the rule definition, however no index matching: ["logs-endpoint.alerts-*"] was found. This warning will continue to appear until a matching index is created or this rule is de-activated. If you have recently enrolled agents enabled with Endpoint Security through Fleet, this warning should stop once an alert is sent from an agent. name: "fake name" id: "fake id" rule id: "fake rule id" signals index: "fakeindex"' ); - expect(res).toBeTruthy(); + expect(ruleExecutionLogger.logStatusChange).toHaveBeenCalledWith({ + newStatus: RuleExecutionStatus['partial failure'], + message: + 'This rule is attempting to query data from Elasticsearch indices listed in the "Index pattern" section of the rule definition, however no index matching: ["logs-endpoint.alerts-*"] was found. This warning will continue to appear until a matching index is created or this rule is de-activated. If you have recently enrolled agents enabled with Endpoint Security through Fleet, this warning should stop once an alert is sent from an agent.', + }); }); test('returns true when missing logs-endpoint.alerts-* index and rule name is NOT Endpoint Security', async () => { @@ -772,26 +788,35 @@ describe('utils', () => { fields: {}, }, }; + + // SUT uses rule execution logger's context to check the rule name + const ruleExecutionLogger = ruleExecutionLogMock.logger.create({ + ruleName: 'NOT Endpoint Security', + }); + mockLogger.warn.mockClear(); + const res = await hasTimestampFields({ timestampField, - ruleName: 'NOT Endpoint Security', timestampFieldCapsResponse: timestampFieldCapsResponse as TransportResult< // eslint-disable-next-line @typescript-eslint/no-explicit-any Record >, inputIndices: ['logs-endpoint.alerts-*'], - ruleStatusClient, - ruleId: 'ruleId', - ruleType: 'ruleType', - spaceId: 'default', + ruleExecutionLogger, logger: mockLogger, buildRuleMessage, }); + + expect(res).toBeTruthy(); expect(mockLogger.warn).toHaveBeenCalledWith( 'This rule is attempting to query data from Elasticsearch indices listed in the "Index pattern" section of the rule definition, however no index matching: ["logs-endpoint.alerts-*"] was found. This warning will continue to appear until a matching index is created or this rule is de-activated. name: "fake name" id: "fake id" rule id: "fake rule id" signals index: "fakeindex"' ); - expect(res).toBeTruthy(); + expect(ruleExecutionLogger.logStatusChange).toHaveBeenCalledWith({ + newStatus: RuleExecutionStatus['partial failure'], + message: + 'This rule is attempting to query data from Elasticsearch indices listed in the "Index pattern" section of the rule definition, however no index matching: ["logs-endpoint.alerts-*"] was found. This warning will continue to appear until a matching index is created or this rule is de-activated.', + }); }); }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.ts index de2e8975788807..21f7f90a95de90 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.ts @@ -21,7 +21,7 @@ import { TimestampOverrideOrUndefined, Privilege, RuleExecutionStatus, -} from '../../../../common/detection_engine/schemas/common/schemas'; +} from '../../../../common/detection_engine/schemas/common'; import { ElasticsearchClient, Logger, @@ -60,7 +60,7 @@ import { } from '../schemas/rule_schemas'; import { RACAlert, WrappedRACAlert } from '../rule_types/types'; import { SearchTypes } from '../../../../common/detection_engine/types'; -import { IRuleExecutionLogClient } from '../rule_execution_log/types'; +import { IRuleExecutionLogger } from '../rule_execution_log'; import { withSecuritySpan } from '../../../utils/with_security_span'; interface SortExceptionsReturn { @@ -89,22 +89,9 @@ export const hasReadIndexPrivileges = async (args: { privileges: Privilege; logger: Logger; buildRuleMessage: BuildRuleMessage; - ruleStatusClient: IRuleExecutionLogClient; - ruleId: string; - ruleName: string; - ruleType: string; - spaceId: string; + ruleExecutionLogger: IRuleExecutionLogger; }): Promise => { - const { - privileges, - logger, - buildRuleMessage, - ruleStatusClient, - ruleId, - ruleName, - ruleType, - spaceId, - } = args; + const { privileges, logger, buildRuleMessage, ruleExecutionLogger } = args; const indexNames = Object.keys(privileges.index); const [, indexesWithNoReadPrivileges] = partition( @@ -119,13 +106,9 @@ export const hasReadIndexPrivileges = async (args: { indexesWithNoReadPrivileges )}`; logger.warn(buildRuleMessage(errorString)); - await ruleStatusClient.logStatusChange({ - message: errorString, - ruleId, - ruleName, - ruleType, - spaceId, + await ruleExecutionLogger.logStatusChange({ newStatus: RuleExecutionStatus['partial failure'], + message: errorString, }); return true; } @@ -134,32 +117,26 @@ export const hasReadIndexPrivileges = async (args: { export const hasTimestampFields = async (args: { timestampField: string; - ruleName: string; // any is derived from here // node_modules/@elastic/elasticsearch/lib/api/kibana.d.ts // eslint-disable-next-line @typescript-eslint/no-explicit-any timestampFieldCapsResponse: TransportResult, unknown>; inputIndices: string[]; - ruleStatusClient: IRuleExecutionLogClient; - ruleId: string; - spaceId: string; - ruleType: string; + ruleExecutionLogger: IRuleExecutionLogger; logger: Logger; buildRuleMessage: BuildRuleMessage; }): Promise => { const { timestampField, - ruleName, timestampFieldCapsResponse, inputIndices, - ruleStatusClient, - ruleId, - ruleType, - spaceId, + ruleExecutionLogger, logger, buildRuleMessage, } = args; + const { ruleName } = ruleExecutionLogger.context; + if (isEmpty(timestampFieldCapsResponse.body.indices)) { const errorString = `This rule is attempting to query data from Elasticsearch indices listed in the "Index pattern" section of the rule definition, however no index matching: ${JSON.stringify( inputIndices @@ -169,13 +146,9 @@ export const hasTimestampFields = async (args: { : '' }`; logger.warn(buildRuleMessage(errorString.trimEnd())); - await ruleStatusClient.logStatusChange({ - message: errorString.trimEnd(), - ruleId, - ruleName, - ruleType, - spaceId, + await ruleExecutionLogger.logStatusChange({ newStatus: RuleExecutionStatus['partial failure'], + message: errorString.trimEnd(), }); return true; } else if ( @@ -195,15 +168,13 @@ export const hasTimestampFields = async (args: { ? timestampFieldCapsResponse.body.indices : timestampFieldCapsResponse.body.fields[timestampField]?.unmapped?.indices )}`; + logger.warn(buildRuleMessage(errorString)); - await ruleStatusClient.logStatusChange({ - message: errorString, - ruleId, - ruleName, - ruleType, - spaceId, + await ruleExecutionLogger.logStatusChange({ newStatus: RuleExecutionStatus['partial failure'], + message: errorString, }); + return true; } return false; diff --git a/x-pack/plugins/security_solution/server/plugin.ts b/x-pack/plugins/security_solution/server/plugin.ts index 91118d0ef4e896..784e2ed7597982 100644 --- a/x-pack/plugins/security_solution/server/plugin.ts +++ b/x-pack/plugins/security_solution/server/plugin.ts @@ -67,7 +67,10 @@ import { PolicyWatcher } from './endpoint/lib/policy/license_watch'; import { migrateArtifactsToFleet } from './endpoint/lib/artifacts/migrate_artifacts_to_fleet'; import aadFieldConversion from './lib/detection_engine/routes/index/signal_aad_mapping.json'; import previewPolicy from './lib/detection_engine/routes/index/preview_policy.json'; -import { registerEventLogProvider } from './lib/detection_engine/rule_execution_log/event_log_adapter/register_event_log_provider'; +import { + registerEventLogProvider, + ruleExecutionLoggerFactory, +} from './lib/detection_engine/rule_execution_log'; import { getKibanaPrivilegesFeaturePrivileges, getCasesKibanaFeature } from './features'; import { EndpointMetadataService } from './endpoint/services/metadata'; import { CreateRuleOptions } from './lib/detection_engine/rule_types/types'; @@ -228,6 +231,7 @@ export class Plugin implements ISecuritySolutionPlugin { config: this.config, ruleDataClient, eventLogService, + ruleExecutionLoggerFactory, }; const securityRuleTypeWrapper = createSecurityRuleTypeWrapper(securityRuleTypeOptions); diff --git a/x-pack/plugins/security_solution/server/request_context_factory.ts b/x-pack/plugins/security_solution/server/request_context_factory.ts index 26bb56113e635e..c43b667896c111 100644 --- a/x-pack/plugins/security_solution/server/request_context_factory.ts +++ b/x-pack/plugins/security_solution/server/request_context_factory.ts @@ -5,12 +5,14 @@ * 2.0. */ +import { memoize } from 'lodash'; + import { Logger, KibanaRequest, RequestHandlerContext } from 'kibana/server'; import { DEFAULT_SPACE_ID } from '../common/constants'; import { AppClientFactory } from './client'; import { ConfigType } from './config'; -import { RuleExecutionLogClient } from './lib/detection_engine/rule_execution_log/rule_execution_log_client'; +import { ruleExecutionLogClientFactory } from './lib/detection_engine/rule_execution_log'; import { buildFrameworkRequest } from './lib/timeline/utils/common'; import { SecuritySolutionPluginCoreSetupDependencies, @@ -101,14 +103,13 @@ export class RequestContextFactory implements IRequestContextFactory { getRuleDataService: () => ruleRegistry.ruleDataService, - getExecutionLogClient: () => - new RuleExecutionLogClient({ - underlyingClient: config.ruleExecutionLog.underlyingClient, - savedObjectsClient: context.core.savedObjects.client, - eventLogService: plugins.eventLog, - eventLogClient: startPlugins.eventLog.getClient(request), - logger, - }), + getExecutionLogClient: memoize(() => + ruleExecutionLogClientFactory( + context.core.savedObjects.client, + startPlugins.eventLog.getClient(request), + logger + ) + ), getExceptionListClient: () => { if (!lists) { diff --git a/x-pack/plugins/security_solution/server/routes/index.ts b/x-pack/plugins/security_solution/server/routes/index.ts index d7cc745847f316..13788cbae9fde6 100644 --- a/x-pack/plugins/security_solution/server/routes/index.ts +++ b/x-pack/plugins/security_solution/server/routes/index.ts @@ -36,7 +36,7 @@ import { deleteRulesBulkRoute } from '../lib/detection_engine/routes/rules/delet import { performBulkActionRoute } from '../lib/detection_engine/routes/rules/perform_bulk_action_route'; import { importRulesRoute } from '../lib/detection_engine/routes/rules/import_rules_route'; import { exportRulesRoute } from '../lib/detection_engine/routes/rules/export_rules_route'; -import { findRuleStatusInternalRoute } from '../lib/detection_engine/routes/rules/find_rule_status_internal_route'; +import { getRuleExecutionEventsRoute } from '../lib/detection_engine/routes/rules/get_rule_execution_events_route'; import { getPrepackagedRulesStatusRoute } from '../lib/detection_engine/routes/rules/get_prepackaged_rules_status_route'; import { createTimelinesRoute, @@ -86,7 +86,7 @@ export const initRoutes = ( ) => { const isRuleRegistryEnabled = ruleDataClient != null; // Detection Engine Rule routes that have the REST endpoints of /api/detection_engine/rules - // All REST rule creation, deletion, updating, etc...... + // All REST rule creation, deletion, updating, etc createRulesRoute(router, ml, isRuleRegistryEnabled); readRulesRoute(router, logger, isRuleRegistryEnabled); updateRulesRoute(router, ml, isRuleRegistryEnabled); @@ -114,6 +114,8 @@ export const initRoutes = ( deleteRulesBulkRoute(router, isRuleRegistryEnabled); performBulkActionRoute(router, ml, logger, isRuleRegistryEnabled); + getRuleExecutionEventsRoute(router); + createTimelinesRoute(router, config, security); patchTimelinesRoute(router, config, security); importRulesRoute(router, config, ml, isRuleRegistryEnabled); @@ -134,8 +136,6 @@ export const initRoutes = ( persistNoteRoute(router, config, security); persistPinnedEventRoute(router, config, security); - findRuleStatusInternalRoute(router); - // Detection Engine Signals routes that have the REST endpoints of /api/detection_engine/signals // POST /api/detection_engine/signals/status // Example usage can be found in security_solution/server/lib/detection_engine/scripts/signals diff --git a/x-pack/plugins/security_solution/server/saved_objects.ts b/x-pack/plugins/security_solution/server/saved_objects.ts index 53618d738984be..0eca269a018cea 100644 --- a/x-pack/plugins/security_solution/server/saved_objects.ts +++ b/x-pack/plugins/security_solution/server/saved_objects.ts @@ -9,10 +9,9 @@ import { CoreSetup } from '../../../../src/core/server'; import { noteType, pinnedEventType, timelineType } from './lib/timeline/saved_object_mappings'; // eslint-disable-next-line no-restricted-imports -import { legacyRuleStatusType } from './lib/detection_engine/rules/legacy_rule_status/legacy_rule_status_saved_object_mappings'; -import { ruleAssetType } from './lib/detection_engine/rules/rule_asset/rule_asset_saved_object_mappings'; -// eslint-disable-next-line no-restricted-imports import { legacyType as legacyRuleActionsType } from './lib/detection_engine/rule_actions/legacy_saved_object_mappings'; +import { ruleExecutionInfoType } from './lib/detection_engine/rule_execution_log'; +import { ruleAssetType } from './lib/detection_engine/rules/rule_asset/rule_asset_saved_object_mappings'; import { type as signalsMigrationType } from './lib/detection_engine/migrations/saved_objects'; import { exceptionsArtifactType, @@ -23,7 +22,7 @@ const types = [ noteType, pinnedEventType, legacyRuleActionsType, - legacyRuleStatusType, + ruleExecutionInfoType, ruleAssetType, timelineType, exceptionsArtifactType, diff --git a/x-pack/plugins/security_solution/server/types.ts b/x-pack/plugins/security_solution/server/types.ts index 75686d78340702..3be7a5e998b769 100644 --- a/x-pack/plugins/security_solution/server/types.ts +++ b/x-pack/plugins/security_solution/server/types.ts @@ -15,7 +15,7 @@ import type { IRuleDataService } from '../../rule_registry/server'; import { AppClient } from './client'; import { ConfigType } from './config'; -import { IRuleExecutionLogClient } from './lib/detection_engine/rule_execution_log/types'; +import { IRuleExecutionLogClient } from './lib/detection_engine/rule_execution_log'; import { FrameworkRequest } from './lib/framework'; import { EndpointAuthz } from '../common/endpoint/types/authz'; diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index e17ed6f278acd3..4c4910cede8e76 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -22148,13 +22148,11 @@ "xpack.securitySolution.detectionEngine.ruleDetails.activateRuleLabel": "有効化", "xpack.securitySolution.detectionEngine.ruleDetails.backToRulesButton": "ルール", "xpack.securitySolution.detectionEngine.ruleDetails.deletedRule": "削除されたルール", - "xpack.securitySolution.detectionEngine.ruleDetails.errorCalloutTitle": "ルール失敗", "xpack.securitySolution.detectionEngine.ruleDetails.exceptionsTab": "例外", "xpack.securitySolution.detectionEngine.ruleDetails.experimentalDescription": "実験的", "xpack.securitySolution.detectionEngine.ruleDetails.failureHistoryTab": "エラー履歴", "xpack.securitySolution.detectionEngine.ruleDetails.lastFiveErrorsTitle": "最後の5件のエラー", "xpack.securitySolution.detectionEngine.ruleDetails.pageTitle": "ルール詳細", - "xpack.securitySolution.detectionEngine.ruleDetails.partialErrorCalloutTitle": "警告", "xpack.securitySolution.detectionEngine.ruleDetails.ruleCreationDescription": "作成者:{by} 日付:{date}", "xpack.securitySolution.detectionEngine.ruleDetails.ruleUpdateDescription": "更新者:{by} 日付:{date}", "xpack.securitySolution.detectionEngine.ruleDetails.statusFailedAtColumn": "失敗", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 7850bfaba35c2b..8e4a9aaf86138e 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -22484,13 +22484,11 @@ "xpack.securitySolution.detectionEngine.ruleDetails.activateRuleLabel": "激活", "xpack.securitySolution.detectionEngine.ruleDetails.backToRulesButton": "规则", "xpack.securitySolution.detectionEngine.ruleDetails.deletedRule": "已删除规则", - "xpack.securitySolution.detectionEngine.ruleDetails.errorCalloutTitle": "规则错误位置", "xpack.securitySolution.detectionEngine.ruleDetails.exceptionsTab": "例外", "xpack.securitySolution.detectionEngine.ruleDetails.experimentalDescription": "实验性", "xpack.securitySolution.detectionEngine.ruleDetails.failureHistoryTab": "失败历史记录", "xpack.securitySolution.detectionEngine.ruleDetails.lastFiveErrorsTitle": "上五个错误", "xpack.securitySolution.detectionEngine.ruleDetails.pageTitle": "规则详情", - "xpack.securitySolution.detectionEngine.ruleDetails.partialErrorCalloutTitle": "警告于", "xpack.securitySolution.detectionEngine.ruleDetails.ruleCreationDescription": "由 {by} 于 {date}创建", "xpack.securitySolution.detectionEngine.ruleDetails.ruleUpdateDescription": "由 {by} 于 {date}更新", "xpack.securitySolution.detectionEngine.ruleDetails.statusFailedAtColumn": "失败于", diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/check_privileges.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/check_privileges.ts index 6d2610dfce186c..972fdf8f7c72eb 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/check_privileges.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/check_privileges.ts @@ -70,7 +70,9 @@ export default ({ getService }: FtrProviderContext) => { .set('kbn-xsrf', 'true') .query({ id }) .expect(200); - expect(body?.last_success_message).to.eql( + + // TODO: https://github.com/elastic/kibana/pull/121644 clean up, make type-safe + expect(body?.execution_summary?.last_execution.message).to.eql( `This rule may not have the required read privileges to the following indices/index patterns: ["${index[0]}"]` ); @@ -96,7 +98,9 @@ export default ({ getService }: FtrProviderContext) => { .set('kbn-xsrf', 'true') .query({ id }) .expect(200); - expect(body?.last_success_message).to.eql( + + // TODO: https://github.com/elastic/kibana/pull/121644 clean up, make type-safe + expect(body?.execution_summary?.last_execution.message).to.eql( `This rule may not have the required read privileges to the following indices/index patterns: ["${index[0]}"]` ); diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/create_rules.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/create_rules.ts index 4a572f94b959df..29237d065fd3a8 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/create_rules.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/create_rules.ts @@ -120,8 +120,9 @@ export default ({ getService }: FtrProviderContext) => { .query({ id: body.id }) .expect(200); - expect(rule.status).to.eql('partial failure'); - expect(rule.last_success_message).to.eql( + // TODO: https://github.com/elastic/kibana/pull/121644 clean up, make type-safe + expect(rule?.execution_summary?.last_execution.status).to.eql('partial failure'); + expect(rule?.execution_summary?.last_execution.message).to.eql( 'This rule is attempting to query data from Elasticsearch indices listed in the "Index pattern" section of the rule definition, however no index matching: ["does-not-exist-*"] was found. This warning will continue to appear until a matching index is created or this rule is de-activated.' ); }); @@ -307,8 +308,9 @@ export default ({ getService }: FtrProviderContext) => { .query({ id: bodyId }) .expect(200); - expect(rule?.status).to.eql('partial failure'); - expect(rule?.last_success_message).to.eql( + // TODO: https://github.com/elastic/kibana/pull/121644 clean up, make type-safe + expect(rule?.execution_summary?.last_execution.status).to.eql('partial failure'); + expect(rule?.execution_summary?.last_execution.message).to.eql( 'The following indices are missing the timestamp override field "event.ingested": ["myfakeindex-1"]' ); }); @@ -335,7 +337,8 @@ export default ({ getService }: FtrProviderContext) => { .query({ id: bodyId }) .expect(200); - expect(rule.status).to.eql('partial failure'); + // TODO: https://github.com/elastic/kibana/pull/121644 clean up, make type-safe + expect(rule?.execution_summary?.last_execution.status).to.eql('partial failure'); }); }); }); diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/create_threat_matching.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/create_threat_matching.ts index a50a9bf5bbefee..b85b1fcd4003e2 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/create_threat_matching.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/create_threat_matching.ts @@ -114,7 +114,9 @@ export default ({ getService }: FtrProviderContext) => { const bodyToCompare = removeServerGeneratedProperties(ruleResponse); expect(bodyToCompare).to.eql(getThreatMatchingSchemaPartialMock(true)); - expect(rule.status).to.eql('succeeded'); + + // TODO: https://github.com/elastic/kibana/pull/121644 clean up, make type-safe + expect(rule?.execution_summary?.last_execution.status).to.eql('succeeded'); }); }); @@ -477,7 +479,9 @@ export default ({ getService }: FtrProviderContext) => { .set('kbn-xsrf', 'true') .query({ id }) .expect(200); - expect(body.last_failure_message).to.contain( + + // TODO: https://github.com/elastic/kibana/pull/121644 clean up, make type-safe + expect(body?.execution_summary?.last_execution.message).to.contain( 'execution has exceeded its allotted interval' ); }); diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/generating_signals.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/generating_signals.ts index 8d6764b8a64058..077fba52666df9 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/generating_signals.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/generating_signals.ts @@ -1191,7 +1191,10 @@ export default ({ getService }: FtrProviderContext) => { .get(DETECTION_ENGINE_RULES_URL) .set('kbn-xsrf', 'true') .query({ id: ruleResponse.id }); - const initialStatusDate = new Date(statusResponse.body.status_date); + + // TODO: https://github.com/elastic/kibana/pull/121644 clean up, make type-safe + const ruleStatusDate = statusResponse.body?.execution_summary?.last_execution.date; + const initialStatusDate = new Date(ruleStatusDate); const initialSignal = signals.hits.hits[0]; diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/migrations.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/migrations.ts index 66d33de2ba4daa..04586999aa163a 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/migrations.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/migrations.ts @@ -6,7 +6,6 @@ */ import expect from '@kbn/expect'; -import { IRuleStatusSOAttributes } from '../../../../plugins/security_solution/server/lib/detection_engine/rules/types'; import { FtrProviderContext } from '../../common/ftr_provider_context'; // eslint-disable-next-line import/no-default-export @@ -97,94 +96,6 @@ export default ({ getService }: FtrProviderContext): void => { '7d' ); }); - - it('migrates legacy siem-detection-engine-rule-status to use saved object references', async () => { - const response = await es.get<{ - 'siem-detection-engine-rule-status': { - alertId: string; - }; - references: [{}]; - }>( - { - index: '.kibana', - id: 'siem-detection-engine-rule-status:d62d2980-27c4-11ec-92b0-f7b47106bb35', - }, - { meta: true } - ); - expect(response.statusCode).to.eql(200); - - // references exist and are expected values - expect(response.body._source?.references).to.eql([ - { - name: 'alert_0', - id: 'fb1046a0-0452-11ec-9b15-d13d79d162f3', - type: 'alert', - }, - ]); - - // alertId no longer exist - expect(response.body._source?.['siem-detection-engine-rule-status'].alertId).to.eql( - undefined - ); - }); - - it('migrates legacy siem-detection-engine-rule-status and retains other attributes as the same attributes as before', async () => { - const response = await es.get<{ - 'siem-detection-engine-rule-status': IRuleStatusSOAttributes; - }>( - { - index: '.kibana', - id: 'siem-detection-engine-rule-status:d62d2980-27c4-11ec-92b0-f7b47106bb35', - }, - { meta: true } - ); - expect(response.statusCode).to.eql(200); - - expect(response.body._source?.['siem-detection-engine-rule-status']).to.eql({ - statusDate: '2021-10-11T20:51:26.622Z', - status: 'succeeded', - lastFailureAt: '2021-10-11T18:10:08.982Z', - lastSuccessAt: '2021-10-11T20:51:26.622Z', - lastFailureMessage: - '4 days (323690920ms) were not queried between this rule execution and the last execution, so signals may have been missed. Consider increasing your look behind time or adding more Kibana instances. name: "Threshy" id: "fb1046a0-0452-11ec-9b15-d13d79d162f3" rule id: "b789c80f-f6d8-41f1-8b4f-b4a23342cde2" signals index: ".siem-signals-spong-default"', - lastSuccessMessage: 'succeeded', - gap: '4 days', - bulkCreateTimeDurations: ['34.49'], - searchAfterTimeDurations: ['62.58'], - lastLookBackDate: null, - }); - }); - - // If alertId is not a string/null ensure it is removed as the mapping was removed and so the migration would fail. - // Specific test for this as e2e tests will not catch the mismatch and we can't use the migration test harness - // since this SO is not importable/exportable via the SOM. - // For details see: https://github.com/elastic/kibana/issues/116423 - it('migrates legacy siem-detection-engine-rule-status and removes alertId when not a string', async () => { - const response = await es.get<{ - 'siem-detection-engine-rule-status': IRuleStatusSOAttributes; - }>( - { - index: '.kibana', - id: 'siem-detection-engine-rule-status:d62d2980-27c4-11ec-92b0-f7b47106bb36', - }, - { meta: true } - ); - expect(response.statusCode).to.eql(200); - - expect(response.body._source?.['siem-detection-engine-rule-status']).to.eql({ - statusDate: '2021-10-11T20:51:26.622Z', - status: 'succeeded', - lastFailureAt: '2021-10-11T18:10:08.982Z', - lastSuccessAt: '2021-10-11T20:51:26.622Z', - lastFailureMessage: - '4 days (323690920ms) were not queried between this rule execution and the last execution, so signals may have been missed. Consider increasing your look behind time or adding more Kibana instances. name: "Threshy" id: "fb1046a0-0452-11ec-9b15-d13d79d162f3" rule id: "b789c80f-f6d8-41f1-8b4f-b4a23342cde2" signals index: ".siem-signals-spong-default"', - lastSuccessMessage: 'succeeded', - gap: '4 days', - bulkCreateTimeDurations: ['34.49'], - searchAfterTimeDurations: ['62.58'], - lastLookBackDate: null, - }); - }); }); }); }; diff --git a/x-pack/test/detection_engine_api_integration/utils.ts b/x-pack/test/detection_engine_api_integration/utils.ts index 2f9fba7430d593..04bf0eec6f5b86 100644 --- a/x-pack/test/detection_engine_api_integration/utils.ts +++ b/x-pack/test/detection_engine_api_integration/utils.ts @@ -66,18 +66,10 @@ export const removeServerGeneratedProperties = ( ): Partial => { const { /* eslint-disable @typescript-eslint/naming-convention */ + id, created_at, updated_at, - id, - last_failure_at, - last_failure_message, - last_success_at, - last_success_message, - last_gap, - search_after_time_durations, - bulk_create_time_durations, - status, - status_date, + execution_summary, /* eslint-enable @typescript-eslint/naming-convention */ ...removedProperties } = rule; @@ -538,18 +530,18 @@ export const deleteAllTimelines = async (es: Client): Promise => { }; /** - * Remove all rules statuses from the .kibana index + * Remove all rules execution info saved objects from the .kibana index * This will retry 20 times before giving up and hopefully still not interfere with other tests * @param es The ElasticSearch handle * @param log The tooling logger */ -export const deleteAllRulesStatuses = async (es: Client, log: ToolingLog): Promise => { +export const deleteAllRuleExecutionInfo = async (es: Client, log: ToolingLog): Promise => { return countDownES( async () => { return es.deleteByQuery( { index: '.kibana', - q: 'type:siem-detection-engine-rule-status', + q: 'type:siem-detection-engine-rule-execution-info', wait_for_completion: true, refresh: true, body: {}, @@ -557,7 +549,7 @@ export const deleteAllRulesStatuses = async (es: Client, log: ToolingLog): Promi { meta: true } ); }, - 'deleteAllRulesStatuses', + 'deleteAllRuleExecutionInfo', log ); }; @@ -1369,9 +1361,13 @@ export const waitForRuleSuccessOrStatus = async ( )}, status: ${JSON.stringify(response.status)}` ); } + + // TODO: https://github.com/elastic/kibana/pull/121644 clean up, make type-safe const rule = response.body; + const ruleStatus = rule?.execution_summary?.last_execution.status; + const ruleStatusDate = rule?.execution_summary?.last_execution.date; - if (rule?.status !== status) { + if (ruleStatus !== status) { log.debug( `Did not get an expected status of ${status} while waiting for a rule success or status for rule id ${id} (waitForRuleSuccessOrStatus). Will continue retrying until status is found. body: ${JSON.stringify( response.body @@ -1380,8 +1376,8 @@ export const waitForRuleSuccessOrStatus = async ( } return ( rule != null && - rule.status === status && - (afterDate ? new Date(rule.status_date) > afterDate : true) + ruleStatus === status && + (afterDate ? new Date(ruleStatusDate) > afterDate : true) ); } catch (e) { if ((e as Error).message.includes('got 503 "Service Unavailable"')) { diff --git a/x-pack/test/functional/es_archives/security_solution/migrations/data.json b/x-pack/test/functional/es_archives/security_solution/migrations/data.json index 89eb207b392e8d..832c56c38e4971 100644 --- a/x-pack/test/functional/es_archives/security_solution/migrations/data.json +++ b/x-pack/test/functional/es_archives/security_solution/migrations/data.json @@ -29,66 +29,3 @@ } } } - -{ - "type": "doc", - "value": { - "id": "siem-detection-engine-rule-status:d62d2980-27c4-11ec-92b0-f7b47106bb35", - "index": ".kibana_1", - "source": { - "siem-detection-engine-rule-status": { - "alertId": "fb1046a0-0452-11ec-9b15-d13d79d162f3", - "statusDate": "2021-10-11T20:51:26.622Z", - "status": "succeeded", - "lastFailureAt": "2021-10-11T18:10:08.982Z", - "lastSuccessAt": "2021-10-11T20:51:26.622Z", - "lastFailureMessage": "4 days (323690920ms) were not queried between this rule execution and the last execution, so signals may have been missed. Consider increasing your look behind time or adding more Kibana instances. name: \"Threshy\" id: \"fb1046a0-0452-11ec-9b15-d13d79d162f3\" rule id: \"b789c80f-f6d8-41f1-8b4f-b4a23342cde2\" signals index: \".siem-signals-spong-default\"", - "lastSuccessMessage": "succeeded", - "gap": "4 days", - "bulkCreateTimeDurations": [ - "34.49" - ], - "searchAfterTimeDurations": [ - "62.58" - ], - "lastLookBackDate": null - }, - "type": "siem-detection-engine-rule-status", - "references": [], - "coreMigrationVersion": "7.14.0", - "updated_at": "2021-10-11T20:51:26.657Z" - } - } -} - -{ - "type": "doc", - "value": { - "id": "siem-detection-engine-rule-status:d62d2980-27c4-11ec-92b0-f7b47106bb36", - "index": ".kibana_1", - "source": { - "siem-detection-engine-rule-status": { - "alertId": 1337, - "statusDate": "2021-10-11T20:51:26.622Z", - "status": "succeeded", - "lastFailureAt": "2021-10-11T18:10:08.982Z", - "lastSuccessAt": "2021-10-11T20:51:26.622Z", - "lastFailureMessage": "4 days (323690920ms) were not queried between this rule execution and the last execution, so signals may have been missed. Consider increasing your look behind time or adding more Kibana instances. name: \"Threshy\" id: \"fb1046a0-0452-11ec-9b15-d13d79d162f3\" rule id: \"b789c80f-f6d8-41f1-8b4f-b4a23342cde2\" signals index: \".siem-signals-spong-default\"", - "lastSuccessMessage": "succeeded", - "gap": "4 days", - "bulkCreateTimeDurations": [ - "34.49" - ], - "searchAfterTimeDurations": [ - "62.58" - ], - "lastLookBackDate": null - }, - "type": "siem-detection-engine-rule-status", - "references": [], - "coreMigrationVersion": "7.14.0", - "updated_at": "2021-10-11T20:51:26.657Z" - } - } -} - diff --git a/x-pack/test/functional/es_archives/security_solution/migrations/mappings.json b/x-pack/test/functional/es_archives/security_solution/migrations/mappings.json index 8728ec4ad74a14..1e2b89a3052c84 100644 --- a/x-pack/test/functional/es_archives/security_solution/migrations/mappings.json +++ b/x-pack/test/functional/es_archives/security_solution/migrations/mappings.json @@ -72,7 +72,6 @@ "search-telemetry": "3d1b76c39bfb2cc8296b024d73854724", "canvas-workpad": "b0a1706d356228dbdcb4a17e6b9eb231", "alert": "4373936518133d7f118940e0441bbf40", - "siem-detection-engine-rule-status": "ae783f41c6937db6b7a2ef5c93a9e9b0", "ingest-package-policies": "4525de5ba9d036d8322ecfba3bca93f8", "map": "9134b47593116d7953f6adba096fc463", "legacy-url-alias": "e8dd3b6056ad7e1de32523f457310ecb", @@ -2339,43 +2338,6 @@ } } }, - "siem-detection-engine-rule-status": { - "properties": { - "alertId": { - "type": "keyword" - }, - "bulkCreateTimeDurations": { - "type": "float" - }, - "gap": { - "type": "text" - }, - "lastFailureAt": { - "type": "date" - }, - "lastFailureMessage": { - "type": "text" - }, - "lastLookBackDate": { - "type": "date" - }, - "lastSuccessAt": { - "type": "date" - }, - "lastSuccessMessage": { - "type": "text" - }, - "searchAfterTimeDurations": { - "type": "float" - }, - "status": { - "type": "keyword" - }, - "statusDate": { - "type": "date" - } - } - }, "siem-ui-timeline": { "properties": { "columns": { diff --git a/yarn.lock b/yarn.lock index 369c5edf179d2f..47a01e6cb8aeeb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -23546,10 +23546,10 @@ react-popper@^2.2.4: react-fast-compare "^3.0.1" warning "^4.0.2" -react-query@^3.28.0: - version "3.28.0" - resolved "https://registry.yarnpkg.com/react-query/-/react-query-3.28.0.tgz#1bfe12944860b2b773680054de37f19438f59d1d" - integrity sha512-OeX+nRqs7Zi0MvvtaKxKWE4N966UGtqSVuedOsz8cJh9eW195fgtYZ9nW3hZjIPPmeDY1PkArLUiV4wZvNRDPw== +react-query@^3.34.0: + version "3.34.8" + resolved "https://registry.yarnpkg.com/react-query/-/react-query-3.34.8.tgz#a3be8523fd95f766b04c32847a1b58d8231db03c" + integrity sha512-pl9e2VmVbgKf29Qn/WpmFVtB2g17JPqLLyOQg3GfSs/S2WABvip5xlT464vfXtilLPcJVg9bEHHlqmC38/nvDw== dependencies: "@babel/runtime" "^7.5.5" broadcast-channel "^3.4.1" From 1f0906ea1baaca956cc850a10539cbc28ba14d90 Mon Sep 17 00:00:00 2001 From: Frank Hassanabad Date: Thu, 20 Jan 2022 14:20:50 -0700 Subject: [PATCH 098/108] Fixes the producer to be SERVER_APP_ID (#123504) ## Summary See: https://github.com/elastic/kibana/issues/123500 This is a one line fix to change the `producer` to be the `SERVER_APP_ID` like the others Before: Screen Shot 2022-01-20 at 11 51 17 AM After: Screen Shot 2022-01-20 at 12 39 05 PM --- .../rule_types/saved_query/create_saved_query_alert_type.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/saved_query/create_saved_query_alert_type.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/saved_query/create_saved_query_alert_type.ts index 2ed66ba6526447..2722f31f3eacdd 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/saved_query/create_saved_query_alert_type.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/saved_query/create_saved_query_alert_type.ts @@ -7,6 +7,7 @@ import { validateNonExact } from '@kbn/securitysolution-io-ts-utils'; import { SAVED_QUERY_RULE_TYPE_ID } from '@kbn/securitysolution-rules'; +import { SERVER_APP_ID } from '../../../../../common/constants'; import { CompleteRule, @@ -50,7 +51,7 @@ export const createSavedQueryAlertType = ( }, minimumLicenseRequired: 'basic', isExportable: false, - producer: 'security-solution', + producer: SERVER_APP_ID, async executor(execOptions) { const { runOpts: { From d2db83d017dfba21db5cd70ecbfb7488642926b2 Mon Sep 17 00:00:00 2001 From: Brian Seeders Date: Thu, 20 Jan 2022 16:25:00 -0500 Subject: [PATCH 099/108] Revert "skip flaky suite (#123495)" This reverts commit 35f721db9bef5ffd0d2787a9da83a568c9c598ca. --- .../endpoint/validators/base_validator.test.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/x-pack/plugins/security_solution/server/lists_integration/endpoint/validators/base_validator.test.ts b/x-pack/plugins/security_solution/server/lists_integration/endpoint/validators/base_validator.test.ts index 9d19ed4178a2ae..728e3b8559ed32 100644 --- a/x-pack/plugins/security_solution/server/lists_integration/endpoint/validators/base_validator.test.ts +++ b/x-pack/plugins/security_solution/server/lists_integration/endpoint/validators/base_validator.test.ts @@ -21,8 +21,7 @@ import { GLOBAL_ARTIFACT_TAG, } from '../../../../common/endpoint/service/artifacts'; -// FLAKY: https://github.com/elastic/kibana/issues/123495 -describe.skip('When using Artifacts Exceptions BaseValidator', () => { +describe('When using Artifacts Exceptions BaseValidator', () => { let endpointAppContextServices: EndpointAppContextService; let kibanaRequest: ReturnType; let exceptionLikeItem: ExceptionItemLikeOptions; From f5eec419dfd4d1f5cca9c83d2bc74a973c17ad90 Mon Sep 17 00:00:00 2001 From: Zacqary Adam Xeper Date: Thu, 20 Jan 2022 15:37:30 -0600 Subject: [PATCH 100/108] [Alerting] Add dropdown for number of executions in Rule Details view (#122595) * [Alerting] Add dropdown for number of executions in Rule Details view * Fix tests * Fix missing prop in tests * Add unit test for numberOfExecutions api param * Fix i18n and improve effect use * Fix typescript nit * Fix inline snapshot * Fix test snapshots * Fix snapshot * Fix snapshot * Switch api to number of executions instead of implied date * Fix refresh button and event log filter query * Fix tests for non-numberOfExecutions api calls * Remove extraneous import * Switch execution results to separate query * Fix test * Fix tests Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../lib/alert_summary_from_event_log.test.ts | 30 ++- .../lib/alert_summary_from_event_log.ts | 29 ++- .../routes/get_rule_alert_summary.test.ts | 1 + .../server/routes/get_rule_alert_summary.ts | 3 + .../server/rules_client/rules_client.ts | 52 +++-- .../tests/get_alert_summary.test.ts | 35 ++- .../translations/translations/ja-JP.json | 1 - .../translations/translations/zh-CN.json | 1 - .../lib/alert_api/alert_summary.test.ts | 5 + .../lib/alert_api/alert_summary.ts | 7 +- .../components/alert_details.test.tsx | 1 + .../components/alert_details.tsx | 3 + .../components/alert_details_route.tsx | 1 + .../alert_details/components/alerts.test.tsx | 2 + .../alert_details/components/alerts.tsx | 13 +- .../components/alerts_route.test.tsx | 2 +- .../alert_details/components/alerts_route.tsx | 48 ++++- .../execution_duration_chart.test.tsx | 16 +- .../components/execution_duration_chart.tsx | 200 ++++++++++-------- .../with_bulk_alert_api_operations.tsx | 6 +- 20 files changed, 327 insertions(+), 129 deletions(-) diff --git a/x-pack/plugins/alerting/server/lib/alert_summary_from_event_log.test.ts b/x-pack/plugins/alerting/server/lib/alert_summary_from_event_log.test.ts index 1b1b345b94ef64..6290d5d213046a 100644 --- a/x-pack/plugins/alerting/server/lib/alert_summary_from_event_log.test.ts +++ b/x-pack/plugins/alerting/server/lib/alert_summary_from_event_log.test.ts @@ -19,9 +19,11 @@ describe('alertSummaryFromEventLog', () => { test('no events and muted ids', async () => { const rule = createRule({}); const events: IValidatedEvent[] = []; + const executionEvents: IValidatedEvent[] = []; const summary: AlertSummary = alertSummaryFromEventLog({ rule, events, + executionEvents, dateStart, dateEnd, }); @@ -63,9 +65,11 @@ describe('alertSummaryFromEventLog', () => { muteAll: true, }); const events: IValidatedEvent[] = []; + const executionEvents: IValidatedEvent[] = []; const summary: AlertSummary = alertSummaryFromEventLog({ rule, events, + executionEvents, dateStart: dateString(dateEnd, ONE_HOUR_IN_MILLIS), dateEnd: dateString(dateEnd, ONE_HOUR_IN_MILLIS * 2), }); @@ -102,9 +106,11 @@ describe('alertSummaryFromEventLog', () => { mutedInstanceIds: ['alert-1', 'alert-2'], }); const events: IValidatedEvent[] = []; + const executionEvents: IValidatedEvent[] = []; const summary: AlertSummary = alertSummaryFromEventLog({ rule, events, + executionEvents, dateStart, dateEnd, }); @@ -138,10 +144,12 @@ describe('alertSummaryFromEventLog', () => { const rule = createRule({}); const eventsFactory = new EventsFactory(); const events = eventsFactory.addExecute().advanceTime(10000).addExecute().getEvents(); + const executionEvents = eventsFactory.getEvents(); const summary: AlertSummary = alertSummaryFromEventLog({ rule, events, + executionEvents, dateStart, dateEnd, }); @@ -166,10 +174,12 @@ describe('alertSummaryFromEventLog', () => { .advanceTime(10000) .addExecute('rut roh!') .getEvents(); + const executionEvents = eventsFactory.getEvents(); const summary: AlertSummary = alertSummaryFromEventLog({ rule, events, + executionEvents, dateStart, dateEnd, }); @@ -207,10 +217,12 @@ describe('alertSummaryFromEventLog', () => { .addExecute() .addRecoveredAlert('alert-1') .getEvents(); + const executionEvents = eventsFactory.getEvents(); const summary: AlertSummary = alertSummaryFromEventLog({ rule, events, + executionEvents, dateStart, dateEnd, }); @@ -246,10 +258,12 @@ describe('alertSummaryFromEventLog', () => { .addExecute() .addLegacyResolvedAlert('alert-1') .getEvents(); + const executionEvents = eventsFactory.getEvents(); const summary: AlertSummary = alertSummaryFromEventLog({ rule, events, + executionEvents, dateStart, dateEnd, }); @@ -284,10 +298,12 @@ describe('alertSummaryFromEventLog', () => { .addExecute() .addRecoveredAlert('alert-1') .getEvents(); + const executionEvents = eventsFactory.getEvents(); const summary: AlertSummary = alertSummaryFromEventLog({ rule, events, + executionEvents, dateStart, dateEnd, }); @@ -323,10 +339,12 @@ describe('alertSummaryFromEventLog', () => { .addExecute() .addActiveAlert('alert-1', 'action group A') .getEvents(); + const executionEvents = eventsFactory.getEvents(); const summary: AlertSummary = alertSummaryFromEventLog({ rule, events, + executionEvents, dateStart, dateEnd, }); @@ -362,10 +380,12 @@ describe('alertSummaryFromEventLog', () => { .addExecute() .addActiveAlert('alert-1', undefined) .getEvents(); + const executionEvents = eventsFactory.getEvents(); const summary: AlertSummary = alertSummaryFromEventLog({ rule, events, + executionEvents, dateStart, dateEnd, }); @@ -401,10 +421,12 @@ describe('alertSummaryFromEventLog', () => { .addExecute() .addActiveAlert('alert-1', 'action group B') .getEvents(); + const executionEvents = eventsFactory.getEvents(); const summary: AlertSummary = alertSummaryFromEventLog({ rule, events, + executionEvents, dateStart, dateEnd, }); @@ -439,14 +461,15 @@ describe('alertSummaryFromEventLog', () => { .addExecute() .addActiveAlert('alert-1', 'action group A') .getEvents(); + const executionEvents = eventsFactory.getEvents(); const summary: AlertSummary = alertSummaryFromEventLog({ rule, events, + executionEvents, dateStart, dateEnd, }); - const { lastRun, status, alerts, executionDuration } = summary; expect({ lastRun, status, alerts }).toMatchInlineSnapshot(` Object { @@ -481,14 +504,15 @@ describe('alertSummaryFromEventLog', () => { .addActiveAlert('alert-1', 'action group A') .addRecoveredAlert('alert-2') .getEvents(); + const executionEvents = eventsFactory.getEvents(); const summary: AlertSummary = alertSummaryFromEventLog({ rule, events, + executionEvents, dateStart, dateEnd, }); - const { lastRun, status, alerts, executionDuration } = summary; expect({ lastRun, status, alerts }).toMatchInlineSnapshot(` Object { @@ -536,10 +560,12 @@ describe('alertSummaryFromEventLog', () => { .addExecute() .addActiveAlert('alert-1', 'action group B') .getEvents(); + const executionEvents = eventsFactory.getEvents(); const summary: AlertSummary = alertSummaryFromEventLog({ rule, events, + executionEvents, dateStart, dateEnd, }); diff --git a/x-pack/plugins/alerting/server/lib/alert_summary_from_event_log.ts b/x-pack/plugins/alerting/server/lib/alert_summary_from_event_log.ts index 808c3c38e3f7ee..9a40c4ebf19403 100644 --- a/x-pack/plugins/alerting/server/lib/alert_summary_from_event_log.ts +++ b/x-pack/plugins/alerting/server/lib/alert_summary_from_event_log.ts @@ -15,13 +15,14 @@ const Millis2Nanos = 1000 * 1000; export interface AlertSummaryFromEventLogParams { rule: SanitizedAlert<{ bar: boolean }>; events: IEvent[]; + executionEvents: IEvent[]; dateStart: string; dateEnd: string; } export function alertSummaryFromEventLog(params: AlertSummaryFromEventLogParams): AlertSummary { // initialize the result - const { rule, events, dateStart, dateEnd } = params; + const { rule, events, executionEvents, dateStart, dateEnd } = params; const alertSummary: AlertSummary = { id: rule.id, name: rule.name, @@ -57,6 +58,7 @@ export function alertSummaryFromEventLog(params: AlertSummaryFromEventLogParams) if (provider !== EVENT_LOG_PROVIDER) continue; const action = event?.event?.action; + if (action === undefined) continue; if (action === EVENT_LOG_ACTIONS.execute) { @@ -73,14 +75,6 @@ export function alertSummaryFromEventLog(params: AlertSummaryFromEventLogParams) alertSummary.status = 'OK'; } - if (event?.event?.duration) { - const eventDirationMillis = event?.event?.duration / Millis2Nanos; - eventDurations.push(eventDirationMillis); - if (event?.['@timestamp']) { - eventDurationsWithTimestamp[event?.['@timestamp']] = eventDirationMillis; - } - } - continue; } @@ -106,6 +100,23 @@ export function alertSummaryFromEventLog(params: AlertSummaryFromEventLogParams) } } + for (const event of executionEvents.reverse()) { + const timeStamp = event?.['@timestamp']; + if (timeStamp === undefined) continue; + const action = event?.event?.action; + + if (action === undefined) continue; + if (action !== EVENT_LOG_ACTIONS.execute) { + continue; + } + + if (event?.event?.duration) { + const eventDirationMillis = event.event.duration / Millis2Nanos; + eventDurations.push(eventDirationMillis); + eventDurationsWithTimestamp[event['@timestamp']!] = eventDirationMillis; + } + } + // set the muted status of alerts for (const alertId of rule.mutedInstanceIds) { getAlertStatus(alerts, alertId).muted = true; diff --git a/x-pack/plugins/alerting/server/routes/get_rule_alert_summary.test.ts b/x-pack/plugins/alerting/server/routes/get_rule_alert_summary.test.ts index 6d10c503422a9a..4193e769dc513f 100644 --- a/x-pack/plugins/alerting/server/routes/get_rule_alert_summary.test.ts +++ b/x-pack/plugins/alerting/server/routes/get_rule_alert_summary.test.ts @@ -79,6 +79,7 @@ describe('getRuleAlertSummaryRoute', () => { Object { "dateStart": undefined, "id": "1", + "numberOfExecutions": undefined, }, ] `); diff --git a/x-pack/plugins/alerting/server/routes/get_rule_alert_summary.ts b/x-pack/plugins/alerting/server/routes/get_rule_alert_summary.ts index fe30454b35a33c..097eee875fcee6 100644 --- a/x-pack/plugins/alerting/server/routes/get_rule_alert_summary.ts +++ b/x-pack/plugins/alerting/server/routes/get_rule_alert_summary.ts @@ -22,13 +22,16 @@ const paramSchema = schema.object({ const querySchema = schema.object({ date_start: schema.maybe(schema.string()), + number_of_executions: schema.maybe(schema.number()), }); const rewriteReq: RewriteRequestCase = ({ date_start: dateStart, + number_of_executions: numberOfExecutions, ...rest }) => ({ ...rest, + numberOfExecutions, dateStart, }); diff --git a/x-pack/plugins/alerting/server/rules_client/rules_client.ts b/x-pack/plugins/alerting/server/rules_client/rules_client.ts index 3603a60baadb1e..aa017f91278c1b 100644 --- a/x-pack/plugins/alerting/server/rules_client/rules_client.ts +++ b/x-pack/plugins/alerting/server/rules_client/rules_client.ts @@ -218,6 +218,7 @@ export interface UpdateOptions { export interface GetAlertSummaryParams { id: string; dateStart?: string; + numberOfExecutions?: number; } // NOTE: Changing this prefix will require a migration to update the prefix in all existing `rule` saved objects @@ -532,7 +533,11 @@ export class RulesClient { } } - public async getAlertSummary({ id, dateStart }: GetAlertSummaryParams): Promise { + public async getAlertSummary({ + id, + dateStart, + numberOfExecutions, + }: GetAlertSummaryParams): Promise { this.logger.debug(`getAlertSummary(): getting alert ${id}`); const rule = (await this.get({ id, includeLegacyId: true })) as SanitizedRuleWithLegacyId; @@ -545,7 +550,7 @@ export class RulesClient { // default duration of instance summary is 60 * rule interval const dateNow = new Date(); - const durationMillis = parseDuration(rule.schedule.interval) * 60; + const durationMillis = parseDuration(rule.schedule.interval) * (numberOfExecutions ?? 60); const defaultDateStart = new Date(dateNow.valueOf() - durationMillis); const parsedDateStart = parseDate(dateStart, 'dateStart', defaultDateStart); @@ -553,30 +558,49 @@ export class RulesClient { this.logger.debug(`getAlertSummary(): search the event log for rule ${id}`); let events: IEvent[]; + let executionEvents: IEvent[]; + try { - const queryResults = await eventLogClient.findEventsBySavedObjectIds( - 'alert', - [id], - { - page: 1, - per_page: 10000, - start: parsedDateStart.toISOString(), - end: dateNow.toISOString(), - sort_order: 'desc', - }, - rule.legacyId !== null ? [rule.legacyId] : undefined - ); + const [queryResults, executionResults] = await Promise.all([ + eventLogClient.findEventsBySavedObjectIds( + 'alert', + [id], + { + page: 1, + per_page: 10000, + start: parsedDateStart.toISOString(), + sort_order: 'desc', + end: dateNow.toISOString(), + }, + rule.legacyId !== null ? [rule.legacyId] : undefined + ), + eventLogClient.findEventsBySavedObjectIds( + 'alert', + [id], + { + page: 1, + per_page: numberOfExecutions ?? 60, + filter: 'event.provider: alerting AND event.action:execute', + sort_order: 'desc', + end: dateNow.toISOString(), + }, + rule.legacyId !== null ? [rule.legacyId] : undefined + ), + ]); events = queryResults.data; + executionEvents = executionResults.data; } catch (err) { this.logger.debug( `rulesClient.getAlertSummary(): error searching event log for rule ${id}: ${err.message}` ); events = []; + executionEvents = []; } return alertSummaryFromEventLog({ rule, events, + executionEvents, dateStart: parsedDateStart.toISOString(), dateEnd: dateNow.toISOString(), }); diff --git a/x-pack/plugins/alerting/server/rules_client/tests/get_alert_summary.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/get_alert_summary.test.ts index 7a7ab035aa391e..81d98eff0297a6 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/get_alert_summary.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/get_alert_summary.test.ts @@ -135,6 +135,14 @@ describe('getAlertSummary()', () => { }; eventLogClient.findEventsBySavedObjectIds.mockResolvedValueOnce(eventsResult); + const executionEvents = eventsFactory.getEvents(); + const executionEventsResult = { + ...AlertSummaryFindEventsResult, + total: executionEvents.length, + data: executionEvents, + }; + eventLogClient.findEventsBySavedObjectIds.mockResolvedValueOnce(executionEventsResult); + const dateStart = new Date(Date.now() - 60 * 1000).toISOString(); const durations: Record = eventsFactory.getExecutionDurations(); @@ -203,7 +211,7 @@ describe('getAlertSummary()', () => { await rulesClient.getAlertSummary({ id: '1' }); expect(unsecuredSavedObjectsClient.get).toHaveBeenCalledTimes(1); - expect(eventLogClient.findEventsBySavedObjectIds).toHaveBeenCalledTimes(1); + expect(eventLogClient.findEventsBySavedObjectIds).toHaveBeenCalledTimes(2); expect(eventLogClient.findEventsBySavedObjectIds.mock.calls[0]).toMatchInlineSnapshot(` Array [ "alert", @@ -240,7 +248,7 @@ describe('getAlertSummary()', () => { await rulesClient.getAlertSummary({ id: '1' }); expect(unsecuredSavedObjectsClient.get).toHaveBeenCalledTimes(1); - expect(eventLogClient.findEventsBySavedObjectIds).toHaveBeenCalledTimes(1); + expect(eventLogClient.findEventsBySavedObjectIds).toHaveBeenCalledTimes(2); expect(eventLogClient.findEventsBySavedObjectIds.mock.calls[0]).toMatchInlineSnapshot(` Array [ "alert", @@ -269,7 +277,7 @@ describe('getAlertSummary()', () => { await rulesClient.getAlertSummary({ id: '1', dateStart }); expect(unsecuredSavedObjectsClient.get).toHaveBeenCalledTimes(1); - expect(eventLogClient.findEventsBySavedObjectIds).toHaveBeenCalledTimes(1); + expect(eventLogClient.findEventsBySavedObjectIds).toHaveBeenCalledTimes(2); const { start, end } = eventLogClient.findEventsBySavedObjectIds.mock.calls[0][2]!; expect({ start, end }).toMatchInlineSnapshot(` @@ -288,7 +296,7 @@ describe('getAlertSummary()', () => { await rulesClient.getAlertSummary({ id: '1', dateStart }); expect(unsecuredSavedObjectsClient.get).toHaveBeenCalledTimes(1); - expect(eventLogClient.findEventsBySavedObjectIds).toHaveBeenCalledTimes(1); + expect(eventLogClient.findEventsBySavedObjectIds).toHaveBeenCalledTimes(2); const { start, end } = eventLogClient.findEventsBySavedObjectIds.mock.calls[0][2]!; expect({ start, end }).toMatchInlineSnapshot(` @@ -299,6 +307,25 @@ describe('getAlertSummary()', () => { `); }); + test('calls event log client with number of executions', async () => { + unsecuredSavedObjectsClient.get.mockResolvedValueOnce(getRuleSavedObject()); + eventLogClient.findEventsBySavedObjectIds.mockResolvedValueOnce(AlertSummaryFindEventsResult); + + const numberOfExecutions = 15; + await rulesClient.getAlertSummary({ id: '1', numberOfExecutions }); + + expect(unsecuredSavedObjectsClient.get).toHaveBeenCalledTimes(1); + expect(eventLogClient.findEventsBySavedObjectIds).toHaveBeenCalledTimes(2); + const { start, end } = eventLogClient.findEventsBySavedObjectIds.mock.calls[1][2]!; + + expect({ start, end }).toMatchInlineSnapshot(` + Object { + "end": "2019-02-12T21:01:22.479Z", + "start": undefined, + } + `); + }); + test('invalid start date throws an error', async () => { unsecuredSavedObjectsClient.get.mockResolvedValueOnce(getRuleSavedObject()); eventLogClient.findEventsBySavedObjectIds.mockResolvedValueOnce(AlertSummaryFindEventsResult); diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 4c4910cede8e76..7cce3bbf6a4105 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -26073,7 +26073,6 @@ "xpack.triggersActionsUI.sections.editConnectorForm.updateSuccessNotificationText": "「{connectorName}」を更新しました", "xpack.triggersActionsUI.sections.executionDurationChart.executionDurationNoData": "このルールの実行がありません。", "xpack.triggersActionsUI.sections.executionDurationChart.recentDurationsTitle": "最近の実行時間", - "xpack.triggersActionsUI.sections.executionDurationChart.recentDurationsTooltip": "最近のルール実行には、前回の{numExecutions}実行までが含まれています。", "xpack.triggersActionsUI.sections.manageLicense.manageLicenseCancelButtonText": "キャンセル", "xpack.triggersActionsUI.sections.manageLicense.manageLicenseConfirmButtonText": "ライセンスの管理", "xpack.triggersActionsUI.sections.manageLicense.manageLicenseMessage": "ルールタイプ{alertTypeId}は無効です。{licenseRequired}ライセンスが必要です。アップグレードオプションを表示するには、[ライセンス管理]に移動してください。", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 8e4a9aaf86138e..b3c8ef78be31cd 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -26521,7 +26521,6 @@ "xpack.triggersActionsUI.sections.editConnectorForm.updateSuccessNotificationText": "已更新“{connectorName}”", "xpack.triggersActionsUI.sections.executionDurationChart.executionDurationNoData": "此规则没有可用执行。", "xpack.triggersActionsUI.sections.executionDurationChart.recentDurationsTitle": "最近执行持续时间", - "xpack.triggersActionsUI.sections.executionDurationChart.recentDurationsTooltip": "最近规则执行最多包括最后 {numExecutions} 个执行。", "xpack.triggersActionsUI.sections.manageLicense.manageLicenseCancelButtonText": "取消", "xpack.triggersActionsUI.sections.manageLicense.manageLicenseConfirmButtonText": "管理许可证", "xpack.triggersActionsUI.sections.manageLicense.manageLicenseMessage": "规则类型 {alertTypeId} 已禁用,因为它需要{licenseRequired}许可证。继续前往“许可证管理”查看升级选项。", diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/alert_api/alert_summary.test.ts b/x-pack/plugins/triggers_actions_ui/public/application/lib/alert_api/alert_summary.test.ts index 42044ef5e4df1b..7a1fdbe53c7c54 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/lib/alert_api/alert_summary.test.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/lib/alert_api/alert_summary.test.ts @@ -60,6 +60,11 @@ describe('loadAlertSummary', () => { expect(http.get.mock.calls[0]).toMatchInlineSnapshot(` Array [ "/internal/alerting/rule/te%2Fst/_alert_summary", + Object { + "query": Object { + "number_of_executions": undefined, + }, + }, ] `); }); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/alert_api/alert_summary.ts b/x-pack/plugins/triggers_actions_ui/public/application/lib/alert_api/alert_summary.ts index d11b1191accc51..55ba674dbd7f51 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/lib/alert_api/alert_summary.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/lib/alert_api/alert_summary.ts @@ -40,12 +40,17 @@ const rewriteBodyRes: RewriteRequestCase = ({ export async function loadAlertSummary({ http, ruleId, + numberOfExecutions, }: { http: HttpSetup; ruleId: string; + numberOfExecutions?: number; }): Promise { const res = await http.get>( - `${INTERNAL_BASE_ALERTING_API_PATH}/rule/${encodeURIComponent(ruleId)}/_alert_summary` + `${INTERNAL_BASE_ALERTING_API_PATH}/rule/${encodeURIComponent(ruleId)}/_alert_summary`, + { + query: { number_of_executions: numberOfExecutions }, + } ); return rewriteBodyRes(res); } diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details.test.tsx index 7694f289963a31..b92b4289ea905e 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details.test.tsx @@ -57,6 +57,7 @@ const mockAlertApis = { enableAlert: jest.fn(), disableAlert: jest.fn(), requestRefresh: jest.fn(), + refreshToken: Date.now(), }; const authorizedConsumers = { diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details.tsx index 5b6ddc1b3345c1..1bb979ee86052b 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_details.tsx @@ -50,6 +50,7 @@ export type AlertDetailsProps = { alertType: RuleType; actionTypes: ActionType[]; requestRefresh: () => Promise; + refreshToken?: number; } & Pick; export const AlertDetails: React.FunctionComponent = ({ @@ -61,6 +62,7 @@ export const AlertDetails: React.FunctionComponent = ({ unmuteAlert, muteAlert, requestRefresh, + refreshToken, }) => { const history = useHistory(); const { @@ -443,6 +445,7 @@ export const AlertDetails: React.FunctionComponent = ({ {alert.enabled ? ( alertType={alertType} actionTypes={actionTypes} requestRefresh={async () => requestRefresh(Date.now())} + refreshToken={refreshToken} /> ) : ( diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alerts.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alerts.test.tsx index fb8892ece8b68a..075f6dedeb06ab 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alerts.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alerts.test.tsx @@ -24,6 +24,8 @@ const mockAPIs = { muteAlertInstance: jest.fn(), unmuteAlertInstance: jest.fn(), requestRefresh: jest.fn(), + numberOfExecutions: 60, + onChangeDuration: jest.fn(), }; beforeAll(() => { diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alerts.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alerts.tsx index 59a0adea64fed5..9d4ef14dec64af 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alerts.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alerts.tsx @@ -53,7 +53,10 @@ type AlertsProps = { readOnly: boolean; alertSummary: AlertSummary; requestRefresh: () => Promise; + numberOfExecutions: number; + onChangeDuration: (length: number) => void; durationEpoch?: number; + isLoadingChart?: boolean; } & Pick; export const alertsTableColumns = ( @@ -155,7 +158,10 @@ export function Alerts({ muteAlertInstance, unmuteAlertInstance, requestRefresh, + numberOfExecutions, + onChangeDuration, durationEpoch = Date.now(), + isLoadingChart, }: AlertsProps) { const [pagination, setPagination] = useState({ index: 0, @@ -257,7 +263,12 @@ export function Alerts({ - + diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alerts_route.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alerts_route.test.tsx index 36b73bbbf82c0a..e0b2ac6c2e6c83 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alerts_route.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alerts_route.test.tsx @@ -49,7 +49,7 @@ describe('getAlertState useEffect handler', () => { await getAlertSummary(rule.id, loadAlertSummary, setAlertSummary, toastNotifications); - expect(loadAlertSummary).toHaveBeenCalledWith(rule.id); + expect(loadAlertSummary).toHaveBeenCalledWith(rule.id, undefined); expect(setAlertSummary).toHaveBeenCalledWith(alertSummary); }); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alerts_route.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alerts_route.tsx index e55181d9b1a04f..07e45c8d2b2d06 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alerts_route.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alerts_route.tsx @@ -7,7 +7,7 @@ import { i18n } from '@kbn/i18n'; import { ToastsApi } from 'kibana/public'; -import React, { useState, useEffect } from 'react'; +import React, { useState, useEffect, useRef, useCallback } from 'react'; import { Rule, AlertSummary, RuleType } from '../../../../types'; import { ComponentOpts as AlertApis, @@ -22,6 +22,7 @@ type WithAlertSummaryProps = { ruleType: RuleType; readOnly: boolean; requestRefresh: () => Promise; + refreshToken?: number; } & Pick; export const AlertsRoute: React.FunctionComponent = ({ @@ -30,17 +31,48 @@ export const AlertsRoute: React.FunctionComponent = ({ readOnly, requestRefresh, loadAlertSummary: loadAlertSummary, + refreshToken, }) => { const { notifications: { toasts }, } = useKibana().services; const [alertSummary, setAlertSummary] = useState(null); + const [numberOfExecutions, setNumberOfExecutions] = useState(60); + const [isLoadingChart, setIsLoadingChart] = useState(true); + const ruleID = useRef(null); + const refreshTokenRef = useRef(refreshToken); + + const getAlertSummaryWithLoadingState = useCallback( + async (executions: number = numberOfExecutions) => { + setIsLoadingChart(true); + await getAlertSummary(ruleID.current!, loadAlertSummary, setAlertSummary, toasts, executions); + setIsLoadingChart(false); + }, + [setIsLoadingChart, ruleID, loadAlertSummary, setAlertSummary, toasts, numberOfExecutions] + ); + + useEffect(() => { + if (ruleID.current !== rule.id) { + ruleID.current = rule.id; + getAlertSummaryWithLoadingState(); + } + }, [rule, ruleID, getAlertSummaryWithLoadingState]); useEffect(() => { - getAlertSummary(rule.id, loadAlertSummary, setAlertSummary, toasts); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [rule]); + if (refreshTokenRef.current !== refreshToken) { + refreshTokenRef.current = refreshToken; + getAlertSummaryWithLoadingState(); + } + }, [refreshToken, refreshTokenRef, getAlertSummaryWithLoadingState]); + + const onChangeDuration = useCallback( + (executions: number) => { + setNumberOfExecutions(executions); + getAlertSummaryWithLoadingState(executions); + }, + [getAlertSummaryWithLoadingState] + ); return alertSummary ? ( = ({ ruleType={ruleType} readOnly={readOnly} alertSummary={alertSummary} + numberOfExecutions={numberOfExecutions} + isLoadingChart={isLoadingChart} + onChangeDuration={onChangeDuration} /> ) : ( @@ -59,10 +94,11 @@ export async function getAlertSummary( ruleId: string, loadAlertSummary: AlertApis['loadAlertSummary'], setAlertSummary: React.Dispatch>, - toasts: Pick + toasts: Pick, + executionDuration?: number ) { try { - const loadedSummary = await loadAlertSummary(ruleId); + const loadedSummary = await loadAlertSummary(ruleId, executionDuration); setAlertSummary(loadedSummary); } catch (e) { toasts.addDanger({ diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/execution_duration_chart.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/execution_duration_chart.test.tsx index 9d32dd27cd2f43..f524ff4426b6a9 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/execution_duration_chart.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/execution_duration_chart.test.tsx @@ -14,7 +14,13 @@ describe('execution duration chart', () => { it('renders empty state when no execution duration values are available', async () => { const executionDuration = mockExecutionDuration(); - const wrapper = mountWithIntl(); + const wrapper = mountWithIntl( + {}} + /> + ); await act(async () => { await nextTick(); @@ -32,7 +38,13 @@ describe('execution duration chart', () => { valuesWithTimestamp: { '17 Nov 2021 @ 19:19:17': 1, '17 Nov 2021 @ 20:19:17': 2 }, }); - const wrapper = mountWithIntl(); + const wrapper = mountWithIntl( + {}} + /> + ); await act(async () => { await nextTick(); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/execution_duration_chart.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/execution_duration_chart.tsx index d74c1c52e8b073..6cf5e172ff284b 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/execution_duration_chart.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/execution_duration_chart.tsx @@ -6,15 +6,16 @@ */ import { i18n } from '@kbn/i18n'; -import React from 'react'; +import React, { useCallback } from 'react'; import { FormattedMessage } from '@kbn/i18n-react'; import { EuiFlexGroup, EuiFlexItem, EuiPanel, EuiEmptyPrompt, - EuiIconTip, EuiTitle, + EuiSelect, + EuiLoadingChart, } from '@elastic/eui'; import { euiLightVars as lightEuiTheme } from '@kbn/ui-shared-deps-src/theme'; import { Axis, BarSeries, Chart, CurveType, LineSeries, Settings } from '@elastic/charts'; @@ -27,16 +28,38 @@ export interface ComponentOpts { average: number; valuesWithTimestamp: Record; }; + numberOfExecutions: number; + onChangeDuration: (length: number) => void; + isLoading?: boolean; } -const DESIRED_NUM_EXECUTION_DURATIONS = 30; +const NUM_EXECUTIONS_OPTIONS = [120, 60, 30, 15].map((value) => ({ + value, + text: i18n.translate( + 'xpack.triggersActionsUI.sections.executionDurationChart.numberOfExecutionsOption', + { + defaultMessage: '{value} executions', + values: { + value, + }, + } + ), +})); export const ExecutionDurationChart: React.FunctionComponent = ({ executionDuration, + numberOfExecutions, + onChangeDuration, + isLoading, }: ComponentOpts) => { const paddedExecutionDurations = padOrTruncateDurations( executionDuration.valuesWithTimestamp, - DESIRED_NUM_EXECUTION_DURATIONS + numberOfExecutions + ); + + const onChange = useCallback( + ({ target }) => onChangeDuration(Number(target.value)), + [onChangeDuration] ); return ( @@ -52,92 +75,99 @@ export const ExecutionDurationChart: React.FunctionComponent = ({ - - - - - - {executionDuration.valuesWithTimestamp && - Object.entries(executionDuration.valuesWithTimestamp).length > 0 ? ( - <> - - - [ - timestamp ? moment(timestamp).format('D MMM YYYY @ HH:mm:ss') : ndx, - val, - ])} - minBarHeight={2} - /> - + + [ - timestamp ? moment(timestamp).format('D MMM YYYY @ HH:mm:ss') : ndx, - val ? executionDuration.average : null, - ])} - curve={CurveType.CURVE_NATURAL} + onChange={onChange} /> - formatMillisForDisplay(d)} /> - - - ) : ( - <> - -

- -

- - } - /> - + + + + {isLoading && ( + + + + + )} + {!isLoading && + (executionDuration.valuesWithTimestamp && + Object.entries(executionDuration.valuesWithTimestamp).length > 0 ? ( + <> + + + [ + timestamp ? moment(timestamp).format('D MMM YYYY @ HH:mm:ss') : ndx, + val, + ])} + minBarHeight={2} + /> + [ + timestamp ? moment(timestamp).format('D MMM YYYY @ HH:mm:ss') : ndx, + val ? executionDuration.average : null, + ])} + curve={CurveType.CURVE_NATURAL} + /> + formatMillisForDisplay(d)} /> + + + ) : ( + <> + +

+ +

+ + } + /> + + ))} ); }; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/with_bulk_alert_api_operations.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/with_bulk_alert_api_operations.tsx index 1a4c3ad5f4df9e..0308e17ac342c5 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/with_bulk_alert_api_operations.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/with_bulk_alert_api_operations.tsx @@ -57,7 +57,7 @@ export interface ComponentOpts { }>; loadAlert: (id: Rule['id']) => Promise; loadAlertState: (id: Rule['id']) => Promise; - loadAlertSummary: (id: Rule['id']) => Promise; + loadAlertSummary: (id: Rule['id'], numberOfExecutions?: number) => Promise; loadAlertTypes: () => Promise; getHealth: () => Promise; resolveRule: (id: Rule['id']) => Promise; @@ -127,7 +127,9 @@ export function withBulkAlertOperations( deleteAlert={async (alert: Rule) => deleteAlerts({ http, ids: [alert.id] })} loadAlert={async (alertId: Rule['id']) => loadAlert({ http, alertId })} loadAlertState={async (alertId: Rule['id']) => loadAlertState({ http, alertId })} - loadAlertSummary={async (ruleId: Rule['id']) => loadAlertSummary({ http, ruleId })} + loadAlertSummary={async (ruleId: Rule['id'], numberOfExecutions?: number) => + loadAlertSummary({ http, ruleId, numberOfExecutions }) + } loadAlertTypes={async () => loadAlertTypes({ http })} resolveRule={async (ruleId: Rule['id']) => resolveRule({ http, ruleId })} getHealth={async () => alertingFrameworkHealth({ http })} From 6d07ea57355e6a69f0beaca55cd81e4d691ff516 Mon Sep 17 00:00:00 2001 From: Chris Cowan Date: Thu, 20 Jan 2022 14:42:36 -0700 Subject: [PATCH 101/108] [Metrics UI] Rewrite the data fetching for Inventory Threshold rule (#123095) * [Metrics UI] Rewrite the data fetching for Inventory Threshold rule * Adding support for rate aggregations with interfaces * Fixing unused deps * Adding index options to request * removing ts-ignores * Fixing logRate aggregation * Removing unused deps * Updating data * fixing tests with new data * Adding tests for network traffic and log rate * removing todo comment * Adding tests for Pods network traffic * Change after key to use correct nextAfterKey value --- .../infra/common/inventory_models/types.ts | 2 +- .../evaluate_condition.ts | 101 +- .../lib/calculate_from_based_on_metric.ts | 35 + .../lib/calculate_rate_timeranges.ts | 30 + .../lib/create_log_rate_aggs.ts | 22 + .../lib/create_metric_aggregations.ts | 59 + .../lib/create_rate_agg_with_interface.ts | 69 + .../lib/create_rate_aggs.ts | 50 + .../lib/create_request.ts | 71 + .../lib/get_data.ts | 92 + .../inventory_metric_threshold/lib/is_rate.ts | 32 + .../metric_threshold/lib/evaluate_rule.ts | 1 - .../apis/metrics_ui/constants.ts | 8 +- .../metrics_ui/inventory_threshold_alert.ts | 378 +- .../apis/metrics_ui/metrics_alerting.ts | 4 - .../infra/8.0.0/hosts_only/data.json.gz | Bin 345 -> 4926 bytes .../infra/8.0.0/hosts_only/mappings.json | 15301 +--------------- .../infra/8.0.0/pods_only/data.json.gz | Bin 0 -> 7906 bytes .../infra/8.0.0/pods_only/mappings.json | 247 + 19 files changed, 1113 insertions(+), 15389 deletions(-) create mode 100644 x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/lib/calculate_from_based_on_metric.ts create mode 100644 x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/lib/calculate_rate_timeranges.ts create mode 100644 x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/lib/create_log_rate_aggs.ts create mode 100644 x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/lib/create_metric_aggregations.ts create mode 100644 x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/lib/create_rate_agg_with_interface.ts create mode 100644 x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/lib/create_rate_aggs.ts create mode 100644 x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/lib/create_request.ts create mode 100644 x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/lib/get_data.ts create mode 100644 x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/lib/is_rate.ts create mode 100644 x-pack/test/functional/es_archives/infra/8.0.0/pods_only/data.json.gz create mode 100644 x-pack/test/functional/es_archives/infra/8.0.0/pods_only/mappings.json diff --git a/x-pack/plugins/infra/common/inventory_models/types.ts b/x-pack/plugins/infra/common/inventory_models/types.ts index 35fd7a13a4084d..2d4348ddde5de8 100644 --- a/x-pack/plugins/infra/common/inventory_models/types.ts +++ b/x-pack/plugins/infra/common/inventory_models/types.ts @@ -252,7 +252,7 @@ export const ESCaridnalityAggRT = rt.type({ export const ESBucketScriptAggRT = rt.type({ bucket_script: rt.intersection([ rt.type({ - buckets_path: rt.record(rt.string, rt.union([rt.undefined, rt.string])), + buckets_path: rt.record(rt.string, rt.string), script: rt.type({ source: rt.string, lang: rt.keyof({ painless: null, expression: null }), diff --git a/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/evaluate_condition.ts b/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/evaluate_condition.ts index b78c5eb291adb1..8224c950873399 100644 --- a/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/evaluate_condition.ts +++ b/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/evaluate_condition.ts @@ -5,25 +5,16 @@ * 2.0. */ -import { mapValues, last, first } from 'lodash'; +import { mapValues } from 'lodash'; import moment from 'moment'; import { ElasticsearchClient } from 'kibana/server'; -import { - isTooManyBucketsPreviewException, - TOO_MANY_BUCKETS_PREVIEW_EXCEPTION, -} from '../../../../common/alerting/metrics'; -import { InfraDatabaseSearchResponse, CallWithRequestParams } from '../../adapters/framework'; import { Comparator, InventoryMetricConditions } from './types'; import { InventoryItemType, SnapshotMetricType } from '../../../../common/inventory_models/types'; -import { - InfraTimerangeInput, - SnapshotRequest, - SnapshotCustomMetricInput, -} from '../../../../common/http_api'; +import { InfraTimerangeInput } from '../../../../common/http_api'; import { InfraSource } from '../../sources'; -import { UNGROUPED_FACTORY_KEY } from '../common/utils'; -import { getNodes } from '../../../routes/snapshot/lib/get_nodes'; import { LogQueryFields } from '../../../services/log_queries/get_log_query_fields'; +import { calcualteFromBasedOnMetric } from './lib/calculate_from_based_on_metric'; +import { getData } from './lib/get_data'; type ConditionResult = InventoryMetricConditions & { shouldFire: boolean[]; @@ -61,10 +52,11 @@ export const evaluateCondition = async ({ const timerange = { to: to.valueOf(), - from: to.clone().subtract(condition.timeSize, condition.timeUnit).valueOf(), + from: calcualteFromBasedOnMetric(to, condition, nodeType, metric, customMetric), interval: `${condition.timeSize}${condition.timeUnit}`, forceInterval: true, } as InfraTimerangeInput; + if (lookbackSize) { timerange.lookbackSize = lookbackSize; } @@ -87,18 +79,15 @@ export const evaluateCondition = async ({ const valueEvaluator = (value?: DataValue, t?: number[], c?: Comparator) => { if (value === undefined || value === null || !t || !c) return [false]; const comparisonFunction = comparatorMap[c]; - return Array.isArray(value) - ? value.map((v) => comparisonFunction(Number(v), t)) - : [comparisonFunction(value as number, t)]; + return [comparisonFunction(value as number, t)]; }; const result = mapValues(currentValues, (value) => { - if (isTooManyBucketsPreviewException(value)) throw value; return { ...condition, shouldFire: valueEvaluator(value, threshold, comparator), shouldWarn: valueEvaluator(value, warningThreshold, warningComparator), - isNoData: Array.isArray(value) ? value.map((v) => v === null) : [value === null], + isNoData: [value === null], isError: value === undefined, currentValue: getCurrentValue(value), }; @@ -107,82 +96,12 @@ export const evaluateCondition = async ({ return result as Record; }; -const getCurrentValue: (value: any) => number = (value) => { - if (Array.isArray(value)) return getCurrentValue(last(value)); +const getCurrentValue: (value: number | null) => number = (value) => { if (value !== null) return Number(value); return NaN; }; -type DataValue = number | null | Array; -const getData = async ( - esClient: ElasticsearchClient, - nodeType: InventoryItemType, - metric: SnapshotMetricType, - timerange: InfraTimerangeInput, - source: InfraSource, - logQueryFields: LogQueryFields | undefined, - compositeSize: number, - filterQuery?: string, - customMetric?: SnapshotCustomMetricInput -) => { - const client = async ( - options: CallWithRequestParams - ): Promise> => - // @ts-expect-error SearchResponse.body.timeout is optional - (await esClient.search(options)).body as InfraDatabaseSearchResponse; - - const metrics = [ - metric === 'custom' ? (customMetric as SnapshotCustomMetricInput) : { type: metric }, - ]; - - const snapshotRequest: SnapshotRequest = { - filterQuery, - nodeType, - groupBy: [], - sourceId: 'default', - metrics, - timerange, - includeTimeseries: Boolean(timerange.lookbackSize), - }; - try { - const { nodes } = await getNodes( - client, - snapshotRequest, - source, - compositeSize, - logQueryFields - ); - - if (!nodes.length) return { [UNGROUPED_FACTORY_KEY]: null }; // No Data state - - return nodes.reduce((acc, n) => { - const { name: nodeName } = n; - const m = first(n.metrics); - if (m && m.value && m.timeseries) { - const { timeseries } = m; - const values = timeseries.rows.map((row) => row.metric_0) as Array; - acc[nodeName] = values; - } else { - acc[nodeName] = m && m.value; - } - return acc; - }, {} as Record | undefined | null>); - } catch (e) { - if (timerange.lookbackSize) { - // This code should only ever be reached when previewing the alert, not executing it - const causedByType = e.body?.error?.caused_by?.type; - if (causedByType === 'too_many_buckets_exception') { - return { - [UNGROUPED_FACTORY_KEY]: { - [TOO_MANY_BUCKETS_PREVIEW_EXCEPTION]: true, - maxBuckets: e.body.error.caused_by.max_buckets, - }, - }; - } - } - return { [UNGROUPED_FACTORY_KEY]: undefined }; - } -}; +type DataValue = number | null; const comparatorMap = { [Comparator.BETWEEN]: (value: number, [a, b]: number[]) => diff --git a/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/lib/calculate_from_based_on_metric.ts b/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/lib/calculate_from_based_on_metric.ts new file mode 100644 index 00000000000000..7c6031dffd57dd --- /dev/null +++ b/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/lib/calculate_from_based_on_metric.ts @@ -0,0 +1,35 @@ +/* + * 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 { Moment } from 'moment'; +import { SnapshotCustomMetricInput } from '../../../../../common/http_api'; +import { + InventoryItemType, + SnapshotMetricType, +} from '../../../../../common/inventory_models/types'; +import { InventoryMetricConditions } from '../types'; +import { isRate } from './is_rate'; +import { findInventoryModel } from '../../../../../common/inventory_models'; + +export const calcualteFromBasedOnMetric = ( + to: Moment, + condition: InventoryMetricConditions, + nodeType: InventoryItemType, + metric: SnapshotMetricType, + customMetric?: SnapshotCustomMetricInput +) => { + const inventoryModel = findInventoryModel(nodeType); + const metricAgg = inventoryModel.metrics.snapshot[metric]; + if (isRate(metricAgg, customMetric)) { + return to + .clone() + .subtract(condition.timeSize * 2, condition.timeUnit) + .valueOf(); + } else { + return to.clone().subtract(condition.timeSize, condition.timeUnit).valueOf(); + } +}; diff --git a/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/lib/calculate_rate_timeranges.ts b/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/lib/calculate_rate_timeranges.ts new file mode 100644 index 00000000000000..67a56065289ed4 --- /dev/null +++ b/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/lib/calculate_rate_timeranges.ts @@ -0,0 +1,30 @@ +/* + * 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 { InfraTimerangeInput } from '../../../../../common/http_api'; + +export const calculateRateTimeranges = (timerange: InfraTimerangeInput) => { + // This is the total number of milliseconds for the entire timerange + const totalTime = timerange.to - timerange.from; + // Halfway is the to minus half the total time; + const halfway = timerange.to - totalTime / 2; + // The interval is half the total time (divided by 1000 to convert to seconds) + const intervalInSeconds = totalTime / 2000; + + // The first bucket is from the beginning of the time range to the halfway point + const firstBucketRange = { + from: timerange.from, + to: halfway, + }; + + // The second bucket is from the halfway point to the end of the timerange + const secondBucketRange = { + from: halfway, + to: timerange.to, + }; + + return { firstBucketRange, secondBucketRange, intervalInSeconds }; +}; diff --git a/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/lib/create_log_rate_aggs.ts b/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/lib/create_log_rate_aggs.ts new file mode 100644 index 00000000000000..4e7e85efb68f7b --- /dev/null +++ b/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/lib/create_log_rate_aggs.ts @@ -0,0 +1,22 @@ +/* + * 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 { InfraTimerangeInput } from '../../../../../common/http_api'; + +export const createLogRateAggs = (timerange: InfraTimerangeInput, id: string) => { + const intervalInSeconds = (timerange.to - timerange.from) / 1000; + return { + [id]: { + bucket_script: { + buckets_path: { + count: `_count`, + }, + script: `params.count > 0.0 ? params.count / ${intervalInSeconds}: null`, + }, + }, + }; +}; diff --git a/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/lib/create_metric_aggregations.ts b/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/lib/create_metric_aggregations.ts new file mode 100644 index 00000000000000..6d516fa54b5f17 --- /dev/null +++ b/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/lib/create_metric_aggregations.ts @@ -0,0 +1,59 @@ +/* + * 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 { get } from 'lodash'; +import { + InventoryItemType, + SnapshotMetricType, +} from '../../../../../common/inventory_models/types'; +import { findInventoryModel } from '../../../../../common/inventory_models'; +import { InfraTimerangeInput, SnapshotCustomMetricInput } from '../../../../../common/http_api'; +import { isMetricRate, isCustomMetricRate, isInterfaceRateAgg } from './is_rate'; +import { createRateAggs } from './create_rate_aggs'; +import { createLogRateAggs } from './create_log_rate_aggs'; +import { createRateAggsWithInterface } from './create_rate_agg_with_interface'; + +export const createMetricAggregations = ( + timerange: InfraTimerangeInput, + nodeType: InventoryItemType, + metric: SnapshotMetricType, + customMetric?: SnapshotCustomMetricInput +) => { + const inventoryModel = findInventoryModel(nodeType); + if (customMetric && customMetric.field) { + if (isCustomMetricRate(customMetric)) { + return createRateAggs(timerange, customMetric.id, customMetric.field); + } + return { + [customMetric.id]: { + [customMetric.aggregation]: { + field: customMetric.field, + }, + }, + }; + } else if (metric === 'logRate') { + return createLogRateAggs(timerange, metric); + } else { + const metricAgg = inventoryModel.metrics.snapshot[metric]; + if (isInterfaceRateAgg(metricAgg)) { + const field = get( + metricAgg, + `${metric}_interfaces.aggregations.${metric}_interface_max.max.field` + ) as unknown as string; + const interfaceField = get( + metricAgg, + `${metric}_interfaces.terms.field` + ) as unknown as string; + return createRateAggsWithInterface(timerange, metric, field, interfaceField); + } + if (isMetricRate(metricAgg)) { + const field = get(metricAgg, `${metric}_max.max.field`) as unknown as string; + return createRateAggs(timerange, metric, field); + } + return metricAgg; + } +}; diff --git a/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/lib/create_rate_agg_with_interface.ts b/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/lib/create_rate_agg_with_interface.ts new file mode 100644 index 00000000000000..ee58dfac70f52d --- /dev/null +++ b/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/lib/create_rate_agg_with_interface.ts @@ -0,0 +1,69 @@ +/* + * 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 { InfraTimerangeInput } from '../../../../../common/http_api'; +import { calculateRateTimeranges } from './calculate_rate_timeranges'; + +export const createRateAggsWithInterface = ( + timerange: InfraTimerangeInput, + id: string, + field: string, + interfaceField: string +) => { + const { firstBucketRange, secondBucketRange, intervalInSeconds } = + calculateRateTimeranges(timerange); + + const interfaceAggs = { + interfaces: { + terms: { + field: interfaceField, + }, + aggs: { maxValue: { max: { field } } }, + }, + sumOfInterfaces: { + sum_bucket: { + buckets_path: 'interfaces>maxValue', + }, + }, + }; + + return { + [`${id}_first_bucket`]: { + filter: { + range: { + '@timestamp': { + gte: firstBucketRange.from, + lt: firstBucketRange.to, + format: 'epoch_millis', + }, + }, + }, + aggs: interfaceAggs, + }, + [`${id}_second_bucket`]: { + filter: { + range: { + '@timestamp': { + gte: secondBucketRange.from, + lt: secondBucketRange.to, + format: 'epoch_millis', + }, + }, + }, + aggs: interfaceAggs, + }, + [id]: { + bucket_script: { + buckets_path: { + first: `${id}_first_bucket.sumOfInterfaces`, + second: `${id}_second_bucket.sumOfInterfaces`, + }, + script: `params.second > 0.0 && params.first > 0.0 && params.second > params.first ? (params.second - params.first) / ${intervalInSeconds}: null`, + }, + }, + }; +}; diff --git a/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/lib/create_rate_aggs.ts b/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/lib/create_rate_aggs.ts new file mode 100644 index 00000000000000..af786d41fd11dd --- /dev/null +++ b/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/lib/create_rate_aggs.ts @@ -0,0 +1,50 @@ +/* + * 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 { InfraTimerangeInput } from '../../../../../common/http_api'; +import { calculateRateTimeranges } from './calculate_rate_timeranges'; + +export const createRateAggs = (timerange: InfraTimerangeInput, id: string, field: string) => { + const { firstBucketRange, secondBucketRange, intervalInSeconds } = + calculateRateTimeranges(timerange); + + return { + [`${id}_first_bucket`]: { + filter: { + range: { + '@timestamp': { + gte: firstBucketRange.from, + lt: firstBucketRange.to, + format: 'epoch_millis', + }, + }, + }, + aggs: { maxValue: { max: { field } } }, + }, + [`${id}_second_bucket`]: { + filter: { + range: { + '@timestamp': { + gte: secondBucketRange.from, + lt: secondBucketRange.to, + format: 'epoch_millis', + }, + }, + }, + aggs: { maxValue: { max: { field } } }, + }, + [id]: { + bucket_script: { + buckets_path: { + first: `${id}_first_bucket.maxValue`, + second: `${id}_second_bucket.maxValue`, + }, + script: `params.second > 0.0 && params.first > 0.0 && params.second > params.first ? (params.second - params.first) / ${intervalInSeconds}: null`, + }, + }, + }; +}; diff --git a/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/lib/create_request.ts b/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/lib/create_request.ts new file mode 100644 index 00000000000000..2472a01f400952 --- /dev/null +++ b/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/lib/create_request.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { ESSearchRequest } from 'src/core/types/elasticsearch'; +import { findInventoryFields } from '../../../../../common/inventory_models'; +import { InfraTimerangeInput, SnapshotCustomMetricInput } from '../../../../../common/http_api'; +import { + InventoryItemType, + SnapshotMetricType, +} from '../../../../../common/inventory_models/types'; +import { parseFilterQuery } from '../../../../utils/serialized_query'; +import { createMetricAggregations } from './create_metric_aggregations'; + +export const createRequest = ( + index: string, + nodeType: InventoryItemType, + metric: SnapshotMetricType, + timerange: InfraTimerangeInput, + compositeSize: number, + afterKey: { node: string } | undefined, + filterQuery?: string, + customMetric?: SnapshotCustomMetricInput +) => { + const filters: any[] = [ + { + range: { + '@timestamp': { + gte: timerange.from, + lte: timerange.to, + format: 'epoch_millis', + }, + }, + }, + ]; + const parsedFilters = parseFilterQuery(filterQuery); + if (parsedFilters) { + filters.push(parsedFilters); + } + + const inventoryFields = findInventoryFields(nodeType); + + const composite: any = { + size: compositeSize, + sources: [{ node: { terms: { field: inventoryFields.id } } }], + }; + if (afterKey) { + composite.after = afterKey; + } + const metricAggregations = createMetricAggregations(timerange, nodeType, metric, customMetric); + + const request: ESSearchRequest = { + allow_no_indices: true, + ignore_unavailable: true, + index, + body: { + size: 0, + query: { bool: { filter: filters } }, + aggs: { + nodes: { + composite, + aggs: metricAggregations, + }, + }, + }, + }; + + return request; +}; diff --git a/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/lib/get_data.ts b/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/lib/get_data.ts new file mode 100644 index 00000000000000..83751087d9affc --- /dev/null +++ b/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/lib/get_data.ts @@ -0,0 +1,92 @@ +/* + * 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 { ElasticsearchClient } from 'kibana/server'; +import { InfraTimerangeInput, SnapshotCustomMetricInput } from '../../../../../common/http_api'; +import { + InventoryItemType, + SnapshotMetricType, +} from '../../../../../common/inventory_models/types'; +import { LogQueryFields } from '../../../../services/log_queries/get_log_query_fields'; +import { InfraSource } from '../../../sources'; +import { createRequest } from './create_request'; + +interface BucketKey { + node: string; +} +type Response = Record; +type Metric = Record; +interface Bucket { + key: BucketKey; + doc_count: number; +} +type NodeBucket = Bucket & Metric; +interface ResponseAggregations { + nodes: { + after_key?: BucketKey; + buckets: NodeBucket[]; + }; +} + +export const getData = async ( + esClient: ElasticsearchClient, + nodeType: InventoryItemType, + metric: SnapshotMetricType, + timerange: InfraTimerangeInput, + source: InfraSource, + logQueryFields: LogQueryFields | undefined, + compositeSize: number, + filterQuery?: string, + customMetric?: SnapshotCustomMetricInput, + afterKey?: BucketKey, + previousNodes: Response = {} +): Promise => { + const handleResponse = (aggs: ResponseAggregations, previous: Response) => { + const { nodes } = aggs; + const nextAfterKey = nodes.after_key; + for (const bucket of nodes.buckets) { + const metricId = customMetric && customMetric.field ? customMetric.id : metric; + previous[bucket.key.node] = bucket?.[metricId]?.value ?? null; + } + if (nextAfterKey && nodes.buckets.length === compositeSize) { + return getData( + esClient, + nodeType, + metric, + timerange, + source, + logQueryFields, + compositeSize, + filterQuery, + customMetric, + nextAfterKey, + previous + ); + } + return previous; + }; + + const index = + metric === 'logRate' && logQueryFields + ? logQueryFields.indexPattern + : source.configuration.metricAlias; + const request = createRequest( + index, + nodeType, + metric, + timerange, + compositeSize, + afterKey, + filterQuery, + customMetric + ); + const { body } = await esClient.search(request); + if (body.aggregations) { + return handleResponse(body.aggregations, previousNodes); + } + return previousNodes; +}; diff --git a/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/lib/is_rate.ts b/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/lib/is_rate.ts new file mode 100644 index 00000000000000..b29c6ac71cc507 --- /dev/null +++ b/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/lib/is_rate.ts @@ -0,0 +1,32 @@ +/* + * 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 { has } from 'lodash'; +import { MetricsUIAggregation } from '../../../../../common/inventory_models/types'; +import { SnapshotCustomMetricInput } from '../../../../../common/http_api'; + +export const isMetricRate = (metric: MetricsUIAggregation): boolean => { + const values = Object.values(metric); + return values.some((agg) => has(agg, 'derivative')) && values.some((agg) => has(agg, 'max')); +}; + +export const isCustomMetricRate = (customMetric: SnapshotCustomMetricInput) => { + return customMetric.aggregation === 'rate'; +}; + +export const isInterfaceRateAgg = (metric: MetricsUIAggregation) => { + const values = Object.values(metric); + return values.some((agg) => has(agg, 'terms')) && values.some((agg) => has(agg, 'sum_bucket')); +}; + +export const isRate = (metric: MetricsUIAggregation, customMetric?: SnapshotCustomMetricInput) => { + return ( + isMetricRate(metric) || + isInterfaceRateAgg(metric) || + (customMetric && isCustomMetricRate(customMetric)) + ); +}; diff --git a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/lib/evaluate_rule.ts b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/lib/evaluate_rule.ts index 01c8f252fc71b2..a3de79368cb806 100644 --- a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/lib/evaluate_rule.ts +++ b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/lib/evaluate_rule.ts @@ -217,7 +217,6 @@ const getMetric: ( return groupedResults; } const { body: result } = await esClient.search({ - // @ts-expect-error buckets_path is not compatible body: searchBody, index, }); diff --git a/x-pack/test/api_integration/apis/metrics_ui/constants.ts b/x-pack/test/api_integration/apis/metrics_ui/constants.ts index 57963179aa8e47..9ef8c5e6b94078 100644 --- a/x-pack/test/api_integration/apis/metrics_ui/constants.ts +++ b/x-pack/test/api_integration/apis/metrics_ui/constants.ts @@ -19,9 +19,13 @@ export const DATES = { }, }, '8.0.0': { + pods_only: { + min: new Date('2022-01-20T17:09:55.124Z').getTime(), + max: new Date('2022-01-20T17:14:57.378Z').getTime(), + }, hosts_only: { - min: new Date('2022-01-02T00:00:00.000Z').getTime(), - max: new Date('2022-01-02T00:05:30.000Z').getTime(), + min: new Date('2022-01-18T19:57:47.534Z').getTime(), + max: new Date('2022-01-18T20:02:50.043Z').getTime(), }, logs_and_metrics: { min: 1562786660845, diff --git a/x-pack/test/api_integration/apis/metrics_ui/inventory_threshold_alert.ts b/x-pack/test/api_integration/apis/metrics_ui/inventory_threshold_alert.ts index a6e0ce1bc628f7..a5f72f1c43b815 100644 --- a/x-pack/test/api_integration/apis/metrics_ui/inventory_threshold_alert.ts +++ b/x-pack/test/api_integration/apis/metrics_ui/inventory_threshold_alert.ts @@ -15,7 +15,10 @@ import { InfraSource } from '../../../../plugins/infra/server/lib/sources'; import { FtrProviderContext } from '../../ftr_provider_context'; import { DATES } from './constants'; import { evaluateCondition } from '../../../../plugins/infra/server/lib/alerting/inventory_metric_threshold/evaluate_condition'; -import { InventoryItemType } from '../../../../plugins/infra/common/inventory_models/types'; +import { + InventoryItemType, + SnapshotMetricType, +} from '../../../../plugins/infra/common/inventory_models/types'; export default function ({ getService }: FtrProviderContext) { const esArchiver = getService('esArchiver'); @@ -40,7 +43,7 @@ export default function ({ getService }: FtrProviderContext) { type: 'index_pattern', indexPatternId: 'some-test-id', }, - metricAlias: 'metricbeat-*', + metricAlias: 'metrics-*,metricbeat-*', inventoryDefaultView: 'default', metricsExplorerDefaultView: 'default', anomalyThreshold: 70, @@ -78,50 +81,339 @@ export default function ({ getService }: FtrProviderContext) { }; describe('Inventory Threshold Rule Executor', () => { - before(() => esArchiver.load('x-pack/test/functional/es_archives/infra/8.0.0/hosts_only')); - after(() => esArchiver.unload('x-pack/test/functional/es_archives/infra/8.0.0/hosts_only')); - it('should work FOR LAST 1 minute', async () => { - const results = await evaluateCondition({ - ...baseOptions, - esClient: convertToKibanaClient(esClient), + describe('CPU per Host', () => { + before(() => esArchiver.load('x-pack/test/functional/es_archives/infra/8.0.0/hosts_only')); + after(() => esArchiver.unload('x-pack/test/functional/es_archives/infra/8.0.0/hosts_only')); + it('should work FOR LAST 1 minute', async () => { + const results = await evaluateCondition({ + ...baseOptions, + esClient: convertToKibanaClient(esClient), + }); + expect(results).to.eql({ + 'host-0': { + metric: 'cpu', + timeSize: 1, + timeUnit: 'm', + sourceId: 'default', + threshold: [100], + comparator: '>', + shouldFire: [true], + shouldWarn: [false], + isNoData: [false], + isError: false, + currentValue: 1.109, + }, + 'host-1': { + metric: 'cpu', + timeSize: 1, + timeUnit: 'm', + sourceId: 'default', + threshold: [100], + comparator: '>', + shouldFire: [false], + shouldWarn: [false], + isNoData: [false], + isError: false, + currentValue: 0.7703333333333333, + }, + }); }); - expect(results).to.eql({ - 'host-01': { - metric: 'cpu', - timeSize: 1, - timeUnit: 'm', - sourceId: 'default', - threshold: [100], - comparator: '>', - shouldFire: [true], - shouldWarn: [false], - isNoData: [false], - isError: false, - currentValue: 1.01, - }, + it('should work FOR LAST 5 minute', async () => { + const options = { + ...baseOptions, + condition: { ...baseCondition, timeSize: 5 }, + esClient: convertToKibanaClient(esClient), + }; + const results = await evaluateCondition(options); + expect(results).to.eql({ + 'host-0': { + metric: 'cpu', + timeSize: 5, + timeUnit: 'm', + sourceId: 'default', + threshold: [100], + comparator: '>', + shouldFire: [true], + shouldWarn: [false], + isNoData: [false], + isError: false, + currentValue: 1.0376666666666665, + }, + 'host-1': { + metric: 'cpu', + timeSize: 5, + timeUnit: 'm', + sourceId: 'default', + threshold: [100], + comparator: '>', + shouldFire: [false], + shouldWarn: [false], + isNoData: [false], + isError: false, + currentValue: 0.9192, + }, + }); }); }); - it('should work FOR LAST 5 minute', async () => { - const options = { - ...baseOptions, - condition: { ...baseCondition, timeSize: 5 }, - esClient: convertToKibanaClient(esClient), - }; - const results = await evaluateCondition(options); - expect(results).to.eql({ - 'host-01': { - metric: 'cpu', - timeSize: 5, - timeUnit: 'm', - sourceId: 'default', - threshold: [100], - comparator: '>', - shouldFire: [false], - shouldWarn: [false], - isNoData: [false], - isError: false, - currentValue: 0.24000000000000002, - }, + + describe('Inbound network traffic per host', () => { + before(() => esArchiver.load('x-pack/test/functional/es_archives/infra/8.0.0/hosts_only')); + after(() => esArchiver.unload('x-pack/test/functional/es_archives/infra/8.0.0/hosts_only')); + it('should work FOR LAST 1 minute', async () => { + const results = await evaluateCondition({ + ...baseOptions, + condition: { + ...baseCondition, + metric: 'rx', + threshold: [1], + }, + esClient: convertToKibanaClient(esClient), + }); + expect(results).to.eql({ + 'host-0': { + metric: 'rx', + timeSize: 1, + timeUnit: 'm', + sourceId: 'default', + threshold: [1], + comparator: '>', + shouldFire: [true], + shouldWarn: [false], + isNoData: [false], + isError: false, + currentValue: 1666.6666666666667, + }, + 'host-1': { + metric: 'rx', + timeSize: 1, + timeUnit: 'm', + sourceId: 'default', + threshold: [1], + comparator: '>', + shouldFire: [true], + shouldWarn: [false], + isNoData: [false], + isError: false, + currentValue: 2000, + }, + }); + }); + it('should work FOR LAST 5 minute', async () => { + const options = { + ...baseOptions, + condition: { + ...baseCondition, + metric: 'rx' as SnapshotMetricType, + threshold: [1], + timeSize: 5, + }, + esClient: convertToKibanaClient(esClient), + }; + const results = await evaluateCondition(options); + expect(results).to.eql({ + 'host-0': { + metric: 'rx', + timeSize: 5, + timeUnit: 'm', + sourceId: 'default', + threshold: [1], + comparator: '>', + shouldFire: [true], + shouldWarn: [false], + isNoData: [false], + isError: false, + currentValue: 2266.6666666666665, + }, + 'host-1': { + metric: 'rx', + timeSize: 5, + timeUnit: 'm', + sourceId: 'default', + threshold: [1], + comparator: '>', + shouldFire: [true], + shouldWarn: [false], + isNoData: [false], + isError: false, + currentValue: 2266.6666666666665, + }, + }); + }); + }); + + describe('Log rate per host', () => { + before(() => esArchiver.load('x-pack/test/functional/es_archives/infra/8.0.0/hosts_only')); + after(() => esArchiver.unload('x-pack/test/functional/es_archives/infra/8.0.0/hosts_only')); + it('should work FOR LAST 1 minute', async () => { + const results = await evaluateCondition({ + ...baseOptions, + logQueryFields: { indexPattern: 'metricbeat-*' }, + condition: { + ...baseCondition, + metric: 'logRate', + threshold: [1], + }, + esClient: convertToKibanaClient(esClient), + }); + expect(results).to.eql({ + 'host-0': { + metric: 'logRate', + timeSize: 1, + timeUnit: 'm', + sourceId: 'default', + threshold: [1], + comparator: '>', + shouldFire: [false], + shouldWarn: [false], + isNoData: [false], + isError: false, + currentValue: 0.3, + }, + 'host-1': { + metric: 'logRate', + timeSize: 1, + timeUnit: 'm', + sourceId: 'default', + threshold: [1], + comparator: '>', + shouldFire: [false], + shouldWarn: [false], + isNoData: [false], + isError: false, + currentValue: 0.3, + }, + }); + }); + it('should work FOR LAST 5 minute', async () => { + const options = { + ...baseOptions, + logQueryFields: { indexPattern: 'metricbeat-*' }, + condition: { + ...baseCondition, + metric: 'logRate' as SnapshotMetricType, + threshold: [1], + timeSize: 5, + }, + esClient: convertToKibanaClient(esClient), + }; + const results = await evaluateCondition(options); + expect(results).to.eql({ + 'host-0': { + metric: 'logRate', + timeSize: 5, + timeUnit: 'm', + sourceId: 'default', + threshold: [1], + comparator: '>', + shouldFire: [false], + shouldWarn: [false], + isNoData: [false], + isError: false, + currentValue: 0.3, + }, + 'host-1': { + metric: 'logRate', + timeSize: 5, + timeUnit: 'm', + sourceId: 'default', + threshold: [1], + comparator: '>', + shouldFire: [false], + shouldWarn: [false], + isNoData: [false], + isError: false, + currentValue: 0.3, + }, + }); + }); + }); + + describe('Network rate per pod', () => { + before(() => esArchiver.load('x-pack/test/functional/es_archives/infra/8.0.0/pods_only')); + after(() => esArchiver.unload('x-pack/test/functional/es_archives/infra/8.0.0/pods_only')); + it('should work FOR LAST 1 minute', async () => { + const results = await evaluateCondition({ + ...baseOptions, + startTime: DATES['8.0.0'].pods_only.max, + nodeType: 'pod' as InventoryItemType, + condition: { + ...baseCondition, + metric: 'rx', + threshold: [1], + }, + esClient: convertToKibanaClient(esClient), + }); + expect(results).to.eql({ + '7d6d7955-f853-42b1-8613-11f52d0d2725': { + metric: 'rx', + timeSize: 1, + timeUnit: 'm', + sourceId: 'default', + threshold: [1], + comparator: '>', + shouldFire: [true], + shouldWarn: [false], + isNoData: [false], + isError: false, + currentValue: 43332.833333333336, + }, + 'ed01e3a3-4787-42f6-b73e-ac9e97294e9d': { + metric: 'rx', + timeSize: 1, + timeUnit: 'm', + sourceId: 'default', + threshold: [1], + comparator: '>', + shouldFire: [true], + shouldWarn: [false], + isNoData: [false], + isError: false, + currentValue: 42783.833333333336, + }, + }); + }); + it('should work FOR LAST 5 minute', async () => { + const results = await evaluateCondition({ + ...baseOptions, + startTime: DATES['8.0.0'].pods_only.max, + logQueryFields: { indexPattern: 'metricbeat-*' }, + nodeType: 'pod', + condition: { + ...baseCondition, + metric: 'rx', + threshold: [1], + timeSize: 5, + }, + esClient: convertToKibanaClient(esClient), + }); + expect(results).to.eql({ + '7d6d7955-f853-42b1-8613-11f52d0d2725': { + metric: 'rx', + timeSize: 5, + timeUnit: 'm', + sourceId: 'default', + threshold: [1], + comparator: '>', + shouldFire: [true], + shouldWarn: [false], + isNoData: [false], + isError: false, + currentValue: 50197.666666666664, + }, + 'ed01e3a3-4787-42f6-b73e-ac9e97294e9d': { + metric: 'rx', + timeSize: 5, + timeUnit: 'm', + sourceId: 'default', + threshold: [1], + comparator: '>', + shouldFire: [true], + shouldWarn: [false], + isNoData: [false], + isError: false, + currentValue: 50622.066666666666, + }, + }); }); }); }); diff --git a/x-pack/test/api_integration/apis/metrics_ui/metrics_alerting.ts b/x-pack/test/api_integration/apis/metrics_ui/metrics_alerting.ts index fd9767e13d9ef3..02a9f3070fe580 100644 --- a/x-pack/test/api_integration/apis/metrics_ui/metrics_alerting.ts +++ b/x-pack/test/api_integration/apis/metrics_ui/metrics_alerting.ts @@ -40,7 +40,6 @@ export default function ({ getService }: FtrProviderContext) { const searchBody = getElasticsearchMetricQuery(getSearchParams(aggType), timeframe, 100); const result = await client.search({ index, - // @ts-expect-error @elastic/elasticsearch AggregationsBucketsPath is not valid body: searchBody, }); @@ -64,7 +63,6 @@ export default function ({ getService }: FtrProviderContext) { ); const result = await client.search({ index, - // @ts-expect-error @elastic/elasticsearch AggregationsBucketsPath is not valid body: searchBody, }); @@ -87,7 +85,6 @@ export default function ({ getService }: FtrProviderContext) { ); const result = await client.search({ index, - // @ts-expect-error @elastic/elasticsearch AggregationsBucketsPath is not valid body: searchBody, }); @@ -109,7 +106,6 @@ export default function ({ getService }: FtrProviderContext) { ); const result = await client.search({ index, - // @ts-expect-error @elastic/elasticsearch AggregationsBucketsPath is not valid body: searchBody, }); diff --git a/x-pack/test/functional/es_archives/infra/8.0.0/hosts_only/data.json.gz b/x-pack/test/functional/es_archives/infra/8.0.0/hosts_only/data.json.gz index bdd31f088a41ab7c0f81423cdedb4a5d508af7a6..217442c2cf338f2357d487a50558a2f5e7fab604 100644 GIT binary patch literal 4926 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 literal 0 HcmV?d00001 diff --git a/x-pack/test/functional/es_archives/infra/8.0.0/pods_only/mappings.json b/x-pack/test/functional/es_archives/infra/8.0.0/pods_only/mappings.json new file mode 100644 index 00000000000000..d979f8968937cd --- /dev/null +++ b/x-pack/test/functional/es_archives/infra/8.0.0/pods_only/mappings.json @@ -0,0 +1,247 @@ +{ + "type": "index", + "value": { + "aliases": { + "metrics-fake_k8s": { + } + }, + "index": "high-cardinality-data-fake_k8s-2022-01-20", + "mappings": { + "date_detection": false, + "dynamic_templates": [ + { + "labels": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "labels.*" + } + }, + { + "strings_as_keyword": { + "mapping": { + "ignore_above": 1024, + "type": "keyword" + }, + "match_mapping_type": "string" + } + } + ], + "properties": { + "@timestamp": { + "type": "date" + }, + "event": { + "properties": { + "dataset": { + "ignore_above": 256, + "type": "keyword" + }, + "duration": { + "type": "long" + }, + "module": { + "ignore_above": 256, + "type": "keyword" + } + } + }, + "kubernetes": { + "properties": { + "namespace": { + "ignore_above": 1024, + "type": "keyword" + }, + "node": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "pod": { + "properties": { + "cpu": { + "properties": { + "usage": { + "properties": { + "limit": { + "properties": { + "pct": { + "scaling_factor": 1000, + "type": "scaled_float" + } + } + }, + "nanocores": { + "type": "long" + }, + "node": { + "properties": { + "pct": { + "scaling_factor": 1000, + "type": "scaled_float" + } + } + } + } + } + } + }, + "host_ip": { + "ignore_above": 256, + "type": "keyword" + }, + "ip": { + "ignore_above": 256, + "type": "keyword" + }, + "memory": { + "properties": { + "usage": { + "properties": { + "available": { + "properties": { + "bytes": { + "type": "long" + } + } + }, + "bytes": { + "type": "long" + }, + "limit": { + "properties": { + "pct": { + "scaling_factor": 1000, + "type": "scaled_float" + } + } + }, + "major_page_faults": { + "type": "long" + }, + "node": { + "properties": { + "pct": { + "scaling_factor": 1000, + "type": "scaled_float" + } + } + }, + "page_faults": { + "type": "long" + }, + "rss": { + "properties": { + "bytes": { + "type": "long" + } + } + }, + "working_set": { + "properties": { + "bytes": { + "type": "long" + } + } + } + } + } + } + }, + "name": { + "ignore_above": 256, + "type": "keyword" + }, + "network": { + "properties": { + "rx": { + "properties": { + "bytes": { + "type": "long" + }, + "errors": { + "type": "long" + } + } + }, + "tx": { + "properties": { + "bytes": { + "type": "long" + }, + "errors": { + "type": "long" + } + } + } + } + }, + "startTime": { + "type": "date" + }, + "status": { + "properties": { + "phase": { + "ignore_above": 1024, + "type": "keyword" + }, + "ready": { + "ignore_above": 1024, + "type": "keyword" + }, + "scheduled": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "uid": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "metricset": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "period": { + "type": "long" + } + } + }, + "service": { + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "settings": { + "index": { + "mapping": { + "total_fields": { + "limit": "10000" + } + }, + "number_of_replicas": "0", + "number_of_shards": "1" + } + } + } +} \ No newline at end of file From 2d3c95c20d014d0c3e21eb7ab72e624d4526fc14 Mon Sep 17 00:00:00 2001 From: Shahzad Date: Thu, 20 Jan 2022 22:48:25 +0100 Subject: [PATCH 102/108] [Synthetics Service] Make service keys optional (#123507) --- x-pack/plugins/uptime/common/config.ts | 4 ++-- .../server/lib/synthetics_service/get_service_locations.ts | 7 ++++++- .../rest_api/synthetics_service/get_service_locations.ts | 2 +- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/x-pack/plugins/uptime/common/config.ts b/x-pack/plugins/uptime/common/config.ts index 3e8c6cc0092076..6a2c630d31fae7 100644 --- a/x-pack/plugins/uptime/common/config.ts +++ b/x-pack/plugins/uptime/common/config.ts @@ -10,10 +10,10 @@ import { schema, TypeOf } from '@kbn/config-schema'; import { sslSchema } from '@kbn/server-http-tools'; const serviceConfig = schema.object({ - enabled: schema.boolean(), + enabled: schema.maybe(schema.boolean()), username: schema.maybe(schema.string()), password: schema.maybe(schema.string()), - manifestUrl: schema.string(), + manifestUrl: schema.maybe(schema.string()), hosts: schema.maybe(schema.arrayOf(schema.string())), syncInterval: schema.maybe(schema.string()), tls: schema.maybe(sslSchema), diff --git a/x-pack/plugins/uptime/server/lib/synthetics_service/get_service_locations.ts b/x-pack/plugins/uptime/server/lib/synthetics_service/get_service_locations.ts index 4802b4687e00d8..54686b282bbb48 100644 --- a/x-pack/plugins/uptime/server/lib/synthetics_service/get_service_locations.ts +++ b/x-pack/plugins/uptime/server/lib/synthetics_service/get_service_locations.ts @@ -12,8 +12,13 @@ import { ServiceLocationsApiResponse, } from '../../../common/runtime_types'; -export async function getServiceLocations({ manifestUrl }: { manifestUrl: string }) { +export async function getServiceLocations({ manifestUrl }: { manifestUrl?: string }) { const locations: ServiceLocations = []; + + if (!manifestUrl) { + return { locations }; + } + try { const { data } = await axios.get<{ locations: Record }>(manifestUrl); diff --git a/x-pack/plugins/uptime/server/rest_api/synthetics_service/get_service_locations.ts b/x-pack/plugins/uptime/server/rest_api/synthetics_service/get_service_locations.ts index 0c51a53e8fd03c..e785ec583d8ca8 100644 --- a/x-pack/plugins/uptime/server/rest_api/synthetics_service/get_service_locations.ts +++ b/x-pack/plugins/uptime/server/rest_api/synthetics_service/get_service_locations.ts @@ -14,5 +14,5 @@ export const getServiceLocationsRoute: UMRestApiRouteFactory = () => ({ path: API_URLS.SERVICE_LOCATIONS, validate: {}, handler: async ({ server }): Promise => - getServiceLocations({ manifestUrl: server.config.service!.manifestUrl }), + getServiceLocations({ manifestUrl: server.config.service!.manifestUrl! }), }); From 94e2e9a85d9d2e529170d5050679f33982834e1b Mon Sep 17 00:00:00 2001 From: Tim Sullivan Date: Thu, 20 Jan 2022 14:49:31 -0700 Subject: [PATCH 103/108] [Reporting] Update references to deprecated internal APIs (#123013) * [Reporting] Update reference to fieldFormats plugin * fix license$ reference * fix type refs * rename index pattern to data view * fix locator.getUrl * fix deprecated reference to security.authc * revert and see * fix security * fix mock router * Revert "revert and see" This reverts commit 655be8f77fbfbcd9c7f0e4814d68b78a3dd037d4. * oops another resolved fixme * fix security in the integration tests * fix authorized_user jest test * Apply suggestions from code review Co-authored-by: Michael Dokolin * lint fix Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Michael Dokolin --- x-pack/plugins/reporting/kibana.json | 1 + .../management/components/ilm_policy_link.tsx | 13 +- .../reporting/public/management/index.ts | 4 +- x-pack/plugins/reporting/server/core.ts | 30 ++-- .../generate_csv/generate_csv.ts | 9 +- x-pack/plugins/reporting/server/plugin.ts | 34 ++-- .../generation_from_jobparams.test.ts | 8 +- .../lib/authorized_user_pre_routing.test.ts | 149 +++++++++++------- .../routes/lib/authorized_user_pre_routing.ts | 5 +- .../reporting/server/routes/lib/get_user.ts | 4 +- .../management/integration_tests/jobs.test.ts | 66 ++++---- x-pack/plugins/reporting/server/services.ts | 4 +- .../create_mock_reportingplugin.ts | 14 +- x-pack/plugins/reporting/server/types.ts | 9 +- 14 files changed, 191 insertions(+), 159 deletions(-) diff --git a/x-pack/plugins/reporting/kibana.json b/x-pack/plugins/reporting/kibana.json index 57cfc25c4b5288..e7162d0974de6d 100644 --- a/x-pack/plugins/reporting/kibana.json +++ b/x-pack/plugins/reporting/kibana.json @@ -11,6 +11,7 @@ "configPath": ["xpack", "reporting"], "requiredPlugins": [ "data", + "fieldFormats", "esUiShared", "home", "management", diff --git a/x-pack/plugins/reporting/public/management/components/ilm_policy_link.tsx b/x-pack/plugins/reporting/public/management/components/ilm_policy_link.tsx index dfb884c24e917f..3fdc83c341ed92 100644 --- a/x-pack/plugins/reporting/public/management/components/ilm_policy_link.tsx +++ b/x-pack/plugins/reporting/public/management/components/ilm_policy_link.tsx @@ -31,14 +31,11 @@ export const IlmPolicyLink: FunctionComponent = ({ locator, navigateToUrl data-test-subj="ilmPolicyLink" size="xs" onClick={() => { - locator - .getUrl({ - page: 'policy_edit', - policyName: ILM_POLICY_NAME, - }) - .then((url) => { - navigateToUrl(url); - }); + const url = locator.getRedirectUrl({ + page: 'policy_edit', + policyName: ILM_POLICY_NAME, + }); + navigateToUrl(url); }} > {i18nTexts.buttonLabel} diff --git a/x-pack/plugins/reporting/public/management/index.ts b/x-pack/plugins/reporting/public/management/index.ts index 7bd7845051d2c8..491e2df445d32f 100644 --- a/x-pack/plugins/reporting/public/management/index.ts +++ b/x-pack/plugins/reporting/public/management/index.ts @@ -6,7 +6,7 @@ */ import { ApplicationStart, ToastsSetup } from 'src/core/public'; -import { LicensingPluginSetup } from '../../../licensing/public'; +import { LicensingPluginStart } from '../../../licensing/public'; import { UseIlmPolicyStatusReturn } from '../lib/ilm_policy_status_context'; import { ReportingAPIClient } from '../lib/reporting_api_client'; import { ClientConfigType } from '../plugin'; @@ -15,7 +15,7 @@ import type { SharePluginSetup } from '../shared_imports'; export interface ListingProps { apiClient: ReportingAPIClient; capabilities: ApplicationStart['capabilities']; - license$: LicensingPluginSetup['license$']; // FIXME: license$ is deprecated + license$: LicensingPluginStart['license$']; pollConfig: ClientConfigType['poll']; redirect: ApplicationStart['navigateToApp']; navigateToUrl: ApplicationStart['navigateToUrl']; diff --git a/x-pack/plugins/reporting/server/core.ts b/x-pack/plugins/reporting/server/core.ts index a29e709b4442df..5c00089afc381d 100644 --- a/x-pack/plugins/reporting/server/core.ts +++ b/x-pack/plugins/reporting/server/core.ts @@ -8,36 +8,36 @@ import Hapi from '@hapi/hapi'; import * as Rx from 'rxjs'; import { filter, first, map, switchMap, take } from 'rxjs/operators'; -import { +import type { BasePath, IClusterClient, - KibanaRequest, PackageInfo, PluginInitializerContext, SavedObjectsClientContract, SavedObjectsServiceStart, - ServiceStatusLevels, StatusServiceSetup, UiSettingsServiceStart, -} from '../../../../src/core/server'; -import { PluginStart as DataPluginStart } from '../../../../src/plugins/data/server'; -import { IEventLogService } from '../../event_log/server'; -import { PluginSetupContract as FeaturesPluginSetup } from '../../features/server'; -import { LicensingPluginStart } from '../../licensing/server'; +} from 'src/core/server'; +import type { PluginStart as DataPluginStart } from 'src/plugins/data/server'; +import type { FieldFormatsStart } from 'src/plugins/field_formats/server'; +import { KibanaRequest, ServiceStatusLevels } from '../../../../src/core/server'; +import type { IEventLogService } from '../../event_log/server'; +import type { PluginSetupContract as FeaturesPluginSetup } from '../../features/server'; +import type { LicensingPluginStart } from '../../licensing/server'; import type { ScreenshotResult, ScreenshottingStart } from '../../screenshotting/server'; -import { SecurityPluginSetup } from '../../security/server'; +import type { SecurityPluginSetup, SecurityPluginStart } from '../../security/server'; import { DEFAULT_SPACE_ID } from '../../spaces/common/constants'; -import { SpacesPluginSetup } from '../../spaces/server'; -import { TaskManagerSetupContract, TaskManagerStartContract } from '../../task_manager/server'; +import type { SpacesPluginSetup } from '../../spaces/server'; +import type { TaskManagerSetupContract, TaskManagerStartContract } from '../../task_manager/server'; import { REPORTING_REDIRECT_LOCATOR_STORE_KEY } from '../common/constants'; import { durationToNumber } from '../common/schema_utils'; -import { ReportingConfig, ReportingSetup } from './'; +import type { ReportingConfig, ReportingSetup } from './'; import { ReportingConfigType } from './config'; import { checkLicense, getExportTypesRegistry, LevelLogger } from './lib'; import { reportingEventLoggerFactory } from './lib/event_logger/logger'; -import { IReport, ReportingStore } from './lib/store'; +import type { IReport, ReportingStore } from './lib/store'; import { ExecuteReportTask, MonitorReportsTask, ReportTaskParams } from './lib/tasks'; -import { ReportingPluginRouter, ScreenshotOptions } from './types'; +import type { ReportingPluginRouter, ScreenshotOptions } from './types'; export interface ReportingInternalSetup { eventLog: IEventLogService; @@ -57,9 +57,11 @@ export interface ReportingInternalStart { uiSettings: UiSettingsServiceStart; esClient: IClusterClient; data: DataPluginStart; + fieldFormats: FieldFormatsStart; licensing: LicensingPluginStart; logger: LevelLogger; screenshotting: ScreenshottingStart; + security?: SecurityPluginStart; taskManager: TaskManagerStartContract; } diff --git a/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts b/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts index 08f17fd3acbd1f..804fc66c547581 100644 --- a/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts +++ b/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts @@ -13,7 +13,7 @@ import type { Datatable } from 'src/plugins/expressions/server'; import type { Writable } from 'stream'; import type { ReportingConfig } from '../../..'; import type { - IndexPattern, + DataView, ISearchSource, ISearchStartSearchSource, SearchFieldValue, @@ -81,11 +81,7 @@ export class CsvGenerator { private stream: Writable ) {} - private async scan( - index: IndexPattern, - searchSource: ISearchSource, - settings: CsvExportSettings - ) { + private async scan(index: DataView, searchSource: ISearchSource, settings: CsvExportSettings) { const { scroll: scrollSettings, includeFrozen } = settings; const searchBody = searchSource.getSearchRequestBody(); this.logger.debug(`executing search request`); @@ -432,7 +428,6 @@ export class CsvGenerator { this.logger.debug(`Finished generating. Row count: ${this.csvRowCount}.`); - // FIXME: https://github.com/elastic/kibana/issues/112186 -- find root cause if (!this.maxSizeReached && this.csvRowCount !== totalRecords) { this.logger.warning( `ES scroll returned fewer total hits than expected! ` + diff --git a/x-pack/plugins/reporting/server/plugin.ts b/x-pack/plugins/reporting/server/plugin.ts index 32285772d0e233..3b25fedd0d5fb5 100644 --- a/x-pack/plugins/reporting/server/plugin.ts +++ b/x-pack/plugins/reporting/server/plugin.ts @@ -38,7 +38,6 @@ export class ReportingPlugin public setup(core: CoreSetup, plugins: ReportingSetupDeps) { const { http, status } = core; - const { features, eventLog, security, spaces, taskManager } = plugins; const reportingCore = new ReportingCore(this.logger, this.initContext); @@ -53,22 +52,15 @@ export class ReportingPlugin } }); - const basePath = http.basePath; - const router = http.createRouter(); - reportingCore.pluginSetup({ - status, - features, - eventLog, - security, - spaces, - taskManager, - basePath, - router, logger: this.logger, + status, + basePath: http.basePath, + router: http.createRouter(), + ...plugins, }); - registerEventLogProviderActions(eventLog); + registerEventLogProviderActions(plugins.eventLog); registerUiSettings(core); registerDeprecations({ core, reportingCore }); registerReportingUsageCollector(reportingCore, plugins.usageCollection); @@ -92,27 +84,25 @@ export class ReportingPlugin public start(core: CoreStart, plugins: ReportingStartDeps) { const { elasticsearch, savedObjects, uiSettings } = core; - const { data, licensing, screenshotting, taskManager } = plugins; - // use data plugin for csv formats - setFieldFormats(data.fieldFormats); // FIXME: 'fieldFormats' is deprecated. + + // use fieldFormats plugin for csv formats + setFieldFormats(plugins.fieldFormats); const reportingCore = this.reportingCore!; // async background start (async () => { await reportingCore.pluginSetsUp(); - const store = new ReportingStore(reportingCore, this.logger); + const logger = this.logger; + const store = new ReportingStore(reportingCore, logger); await reportingCore.pluginStart({ - logger: this.logger, + logger, esClient: elasticsearch.client, savedObjects, uiSettings, store, - data, - licensing, - screenshotting, - taskManager, + ...plugins, }); // Note: this must be called after ReportingCore.pluginStart diff --git a/x-pack/plugins/reporting/server/routes/generate/integration_tests/generation_from_jobparams.test.ts b/x-pack/plugins/reporting/server/routes/generate/integration_tests/generation_from_jobparams.test.ts index 3ec735083d7cc3..f6db9e92086eb2 100644 --- a/x-pack/plugins/reporting/server/routes/generate/integration_tests/generation_from_jobparams.test.ts +++ b/x-pack/plugins/reporting/server/routes/generate/integration_tests/generation_from_jobparams.test.ts @@ -51,9 +51,6 @@ describe('POST /api/reporting/generate', () => { const mockSetupDeps = createMockPluginSetup({ security: { license: { isEnabled: () => true }, - authc: { - getCurrentUser: () => ({ id: '123', roles: ['superuser'], username: 'Tom Riddle' }), - }, }, router: httpSetup.createRouter(''), }); @@ -64,6 +61,11 @@ describe('POST /api/reporting/generate', () => { ...licensingMock.createStart(), license$: new BehaviorSubject({ isActive: true, isAvailable: true, type: 'gold' }), }, + security: { + authc: { + getCurrentUser: () => ({ id: '123', roles: ['superuser'], username: 'Tom Riddle' }), + }, + }, }, mockConfigSchema ); diff --git a/x-pack/plugins/reporting/server/routes/lib/authorized_user_pre_routing.test.ts b/x-pack/plugins/reporting/server/routes/lib/authorized_user_pre_routing.test.ts index e2ff52036764b1..51e0994b591092 100644 --- a/x-pack/plugins/reporting/server/routes/lib/authorized_user_pre_routing.test.ts +++ b/x-pack/plugins/reporting/server/routes/lib/authorized_user_pre_routing.test.ts @@ -8,13 +8,20 @@ import { KibanaRequest, KibanaResponseFactory } from 'src/core/server'; import { coreMock, httpServerMock } from 'src/core/server/mocks'; import { ReportingCore } from '../../'; -import { ReportingInternalSetup } from '../../core'; -import { createMockConfigSchema, createMockReportingCore } from '../../test_helpers'; +import { ReportingInternalSetup, ReportingInternalStart } from '../../core'; +import { + createMockConfigSchema, + createMockPluginSetup, + createMockPluginStart, + createMockReportingCore, +} from '../../test_helpers'; import type { ReportingRequestHandlerContext } from '../../types'; import { authorizedUserPreRouting } from './authorized_user_pre_routing'; let mockCore: ReportingCore; -const mockReportingConfig = createMockConfigSchema({ roles: { enabled: false } }); +let mockSetupDeps: ReportingInternalSetup; +let mockStartDeps: ReportingInternalStart; +let mockReportingConfig = createMockConfigSchema({ roles: { enabled: false } }); const getMockContext = () => ({ @@ -36,20 +43,30 @@ const getMockResponseFactory = () => describe('authorized_user_pre_routing', function () { beforeEach(async () => { - mockCore = await createMockReportingCore(mockReportingConfig); + mockSetupDeps = createMockPluginSetup({ + security: { license: { isEnabled: () => true } }, + }); + + mockStartDeps = await createMockPluginStart( + { + security: { + authc: { + getCurrentUser: () => ({ id: '123', roles: ['superuser'], username: 'Tom Riddle' }), + }, + }, + }, + mockReportingConfig + ); + mockCore = await createMockReportingCore(mockReportingConfig, mockSetupDeps, mockStartDeps); }); it('should return from handler with a "false" user when security plugin is not found', async function () { - mockCore.getPluginSetupDeps = () => - ({ - // @ts-ignore - ...mockCore.pluginSetupDeps, - security: undefined, // disable security - } as unknown as ReportingInternalSetup); + mockSetupDeps = createMockPluginSetup({ security: undefined }); + mockCore = await createMockReportingCore(mockReportingConfig, mockSetupDeps, mockStartDeps); const mockResponseFactory = httpServerMock.createResponseFactory() as KibanaResponseFactory; let handlerCalled = false; - authorizedUserPreRouting(mockCore, (user: unknown) => { + await authorizedUserPreRouting(mockCore, (user: unknown) => { expect(user).toBe(false); // verify the user is a false value handlerCalled = true; return Promise.resolve({ status: 200, options: {} }); @@ -59,20 +76,14 @@ describe('authorized_user_pre_routing', function () { }); it('should return from handler with a "false" user when security is disabled', async function () { - mockCore.getPluginSetupDeps = () => - ({ - // @ts-ignore - ...mockCore.pluginSetupDeps, - security: { - license: { - isEnabled: () => false, - }, - }, // disable security - } as unknown as ReportingInternalSetup); + mockSetupDeps = createMockPluginSetup({ + security: { license: { isEnabled: () => false } }, // disable security + }); + mockCore = await createMockReportingCore(mockReportingConfig, mockSetupDeps, mockStartDeps); const mockResponseFactory = httpServerMock.createResponseFactory() as KibanaResponseFactory; let handlerCalled = false; - authorizedUserPreRouting(mockCore, (user: unknown) => { + await authorizedUserPreRouting(mockCore, (user: unknown) => { expect(user).toBe(false); // verify the user is a false value handlerCalled = true; return Promise.resolve({ status: 200, options: {} }); @@ -82,82 +93,104 @@ describe('authorized_user_pre_routing', function () { }); it('should return with 401 when security is enabled and the request is unauthenticated', async function () { - mockCore.getPluginSetupDeps = () => - ({ - // @ts-ignore - ...mockCore.pluginSetupDeps, - security: { - license: { isEnabled: () => true }, - authc: { getCurrentUser: () => null }, - }, - } as unknown as ReportingInternalSetup); + mockSetupDeps = createMockPluginSetup({ + security: { license: { isEnabled: () => true } }, + }); + mockStartDeps = await createMockPluginStart( + { security: { authc: { getCurrentUser: () => null } } }, + mockReportingConfig + ); + mockCore = await createMockReportingCore(mockReportingConfig, mockSetupDeps, mockStartDeps); const mockHandler = () => { throw new Error('Handler callback should not be called'); }; const requestHandler = authorizedUserPreRouting(mockCore, mockHandler); - const mockResponseFactory = getMockResponseFactory(); - expect(requestHandler(getMockContext(), getMockRequest(), mockResponseFactory)).toMatchObject({ + await expect( + requestHandler(getMockContext(), getMockRequest(), getMockResponseFactory()) + ).resolves.toMatchObject({ body: `Sorry, you aren't authenticated`, }); }); describe('Deprecated: security roles for access control', () => { beforeEach(async () => { - const mockReportingConfigDeprecated = createMockConfigSchema({ + mockReportingConfig = createMockConfigSchema({ roles: { allow: ['reporting_user'], enabled: true, }, }); - mockCore = await createMockReportingCore(mockReportingConfigDeprecated); }); it(`should return with 403 when security is enabled but user doesn't have the allowed role`, async function () { - mockCore.getPluginSetupDeps = () => - ({ - // @ts-ignore - ...mockCore.pluginSetupDeps, + mockStartDeps = await createMockPluginStart( + { security: { - license: { isEnabled: () => true }, - authc: { getCurrentUser: () => ({ username: 'friendlyuser', roles: ['cowboy'] }) }, + authc: { + getCurrentUser: () => ({ id: '123', roles: ['peasant'], username: 'Tom Riddle' }), + }, }, - } as unknown as ReportingInternalSetup); - const mockResponseFactory = getMockResponseFactory(); - + }, + mockReportingConfig + ); + mockCore = await createMockReportingCore(mockReportingConfig, mockSetupDeps, mockStartDeps); const mockHandler = () => { throw new Error('Handler callback should not be called'); }; + expect( - authorizedUserPreRouting(mockCore, mockHandler)( + await authorizedUserPreRouting(mockCore, mockHandler)( getMockContext(), getMockRequest(), - mockResponseFactory + getMockResponseFactory() ) ).toMatchObject({ body: `Sorry, you don't have access to Reporting` }); }); - it('should return from handler when security is enabled and user has explicitly allowed role', function (done) { - mockCore.getPluginSetupDeps = () => - ({ - // @ts-ignore - ...mockCore.pluginSetupDeps, + it('should return from handler when security is enabled and user has explicitly allowed role', async function () { + mockStartDeps = await createMockPluginStart( + { security: { - license: { isEnabled: () => true }, authc: { getCurrentUser: () => ({ username: 'friendlyuser', roles: ['reporting_user'] }), }, }, - } as unknown as ReportingInternalSetup); - const mockResponseFactory = getMockResponseFactory(); + }, + mockReportingConfig + ); + mockCore = await createMockReportingCore(mockReportingConfig, mockSetupDeps, mockStartDeps); - authorizedUserPreRouting(mockCore, (user) => { + let handlerCalled = false; + await authorizedUserPreRouting(mockCore, (user: unknown) => { expect(user).toMatchObject({ roles: ['reporting_user'], username: 'friendlyuser' }); - done(); + handlerCalled = true; return Promise.resolve({ status: 200, options: {} }); - })(getMockContext(), getMockRequest(), mockResponseFactory); + })(getMockContext(), getMockRequest(), getMockResponseFactory()); + expect(handlerCalled).toBe(true); }); - it('should return from handler when security is enabled and user has superuser role', async function () {}); + it('should return from handler when security is enabled and user has superuser role', async function () { + mockStartDeps = await createMockPluginStart( + { + security: { + authc: { getCurrentUser: () => ({ username: 'friendlyuser', roles: ['superuser'] }) }, + }, + }, + mockReportingConfig + ); + mockCore = await createMockReportingCore(mockReportingConfig, mockSetupDeps, mockStartDeps); + + const handler = jest.fn().mockResolvedValue({ status: 200, options: {} }); + await authorizedUserPreRouting(mockCore, handler)( + getMockContext(), + getMockRequest(), + getMockResponseFactory() + ); + + expect(handler).toHaveBeenCalled(); + const [[user]] = handler.mock.calls; + expect(user).toMatchObject({ roles: ['superuser'], username: 'friendlyuser' }); + }); }); }); diff --git a/x-pack/plugins/reporting/server/routes/lib/authorized_user_pre_routing.ts b/x-pack/plugins/reporting/server/routes/lib/authorized_user_pre_routing.ts index 2c6a01e6154871..7cf7e0b365f267 100644 --- a/x-pack/plugins/reporting/server/routes/lib/authorized_user_pre_routing.ts +++ b/x-pack/plugins/reporting/server/routes/lib/authorized_user_pre_routing.ts @@ -30,12 +30,13 @@ export const authorizedUserPreRouting = ( ): RequestHandler => { const { logger, security } = reporting.getPluginSetupDeps(); - return (context, req, res) => { + return async (context, req, res) => { + const { security: securityStart } = await reporting.getPluginStartDeps(); try { let user: ReportingRequestUser = false; if (security && security.license.isEnabled()) { // find the authenticated user, or null if security is not enabled - user = getUser(req, security); + user = getUser(req, securityStart); if (!user) { // security is enabled but the user is null return res.unauthorized({ body: `Sorry, you aren't authenticated` }); diff --git a/x-pack/plugins/reporting/server/routes/lib/get_user.ts b/x-pack/plugins/reporting/server/routes/lib/get_user.ts index cc5c97c7a3552d..837acf74ba8850 100644 --- a/x-pack/plugins/reporting/server/routes/lib/get_user.ts +++ b/x-pack/plugins/reporting/server/routes/lib/get_user.ts @@ -6,8 +6,8 @@ */ import { KibanaRequest } from 'kibana/server'; -import { SecurityPluginSetup } from '../../../../security/server'; +import { SecurityPluginStart } from '../../../../security/server'; -export function getUser(request: KibanaRequest, security?: SecurityPluginSetup) { +export function getUser(request: KibanaRequest, security?: SecurityPluginStart) { return security?.authc.getCurrentUser(request) ?? false; } diff --git a/x-pack/plugins/reporting/server/routes/management/integration_tests/jobs.test.ts b/x-pack/plugins/reporting/server/routes/management/integration_tests/jobs.test.ts index 6cbe7f27fa2792..9551f60f8c8e06 100644 --- a/x-pack/plugins/reporting/server/routes/management/integration_tests/jobs.test.ts +++ b/x-pack/plugins/reporting/server/routes/management/integration_tests/jobs.test.ts @@ -48,6 +48,8 @@ describe('GET /api/reporting/jobs/download', () => { }; }; + const mockConfigSchema = createMockConfigSchema({ roles: { enabled: false } }); + beforeEach(async () => { ({ server, httpSetup } = await setupServer(reportingSymbol)); httpSetup.registerRouteHandlerContext( @@ -56,14 +58,9 @@ describe('GET /api/reporting/jobs/download', () => { () => ({ usesUiCapabilities: jest.fn() }) ); - const mockConfigSchema = createMockConfigSchema({ roles: { enabled: false } }); - mockSetupDeps = createMockPluginSetup({ security: { license: { isEnabled: () => true }, - authc: { - getCurrentUser: () => ({ id: '123', roles: ['superuser'], username: 'Tom Riddle' }), - }, }, router: httpSetup.createRouter(''), }); @@ -74,6 +71,11 @@ describe('GET /api/reporting/jobs/download', () => { ...licensingMock.createStart(), license$: new BehaviorSubject({ isActive: true, isAvailable: true, type: 'gold' }), }, + security: { + authc: { + getCurrentUser: () => ({ id: '123', roles: ['superuser'], username: 'Tom Riddle' }), + }, + }, }, mockConfigSchema ); @@ -128,19 +130,17 @@ describe('GET /api/reporting/jobs/download', () => { }); it('fails on unauthenticated users', async () => { - // @ts-ignore - core.pluginSetupDeps = { - // @ts-ignore - ...core.pluginSetupDeps, - security: { - license: { - isEnabled: () => true, - }, - authc: { - getCurrentUser: () => undefined, + mockStartDeps = await createMockPluginStart( + { + licensing: { + ...licensingMock.createStart(), + license$: new BehaviorSubject({ isActive: true, isAvailable: true, type: 'gold' }), }, + security: { authc: { getCurrentUser: () => undefined } }, }, - } as unknown as ReportingInternalSetup; + mockConfigSchema + ); + core = await createMockReportingCore(mockConfigSchema, mockSetupDeps, mockStartDeps); registerJobInfoRoutes(core); await server.start(); @@ -330,25 +330,27 @@ describe('GET /api/reporting/jobs/download', () => { describe('Deprecated: role-based access control', () => { it('fails on users without the appropriate role', async () => { - const deprecatedConfig = createMockConfigSchema({ roles: { enabled: true } }); - core = await createMockReportingCore(deprecatedConfig, mockSetupDeps); - // @ts-ignore - core.pluginSetupDeps = { - // @ts-ignore - ...core.pluginSetupDeps, - security: { - license: { - isEnabled: () => true, + mockStartDeps = await createMockPluginStart( + { + licensing: { + ...licensingMock.createStart(), + license$: new BehaviorSubject({ isActive: true, isAvailable: true, type: 'gold' }), }, - authc: { - getCurrentUser: () => ({ - id: '123', - roles: ['peasant'], - username: 'Tom Riddle', - }), + security: { + authc: { + getCurrentUser: () => ({ id: '123', roles: ['peasant'], username: 'Tom Riddle' }), + }, }, }, - } as unknown as ReportingInternalSetup; + mockConfigSchema + ); + + core = await createMockReportingCore( + createMockConfigSchema({ roles: { enabled: true } }), + mockSetupDeps, + mockStartDeps + ); + registerJobInfoRoutes(core); await server.start(); diff --git a/x-pack/plugins/reporting/server/services.ts b/x-pack/plugins/reporting/server/services.ts index 21846588659204..55f32e21e4784f 100644 --- a/x-pack/plugins/reporting/server/services.ts +++ b/x-pack/plugins/reporting/server/services.ts @@ -5,8 +5,8 @@ * 2.0. */ +import { FieldFormatsStart } from 'src/plugins/field_formats/server'; import { createGetterSetter } from '../../../../src/plugins/kibana_utils/server'; -import { PluginStart as DataPluginStart } from '../../../../src/plugins/data/server'; export const [getFieldFormats, setFieldFormats] = - createGetterSetter('FieldFormats'); + createGetterSetter('FieldFormats'); diff --git a/x-pack/plugins/reporting/server/test_helpers/create_mock_reportingplugin.ts b/x-pack/plugins/reporting/server/test_helpers/create_mock_reportingplugin.ts index 1f6d7bcff5176d..aa065e7be52c77 100644 --- a/x-pack/plugins/reporting/server/test_helpers/create_mock_reportingplugin.ts +++ b/x-pack/plugins/reporting/server/test_helpers/create_mock_reportingplugin.ts @@ -14,6 +14,7 @@ import { coreMock, elasticsearchServiceMock, statusServiceMock } from 'src/core/ // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { dataPluginMock } from 'src/plugins/data/server/mocks'; import { FieldFormatsRegistry } from 'src/plugins/field_formats/common'; +import { fieldFormatsMock } from 'src/plugins/field_formats/common/mocks'; import { DeepPartial } from 'utility-types'; import { ReportingConfig, ReportingCore } from '../'; import { featuresPluginMock } from '../../../features/server/mocks'; @@ -34,12 +35,12 @@ export const createMockPluginSetup = ( return { features: featuresPluginMock.createSetup(), basePath: { set: jest.fn() }, - router: setupMock.router, + router: { get: jest.fn(), post: jest.fn(), put: jest.fn(), delete: jest.fn() }, security: securityMock.createSetup(), taskManager: taskManagerMock.createSetup(), logger: createMockLevelLogger(), status: statusServiceMock.createSetupContract(), - eventLog: setupMock.eventLog || { + eventLog: { registerProviderActions: jest.fn(), getLogger: jest.fn(() => ({ logEvent: jest.fn() })), }, @@ -63,9 +64,10 @@ export const createMockPluginStart = async ( ): Promise => { return { esClient: elasticsearchServiceMock.createClusterClient(), - savedObjects: startMock.savedObjects || { getScopedClient: jest.fn() }, - uiSettings: startMock.uiSettings || { asScopedToClient: () => ({ get: jest.fn() }) }, - data: startMock.data || dataPluginMock.createStartContract(), + savedObjects: { getScopedClient: jest.fn() }, + uiSettings: { asScopedToClient: () => ({ get: jest.fn() }) }, + data: dataPluginMock.createStartContract(), + fieldFormats: () => Promise.resolve(fieldFormatsMock), store: await createMockReportingStore(config), taskManager: { schedule: jest.fn().mockImplementation(() => ({ id: 'taskId' })), @@ -76,7 +78,7 @@ export const createMockPluginStart = async ( license$: new BehaviorSubject({ isAvailable: true, isActive: true, type: 'basic' }), }, logger, - screenshotting: startMock.screenshotting || createMockScreenshottingStart(), + screenshotting: createMockScreenshottingStart(), ...startMock, }; }; diff --git a/x-pack/plugins/reporting/server/types.ts b/x-pack/plugins/reporting/server/types.ts index e558448950c79b..c695df6d0a410f 100644 --- a/x-pack/plugins/reporting/server/types.ts +++ b/x-pack/plugins/reporting/server/types.ts @@ -8,6 +8,7 @@ import type { IRouter, RequestHandlerContext } from 'src/core/server'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths import type { DataPluginStart } from 'src/plugins/data/server/plugin'; +import { FieldFormatsStart } from 'src/plugins/field_formats/server'; import type { ScreenshotModePluginSetup } from 'src/plugins/screenshot_mode/server'; import type { UsageCollectionSetup } from 'src/plugins/usage_collection/server'; import type { Writable } from 'stream'; @@ -18,7 +19,11 @@ import type { ScreenshotOptions as BaseScreenshotOptions, ScreenshottingStart, } from '../../screenshotting/server'; -import type { AuthenticatedUser, SecurityPluginSetup } from '../../security/server'; +import type { + AuthenticatedUser, + SecurityPluginSetup, + SecurityPluginStart, +} from '../../security/server'; import type { SpacesPluginSetup } from '../../spaces/server'; import type { TaskManagerSetupContract, TaskManagerStartContract } from '../../task_manager/server'; import type { CancellationToken } from '../common/cancellation_token'; @@ -105,8 +110,10 @@ export interface ReportingSetupDeps { */ export interface ReportingStartDeps { data: DataPluginStart; + fieldFormats: FieldFormatsStart; licensing: LicensingPluginStart; screenshotting: ScreenshottingStart; + security?: SecurityPluginStart; taskManager: TaskManagerStartContract; } From 356861d23bd887e5f2d5a2c0f0103a80f59715b8 Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Thu, 20 Jan 2022 22:04:19 +0000 Subject: [PATCH 104/108] chore(NA): splits types from code on @kbn/ui-shared-deps-src (#123313) * chore(NA): splits types from code on @kbn/ui-shared-deps-src * chore(NA): break flot-charts into another package * chore(NA): skip failing tests * chore(NA): remove skip and add correct value * chore(NA): fix new ui-theme import * chore(NA): adding fleet cloned test * chore(NA): remove cloned test * chore(NA): remove added typo --- .eslintignore | 2 +- .eslintrc.js | 2 +- .i18nrc.json | 2 +- package.json | 4 + packages/BUILD.bazel | 4 + .../elastic-eslint-config-kibana/.eslintrc.js | 2 +- .../flot_charts => kbn-flot-charts}/API.md | 0 packages/kbn-flot-charts/BUILD.bazel | 51 ++++++++ .../flot_charts => kbn-flot-charts}/index.js | 32 +++-- .../lib}/jquery_colorhelpers.js | 0 .../lib}/jquery_flot.js | 0 .../lib}/jquery_flot_axislabels.js | 0 .../lib}/jquery_flot_canvas.js | 0 .../lib}/jquery_flot_categories.js | 0 .../lib}/jquery_flot_crosshair.js | 0 .../lib}/jquery_flot_errorbars.js | 0 .../lib}/jquery_flot_fillbetween.js | 0 .../lib}/jquery_flot_image.js | 0 .../lib}/jquery_flot_log.js | 0 .../lib}/jquery_flot_navigate.js | 0 .../lib}/jquery_flot_pie.js | 0 .../lib}/jquery_flot_resize.js | 0 .../lib}/jquery_flot_selection.js | 0 .../lib}/jquery_flot_stack.js | 0 .../lib}/jquery_flot_symbol.js | 0 .../lib}/jquery_flot_threshold.js | 0 .../lib}/jquery_flot_time.js | 0 packages/kbn-flot-charts/package.json | 7 ++ packages/kbn-optimizer/BUILD.bazel | 2 +- .../src/worker/webpack.config.ts | 2 +- packages/kbn-storybook/BUILD.bazel | 2 +- .../src/lib/run_storybook_cli.ts | 2 +- packages/kbn-ui-shared-deps-src/BUILD.bazel | 32 +++-- .../flot_charts/package.json | 4 - packages/kbn-ui-shared-deps-src/package.json | 3 +- .../src/{index.js => definitions.js} | 13 ++- packages/kbn-ui-shared-deps-src/src/entry.js | 4 +- packages/kbn-ui-shared-deps-src/src/index.ts | 29 +++++ .../kbn-ui-shared-deps-src/theme/package.json | 4 - .../kbn-ui-shared-deps-src/webpack.config.js | 15 +-- packages/kbn-ui-theme/BUILD.bazel | 110 ++++++++++++++++++ packages/kbn-ui-theme/package.json | 8 ++ packages/kbn-ui-theme/src/index.ts | 11 ++ .../src/theme.ts | 0 packages/kbn-ui-theme/tsconfig.json | 14 +++ .../bundle_routes/register_bundle_routes.ts | 2 +- .../bootstrap/get_js_dependency_paths.ts | 2 +- src/core/server/rendering/render_utils.ts | 2 +- .../public/static/components/current_time.tsx | 5 +- .../public/static/components/endzones.tsx | 5 +- .../components/form_fields/type_field.tsx | 2 +- src/plugins/dev_tools/public/application.tsx | 2 +- .../discover_grid_document_selection.tsx | 5 +- .../discover_grid_expand_button.tsx | 5 +- .../discover_grid/get_render_cell_value.tsx | 5 +- .../components/pager/tool_bar_pagination.tsx | 2 +- .../public/react_expression_renderer.tsx | 2 +- .../components/tutorial/instruction_set.js | 2 +- .../public/cluster_configuration_form.tsx | 2 +- .../public/single_chars_field.tsx | 2 +- .../public/use_verification.tsx | 2 +- .../common/eui_styled_components.tsx | 2 +- .../public/code_editor/code_editor_field.tsx | 5 +- .../public/code_editor/editor_theme.ts | 5 +- .../public/data_model/vega_parser.test.js | 2 +- .../vega/public/data_model/vega_parser.ts | 2 +- .../vislib/components/tooltip/tooltip.js | 2 +- x-pack/plugins/apm/common/viz_colors.ts | 2 +- .../plugins/apm/public/application/uxApp.tsx | 2 +- .../percentile_annotations.tsx | 2 +- .../url_filter/url_search/render_option.tsx | 2 +- .../app/service_map/Controls.test.tsx | 2 +- .../public/components/routing/app_root.tsx | 2 +- .../apm/public/utils/httpStatusCodeToColor.ts | 2 +- .../java/gc/fetch_and_transform_gc_metrics.ts | 2 +- .../by_agent/java/gc/get_gc_rate_chart.ts | 2 +- .../by_agent/java/gc/get_gc_time_chart.ts | 2 +- .../by_agent/java/heap_memory/index.ts | 2 +- .../by_agent/java/non_heap_memory/index.ts | 2 +- .../by_agent/java/thread_count/index.ts | 2 +- .../metrics/by_agent/shared/cpu/index.ts | 2 +- .../metrics/fetch_and_transform_metrics.ts | 2 +- .../canvas/shareable_runtime/api/index.ts | 2 +- .../public/common/mock/test_providers.tsx | 2 +- .../components/header_page/index.test.tsx | 2 +- .../utility_bar/utility_bar.test.tsx | 2 +- .../stats_table/hooks/use_color_range.ts | 5 +- .../agents/components/agent_health.tsx | 2 +- .../sections/agents/services/agent_status.tsx | 2 +- .../shared_components/coloring/utils.ts | 2 +- .../xy_visualization/color_assignment.ts | 2 +- .../expression_reference_lines.tsx | 2 +- .../reducers/map/default_map_settings.ts | 2 +- .../ml/common/util/group_color_utils.ts | 2 +- .../color_range_legend/use_color_range.ts | 5 +- .../components/job_messages/job_messages.tsx | 2 +- .../scatterplot_matrix.test.tsx | 2 +- .../scatterplot_matrix_vega_lite_spec.test.ts | 2 +- .../scatterplot_matrix_vega_lite_spec.ts | 2 +- .../get_roc_curve_chart_vega_lite_spec.tsx | 2 +- .../decision_path_chart.tsx | 2 +- .../feature_importance_summary.tsx | 2 +- .../components/charts/common/settings.ts | 5 +- .../core_web_vitals/palette_legends.tsx | 2 +- x-pack/plugins/osquery/public/application.tsx | 2 +- .../public/components/token_field.tsx | 2 +- .../plugins/security/server/prompt_page.tsx | 2 +- .../__examples__/index.stories.tsx | 2 +- .../conditions_table/index.stories.tsx | 2 +- .../viewer/exception_item/index.stories.tsx | 2 +- .../exceptions_viewer_header.stories.tsx | 2 +- .../components/header_page/index.test.tsx | 2 +- .../components/header_section/index.test.tsx | 2 +- .../item_details_card/index.stories.tsx | 2 +- .../text_field_value/index.stories.tsx | 2 +- .../threat_match/logic_buttons.stories.tsx | 2 +- .../utility_bar/utility_bar.test.tsx | 2 +- .../public/common/lib/theme/use_eui_theme.tsx | 5 +- .../public/common/mock/test_providers.tsx | 2 +- .../components/rules/severity_badge/index.tsx | 2 +- .../components/rules/step_about_rule/data.tsx | 2 +- .../common/host_risk_score.test.tsx | 2 +- .../components/common/host_risk_score.tsx | 2 +- .../components/host_score_over_time/index.tsx | 2 +- .../kpi_hosts/risky_hosts/index.tsx | 2 +- .../components/config_form/index.stories.tsx | 2 +- .../trusted_apps_grid/index.stories.tsx | 2 +- .../view_type_toggle/index.stories.tsx | 2 +- .../network/components/details/index.tsx | 5 +- .../map_tool_tip/tooltip_footer.tsx | 2 +- .../components/host_overview/index.tsx | 5 +- .../public/resolver/view/use_colors.ts | 2 +- .../public/resolver/view/use_cube_assets.ts | 2 +- .../body/column_headers/helpers.test.tsx | 2 +- .../t_grid/body/column_headers/helpers.tsx | 2 +- .../components/t_grid/body/constants.ts | 2 +- .../components/t_grid/body/helpers.test.tsx | 2 +- .../t_grid/integrated/index.test.tsx | 2 +- .../timelines/public/mock/test_providers.tsx | 2 +- .../expanded_row_messages_pane.tsx | 2 +- .../components/execution_duration_chart.tsx | 2 +- .../public/contexts/uptime_theme_context.tsx | 2 +- yarn.lock | 16 +++ 143 files changed, 417 insertions(+), 193 deletions(-) rename packages/{kbn-ui-shared-deps-src/src/flot_charts => kbn-flot-charts}/API.md (100%) create mode 100644 packages/kbn-flot-charts/BUILD.bazel rename packages/{kbn-ui-shared-deps-src/src/flot_charts => kbn-flot-charts}/index.js (62%) rename packages/{kbn-ui-shared-deps-src/src/flot_charts => kbn-flot-charts/lib}/jquery_colorhelpers.js (100%) rename packages/{kbn-ui-shared-deps-src/src/flot_charts => kbn-flot-charts/lib}/jquery_flot.js (100%) rename packages/{kbn-ui-shared-deps-src/src/flot_charts => kbn-flot-charts/lib}/jquery_flot_axislabels.js (100%) rename packages/{kbn-ui-shared-deps-src/src/flot_charts => kbn-flot-charts/lib}/jquery_flot_canvas.js (100%) rename packages/{kbn-ui-shared-deps-src/src/flot_charts => kbn-flot-charts/lib}/jquery_flot_categories.js (100%) rename packages/{kbn-ui-shared-deps-src/src/flot_charts => kbn-flot-charts/lib}/jquery_flot_crosshair.js (100%) rename packages/{kbn-ui-shared-deps-src/src/flot_charts => kbn-flot-charts/lib}/jquery_flot_errorbars.js (100%) rename packages/{kbn-ui-shared-deps-src/src/flot_charts => kbn-flot-charts/lib}/jquery_flot_fillbetween.js (100%) rename packages/{kbn-ui-shared-deps-src/src/flot_charts => kbn-flot-charts/lib}/jquery_flot_image.js (100%) rename packages/{kbn-ui-shared-deps-src/src/flot_charts => kbn-flot-charts/lib}/jquery_flot_log.js (100%) rename packages/{kbn-ui-shared-deps-src/src/flot_charts => kbn-flot-charts/lib}/jquery_flot_navigate.js (100%) rename packages/{kbn-ui-shared-deps-src/src/flot_charts => kbn-flot-charts/lib}/jquery_flot_pie.js (100%) rename packages/{kbn-ui-shared-deps-src/src/flot_charts => kbn-flot-charts/lib}/jquery_flot_resize.js (100%) rename packages/{kbn-ui-shared-deps-src/src/flot_charts => kbn-flot-charts/lib}/jquery_flot_selection.js (100%) rename packages/{kbn-ui-shared-deps-src/src/flot_charts => kbn-flot-charts/lib}/jquery_flot_stack.js (100%) rename packages/{kbn-ui-shared-deps-src/src/flot_charts => kbn-flot-charts/lib}/jquery_flot_symbol.js (100%) rename packages/{kbn-ui-shared-deps-src/src/flot_charts => kbn-flot-charts/lib}/jquery_flot_threshold.js (100%) rename packages/{kbn-ui-shared-deps-src/src/flot_charts => kbn-flot-charts/lib}/jquery_flot_time.js (100%) create mode 100755 packages/kbn-flot-charts/package.json delete mode 100644 packages/kbn-ui-shared-deps-src/flot_charts/package.json rename packages/kbn-ui-shared-deps-src/src/{index.js => definitions.js} (89%) create mode 100644 packages/kbn-ui-shared-deps-src/src/index.ts delete mode 100644 packages/kbn-ui-shared-deps-src/theme/package.json create mode 100644 packages/kbn-ui-theme/BUILD.bazel create mode 100644 packages/kbn-ui-theme/package.json create mode 100644 packages/kbn-ui-theme/src/index.ts rename packages/{kbn-ui-shared-deps-src => kbn-ui-theme}/src/theme.ts (100%) create mode 100644 packages/kbn-ui-theme/tsconfig.json diff --git a/.eslintignore b/.eslintignore index 5ae3fe7b0967d6..7b9b7f77e83792 100644 --- a/.eslintignore +++ b/.eslintignore @@ -35,7 +35,7 @@ snapshots.js /packages/kbn-test/src/functional_test_runner/__tests__/fixtures/ /packages/kbn-test/src/functional_test_runner/lib/config/__tests__/fixtures/ /packages/kbn-ui-framework/dist -/packages/kbn-ui-shared-deps-src/src/flot_charts +/packages/kbn-flot-charts/lib /packages/kbn-monaco/src/painless/antlr # Bazel diff --git a/.eslintrc.js b/.eslintrc.js index b303a9fefb6914..5ee75d186eb240 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1569,7 +1569,7 @@ module.exports = { }, }, { - files: ['packages/kbn-ui-shared-deps-src/src/flot_charts/**/*.js'], + files: ['packages/kbn-flot-charts/lib/**/*.js'], env: { jquery: true, }, diff --git a/.i18nrc.json b/.i18nrc.json index 4331c170d141fc..043e1e28a0e9db 100644 --- a/.i18nrc.json +++ b/.i18nrc.json @@ -32,7 +32,7 @@ "expressionShape": "src/plugins/expression_shape", "expressionTagcloud": "src/plugins/chart_expressions/expression_tagcloud", "fieldFormats": "src/plugins/field_formats", - "flot": "packages/kbn-ui-shared-deps-src/src/flot_charts", + "flot": "packages/kbn-flot-charts/lib", "home": "src/plugins/home", "indexPatternEditor": "src/plugins/data_view_editor", "indexPatternFieldEditor": "src/plugins/data_view_field_editor", diff --git a/package.json b/package.json index 0bd1b5c9e5b552..4e7044b458a44f 100644 --- a/package.json +++ b/package.json @@ -137,6 +137,7 @@ "@kbn/crypto": "link:bazel-bin/packages/kbn-crypto", "@kbn/es-query": "link:bazel-bin/packages/kbn-es-query", "@kbn/field-types": "link:bazel-bin/packages/kbn-field-types", + "@kbn/flot-charts": "link:bazel-bin/packages/kbn-flot-charts", "@kbn/i18n": "link:bazel-bin/packages/kbn-i18n", "@kbn/i18n-react": "link:bazel-bin/packages/kbn-i18n-react", "@kbn/interpreter": "link:bazel-bin/packages/kbn-interpreter", @@ -169,6 +170,7 @@ "@kbn/ui-framework": "link:bazel-bin/packages/kbn-ui-framework", "@kbn/ui-shared-deps-npm": "link:bazel-bin/packages/kbn-ui-shared-deps-npm", "@kbn/ui-shared-deps-src": "link:bazel-bin/packages/kbn-ui-shared-deps-src", + "@kbn/ui-theme": "link:bazel-bin/packages/kbn-ui-theme", "@kbn/utility-types": "link:bazel-bin/packages/kbn-utility-types", "@kbn/utils": "link:bazel-bin/packages/kbn-utils", "@loaders.gl/core": "^2.3.1", @@ -602,6 +604,8 @@ "@types/kbn__std": "link:bazel-bin/packages/kbn-std/npm_module_types", "@types/kbn__telemetry-tools": "link:bazel-bin/packages/kbn-telemetry-tools/npm_module_types", "@types/kbn__ui-shared-deps-npm": "link:bazel-bin/packages/kbn-ui-shared-deps-npm/npm_module_types", + "@types/kbn__ui-shared-deps-src": "link:bazel-bin/packages/kbn-ui-shared-deps-src/npm_module_types", + "@types/kbn__ui-theme": "link:bazel-bin/packages/kbn-ui-theme/npm_module_types", "@types/kbn__utility-types": "link:bazel-bin/packages/kbn-utility-types/npm_module_types", "@types/kbn__utils": "link:bazel-bin/packages/kbn-utils/npm_module_types", "@types/license-checker": "15.0.0", diff --git a/packages/BUILD.bazel b/packages/BUILD.bazel index 7c8259b2f6857e..be4d1087bc21a2 100644 --- a/packages/BUILD.bazel +++ b/packages/BUILD.bazel @@ -26,6 +26,7 @@ filegroup( "//packages/kbn-eslint-plugin-eslint:build", "//packages/kbn-expect:build", "//packages/kbn-field-types:build", + "//packages/kbn-flot-charts:build", "//packages/kbn-i18n:build", "//packages/kbn-i18n-react:build", "//packages/kbn-interpreter:build", @@ -66,6 +67,7 @@ filegroup( "//packages/kbn-ui-framework:build", "//packages/kbn-ui-shared-deps-npm:build", "//packages/kbn-ui-shared-deps-src:build", + "//packages/kbn-ui-theme:build", "//packages/kbn-utility-types:build", "//packages/kbn-utils:build", ], @@ -121,6 +123,8 @@ filegroup( "//packages/kbn-std:build_types", "//packages/kbn-telemetry-tools:build_types", "//packages/kbn-ui-shared-deps-npm:build_types", + "//packages/kbn-ui-shared-deps-src:build_types", + "//packages/kbn-ui-theme:build_types", "//packages/kbn-utility-types:build_types", "//packages/kbn-utils:build_types", ], diff --git a/packages/elastic-eslint-config-kibana/.eslintrc.js b/packages/elastic-eslint-config-kibana/.eslintrc.js index fe6ea54bbde055..8193380d662d8c 100644 --- a/packages/elastic-eslint-config-kibana/.eslintrc.js +++ b/packages/elastic-eslint-config-kibana/.eslintrc.js @@ -94,7 +94,7 @@ module.exports = { ].map(from => ({ from, to: false, - disallowedMessage: `Use "@kbn/ui-shared-deps-src/theme" to access theme vars.` + disallowedMessage: `Use "@kbn/ui-theme" to access theme vars.` })), ], ], diff --git a/packages/kbn-ui-shared-deps-src/src/flot_charts/API.md b/packages/kbn-flot-charts/API.md similarity index 100% rename from packages/kbn-ui-shared-deps-src/src/flot_charts/API.md rename to packages/kbn-flot-charts/API.md diff --git a/packages/kbn-flot-charts/BUILD.bazel b/packages/kbn-flot-charts/BUILD.bazel new file mode 100644 index 00000000000000..d819fa05c7d16d --- /dev/null +++ b/packages/kbn-flot-charts/BUILD.bazel @@ -0,0 +1,51 @@ +load("@build_bazel_rules_nodejs//:index.bzl", "js_library") +load("//src/dev/bazel:index.bzl", "pkg_npm") + +PKG_BASE_NAME = "kbn-flot-charts" +PKG_REQUIRE_NAME = "@kbn/flot-charts" + +SOURCE_FILES = glob([ + "lib/**/*.js", + "index.js", +]) + +SRCS = SOURCE_FILES + +filegroup( + name = "srcs", + srcs = SRCS, +) + +NPM_MODULE_EXTRA_FILES = [ + "package.json", + "API.md", +] + +RUNTIME_DEPS = [ + "//packages/kbn-i18n", +] + +js_library( + name = PKG_BASE_NAME, + srcs = NPM_MODULE_EXTRA_FILES + [ + ":srcs", + ], + deps = RUNTIME_DEPS, + package_name = PKG_REQUIRE_NAME, + visibility = ["//visibility:public"], +) + +pkg_npm( + name = "npm_module", + deps = [ + ":%s" % PKG_BASE_NAME, + ] +) + +filegroup( + name = "build", + srcs = [ + ":npm_module", + ], + visibility = ["//visibility:public"], +) diff --git a/packages/kbn-ui-shared-deps-src/src/flot_charts/index.js b/packages/kbn-flot-charts/index.js similarity index 62% rename from packages/kbn-ui-shared-deps-src/src/flot_charts/index.js rename to packages/kbn-flot-charts/index.js index 4f6468262e3b43..5f0620f6c61fb1 100644 --- a/packages/kbn-ui-shared-deps-src/src/flot_charts/index.js +++ b/packages/kbn-flot-charts/index.js @@ -1,3 +1,11 @@ +/* + * 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. + */ + /* @notice * * This product includes code that is based on flot-charts, which was available @@ -26,15 +34,15 @@ * THE SOFTWARE. */ -import './jquery_flot'; -import './jquery_flot_canvas'; -import './jquery_flot_time'; -import './jquery_flot_symbol'; -import './jquery_flot_crosshair'; -import './jquery_flot_selection'; -import './jquery_flot_pie'; -import './jquery_flot_stack'; -import './jquery_flot_threshold'; -import './jquery_flot_fillbetween'; -import './jquery_flot_log'; -import './jquery_flot_axislabels'; +import './lib/jquery_flot'; +import './lib/jquery_flot_canvas'; +import './lib/jquery_flot_time'; +import './lib/jquery_flot_symbol'; +import './lib/jquery_flot_crosshair'; +import './lib/jquery_flot_selection'; +import './lib/jquery_flot_pie'; +import './lib/jquery_flot_stack'; +import './lib/jquery_flot_threshold'; +import './lib/jquery_flot_fillbetween'; +import './lib/jquery_flot_log'; +import './lib/jquery_flot_axislabels'; diff --git a/packages/kbn-ui-shared-deps-src/src/flot_charts/jquery_colorhelpers.js b/packages/kbn-flot-charts/lib/jquery_colorhelpers.js similarity index 100% rename from packages/kbn-ui-shared-deps-src/src/flot_charts/jquery_colorhelpers.js rename to packages/kbn-flot-charts/lib/jquery_colorhelpers.js diff --git a/packages/kbn-ui-shared-deps-src/src/flot_charts/jquery_flot.js b/packages/kbn-flot-charts/lib/jquery_flot.js similarity index 100% rename from packages/kbn-ui-shared-deps-src/src/flot_charts/jquery_flot.js rename to packages/kbn-flot-charts/lib/jquery_flot.js diff --git a/packages/kbn-ui-shared-deps-src/src/flot_charts/jquery_flot_axislabels.js b/packages/kbn-flot-charts/lib/jquery_flot_axislabels.js similarity index 100% rename from packages/kbn-ui-shared-deps-src/src/flot_charts/jquery_flot_axislabels.js rename to packages/kbn-flot-charts/lib/jquery_flot_axislabels.js diff --git a/packages/kbn-ui-shared-deps-src/src/flot_charts/jquery_flot_canvas.js b/packages/kbn-flot-charts/lib/jquery_flot_canvas.js similarity index 100% rename from packages/kbn-ui-shared-deps-src/src/flot_charts/jquery_flot_canvas.js rename to packages/kbn-flot-charts/lib/jquery_flot_canvas.js diff --git a/packages/kbn-ui-shared-deps-src/src/flot_charts/jquery_flot_categories.js b/packages/kbn-flot-charts/lib/jquery_flot_categories.js similarity index 100% rename from packages/kbn-ui-shared-deps-src/src/flot_charts/jquery_flot_categories.js rename to packages/kbn-flot-charts/lib/jquery_flot_categories.js diff --git a/packages/kbn-ui-shared-deps-src/src/flot_charts/jquery_flot_crosshair.js b/packages/kbn-flot-charts/lib/jquery_flot_crosshair.js similarity index 100% rename from packages/kbn-ui-shared-deps-src/src/flot_charts/jquery_flot_crosshair.js rename to packages/kbn-flot-charts/lib/jquery_flot_crosshair.js diff --git a/packages/kbn-ui-shared-deps-src/src/flot_charts/jquery_flot_errorbars.js b/packages/kbn-flot-charts/lib/jquery_flot_errorbars.js similarity index 100% rename from packages/kbn-ui-shared-deps-src/src/flot_charts/jquery_flot_errorbars.js rename to packages/kbn-flot-charts/lib/jquery_flot_errorbars.js diff --git a/packages/kbn-ui-shared-deps-src/src/flot_charts/jquery_flot_fillbetween.js b/packages/kbn-flot-charts/lib/jquery_flot_fillbetween.js similarity index 100% rename from packages/kbn-ui-shared-deps-src/src/flot_charts/jquery_flot_fillbetween.js rename to packages/kbn-flot-charts/lib/jquery_flot_fillbetween.js diff --git a/packages/kbn-ui-shared-deps-src/src/flot_charts/jquery_flot_image.js b/packages/kbn-flot-charts/lib/jquery_flot_image.js similarity index 100% rename from packages/kbn-ui-shared-deps-src/src/flot_charts/jquery_flot_image.js rename to packages/kbn-flot-charts/lib/jquery_flot_image.js diff --git a/packages/kbn-ui-shared-deps-src/src/flot_charts/jquery_flot_log.js b/packages/kbn-flot-charts/lib/jquery_flot_log.js similarity index 100% rename from packages/kbn-ui-shared-deps-src/src/flot_charts/jquery_flot_log.js rename to packages/kbn-flot-charts/lib/jquery_flot_log.js diff --git a/packages/kbn-ui-shared-deps-src/src/flot_charts/jquery_flot_navigate.js b/packages/kbn-flot-charts/lib/jquery_flot_navigate.js similarity index 100% rename from packages/kbn-ui-shared-deps-src/src/flot_charts/jquery_flot_navigate.js rename to packages/kbn-flot-charts/lib/jquery_flot_navigate.js diff --git a/packages/kbn-ui-shared-deps-src/src/flot_charts/jquery_flot_pie.js b/packages/kbn-flot-charts/lib/jquery_flot_pie.js similarity index 100% rename from packages/kbn-ui-shared-deps-src/src/flot_charts/jquery_flot_pie.js rename to packages/kbn-flot-charts/lib/jquery_flot_pie.js diff --git a/packages/kbn-ui-shared-deps-src/src/flot_charts/jquery_flot_resize.js b/packages/kbn-flot-charts/lib/jquery_flot_resize.js similarity index 100% rename from packages/kbn-ui-shared-deps-src/src/flot_charts/jquery_flot_resize.js rename to packages/kbn-flot-charts/lib/jquery_flot_resize.js diff --git a/packages/kbn-ui-shared-deps-src/src/flot_charts/jquery_flot_selection.js b/packages/kbn-flot-charts/lib/jquery_flot_selection.js similarity index 100% rename from packages/kbn-ui-shared-deps-src/src/flot_charts/jquery_flot_selection.js rename to packages/kbn-flot-charts/lib/jquery_flot_selection.js diff --git a/packages/kbn-ui-shared-deps-src/src/flot_charts/jquery_flot_stack.js b/packages/kbn-flot-charts/lib/jquery_flot_stack.js similarity index 100% rename from packages/kbn-ui-shared-deps-src/src/flot_charts/jquery_flot_stack.js rename to packages/kbn-flot-charts/lib/jquery_flot_stack.js diff --git a/packages/kbn-ui-shared-deps-src/src/flot_charts/jquery_flot_symbol.js b/packages/kbn-flot-charts/lib/jquery_flot_symbol.js similarity index 100% rename from packages/kbn-ui-shared-deps-src/src/flot_charts/jquery_flot_symbol.js rename to packages/kbn-flot-charts/lib/jquery_flot_symbol.js diff --git a/packages/kbn-ui-shared-deps-src/src/flot_charts/jquery_flot_threshold.js b/packages/kbn-flot-charts/lib/jquery_flot_threshold.js similarity index 100% rename from packages/kbn-ui-shared-deps-src/src/flot_charts/jquery_flot_threshold.js rename to packages/kbn-flot-charts/lib/jquery_flot_threshold.js diff --git a/packages/kbn-ui-shared-deps-src/src/flot_charts/jquery_flot_time.js b/packages/kbn-flot-charts/lib/jquery_flot_time.js similarity index 100% rename from packages/kbn-ui-shared-deps-src/src/flot_charts/jquery_flot_time.js rename to packages/kbn-flot-charts/lib/jquery_flot_time.js diff --git a/packages/kbn-flot-charts/package.json b/packages/kbn-flot-charts/package.json new file mode 100755 index 00000000000000..8942cd6a053260 --- /dev/null +++ b/packages/kbn-flot-charts/package.json @@ -0,0 +1,7 @@ +{ + "name": "@kbn/flot-charts", + "version": "1.0.0", + "private": true, + "main": "./index.js", + "license": "SSPL-1.0 OR Elastic License 2.0" +} \ No newline at end of file diff --git a/packages/kbn-optimizer/BUILD.bazel b/packages/kbn-optimizer/BUILD.bazel index 0e5e99c5d1096d..9486f309bd0f3d 100644 --- a/packages/kbn-optimizer/BUILD.bazel +++ b/packages/kbn-optimizer/BUILD.bazel @@ -70,7 +70,7 @@ TYPES_DEPS = [ "//packages/kbn-dev-utils:npm_module_types", "//packages/kbn-std:npm_module_types", "//packages/kbn-ui-shared-deps-npm:npm_module_types", - "//packages/kbn-ui-shared-deps-src", + "//packages/kbn-ui-shared-deps-src:npm_module_types", "//packages/kbn-utils:npm_module_types", "@npm//chalk", "@npm//clean-webpack-plugin", diff --git a/packages/kbn-optimizer/src/worker/webpack.config.ts b/packages/kbn-optimizer/src/worker/webpack.config.ts index 58201152a24597..9454456a35c9ab 100644 --- a/packages/kbn-optimizer/src/worker/webpack.config.ts +++ b/packages/kbn-optimizer/src/worker/webpack.config.ts @@ -16,7 +16,7 @@ import webpackMerge from 'webpack-merge'; import { CleanWebpackPlugin } from 'clean-webpack-plugin'; import CompressionPlugin from 'compression-webpack-plugin'; import UiSharedDepsNpm from '@kbn/ui-shared-deps-npm'; -import UiSharedDepsSrc from '@kbn/ui-shared-deps-src'; +import * as UiSharedDepsSrc from '@kbn/ui-shared-deps-src'; import { Bundle, BundleRefs, WorkerConfig } from '../common'; import { BundleRefsPlugin } from './bundle_refs_plugin'; diff --git a/packages/kbn-storybook/BUILD.bazel b/packages/kbn-storybook/BUILD.bazel index 873167674dd78e..fc7599b0583739 100644 --- a/packages/kbn-storybook/BUILD.bazel +++ b/packages/kbn-storybook/BUILD.bazel @@ -52,7 +52,7 @@ RUNTIME_DEPS = [ TYPES_DEPS = [ "//packages/kbn-dev-utils:npm_module_types", "//packages/kbn-ui-shared-deps-npm:npm_module_types", - "//packages/kbn-ui-shared-deps-src", + "//packages/kbn-ui-shared-deps-src:npm_module_types", "//packages/kbn-utils:npm_module_types", "@npm//@elastic/eui", "@npm//@emotion/cache", diff --git a/packages/kbn-storybook/src/lib/run_storybook_cli.ts b/packages/kbn-storybook/src/lib/run_storybook_cli.ts index 93197a1f2b3183..fa0df75035812a 100644 --- a/packages/kbn-storybook/src/lib/run_storybook_cli.ts +++ b/packages/kbn-storybook/src/lib/run_storybook_cli.ts @@ -11,7 +11,7 @@ import { logger } from '@storybook/node-logger'; import buildStandalone from '@storybook/react/standalone'; import { Flags, run } from '@kbn/dev-utils'; import UiSharedDepsNpm from '@kbn/ui-shared-deps-npm'; -import UiSharedDepsSrc from '@kbn/ui-shared-deps-src'; +import * as UiSharedDepsSrc from '@kbn/ui-shared-deps-src'; import * as constants from './constants'; // Convert the flags to a Storybook loglevel diff --git a/packages/kbn-ui-shared-deps-src/BUILD.bazel b/packages/kbn-ui-shared-deps-src/BUILD.bazel index ce2cbe714a16c8..3617956b15c4a6 100644 --- a/packages/kbn-ui-shared-deps-src/BUILD.bazel +++ b/packages/kbn-ui-shared-deps-src/BUILD.bazel @@ -1,10 +1,11 @@ -load("@npm//@bazel/typescript:index.bzl", "ts_config", "ts_project") -load("@build_bazel_rules_nodejs//:index.bzl", "js_library", "pkg_npm") +load("@npm//@bazel/typescript:index.bzl", "ts_config") +load("@build_bazel_rules_nodejs//:index.bzl", "js_library") load("@npm//webpack-cli:index.bzl", webpack = "webpack_cli") -load("//src/dev/bazel:index.bzl", "jsts_transpiler") +load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") PKG_BASE_NAME = "kbn-ui-shared-deps-src" PKG_REQUIRE_NAME = "@kbn/ui-shared-deps-src" +TYPES_PKG_REQUIRE_NAME = "@types/kbn__ui-shared-deps-src" SOURCE_FILES = glob( [ @@ -23,8 +24,6 @@ filegroup( ) NPM_MODULE_EXTRA_FILES = [ - "flot_charts/package.json", - "theme/package.json", "package.json", "README.md" ] @@ -34,11 +33,13 @@ RUNTIME_DEPS = [ "//packages/elastic-safer-lodash-set", "//packages/kbn-analytics", "//packages/kbn-babel-preset", + "//packages/kbn-flot-charts", "//packages/kbn-i18n", "//packages/kbn-i18n-react", "//packages/kbn-monaco", "//packages/kbn-std", "//packages/kbn-ui-shared-deps-npm", + "//packages/kbn-ui-theme", ] TYPES_DEPS = [ @@ -50,7 +51,7 @@ TYPES_DEPS = [ "//packages/kbn-monaco:npm_module_types", "//packages/kbn-std:npm_module_types", "//packages/kbn-ui-shared-deps-npm:npm_module_types", - "@npm//@elastic/eui", + "//packages/kbn-ui-theme:npm_module_types", "@npm//webpack", ] @@ -105,7 +106,7 @@ webpack( js_library( name = PKG_BASE_NAME, srcs = NPM_MODULE_EXTRA_FILES, - deps = RUNTIME_DEPS + [":target_node", ":tsc_types", ":shared_built_assets"], + deps = RUNTIME_DEPS + [":target_node", ":shared_built_assets"], package_name = PKG_REQUIRE_NAME, visibility = ["//visibility:public"], ) @@ -124,3 +125,20 @@ filegroup( ], visibility = ["//visibility:public"], ) + +pkg_npm_types( + name = "npm_module_types", + srcs = SRCS, + deps = [":tsc_types"], + package_name = TYPES_PKG_REQUIRE_NAME, + tsconfig = ":tsconfig", + visibility = ["//visibility:public"], +) + +filegroup( + name = "build_types", + srcs = [ + ":npm_module_types", + ], + visibility = ["//visibility:public"], +) diff --git a/packages/kbn-ui-shared-deps-src/flot_charts/package.json b/packages/kbn-ui-shared-deps-src/flot_charts/package.json deleted file mode 100644 index 6c2f62447daf5a..00000000000000 --- a/packages/kbn-ui-shared-deps-src/flot_charts/package.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "main": "../target_node/flot_charts/index.js", - "types": "../target_types/flot_charts/index.d.ts" -} \ No newline at end of file diff --git a/packages/kbn-ui-shared-deps-src/package.json b/packages/kbn-ui-shared-deps-src/package.json index 246c19496a5c05..e45e8d5496988e 100644 --- a/packages/kbn-ui-shared-deps-src/package.json +++ b/packages/kbn-ui-shared-deps-src/package.json @@ -3,6 +3,5 @@ "version": "1.0.0", "private": true, "license": "SSPL-1.0 OR Elastic License 2.0", - "main": "target_node/index.js", - "types": "target_types/index.d.ts" + "main": "target_node/index.js" } \ No newline at end of file diff --git a/packages/kbn-ui-shared-deps-src/src/index.js b/packages/kbn-ui-shared-deps-src/src/definitions.js similarity index 89% rename from packages/kbn-ui-shared-deps-src/src/index.js rename to packages/kbn-ui-shared-deps-src/src/definitions.js index 41ea7b03c9eb34..ce859ca4b977f6 100644 --- a/packages/kbn-ui-shared-deps-src/src/index.js +++ b/packages/kbn-ui-shared-deps-src/src/definitions.js @@ -8,28 +8,30 @@ const Path = require('path'); +// extracted const vars /** * Absolute path to the distributable directory */ -exports.distDir = Path.resolve(__dirname, '../shared_built_assets'); +const distDir = Path.resolve(__dirname, '../shared_built_assets'); /** * Filename of the main bundle file in the distributable directory */ -exports.jsFilename = 'kbn-ui-shared-deps-src.js'; +const jsFilename = 'kbn-ui-shared-deps-src.js'; /** * Filename of the main bundle file in the distributable directory */ -exports.cssDistFilename = 'kbn-ui-shared-deps-src.css'; +const cssDistFilename = 'kbn-ui-shared-deps-src.css'; /** * Externals mapping inteded to be used in a webpack config */ -exports.externals = { +const externals = { /** * stateful deps */ + '@kbn/ui-theme': '__kbnSharedDeps__.KbnUiTheme', '@kbn/i18n': '__kbnSharedDeps__.KbnI18n', '@kbn/i18n-react': '__kbnSharedDeps__.KbnI18nReact', '@emotion/react': '__kbnSharedDeps__.EmotionReact', @@ -43,7 +45,6 @@ exports.externals = { 'react-router-dom': '__kbnSharedDeps__.ReactRouterDom', 'styled-components': '__kbnSharedDeps__.StyledComponents', '@kbn/monaco': '__kbnSharedDeps__.KbnMonaco', - '@kbn/ui-shared-deps-src/theme': '__kbnSharedDeps__.Theme', // this is how plugins/consumers from npm load monaco 'monaco-editor/esm/vs/editor/editor.api': '__kbnSharedDeps__.MonacoBarePluginApi', @@ -77,3 +78,5 @@ exports.externals = { history: '__kbnSharedDeps__.History', classnames: '__kbnSharedDeps__.Classnames', }; + +module.exports = { distDir, jsFilename, cssDistFilename, externals }; diff --git a/packages/kbn-ui-shared-deps-src/src/entry.js b/packages/kbn-ui-shared-deps-src/src/entry.js index 424eb4b55cc64d..a52dcc1440efbd 100644 --- a/packages/kbn-ui-shared-deps-src/src/entry.js +++ b/packages/kbn-ui-shared-deps-src/src/entry.js @@ -11,9 +11,10 @@ require('./polyfills'); export const Jquery = require('jquery'); window.$ = window.jQuery = Jquery; // mutates window.jQuery and window.$ -require('./flot_charts'); +require('@kbn/flot-charts'); // stateful deps +export const KbnUiTheme = require('@kbn/ui-theme'); export const KbnI18n = require('@kbn/i18n'); export const KbnI18nReact = require('@kbn/i18n-react'); export const EmotionReact = require('@emotion/react'); @@ -43,7 +44,6 @@ export const ElasticEuiChartsTheme = require('@elastic/eui/dist/eui_charts_theme export const ElasticDatemath = require('@elastic/datemath'); export const ReactBeautifulDnD = require('react-beautiful-dnd'); -export const Theme = require('./theme.ts'); export const Lodash = require('lodash'); export const LodashFp = require('lodash/fp'); diff --git a/packages/kbn-ui-shared-deps-src/src/index.ts b/packages/kbn-ui-shared-deps-src/src/index.ts new file mode 100644 index 00000000000000..c5ed025969fade --- /dev/null +++ b/packages/kbn-ui-shared-deps-src/src/index.ts @@ -0,0 +1,29 @@ +/* + * 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. + */ + +import { distDir, jsFilename, cssDistFilename, externals } from './definitions'; + +/** + * Absolute path to the distributable directory + */ +export { distDir }; + +/** + * Filename of the main bundle file in the distributable directory + */ +export { jsFilename }; + +/** + * Filename of the main bundle file in the distributable directory + */ +export { cssDistFilename }; + +/** + * Externals mapping inteded to be used in a webpack config + */ +export { externals }; diff --git a/packages/kbn-ui-shared-deps-src/theme/package.json b/packages/kbn-ui-shared-deps-src/theme/package.json deleted file mode 100644 index 37d60f83b18e9a..00000000000000 --- a/packages/kbn-ui-shared-deps-src/theme/package.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "main": "../target_node/theme.js", - "types": "../target_types/theme.d.ts" -} \ No newline at end of file diff --git a/packages/kbn-ui-shared-deps-src/webpack.config.js b/packages/kbn-ui-shared-deps-src/webpack.config.js index ad84c9444fd0fa..cd9f3fed1953e9 100644 --- a/packages/kbn-ui-shared-deps-src/webpack.config.js +++ b/packages/kbn-ui-shared-deps-src/webpack.config.js @@ -12,7 +12,7 @@ const webpack = require('webpack'); const MiniCssExtractPlugin = require('mini-css-extract-plugin'); const UiSharedDepsNpm = require('@kbn/ui-shared-deps-npm'); -const UiSharedDepsSrc = require('./src'); +const { distDir: UiSharedDepsSrcDistDir } = require('./src/definitions'); const MOMENT_SRC = require.resolve('moment/min/moment-with-locales.js'); @@ -33,7 +33,7 @@ module.exports = { context: __dirname, devtool: 'cheap-source-map', output: { - path: UiSharedDepsSrc.distDir, + path: UiSharedDepsSrcDistDir, filename: '[name].js', chunkFilename: 'kbn-ui-shared-deps-src.chunk.[id].js', sourceMapFilename: '[file].map', @@ -56,17 +56,6 @@ module.exports = { }, ], }, - { - include: [require.resolve('./src/theme.ts')], - use: [ - { - loader: 'babel-loader', - options: { - presets: [require.resolve('@kbn/babel-preset/webpack_preset')], - }, - }, - ], - }, { test: /\.css$/, use: [MiniCssExtractPlugin.loader, 'css-loader'], diff --git a/packages/kbn-ui-theme/BUILD.bazel b/packages/kbn-ui-theme/BUILD.bazel new file mode 100644 index 00000000000000..8e388efe23757d --- /dev/null +++ b/packages/kbn-ui-theme/BUILD.bazel @@ -0,0 +1,110 @@ +load("@npm//@bazel/typescript:index.bzl", "ts_config") +load("@build_bazel_rules_nodejs//:index.bzl", "js_library") +load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") + +PKG_BASE_NAME = "kbn-ui-theme" +PKG_REQUIRE_NAME = "@kbn/ui-theme" +TYPES_PKG_REQUIRE_NAME = "@types/kbn__ui-theme" + +SOURCE_FILES = glob( + [ + "src/**/*.ts", + ], +) + +SRCS = SOURCE_FILES + +filegroup( + name = "srcs", + srcs = SRCS, +) + +NPM_MODULE_EXTRA_FILES = [ + "package.json", +] + +RUNTIME_DEPS = [ + "@npm//@elastic/eui", +] + +TYPES_DEPS = [ + "@npm//@elastic/eui", + "@npm//@types/node", + "@npm//tslib", +] + +jsts_transpiler( + name = "target_node", + srcs = SRCS, + build_pkg_name = package_name(), +) + +jsts_transpiler( + name = "target_web", + srcs = SRCS, + build_pkg_name = package_name(), + web = True, +) + +ts_config( + name = "tsconfig", + src = "tsconfig.json", + deps = [ + "//:tsconfig.base.json", + "//:tsconfig.bazel.json", + ], +) + +ts_project( + name = "tsc_types", + args = ['--pretty'], + srcs = SRCS, + deps = TYPES_DEPS, + declaration = True, + declaration_map = True, + emit_declaration_only = True, + out_dir = "target_types", + source_map = True, + root_dir = "src", + tsconfig = ":tsconfig", +) + +js_library( + name = PKG_BASE_NAME, + srcs = NPM_MODULE_EXTRA_FILES, + deps = RUNTIME_DEPS + [":target_node", ":target_web"], + package_name = PKG_REQUIRE_NAME, + visibility = ["//visibility:public"], +) + +pkg_npm( + name = "npm_module", + deps = [ + ":%s" % PKG_BASE_NAME, + ] +) + +filegroup( + name = "build", + srcs = [ + ":npm_module", + ], + visibility = ["//visibility:public"], +) + +pkg_npm_types( + name = "npm_module_types", + srcs = SRCS, + deps = [":tsc_types"], + package_name = TYPES_PKG_REQUIRE_NAME, + tsconfig = ":tsconfig", + visibility = ["//visibility:public"], +) + +filegroup( + name = "build_types", + srcs = [ + ":npm_module_types", + ], + visibility = ["//visibility:public"], +) diff --git a/packages/kbn-ui-theme/package.json b/packages/kbn-ui-theme/package.json new file mode 100644 index 00000000000000..40fd88b77e7b5f --- /dev/null +++ b/packages/kbn-ui-theme/package.json @@ -0,0 +1,8 @@ +{ + "name": "@kbn/ui-theme", + "version": "1.0.0", + "private": true, + "main": "./target_node/index.js", + "browser": "./target_web/index.js", + "license": "SSPL-1.0 OR Elastic License 2.0" +} diff --git a/packages/kbn-ui-theme/src/index.ts b/packages/kbn-ui-theme/src/index.ts new file mode 100644 index 00000000000000..8acacd8005c9d2 --- /dev/null +++ b/packages/kbn-ui-theme/src/index.ts @@ -0,0 +1,11 @@ +/* + * 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. + */ + +export type { Theme } from './theme'; + +export { darkMode, euiDarkVars, euiLightVars, euiThemeVars, tag, version } from './theme'; diff --git a/packages/kbn-ui-shared-deps-src/src/theme.ts b/packages/kbn-ui-theme/src/theme.ts similarity index 100% rename from packages/kbn-ui-shared-deps-src/src/theme.ts rename to packages/kbn-ui-theme/src/theme.ts diff --git a/packages/kbn-ui-theme/tsconfig.json b/packages/kbn-ui-theme/tsconfig.json new file mode 100644 index 00000000000000..e1c27e88f1c91f --- /dev/null +++ b/packages/kbn-ui-theme/tsconfig.json @@ -0,0 +1,14 @@ +{ + "extends": "../../tsconfig.bazel.json", + "compilerOptions": { + "declaration": true, + "declarationMap": true, + "emitDeclarationOnly": true, + "outDir": "./target_types", + "sourceMap": true, + "sourceRoot": "../../../../packages/kbn-ui-theme/src", + "stripInternal": true, + "types": ["node"] + }, + "include": ["src/**/*"] +} diff --git a/src/core/server/core_app/bundle_routes/register_bundle_routes.ts b/src/core/server/core_app/bundle_routes/register_bundle_routes.ts index 4fdf6da00e7abe..d27add39687f9b 100644 --- a/src/core/server/core_app/bundle_routes/register_bundle_routes.ts +++ b/src/core/server/core_app/bundle_routes/register_bundle_routes.ts @@ -10,7 +10,7 @@ import { join } from 'path'; import { PackageInfo } from '@kbn/config'; import { fromRoot } from '@kbn/utils'; import UiSharedDepsNpm from '@kbn/ui-shared-deps-npm'; -import UiSharedDepsSrc from '@kbn/ui-shared-deps-src'; +import * as UiSharedDepsSrc from '@kbn/ui-shared-deps-src'; import { IRouter } from '../../http'; import { UiPlugins } from '../../plugins'; import { FileHashCache } from './file_hash_cache'; diff --git a/src/core/server/rendering/bootstrap/get_js_dependency_paths.ts b/src/core/server/rendering/bootstrap/get_js_dependency_paths.ts index 54a901964c3fb2..b04c407e5a5169 100644 --- a/src/core/server/rendering/bootstrap/get_js_dependency_paths.ts +++ b/src/core/server/rendering/bootstrap/get_js_dependency_paths.ts @@ -7,7 +7,7 @@ */ import UiSharedDepsNpm from '@kbn/ui-shared-deps-npm'; -import UiSharedDepsSrc from '@kbn/ui-shared-deps-src'; +import * as UiSharedDepsSrc from '@kbn/ui-shared-deps-src'; import type { PluginInfo } from './get_plugin_bundle_paths'; export const getJsDependencyPaths = ( diff --git a/src/core/server/rendering/render_utils.ts b/src/core/server/rendering/render_utils.ts index 65cedda7ad4892..b24f5968e4ee9d 100644 --- a/src/core/server/rendering/render_utils.ts +++ b/src/core/server/rendering/render_utils.ts @@ -7,7 +7,7 @@ */ import UiSharedDepsNpm from '@kbn/ui-shared-deps-npm'; -import UiSharedDepsSrc from '@kbn/ui-shared-deps-src'; +import * as UiSharedDepsSrc from '@kbn/ui-shared-deps-src'; import { PublicUiSettingsParams, UserProvidedValues } from '../ui_settings'; export const getSettingValue = ( diff --git a/src/plugins/charts/public/static/components/current_time.tsx b/src/plugins/charts/public/static/components/current_time.tsx index ad05f451b607fa..bac7eb241eec02 100644 --- a/src/plugins/charts/public/static/components/current_time.tsx +++ b/src/plugins/charts/public/static/components/current_time.tsx @@ -10,10 +10,7 @@ import moment, { Moment } from 'moment'; import React, { FC } from 'react'; import { LineAnnotation, AnnotationDomainType, LineAnnotationStyle } from '@elastic/charts'; -import { - euiLightVars as lightEuiTheme, - euiDarkVars as darkEuiTheme, -} from '@kbn/ui-shared-deps-src/theme'; +import { euiLightVars as lightEuiTheme, euiDarkVars as darkEuiTheme } from '@kbn/ui-theme'; interface CurrentTimeProps { isDarkMode: boolean; diff --git a/src/plugins/charts/public/static/components/endzones.tsx b/src/plugins/charts/public/static/components/endzones.tsx index 695b51c9702d24..727004993d171d 100644 --- a/src/plugins/charts/public/static/components/endzones.tsx +++ b/src/plugins/charts/public/static/components/endzones.tsx @@ -17,10 +17,7 @@ import { } from '@elastic/charts'; import { i18n } from '@kbn/i18n'; import { EuiFlexGroup, EuiFlexItem, EuiIcon, EuiSpacer } from '@elastic/eui'; -import { - euiLightVars as lightEuiTheme, - euiDarkVars as darkEuiTheme, -} from '@kbn/ui-shared-deps-src/theme'; +import { euiLightVars as lightEuiTheme, euiDarkVars as darkEuiTheme } from '@kbn/ui-theme'; interface EndzonesProps { isDarkMode: boolean; diff --git a/src/plugins/data_view_editor/public/components/form_fields/type_field.tsx b/src/plugins/data_view_editor/public/components/form_fields/type_field.tsx index f6545d5fcb08ef..11b46c7ee31faa 100644 --- a/src/plugins/data_view_editor/public/components/form_fields/type_field.tsx +++ b/src/plugins/data_view_editor/public/components/form_fields/type_field.tsx @@ -8,7 +8,7 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; -import { euiLightVars } from '@kbn/ui-shared-deps-src/theme'; +import { euiLightVars } from '@kbn/ui-theme'; import { FormattedMessage } from '@kbn/i18n-react'; import { diff --git a/src/plugins/dev_tools/public/application.tsx b/src/plugins/dev_tools/public/application.tsx index dc72cfda790d4c..a3ec8fc0a9af20 100644 --- a/src/plugins/dev_tools/public/application.tsx +++ b/src/plugins/dev_tools/public/application.tsx @@ -13,7 +13,7 @@ import { HashRouter as Router, Switch, Route, Redirect } from 'react-router-dom' import { EuiTab, EuiTabs, EuiToolTip, EuiBetaBadge } from '@elastic/eui'; import { I18nProvider } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; -import { euiThemeVars } from '@kbn/ui-shared-deps-src/theme'; +import { euiThemeVars } from '@kbn/ui-theme'; import { ApplicationStart, ChromeStart, ScopedHistory, CoreTheme } from 'src/core/public'; import { KibanaThemeProvider } from '../../kibana_react/public'; diff --git a/src/plugins/discover/public/components/discover_grid/discover_grid_document_selection.tsx b/src/plugins/discover/public/components/discover_grid/discover_grid_document_selection.tsx index 6fb614327d2af4..a8881b37301e03 100644 --- a/src/plugins/discover/public/components/discover_grid/discover_grid_document_selection.tsx +++ b/src/plugins/discover/public/components/discover_grid/discover_grid_document_selection.tsx @@ -17,10 +17,7 @@ import { EuiDataGridCellValueElementProps, } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; -import { - euiLightVars as themeLight, - euiDarkVars as themeDark, -} from '@kbn/ui-shared-deps-src/theme'; +import { euiLightVars as themeLight, euiDarkVars as themeDark } from '@kbn/ui-theme'; import { DiscoverGridContext } from './discover_grid_context'; import { ElasticSearchHit } from '../../types'; diff --git a/src/plugins/discover/public/components/discover_grid/discover_grid_expand_button.tsx b/src/plugins/discover/public/components/discover_grid/discover_grid_expand_button.tsx index 372fe03666d032..6765a8d24f91a6 100644 --- a/src/plugins/discover/public/components/discover_grid/discover_grid_expand_button.tsx +++ b/src/plugins/discover/public/components/discover_grid/discover_grid_expand_button.tsx @@ -8,10 +8,7 @@ import React, { useContext, useEffect } from 'react'; import { EuiButtonIcon, EuiDataGridCellValueElementProps, EuiToolTip } from '@elastic/eui'; -import { - euiLightVars as themeLight, - euiDarkVars as themeDark, -} from '@kbn/ui-shared-deps-src/theme'; +import { euiLightVars as themeLight, euiDarkVars as themeDark } from '@kbn/ui-theme'; import { i18n } from '@kbn/i18n'; import { DiscoverGridContext } from './discover_grid_context'; import { EsHitRecord } from '../../application/types'; diff --git a/src/plugins/discover/public/components/discover_grid/get_render_cell_value.tsx b/src/plugins/discover/public/components/discover_grid/get_render_cell_value.tsx index e56c3ef2b699b1..436281b119bff4 100644 --- a/src/plugins/discover/public/components/discover_grid/get_render_cell_value.tsx +++ b/src/plugins/discover/public/components/discover_grid/get_render_cell_value.tsx @@ -7,10 +7,7 @@ */ import React, { Fragment, useContext, useEffect } from 'react'; -import { - euiLightVars as themeLight, - euiDarkVars as themeDark, -} from '@kbn/ui-shared-deps-src/theme'; +import { euiLightVars as themeLight, euiDarkVars as themeDark } from '@kbn/ui-theme'; import type { DataView } from 'src/plugins/data/common'; import { diff --git a/src/plugins/discover/public/components/doc_table/components/pager/tool_bar_pagination.tsx b/src/plugins/discover/public/components/doc_table/components/pager/tool_bar_pagination.tsx index 1b07eb89b3e233..8c2e1892d8fc7d 100644 --- a/src/plugins/discover/public/components/doc_table/components/pager/tool_bar_pagination.tsx +++ b/src/plugins/discover/public/components/doc_table/components/pager/tool_bar_pagination.tsx @@ -18,7 +18,7 @@ import { } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; -import { euiLightVars } from '@kbn/ui-shared-deps-src/theme'; +import { euiLightVars } from '@kbn/ui-theme'; interface ToolBarPaginationProps { pageSize: number; diff --git a/src/plugins/expressions/public/react_expression_renderer.tsx b/src/plugins/expressions/public/react_expression_renderer.tsx index abb6b01e77feb4..897d69f356035e 100644 --- a/src/plugins/expressions/public/react_expression_renderer.tsx +++ b/src/plugins/expressions/public/react_expression_renderer.tsx @@ -12,7 +12,7 @@ import { Observable, Subscription } from 'rxjs'; import { filter } from 'rxjs/operators'; import useShallowCompareEffect from 'react-use/lib/useShallowCompareEffect'; import { EuiLoadingChart, EuiProgress } from '@elastic/eui'; -import { euiLightVars as theme } from '@kbn/ui-shared-deps-src/theme'; +import { euiLightVars as theme } from '@kbn/ui-theme'; import { IExpressionLoaderParams, ExpressionRenderError, ExpressionRendererEvent } from './types'; import { ExpressionAstExpression, IInterpreterRenderHandlers } from '../common'; import { ExpressionLoader } from './loader'; diff --git a/src/plugins/home/public/application/components/tutorial/instruction_set.js b/src/plugins/home/public/application/components/tutorial/instruction_set.js index b2cdbde83a2c38..651212f062c8f6 100644 --- a/src/plugins/home/public/application/components/tutorial/instruction_set.js +++ b/src/plugins/home/public/application/components/tutorial/instruction_set.js @@ -27,7 +27,7 @@ import { import * as StatusCheckStates from './status_check_states'; import { injectI18n, FormattedMessage } from '@kbn/i18n-react'; -import { euiThemeVars } from '@kbn/ui-shared-deps-src/theme'; +import { euiThemeVars } from '@kbn/ui-theme'; class InstructionSetUi extends React.Component { constructor(props) { diff --git a/src/plugins/interactive_setup/public/cluster_configuration_form.tsx b/src/plugins/interactive_setup/public/cluster_configuration_form.tsx index 1282f6612dd238..5ce4068039b85e 100644 --- a/src/plugins/interactive_setup/public/cluster_configuration_form.tsx +++ b/src/plugins/interactive_setup/public/cluster_configuration_form.tsx @@ -38,7 +38,7 @@ import useUpdateEffect from 'react-use/lib/useUpdateEffect'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; -import { euiThemeVars } from '@kbn/ui-shared-deps-src/theme'; +import { euiThemeVars } from '@kbn/ui-theme'; import type { Certificate } from '../common'; import { DocLink } from './doc_link'; diff --git a/src/plugins/interactive_setup/public/single_chars_field.tsx b/src/plugins/interactive_setup/public/single_chars_field.tsx index bd66b5ac1fcf1f..1a6a513583bccb 100644 --- a/src/plugins/interactive_setup/public/single_chars_field.tsx +++ b/src/plugins/interactive_setup/public/single_chars_field.tsx @@ -13,7 +13,7 @@ import useList from 'react-use/lib/useList'; import useUpdateEffect from 'react-use/lib/useUpdateEffect'; import { i18n } from '@kbn/i18n'; -import { euiThemeVars } from '@kbn/ui-shared-deps-src/theme'; +import { euiThemeVars } from '@kbn/ui-theme'; export interface SingleCharsFieldProps { defaultValue: string; diff --git a/src/plugins/interactive_setup/public/use_verification.tsx b/src/plugins/interactive_setup/public/use_verification.tsx index fed055a415ebb5..42bcf94ad1f8c7 100644 --- a/src/plugins/interactive_setup/public/use_verification.tsx +++ b/src/plugins/interactive_setup/public/use_verification.tsx @@ -11,7 +11,7 @@ import constate from 'constate'; import type { FunctionComponent } from 'react'; import React, { useEffect, useRef, useState } from 'react'; -import { euiThemeVars } from '@kbn/ui-shared-deps-src/theme'; +import { euiThemeVars } from '@kbn/ui-theme'; import { useKibana } from './use_kibana'; import { VerificationCodeForm } from './verification_code_form'; diff --git a/src/plugins/kibana_react/common/eui_styled_components.tsx b/src/plugins/kibana_react/common/eui_styled_components.tsx index 4f680d944b9584..ab45c172fc1b04 100644 --- a/src/plugins/kibana_react/common/eui_styled_components.tsx +++ b/src/plugins/kibana_react/common/eui_styled_components.tsx @@ -10,7 +10,7 @@ import type { DecoratorFn } from '@storybook/react'; import React from 'react'; import * as styledComponents from 'styled-components'; import { ThemedStyledComponentsModule, ThemeProvider, ThemeProviderProps } from 'styled-components'; -import { euiThemeVars, euiLightVars, euiDarkVars } from '@kbn/ui-shared-deps-src/theme'; +import { euiThemeVars, euiLightVars, euiDarkVars } from '@kbn/ui-theme'; export interface EuiTheme { eui: typeof euiThemeVars; diff --git a/src/plugins/kibana_react/public/code_editor/code_editor_field.tsx b/src/plugins/kibana_react/public/code_editor/code_editor_field.tsx index 85263b7006c169..4fe4b87d6d106b 100644 --- a/src/plugins/kibana_react/public/code_editor/code_editor_field.tsx +++ b/src/plugins/kibana_react/public/code_editor/code_editor_field.tsx @@ -7,10 +7,7 @@ */ import React from 'react'; -import { - euiLightVars as lightTheme, - euiDarkVars as darkTheme, -} from '@kbn/ui-shared-deps-src/theme'; +import { euiLightVars as lightTheme, euiDarkVars as darkTheme } from '@kbn/ui-theme'; import { EuiFormControlLayout } from '@elastic/eui'; import { CodeEditor, Props } from './code_editor'; diff --git a/src/plugins/kibana_react/public/code_editor/editor_theme.ts b/src/plugins/kibana_react/public/code_editor/editor_theme.ts index 517fe4cf61a083..9242b7319e5c94 100644 --- a/src/plugins/kibana_react/public/code_editor/editor_theme.ts +++ b/src/plugins/kibana_react/public/code_editor/editor_theme.ts @@ -8,10 +8,7 @@ import { monaco } from '@kbn/monaco'; -import { - euiLightVars as lightTheme, - euiDarkVars as darkTheme, -} from '@kbn/ui-shared-deps-src/theme'; +import { euiLightVars as lightTheme, euiDarkVars as darkTheme } from '@kbn/ui-theme'; // NOTE: For talk around where this theme information will ultimately live, // please see this discuss issue: https://github.com/elastic/kibana/issues/43814 diff --git a/src/plugins/vis_types/vega/public/data_model/vega_parser.test.js b/src/plugins/vis_types/vega/public/data_model/vega_parser.test.js index 13c17b8f4c38fd..bdab3b45a00f67 100644 --- a/src/plugins/vis_types/vega/public/data_model/vega_parser.test.js +++ b/src/plugins/vis_types/vega/public/data_model/vega_parser.test.js @@ -7,7 +7,7 @@ */ import { cloneDeep } from 'lodash'; import 'jest-canvas-mock'; -import { euiThemeVars } from '@kbn/ui-shared-deps-src/theme'; +import { euiThemeVars } from '@kbn/ui-theme'; import { VegaParser } from './vega_parser'; import { bypassExternalUrlCheck } from '../vega_view/vega_base_view'; diff --git a/src/plugins/vis_types/vega/public/data_model/vega_parser.ts b/src/plugins/vis_types/vega/public/data_model/vega_parser.ts index 58daf67e31c9d1..bcaf8afd4fd0c1 100644 --- a/src/plugins/vis_types/vega/public/data_model/vega_parser.ts +++ b/src/plugins/vis_types/vega/public/data_model/vega_parser.ts @@ -11,7 +11,7 @@ import schemaParser from 'vega-schema-url-parser'; import versionCompare from 'compare-versions'; import hjson from 'hjson'; import { euiPaletteColorBlind } from '@elastic/eui'; -import { euiThemeVars } from '@kbn/ui-shared-deps-src/theme'; +import { euiThemeVars } from '@kbn/ui-theme'; import { i18n } from '@kbn/i18n'; import { logger, Warn, None, version as vegaVersion } from 'vega'; diff --git a/src/plugins/vis_types/vislib/public/vislib/components/tooltip/tooltip.js b/src/plugins/vis_types/vislib/public/vislib/components/tooltip/tooltip.js index 1faebdf0ce89cf..2d6e1728668fd1 100644 --- a/src/plugins/vis_types/vislib/public/vislib/components/tooltip/tooltip.js +++ b/src/plugins/vis_types/vislib/public/vislib/components/tooltip/tooltip.js @@ -12,7 +12,7 @@ import $ from 'jquery'; import { Binder } from '../../lib/binder'; import { positionTooltip } from './position_tooltip'; -import { euiLightVars as theme } from '@kbn/ui-shared-deps-src/theme'; +import { euiLightVars as theme } from '@kbn/ui-theme'; let allContents = []; diff --git a/x-pack/plugins/apm/common/viz_colors.ts b/x-pack/plugins/apm/common/viz_colors.ts index 5b4946f3468413..20d525c914549c 100644 --- a/x-pack/plugins/apm/common/viz_colors.ts +++ b/x-pack/plugins/apm/common/viz_colors.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { euiLightVars as lightTheme } from '@kbn/ui-shared-deps-src/theme'; +import { euiLightVars as lightTheme } from '@kbn/ui-theme'; function getVizColorsForTheme(theme = lightTheme) { return [ diff --git a/x-pack/plugins/apm/public/application/uxApp.tsx b/x-pack/plugins/apm/public/application/uxApp.tsx index dde7cfe5399d37..fa29f04fccbadc 100644 --- a/x-pack/plugins/apm/public/application/uxApp.tsx +++ b/x-pack/plugins/apm/public/application/uxApp.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { euiLightVars, euiDarkVars } from '@kbn/ui-shared-deps-src/theme'; +import { euiLightVars, euiDarkVars } from '@kbn/ui-theme'; import { EuiErrorBoundary } from '@elastic/eui'; import { AppMountParameters, CoreStart } from 'kibana/public'; import React from 'react'; diff --git a/x-pack/plugins/apm/public/components/app/rum_dashboard/page_load_distribution/percentile_annotations.tsx b/x-pack/plugins/apm/public/components/app/rum_dashboard/page_load_distribution/percentile_annotations.tsx index 74d9ccdcda8d8f..9982f8a85583cf 100644 --- a/x-pack/plugins/apm/public/components/app/rum_dashboard/page_load_distribution/percentile_annotations.tsx +++ b/x-pack/plugins/apm/public/components/app/rum_dashboard/page_load_distribution/percentile_annotations.tsx @@ -13,7 +13,7 @@ import { LineAnnotationStyle, Position, } from '@elastic/charts'; -import { euiLightVars } from '@kbn/ui-shared-deps-src/theme'; +import { euiLightVars } from '@kbn/ui-theme'; import { EuiToolTip } from '@elastic/eui'; interface Props { diff --git a/x-pack/plugins/apm/public/components/app/rum_dashboard/url_filter/url_search/render_option.tsx b/x-pack/plugins/apm/public/components/app/rum_dashboard/url_filter/url_search/render_option.tsx index 3293760ef71286..9bc9be79bfb561 100644 --- a/x-pack/plugins/apm/public/components/app/rum_dashboard/url_filter/url_search/render_option.tsx +++ b/x-pack/plugins/apm/public/components/app/rum_dashboard/url_filter/url_search/render_option.tsx @@ -8,7 +8,7 @@ import React, { ReactNode } from 'react'; import { EuiHighlight, EuiSelectableOption } from '@elastic/eui'; import styled from 'styled-components'; -import { euiLightVars } from '@kbn/ui-shared-deps-src/theme'; +import { euiLightVars } from '@kbn/ui-theme'; const StyledSpan = styled.span` color: ${euiLightVars.euiColorSuccessText}; diff --git a/x-pack/plugins/apm/public/components/app/service_map/Controls.test.tsx b/x-pack/plugins/apm/public/components/app/service_map/Controls.test.tsx index f2dd9cce8f27e1..0be6bf3e3f5458 100644 --- a/x-pack/plugins/apm/public/components/app/service_map/Controls.test.tsx +++ b/x-pack/plugins/apm/public/components/app/service_map/Controls.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { euiLightVars as lightTheme } from '@kbn/ui-shared-deps-src/theme'; +import { euiLightVars as lightTheme } from '@kbn/ui-theme'; import { render } from '@testing-library/react'; import cytoscape from 'cytoscape'; import React, { ReactNode } from 'react'; diff --git a/x-pack/plugins/apm/public/components/routing/app_root.tsx b/x-pack/plugins/apm/public/components/routing/app_root.tsx index c7b98743c6bea9..5a6749b08e5b7d 100644 --- a/x-pack/plugins/apm/public/components/routing/app_root.tsx +++ b/x-pack/plugins/apm/public/components/routing/app_root.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { euiLightVars, euiDarkVars } from '@kbn/ui-shared-deps-src/theme'; +import { euiLightVars, euiDarkVars } from '@kbn/ui-theme'; import { RouteRenderer, RouterProvider } from '@kbn/typed-react-router-config'; import React from 'react'; import { Route } from 'react-router-dom'; diff --git a/x-pack/plugins/apm/public/utils/httpStatusCodeToColor.ts b/x-pack/plugins/apm/public/utils/httpStatusCodeToColor.ts index 1b44a90fe7bfc3..4caa3bd7701f05 100644 --- a/x-pack/plugins/apm/public/utils/httpStatusCodeToColor.ts +++ b/x-pack/plugins/apm/public/utils/httpStatusCodeToColor.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { euiLightVars as theme } from '@kbn/ui-shared-deps-src/theme'; +import { euiLightVars as theme } from '@kbn/ui-theme'; const { euiColorDarkShade, euiColorWarning } = theme; export const errorColor = '#c23c2b'; diff --git a/x-pack/plugins/apm/server/routes/metrics/by_agent/java/gc/fetch_and_transform_gc_metrics.ts b/x-pack/plugins/apm/server/routes/metrics/by_agent/java/gc/fetch_and_transform_gc_metrics.ts index 790fcf5720745b..1604d22a209a75 100644 --- a/x-pack/plugins/apm/server/routes/metrics/by_agent/java/gc/fetch_and_transform_gc_metrics.ts +++ b/x-pack/plugins/apm/server/routes/metrics/by_agent/java/gc/fetch_and_transform_gc_metrics.ts @@ -6,7 +6,7 @@ */ import { sum, round } from 'lodash'; -import { euiLightVars as theme } from '@kbn/ui-shared-deps-src/theme'; +import { euiLightVars as theme } from '@kbn/ui-theme'; import { isFiniteNumber } from '../../../../../../common/utils/is_finite_number'; import { Setup } from '../../../../../lib/helpers/setup_request'; import { getMetricsDateHistogramParams } from '../../../../../lib/helpers/metrics'; diff --git a/x-pack/plugins/apm/server/routes/metrics/by_agent/java/gc/get_gc_rate_chart.ts b/x-pack/plugins/apm/server/routes/metrics/by_agent/java/gc/get_gc_rate_chart.ts index a22f7df9156170..0476025594b267 100644 --- a/x-pack/plugins/apm/server/routes/metrics/by_agent/java/gc/get_gc_rate_chart.ts +++ b/x-pack/plugins/apm/server/routes/metrics/by_agent/java/gc/get_gc_rate_chart.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { euiLightVars as theme } from '@kbn/ui-shared-deps-src/theme'; +import { euiLightVars as theme } from '@kbn/ui-theme'; import { i18n } from '@kbn/i18n'; import { METRIC_JAVA_GC_COUNT } from '../../../../../../common/elasticsearch_fieldnames'; import { Setup } from '../../../../../lib/helpers/setup_request'; diff --git a/x-pack/plugins/apm/server/routes/metrics/by_agent/java/gc/get_gc_time_chart.ts b/x-pack/plugins/apm/server/routes/metrics/by_agent/java/gc/get_gc_time_chart.ts index 596d871b916f97..b1ef7b5e106f56 100644 --- a/x-pack/plugins/apm/server/routes/metrics/by_agent/java/gc/get_gc_time_chart.ts +++ b/x-pack/plugins/apm/server/routes/metrics/by_agent/java/gc/get_gc_time_chart.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { euiLightVars as theme } from '@kbn/ui-shared-deps-src/theme'; +import { euiLightVars as theme } from '@kbn/ui-theme'; import { i18n } from '@kbn/i18n'; import { METRIC_JAVA_GC_TIME } from '../../../../../../common/elasticsearch_fieldnames'; import { Setup } from '../../../../../lib/helpers/setup_request'; diff --git a/x-pack/plugins/apm/server/routes/metrics/by_agent/java/heap_memory/index.ts b/x-pack/plugins/apm/server/routes/metrics/by_agent/java/heap_memory/index.ts index cde28e77e38ca1..d57dfb184ca88c 100644 --- a/x-pack/plugins/apm/server/routes/metrics/by_agent/java/heap_memory/index.ts +++ b/x-pack/plugins/apm/server/routes/metrics/by_agent/java/heap_memory/index.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { euiLightVars as theme } from '@kbn/ui-shared-deps-src/theme'; +import { euiLightVars as theme } from '@kbn/ui-theme'; import { i18n } from '@kbn/i18n'; import { METRIC_JAVA_HEAP_MEMORY_MAX, diff --git a/x-pack/plugins/apm/server/routes/metrics/by_agent/java/non_heap_memory/index.ts b/x-pack/plugins/apm/server/routes/metrics/by_agent/java/non_heap_memory/index.ts index ffcce74ee6766d..379962d928e287 100644 --- a/x-pack/plugins/apm/server/routes/metrics/by_agent/java/non_heap_memory/index.ts +++ b/x-pack/plugins/apm/server/routes/metrics/by_agent/java/non_heap_memory/index.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { euiLightVars as theme } from '@kbn/ui-shared-deps-src/theme'; +import { euiLightVars as theme } from '@kbn/ui-theme'; import { i18n } from '@kbn/i18n'; import { METRIC_JAVA_NON_HEAP_MEMORY_MAX, diff --git a/x-pack/plugins/apm/server/routes/metrics/by_agent/java/thread_count/index.ts b/x-pack/plugins/apm/server/routes/metrics/by_agent/java/thread_count/index.ts index 699812ffc8463d..b9a49acb3d16e5 100644 --- a/x-pack/plugins/apm/server/routes/metrics/by_agent/java/thread_count/index.ts +++ b/x-pack/plugins/apm/server/routes/metrics/by_agent/java/thread_count/index.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { euiLightVars as theme } from '@kbn/ui-shared-deps-src/theme'; +import { euiLightVars as theme } from '@kbn/ui-theme'; import { i18n } from '@kbn/i18n'; import { METRIC_JAVA_THREAD_COUNT, diff --git a/x-pack/plugins/apm/server/routes/metrics/by_agent/shared/cpu/index.ts b/x-pack/plugins/apm/server/routes/metrics/by_agent/shared/cpu/index.ts index 95c39d4bd55cc5..d09b35e25e3963 100644 --- a/x-pack/plugins/apm/server/routes/metrics/by_agent/shared/cpu/index.ts +++ b/x-pack/plugins/apm/server/routes/metrics/by_agent/shared/cpu/index.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { euiLightVars as theme } from '@kbn/ui-shared-deps-src/theme'; +import { euiLightVars as theme } from '@kbn/ui-theme'; import { i18n } from '@kbn/i18n'; import { METRIC_SYSTEM_CPU_PERCENT, diff --git a/x-pack/plugins/apm/server/routes/metrics/fetch_and_transform_metrics.ts b/x-pack/plugins/apm/server/routes/metrics/fetch_and_transform_metrics.ts index ea06b35c1fc45a..52a099bdcf4058 100644 --- a/x-pack/plugins/apm/server/routes/metrics/fetch_and_transform_metrics.ts +++ b/x-pack/plugins/apm/server/routes/metrics/fetch_and_transform_metrics.ts @@ -6,7 +6,7 @@ */ import { Unionize } from 'utility-types'; -import { euiLightVars as theme } from '@kbn/ui-shared-deps-src/theme'; +import { euiLightVars as theme } from '@kbn/ui-theme'; import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; import { getVizColorForIndex } from '../../../common/viz_colors'; import { AggregationOptionsByType } from '../../../../../../src/core/types/elasticsearch'; diff --git a/x-pack/plugins/canvas/shareable_runtime/api/index.ts b/x-pack/plugins/canvas/shareable_runtime/api/index.ts index 24b0632e2d74c8..ad9e4fcf03cdca 100644 --- a/x-pack/plugins/canvas/shareable_runtime/api/index.ts +++ b/x-pack/plugins/canvas/shareable_runtime/api/index.ts @@ -9,6 +9,6 @@ import 'core-js/stable'; import 'regenerator-runtime/runtime'; import 'whatwg-fetch'; import 'jquery'; -import '@kbn/ui-shared-deps-src/flot_charts'; +import '@kbn/flot-charts'; export * from './shareable'; diff --git a/x-pack/plugins/cases/public/common/mock/test_providers.tsx b/x-pack/plugins/cases/public/common/mock/test_providers.tsx index 477738ddeac16a..5f0c87168375d1 100644 --- a/x-pack/plugins/cases/public/common/mock/test_providers.tsx +++ b/x-pack/plugins/cases/public/common/mock/test_providers.tsx @@ -6,7 +6,7 @@ */ import React from 'react'; -import { euiDarkVars } from '@kbn/ui-shared-deps-src/theme'; +import { euiDarkVars } from '@kbn/ui-theme'; import { I18nProvider } from '@kbn/i18n-react'; import { ThemeProvider } from 'styled-components'; diff --git a/x-pack/plugins/cases/public/components/header_page/index.test.tsx b/x-pack/plugins/cases/public/components/header_page/index.test.tsx index 0c0ff060fb2bcf..4f0da554f3d1b2 100644 --- a/x-pack/plugins/cases/public/components/header_page/index.test.tsx +++ b/x-pack/plugins/cases/public/components/header_page/index.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { euiDarkVars } from '@kbn/ui-shared-deps-src/theme'; +import { euiDarkVars } from '@kbn/ui-theme'; import { shallow } from 'enzyme'; import React from 'react'; diff --git a/x-pack/plugins/cases/public/components/utility_bar/utility_bar.test.tsx b/x-pack/plugins/cases/public/components/utility_bar/utility_bar.test.tsx index 43ebd9bee3ca9a..a1930c17a70b11 100644 --- a/x-pack/plugins/cases/public/components/utility_bar/utility_bar.test.tsx +++ b/x-pack/plugins/cases/public/components/utility_bar/utility_bar.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { euiDarkVars } from '@kbn/ui-shared-deps-src/theme'; +import { euiDarkVars } from '@kbn/ui-theme'; import { mount, shallow } from 'enzyme'; import React from 'react'; import { TestProviders } from '../../common/mock'; diff --git a/x-pack/plugins/data_visualizer/public/application/common/components/stats_table/hooks/use_color_range.ts b/x-pack/plugins/data_visualizer/public/application/common/components/stats_table/hooks/use_color_range.ts index 92a88f4d60670a..2c49f92e68d8e8 100644 --- a/x-pack/plugins/data_visualizer/public/application/common/components/stats_table/hooks/use_color_range.ts +++ b/x-pack/plugins/data_visualizer/public/application/common/components/stats_table/hooks/use_color_range.ts @@ -7,10 +7,7 @@ import d3 from 'd3'; import { useMemo } from 'react'; -import { - euiLightVars as euiThemeLight, - euiDarkVars as euiThemeDark, -} from '@kbn/ui-shared-deps-src/theme'; +import { euiLightVars as euiThemeLight, euiDarkVars as euiThemeDark } from '@kbn/ui-theme'; import { i18n } from '@kbn/i18n'; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_health.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_health.tsx index 8d04a6f3cefc37..b0b9c471b7cb41 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_health.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_health.tsx @@ -9,7 +9,7 @@ import React from 'react'; import { FormattedMessage, FormattedRelative } from '@kbn/i18n-react'; import { EuiBadge, EuiToolTip } from '@elastic/eui'; -import { euiLightVars as euiVars } from '@kbn/ui-shared-deps-src/theme'; +import { euiLightVars as euiVars } from '@kbn/ui-theme'; import type { Agent } from '../../../types'; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/services/agent_status.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/services/agent_status.tsx index d98e9d8673755c..8d5405d3fb4698 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/services/agent_status.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/services/agent_status.tsx @@ -7,7 +7,7 @@ import { euiPaletteColorBlindBehindText } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { euiLightVars } from '@kbn/ui-shared-deps-src/theme'; +import { euiLightVars } from '@kbn/ui-theme'; import type { SimplifiedAgentStatus } from '../../../types'; diff --git a/x-pack/plugins/lens/public/shared_components/coloring/utils.ts b/x-pack/plugins/lens/public/shared_components/coloring/utils.ts index 7cd89b2464c4eb..010f6e99e39bc5 100644 --- a/x-pack/plugins/lens/public/shared_components/coloring/utils.ts +++ b/x-pack/plugins/lens/public/shared_components/coloring/utils.ts @@ -7,7 +7,7 @@ import chroma from 'chroma-js'; import { PaletteOutput, PaletteRegistry } from 'src/plugins/charts/public'; -import { euiLightVars, euiDarkVars } from '@kbn/ui-shared-deps-src/theme'; +import { euiLightVars, euiDarkVars } from '@kbn/ui-theme'; import { isColorDark } from '@elastic/eui'; import type { Datatable } from 'src/plugins/expressions/public'; import { diff --git a/x-pack/plugins/lens/public/xy_visualization/color_assignment.ts b/x-pack/plugins/lens/public/xy_visualization/color_assignment.ts index be7f6f1d1d2252..cb80271f6842de 100644 --- a/x-pack/plugins/lens/public/xy_visualization/color_assignment.ts +++ b/x-pack/plugins/lens/public/xy_visualization/color_assignment.ts @@ -8,7 +8,7 @@ import { uniq, mapValues } from 'lodash'; import type { PaletteOutput, PaletteRegistry } from 'src/plugins/charts/public'; import type { Datatable } from 'src/plugins/expressions'; -import { euiLightVars } from '@kbn/ui-shared-deps-src/theme'; +import { euiLightVars } from '@kbn/ui-theme'; import type { AccessorConfig, FramePublicAPI } from '../types'; import { getColumnToLabelMap } from './state_helpers'; import { FormatFactory, LayerType, layerTypes } from '../../common'; diff --git a/x-pack/plugins/lens/public/xy_visualization/expression_reference_lines.tsx b/x-pack/plugins/lens/public/xy_visualization/expression_reference_lines.tsx index d41baff0bc1dc2..7408987261b41d 100644 --- a/x-pack/plugins/lens/public/xy_visualization/expression_reference_lines.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/expression_reference_lines.tsx @@ -12,7 +12,7 @@ import { EuiIcon } from '@elastic/eui'; import { RectAnnotation, AnnotationDomainType, LineAnnotation, Position } from '@elastic/charts'; import type { PaletteRegistry } from 'src/plugins/charts/public'; import type { FieldFormat } from 'src/plugins/field_formats/common'; -import { euiLightVars } from '@kbn/ui-shared-deps-src/theme'; +import { euiLightVars } from '@kbn/ui-theme'; import type { LayerArgs, YConfig } from '../../common/expressions'; import type { LensMultiTable } from '../../common/types'; import { hasIcon } from './xy_config_panel/reference_line_panel'; diff --git a/x-pack/plugins/maps/public/reducers/map/default_map_settings.ts b/x-pack/plugins/maps/public/reducers/map/default_map_settings.ts index ebde5481a13f52..f5af113b3b3169 100644 --- a/x-pack/plugins/maps/public/reducers/map/default_map_settings.ts +++ b/x-pack/plugins/maps/public/reducers/map/default_map_settings.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { euiThemeVars } from '@kbn/ui-shared-deps-src/theme'; +import { euiThemeVars } from '@kbn/ui-theme'; import { INITIAL_LOCATION, MAX_ZOOM, MIN_ZOOM } from '../../../common/constants'; import { MapSettings } from './types'; diff --git a/x-pack/plugins/ml/common/util/group_color_utils.ts b/x-pack/plugins/ml/common/util/group_color_utils.ts index 63f0e13676d582..b9709671475be4 100644 --- a/x-pack/plugins/ml/common/util/group_color_utils.ts +++ b/x-pack/plugins/ml/common/util/group_color_utils.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { euiDarkVars as euiVars } from '@kbn/ui-shared-deps-src/theme'; +import { euiDarkVars as euiVars } from '@kbn/ui-theme'; import { stringHash } from './string_utils'; diff --git a/x-pack/plugins/ml/public/application/components/color_range_legend/use_color_range.ts b/x-pack/plugins/ml/public/application/components/color_range_legend/use_color_range.ts index 2ccc687d145d04..c1ed6bff306f91 100644 --- a/x-pack/plugins/ml/public/application/components/color_range_legend/use_color_range.ts +++ b/x-pack/plugins/ml/public/application/components/color_range_legend/use_color_range.ts @@ -7,10 +7,7 @@ import d3 from 'd3'; import { useMemo } from 'react'; -import { - euiLightVars as euiThemeLight, - euiDarkVars as euiThemeDark, -} from '@kbn/ui-shared-deps-src/theme'; +import { euiLightVars as euiThemeLight, euiDarkVars as euiThemeDark } from '@kbn/ui-theme'; import { i18n } from '@kbn/i18n'; diff --git a/x-pack/plugins/ml/public/application/components/job_messages/job_messages.tsx b/x-pack/plugins/ml/public/application/components/job_messages/job_messages.tsx index 4b9f9d86799df6..b385ec2bcf6ec0 100644 --- a/x-pack/plugins/ml/public/application/components/job_messages/job_messages.tsx +++ b/x-pack/plugins/ml/public/application/components/job_messages/job_messages.tsx @@ -17,7 +17,7 @@ import { import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; -import { euiLightVars as theme } from '@kbn/ui-shared-deps-src/theme'; +import { euiLightVars as theme } from '@kbn/ui-theme'; import { JobMessage } from '../../../../common/types/audit_message'; import { JobIcon } from '../job_message_icon'; diff --git a/x-pack/plugins/ml/public/application/components/scatterplot_matrix/scatterplot_matrix.test.tsx b/x-pack/plugins/ml/public/application/components/scatterplot_matrix/scatterplot_matrix.test.tsx index c9851589f4c460..c1857979e7d533 100644 --- a/x-pack/plugins/ml/public/application/components/scatterplot_matrix/scatterplot_matrix.test.tsx +++ b/x-pack/plugins/ml/public/application/components/scatterplot_matrix/scatterplot_matrix.test.tsx @@ -10,7 +10,7 @@ import { render, waitFor, screen } from '@testing-library/react'; import { __IntlProvider as IntlProvider } from '@kbn/i18n-react'; -import { euiLightVars as euiThemeLight } from '@kbn/ui-shared-deps-src/theme'; +import { euiLightVars as euiThemeLight } from '@kbn/ui-theme'; import { ScatterplotMatrix } from './scatterplot_matrix'; diff --git a/x-pack/plugins/ml/public/application/components/scatterplot_matrix/scatterplot_matrix_vega_lite_spec.test.ts b/x-pack/plugins/ml/public/application/components/scatterplot_matrix/scatterplot_matrix_vega_lite_spec.test.ts index ed8a49cd36f020..5bc2205827c976 100644 --- a/x-pack/plugins/ml/public/application/components/scatterplot_matrix/scatterplot_matrix_vega_lite_spec.test.ts +++ b/x-pack/plugins/ml/public/application/components/scatterplot_matrix/scatterplot_matrix_vega_lite_spec.test.ts @@ -10,7 +10,7 @@ import 'jest-canvas-mock'; // @ts-ignore import { compile } from 'vega-lite/build/vega-lite'; -import { euiLightVars as euiThemeLight } from '@kbn/ui-shared-deps-src/theme'; +import { euiLightVars as euiThemeLight } from '@kbn/ui-theme'; import { LEGEND_TYPES } from '../vega_chart/common'; diff --git a/x-pack/plugins/ml/public/application/components/scatterplot_matrix/scatterplot_matrix_vega_lite_spec.ts b/x-pack/plugins/ml/public/application/components/scatterplot_matrix/scatterplot_matrix_vega_lite_spec.ts index 83525a4837dc91..442695ea9c8119 100644 --- a/x-pack/plugins/ml/public/application/components/scatterplot_matrix/scatterplot_matrix_vega_lite_spec.ts +++ b/x-pack/plugins/ml/public/application/components/scatterplot_matrix/scatterplot_matrix_vega_lite_spec.ts @@ -9,7 +9,7 @@ // @ts-ignore import type { TopLevelSpec } from 'vega-lite/build/vega-lite'; -import { euiLightVars as euiThemeLight } from '@kbn/ui-shared-deps-src/theme'; +import { euiLightVars as euiThemeLight } from '@kbn/ui-theme'; import { euiPaletteColorBlind, euiPaletteNegative, euiPalettePositive } from '@elastic/eui'; diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/get_roc_curve_chart_vega_lite_spec.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/get_roc_curve_chart_vega_lite_spec.tsx index 2d116e0dd851ed..3ca1f65cf2ecc5 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/get_roc_curve_chart_vega_lite_spec.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/get_roc_curve_chart_vega_lite_spec.tsx @@ -10,7 +10,7 @@ import type { TopLevelSpec } from 'vega-lite/build/vega-lite'; import { euiPaletteColorBlind, euiPaletteGray } from '@elastic/eui'; -import { euiLightVars as euiThemeLight } from '@kbn/ui-shared-deps-src/theme'; +import { euiLightVars as euiThemeLight } from '@kbn/ui-theme'; import { i18n } from '@kbn/i18n'; diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/feature_importance/decision_path_chart.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/feature_importance/decision_path_chart.tsx index d91b742b8cfe1b..dfb95887b2e99d 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/feature_importance/decision_path_chart.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/feature_importance/decision_path_chart.tsx @@ -24,7 +24,7 @@ import { EuiIcon } from '@elastic/eui'; import React, { useCallback, useMemo } from 'react'; import { i18n } from '@kbn/i18n'; -import { euiLightVars as euiVars } from '@kbn/ui-shared-deps-src/theme'; +import { euiLightVars as euiVars } from '@kbn/ui-theme'; import type { DecisionPathPlotData } from './use_classification_path_data'; import { formatSingleValue } from '../../../../../formatters/format_value'; import { diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/total_feature_importance_summary/feature_importance_summary.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/total_feature_importance_summary/feature_importance_summary.tsx index 534459dd074f02..8d5d4c5e4ca235 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/total_feature_importance_summary/feature_importance_summary.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/total_feature_importance_summary/feature_importance_summary.tsx @@ -21,7 +21,7 @@ import { BarSeriesSpec, } from '@elastic/charts'; import { i18n } from '@kbn/i18n'; -import { euiLightVars as euiVars } from '@kbn/ui-shared-deps-src/theme'; +import { euiLightVars as euiVars } from '@kbn/ui-theme'; import { TotalFeatureImportance, isClassificationTotalFeatureImportance, diff --git a/x-pack/plugins/ml/public/application/jobs/new_job/pages/components/charts/common/settings.ts b/x-pack/plugins/ml/public/application/jobs/new_job/pages/components/charts/common/settings.ts index 3d386073849f41..e51fb68ce70967 100644 --- a/x-pack/plugins/ml/public/application/jobs/new_job/pages/components/charts/common/settings.ts +++ b/x-pack/plugins/ml/public/application/jobs/new_job/pages/components/charts/common/settings.ts @@ -5,10 +5,7 @@ * 2.0. */ -import { - euiLightVars as lightTheme, - euiDarkVars as darkTheme, -} from '@kbn/ui-shared-deps-src/theme'; +import { euiLightVars as lightTheme, euiDarkVars as darkTheme } from '@kbn/ui-theme'; import { JobCreatorType, isMultiMetricJobCreator, diff --git a/x-pack/plugins/observability/public/components/shared/core_web_vitals/palette_legends.tsx b/x-pack/plugins/observability/public/components/shared/core_web_vitals/palette_legends.tsx index b9686cc2eccc15..98305dbfdd840f 100644 --- a/x-pack/plugins/observability/public/components/shared/core_web_vitals/palette_legends.tsx +++ b/x-pack/plugins/observability/public/components/shared/core_web_vitals/palette_legends.tsx @@ -16,7 +16,7 @@ import { } from '@elastic/eui'; import styled from 'styled-components'; import { FormattedMessage } from '@kbn/i18n-react'; -import { euiLightVars, euiDarkVars } from '@kbn/ui-shared-deps-src/theme'; +import { euiLightVars, euiDarkVars } from '@kbn/ui-theme'; import { getCoreVitalTooltipMessage, Thresholds } from './core_vital_item'; import { useUiSetting$ } from '../../../../../../../src/plugins/kibana_react/public'; import { diff --git a/x-pack/plugins/osquery/public/application.tsx b/x-pack/plugins/osquery/public/application.tsx index 17d47f757a2a6e..754d924529b192 100644 --- a/x-pack/plugins/osquery/public/application.tsx +++ b/x-pack/plugins/osquery/public/application.tsx @@ -6,7 +6,7 @@ */ import { EuiErrorBoundary } from '@elastic/eui'; -import { euiLightVars, euiDarkVars } from '@kbn/ui-shared-deps-src/theme'; +import { euiLightVars, euiDarkVars } from '@kbn/ui-theme'; import React, { useMemo } from 'react'; import ReactDOM from 'react-dom'; import { Router } from 'react-router-dom'; diff --git a/x-pack/plugins/security/public/components/token_field.tsx b/x-pack/plugins/security/public/components/token_field.tsx index 38a8e45cbb5b5b..7363ce7b28ff81 100644 --- a/x-pack/plugins/security/public/components/token_field.tsx +++ b/x-pack/plugins/security/public/components/token_field.tsx @@ -22,7 +22,7 @@ import type { FunctionComponent, ReactElement } from 'react'; import React from 'react'; import { i18n } from '@kbn/i18n'; -import { euiThemeVars } from '@kbn/ui-shared-deps-src/theme'; +import { euiThemeVars } from '@kbn/ui-theme'; export interface TokenFieldProps extends Omit { value: string; diff --git a/x-pack/plugins/security/server/prompt_page.tsx b/x-pack/plugins/security/server/prompt_page.tsx index bcb2dcf810f301..b3052c6e8db63a 100644 --- a/x-pack/plugins/security/server/prompt_page.tsx +++ b/x-pack/plugins/security/server/prompt_page.tsx @@ -19,7 +19,7 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; import { I18nProvider } from '@kbn/i18n-react'; import UiSharedDepsNpm from '@kbn/ui-shared-deps-npm'; -import UiSharedDepsSrc from '@kbn/ui-shared-deps-src'; +import * as UiSharedDepsSrc from '@kbn/ui-shared-deps-src'; import type { IBasePath } from 'src/core/server'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths diff --git a/x-pack/plugins/security_solution/public/common/components/and_or_badge/__examples__/index.stories.tsx b/x-pack/plugins/security_solution/public/common/components/and_or_badge/__examples__/index.stories.tsx index 231f93e896df9e..8695ad15394779 100644 --- a/x-pack/plugins/security_solution/public/common/components/and_or_badge/__examples__/index.stories.tsx +++ b/x-pack/plugins/security_solution/public/common/components/and_or_badge/__examples__/index.stories.tsx @@ -8,7 +8,7 @@ import { storiesOf } from '@storybook/react'; import React, { ReactNode } from 'react'; import { ThemeProvider } from 'styled-components'; -import { euiLightVars } from '@kbn/ui-shared-deps-src/theme'; +import { euiLightVars } from '@kbn/ui-theme'; import { EuiFlexItem, EuiFlexGroup } from '@elastic/eui'; import { AndOrBadge } from '..'; diff --git a/x-pack/plugins/security_solution/public/common/components/conditions_table/index.stories.tsx b/x-pack/plugins/security_solution/public/common/components/conditions_table/index.stories.tsx index 9efbbc7a3211da..61451cf5a91d97 100644 --- a/x-pack/plugins/security_solution/public/common/components/conditions_table/index.stories.tsx +++ b/x-pack/plugins/security_solution/public/common/components/conditions_table/index.stories.tsx @@ -8,7 +8,7 @@ import React from 'react'; import { ThemeProvider } from 'styled-components'; import { storiesOf, addDecorator } from '@storybook/react'; -import { euiLightVars } from '@kbn/ui-shared-deps-src/theme'; +import { euiLightVars } from '@kbn/ui-theme'; import { createItems, TEST_COLUMNS } from './test_utils'; import { ConditionsTable } from '.'; diff --git a/x-pack/plugins/security_solution/public/common/components/exceptions/viewer/exception_item/index.stories.tsx b/x-pack/plugins/security_solution/public/common/components/exceptions/viewer/exception_item/index.stories.tsx index 898a9e3ab03886..24c22f8ef1dedf 100644 --- a/x-pack/plugins/security_solution/public/common/components/exceptions/viewer/exception_item/index.stories.tsx +++ b/x-pack/plugins/security_solution/public/common/components/exceptions/viewer/exception_item/index.stories.tsx @@ -9,7 +9,7 @@ import { storiesOf, addDecorator } from '@storybook/react'; import { action } from '@storybook/addon-actions'; import React from 'react'; import { ThemeProvider } from 'styled-components'; -import { euiLightVars } from '@kbn/ui-shared-deps-src/theme'; +import { euiLightVars } from '@kbn/ui-theme'; import { ExceptionItem } from './'; import { getExceptionListItemSchemaMock } from '../../../../../../../lists/common/schemas/response/exception_list_item_schema.mock'; diff --git a/x-pack/plugins/security_solution/public/common/components/exceptions/viewer/exceptions_viewer_header.stories.tsx b/x-pack/plugins/security_solution/public/common/components/exceptions/viewer/exceptions_viewer_header.stories.tsx index de56e0eefc1ac5..05cbe352fa72ed 100644 --- a/x-pack/plugins/security_solution/public/common/components/exceptions/viewer/exceptions_viewer_header.stories.tsx +++ b/x-pack/plugins/security_solution/public/common/components/exceptions/viewer/exceptions_viewer_header.stories.tsx @@ -9,7 +9,7 @@ import { storiesOf, addDecorator } from '@storybook/react'; import { action } from '@storybook/addon-actions'; import React from 'react'; import { ThemeProvider } from 'styled-components'; -import { euiLightVars } from '@kbn/ui-shared-deps-src/theme'; +import { euiLightVars } from '@kbn/ui-theme'; import { ExceptionListTypeEnum } from '@kbn/securitysolution-io-ts-list-types'; import { ExceptionsViewerHeader } from './exceptions_viewer_header'; diff --git a/x-pack/plugins/security_solution/public/common/components/header_page/index.test.tsx b/x-pack/plugins/security_solution/public/common/components/header_page/index.test.tsx index 2e25a357e86b1e..5968322ac35394 100644 --- a/x-pack/plugins/security_solution/public/common/components/header_page/index.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/header_page/index.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { euiDarkVars } from '@kbn/ui-shared-deps-src/theme'; +import { euiDarkVars } from '@kbn/ui-theme'; import { shallow } from 'enzyme'; import React from 'react'; diff --git a/x-pack/plugins/security_solution/public/common/components/header_section/index.test.tsx b/x-pack/plugins/security_solution/public/common/components/header_section/index.test.tsx index 07a5ad475aed24..47b6451dd3090c 100644 --- a/x-pack/plugins/security_solution/public/common/components/header_section/index.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/header_section/index.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { euiDarkVars } from '@kbn/ui-shared-deps-src/theme'; +import { euiDarkVars } from '@kbn/ui-theme'; import { mount, shallow } from 'enzyme'; import React from 'react'; diff --git a/x-pack/plugins/security_solution/public/common/components/item_details_card/index.stories.tsx b/x-pack/plugins/security_solution/public/common/components/item_details_card/index.stories.tsx index 74a3d1c3999e9d..38f08698e54283 100644 --- a/x-pack/plugins/security_solution/public/common/components/item_details_card/index.stories.tsx +++ b/x-pack/plugins/security_solution/public/common/components/item_details_card/index.stories.tsx @@ -8,7 +8,7 @@ import React from 'react'; import { ThemeProvider } from 'styled-components'; import { storiesOf, addDecorator } from '@storybook/react'; -import { euiLightVars } from '@kbn/ui-shared-deps-src/theme'; +import { euiLightVars } from '@kbn/ui-theme'; import { ItemDetailsAction, ItemDetailsCard, ItemDetailsPropertySummary } from '.'; diff --git a/x-pack/plugins/security_solution/public/common/components/text_field_value/index.stories.tsx b/x-pack/plugins/security_solution/public/common/components/text_field_value/index.stories.tsx index 146ba8ef825051..3e0cc2d34ce1af 100644 --- a/x-pack/plugins/security_solution/public/common/components/text_field_value/index.stories.tsx +++ b/x-pack/plugins/security_solution/public/common/components/text_field_value/index.stories.tsx @@ -8,7 +8,7 @@ import React from 'react'; import { ThemeProvider } from 'styled-components'; import { storiesOf, addDecorator } from '@storybook/react'; -import { euiLightVars } from '@kbn/ui-shared-deps-src/theme'; +import { euiLightVars } from '@kbn/ui-theme'; import { TextFieldValue } from '.'; diff --git a/x-pack/plugins/security_solution/public/common/components/threat_match/logic_buttons.stories.tsx b/x-pack/plugins/security_solution/public/common/components/threat_match/logic_buttons.stories.tsx index 6497875ac8d4a2..32145412823ecc 100644 --- a/x-pack/plugins/security_solution/public/common/components/threat_match/logic_buttons.stories.tsx +++ b/x-pack/plugins/security_solution/public/common/components/threat_match/logic_buttons.stories.tsx @@ -9,7 +9,7 @@ import { storiesOf, addDecorator } from '@storybook/react'; import { action } from '@storybook/addon-actions'; import React from 'react'; import { ThemeProvider } from 'styled-components'; -import { euiLightVars } from '@kbn/ui-shared-deps-src/theme'; +import { euiLightVars } from '@kbn/ui-theme'; import { LogicButtons } from './logic_buttons'; diff --git a/x-pack/plugins/security_solution/public/common/components/utility_bar/utility_bar.test.tsx b/x-pack/plugins/security_solution/public/common/components/utility_bar/utility_bar.test.tsx index 73acaa48983b43..ac4b2d44204d12 100644 --- a/x-pack/plugins/security_solution/public/common/components/utility_bar/utility_bar.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/utility_bar/utility_bar.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { euiDarkVars } from '@kbn/ui-shared-deps-src/theme'; +import { euiDarkVars } from '@kbn/ui-theme'; import { mount, shallow } from 'enzyme'; import React from 'react'; diff --git a/x-pack/plugins/security_solution/public/common/lib/theme/use_eui_theme.tsx b/x-pack/plugins/security_solution/public/common/lib/theme/use_eui_theme.tsx index 0057666ba4262d..e890d9fe6d650a 100644 --- a/x-pack/plugins/security_solution/public/common/lib/theme/use_eui_theme.tsx +++ b/x-pack/plugins/security_solution/public/common/lib/theme/use_eui_theme.tsx @@ -5,10 +5,7 @@ * 2.0. */ -import { - euiLightVars as lightTheme, - euiDarkVars as darkTheme, -} from '@kbn/ui-shared-deps-src/theme'; +import { euiLightVars as lightTheme, euiDarkVars as darkTheme } from '@kbn/ui-theme'; import { DEFAULT_DARK_MODE } from '../../../../common/constants'; import { useUiSetting$ } from '../kibana'; diff --git a/x-pack/plugins/security_solution/public/common/mock/test_providers.tsx b/x-pack/plugins/security_solution/public/common/mock/test_providers.tsx index 9ad5abc1c7ed23..1909388aea27a5 100644 --- a/x-pack/plugins/security_solution/public/common/mock/test_providers.tsx +++ b/x-pack/plugins/security_solution/public/common/mock/test_providers.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { euiDarkVars } from '@kbn/ui-shared-deps-src/theme'; +import { euiDarkVars } from '@kbn/ui-theme'; import { I18nProvider } from '@kbn/i18n-react'; import React from 'react'; diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/severity_badge/index.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/severity_badge/index.tsx index 835ab73282f1a8..af746d158e2a72 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/severity_badge/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/severity_badge/index.tsx @@ -7,7 +7,7 @@ import { upperFirst } from 'lodash/fp'; import React from 'react'; -import { euiLightVars } from '@kbn/ui-shared-deps-src/theme'; +import { euiLightVars } from '@kbn/ui-theme'; import type { Severity } from '@kbn/securitysolution-io-ts-alerting-types'; import { HealthTruncateText } from '../../../../common/components/health_truncate_text'; diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/step_about_rule/data.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/step_about_rule/data.tsx index df50946f058ba5..b31af0ab269ed3 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/step_about_rule/data.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/step_about_rule/data.tsx @@ -7,7 +7,7 @@ import styled from 'styled-components'; import { EuiHealth } from '@elastic/eui'; -import { euiLightVars } from '@kbn/ui-shared-deps-src/theme'; +import { euiLightVars } from '@kbn/ui-theme'; import React from 'react'; import { Severity } from '@kbn/securitysolution-io-ts-alerting-types'; diff --git a/x-pack/plugins/security_solution/public/hosts/components/common/host_risk_score.test.tsx b/x-pack/plugins/security_solution/public/hosts/components/common/host_risk_score.test.tsx index 1badc0206d12e9..d7e099316cb128 100644 --- a/x-pack/plugins/security_solution/public/hosts/components/common/host_risk_score.test.tsx +++ b/x-pack/plugins/security_solution/public/hosts/components/common/host_risk_score.test.tsx @@ -13,7 +13,7 @@ import { HostRiskScore } from './host_risk_score'; import { EuiHealth, EuiHealthProps } from '@elastic/eui'; -import { euiThemeVars } from '@kbn/ui-shared-deps-src/theme'; +import { euiThemeVars } from '@kbn/ui-theme'; jest.mock('@elastic/eui', () => { const original = jest.requireActual('@elastic/eui'); diff --git a/x-pack/plugins/security_solution/public/hosts/components/common/host_risk_score.tsx b/x-pack/plugins/security_solution/public/hosts/components/common/host_risk_score.tsx index 3f666cf396504b..982cde1e90a004 100644 --- a/x-pack/plugins/security_solution/public/hosts/components/common/host_risk_score.tsx +++ b/x-pack/plugins/security_solution/public/hosts/components/common/host_risk_score.tsx @@ -10,7 +10,7 @@ import React from 'react'; import { EuiHealth, transparentize } from '@elastic/eui'; import styled, { css } from 'styled-components'; -import { euiLightVars } from '@kbn/ui-shared-deps-src/theme'; +import { euiLightVars } from '@kbn/ui-theme'; import { HostRiskSeverity } from '../../../../common/search_strategy'; const HOST_RISK_SEVERITY_COLOUR = { diff --git a/x-pack/plugins/security_solution/public/hosts/components/host_score_over_time/index.tsx b/x-pack/plugins/security_solution/public/hosts/components/host_score_over_time/index.tsx index eb34f9100101b3..9b2c017d3f8d13 100644 --- a/x-pack/plugins/security_solution/public/hosts/components/host_score_over_time/index.tsx +++ b/x-pack/plugins/security_solution/public/hosts/components/host_score_over_time/index.tsx @@ -17,7 +17,7 @@ import { LineAnnotation, TooltipValue, } from '@elastic/charts'; -import { euiThemeVars } from '@kbn/ui-shared-deps-src/theme'; +import { euiThemeVars } from '@kbn/ui-theme'; import { EuiFlexGroup, EuiFlexItem, EuiLoadingChart, EuiText, EuiPanel } from '@elastic/eui'; import styled from 'styled-components'; import { chartDefaultSettings, useTheme } from '../../../common/components/charts/common'; diff --git a/x-pack/plugins/security_solution/public/hosts/components/kpi_hosts/risky_hosts/index.tsx b/x-pack/plugins/security_solution/public/hosts/components/kpi_hosts/risky_hosts/index.tsx index 9e7e01c64a4325..27e0f49bd6de33 100644 --- a/x-pack/plugins/security_solution/public/hosts/components/kpi_hosts/risky_hosts/index.tsx +++ b/x-pack/plugins/security_solution/public/hosts/components/kpi_hosts/risky_hosts/index.tsx @@ -16,7 +16,7 @@ import { } from '@elastic/eui'; import React from 'react'; import styled from 'styled-components'; -import { euiLightVars } from '@kbn/ui-shared-deps-src/theme'; +import { euiLightVars } from '@kbn/ui-theme'; import { InspectButton, BUTTON_CLASS as INPECT_BUTTON_CLASS, diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/components/config_form/index.stories.tsx b/x-pack/plugins/security_solution/public/management/pages/policy/view/components/config_form/index.stories.tsx index 09321244e0abc1..89fe46445b20eb 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/view/components/config_form/index.stories.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/policy/view/components/config_form/index.stories.tsx @@ -8,7 +8,7 @@ import React from 'react'; import { ThemeProvider } from 'styled-components'; import { addDecorator, storiesOf } from '@storybook/react'; -import { euiLightVars } from '@kbn/ui-shared-deps-src/theme'; +import { euiLightVars } from '@kbn/ui-theme'; import { EuiCheckbox, EuiSpacer, EuiSwitch, EuiText } from '@elastic/eui'; import { OperatingSystem } from '../../../../../../../common/endpoint/types'; diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/trusted_apps_grid/index.stories.tsx b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/trusted_apps_grid/index.stories.tsx index ecc18d5d52fd98..79ada902871925 100644 --- a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/trusted_apps_grid/index.stories.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/trusted_apps_grid/index.stories.tsx @@ -9,7 +9,7 @@ import React from 'react'; import { Provider } from 'react-redux'; import { ThemeProvider } from 'styled-components'; import { storiesOf } from '@storybook/react'; -import { euiLightVars } from '@kbn/ui-shared-deps-src/theme'; +import { euiLightVars } from '@kbn/ui-theme'; import { EuiHorizontalRule } from '@elastic/eui'; import { KibanaContextProvider } from '../../../../../../../../../../src/plugins/kibana_react/public'; diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/view_type_toggle/index.stories.tsx b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/view_type_toggle/index.stories.tsx index 484f17318f839f..8ba70769838a36 100644 --- a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/view_type_toggle/index.stories.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/view_type_toggle/index.stories.tsx @@ -8,7 +8,7 @@ import React, { useState } from 'react'; import { ThemeProvider } from 'styled-components'; import { storiesOf, addDecorator } from '@storybook/react'; -import { euiLightVars } from '@kbn/ui-shared-deps-src/theme'; +import { euiLightVars } from '@kbn/ui-theme'; import { ViewType } from '../../../state'; import { ViewTypeToggle } from '.'; diff --git a/x-pack/plugins/security_solution/public/network/components/details/index.tsx b/x-pack/plugins/security_solution/public/network/components/details/index.tsx index 5cd2f4dfd72c8e..af9b5138d853f4 100644 --- a/x-pack/plugins/security_solution/public/network/components/details/index.tsx +++ b/x-pack/plugins/security_solution/public/network/components/details/index.tsx @@ -5,10 +5,7 @@ * 2.0. */ -import { - euiLightVars as lightTheme, - euiDarkVars as darkTheme, -} from '@kbn/ui-shared-deps-src/theme'; +import { euiLightVars as lightTheme, euiDarkVars as darkTheme } from '@kbn/ui-theme'; import React from 'react'; import { DEFAULT_DARK_MODE } from '../../../../common/constants'; diff --git a/x-pack/plugins/security_solution/public/network/components/embeddables/map_tool_tip/tooltip_footer.tsx b/x-pack/plugins/security_solution/public/network/components/embeddables/map_tool_tip/tooltip_footer.tsx index a557ee7b8b190f..fd57256602aa58 100644 --- a/x-pack/plugins/security_solution/public/network/components/embeddables/map_tool_tip/tooltip_footer.tsx +++ b/x-pack/plugins/security_solution/public/network/components/embeddables/map_tool_tip/tooltip_footer.tsx @@ -14,7 +14,7 @@ import { EuiIcon, EuiText, } from '@elastic/eui'; -import { euiLightVars as theme } from '@kbn/ui-shared-deps-src/theme'; +import { euiLightVars as theme } from '@kbn/ui-theme'; import styled from 'styled-components'; import * as i18n from '../translations'; diff --git a/x-pack/plugins/security_solution/public/overview/components/host_overview/index.tsx b/x-pack/plugins/security_solution/public/overview/components/host_overview/index.tsx index 65e85e99e87a00..06f7787085ddc6 100644 --- a/x-pack/plugins/security_solution/public/overview/components/host_overview/index.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/host_overview/index.tsx @@ -6,10 +6,7 @@ */ import { EuiFlexItem, EuiFlexGroup, EuiHorizontalRule } from '@elastic/eui'; -import { - euiLightVars as lightTheme, - euiDarkVars as darkTheme, -} from '@kbn/ui-shared-deps-src/theme'; +import { euiLightVars as lightTheme, euiDarkVars as darkTheme } from '@kbn/ui-theme'; import { getOr } from 'lodash/fp'; import React, { useCallback, useMemo } from 'react'; import styled from 'styled-components'; diff --git a/x-pack/plugins/security_solution/public/resolver/view/use_colors.ts b/x-pack/plugins/security_solution/public/resolver/view/use_colors.ts index f52075cbe4d852..182d710c3c45f8 100644 --- a/x-pack/plugins/security_solution/public/resolver/view/use_colors.ts +++ b/x-pack/plugins/security_solution/public/resolver/view/use_colors.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { darkMode, euiThemeVars } from '@kbn/ui-shared-deps-src/theme'; +import { darkMode, euiThemeVars } from '@kbn/ui-theme'; import { useMemo } from 'react'; type ResolverColorNames = diff --git a/x-pack/plugins/security_solution/public/resolver/view/use_cube_assets.ts b/x-pack/plugins/security_solution/public/resolver/view/use_cube_assets.ts index f5a9c37623c47a..f2fef61d6f3856 100644 --- a/x-pack/plugins/security_solution/public/resolver/view/use_cube_assets.ts +++ b/x-pack/plugins/security_solution/public/resolver/view/use_cube_assets.ts @@ -7,7 +7,7 @@ import { i18n } from '@kbn/i18n'; -import { euiThemeVars } from '@kbn/ui-shared-deps-src/theme'; +import { euiThemeVars } from '@kbn/ui-theme'; import { ButtonColor } from '@elastic/eui'; import { useMemo } from 'react'; import { ResolverProcessType, NodeDataStatus } from '../types'; diff --git a/x-pack/plugins/timelines/public/components/t_grid/body/column_headers/helpers.test.tsx b/x-pack/plugins/timelines/public/components/t_grid/body/column_headers/helpers.test.tsx index 73287c3cf5cec8..4aba02607ec2ed 100644 --- a/x-pack/plugins/timelines/public/components/t_grid/body/column_headers/helpers.test.tsx +++ b/x-pack/plugins/timelines/public/components/t_grid/body/column_headers/helpers.test.tsx @@ -4,7 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { euiThemeVars } from '@kbn/ui-shared-deps-src/theme'; +import { euiThemeVars } from '@kbn/ui-theme'; import { mount } from 'enzyme'; import { omit, set } from 'lodash/fp'; import React from 'react'; diff --git a/x-pack/plugins/timelines/public/components/t_grid/body/column_headers/helpers.tsx b/x-pack/plugins/timelines/public/components/t_grid/body/column_headers/helpers.tsx index 1c2ac89119abb3..35fd814a7c2f4d 100644 --- a/x-pack/plugins/timelines/public/components/t_grid/body/column_headers/helpers.tsx +++ b/x-pack/plugins/timelines/public/components/t_grid/body/column_headers/helpers.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { euiThemeVars } from '@kbn/ui-shared-deps-src/theme'; +import { euiThemeVars } from '@kbn/ui-theme'; import { EuiDataGridColumnActions } from '@elastic/eui'; import { keyBy } from 'lodash/fp'; import React from 'react'; diff --git a/x-pack/plugins/timelines/public/components/t_grid/body/constants.ts b/x-pack/plugins/timelines/public/components/t_grid/body/constants.ts index 2367e6dc38e4c6..3f1889732483d8 100644 --- a/x-pack/plugins/timelines/public/components/t_grid/body/constants.ts +++ b/x-pack/plugins/timelines/public/components/t_grid/body/constants.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { euiThemeVars } from '@kbn/ui-shared-deps-src/theme'; +import { euiThemeVars } from '@kbn/ui-theme'; /** * This is the effective width in pixels of an action button used with diff --git a/x-pack/plugins/timelines/public/components/t_grid/body/helpers.test.tsx b/x-pack/plugins/timelines/public/components/t_grid/body/helpers.test.tsx index 56388b16b1b664..e6550377326500 100644 --- a/x-pack/plugins/timelines/public/components/t_grid/body/helpers.test.tsx +++ b/x-pack/plugins/timelines/public/components/t_grid/body/helpers.test.tsx @@ -18,7 +18,7 @@ import { addBuildingBlockStyle, } from './helpers'; -import { euiThemeVars } from '@kbn/ui-shared-deps-src/theme'; +import { euiThemeVars } from '@kbn/ui-theme'; import { mockDnsEvent } from '../../../mock'; describe('helpers', () => { diff --git a/x-pack/plugins/timelines/public/components/t_grid/integrated/index.test.tsx b/x-pack/plugins/timelines/public/components/t_grid/integrated/index.test.tsx index 0dc8ff58d2ef1a..d58cf96e814753 100644 --- a/x-pack/plugins/timelines/public/components/t_grid/integrated/index.test.tsx +++ b/x-pack/plugins/timelines/public/components/t_grid/integrated/index.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { euiDarkVars } from '@kbn/ui-shared-deps-src/theme'; +import { euiDarkVars } from '@kbn/ui-theme'; import React from 'react'; import { render, screen } from '@testing-library/react'; import { TGridIntegrated, TGridIntegratedProps } from './index'; diff --git a/x-pack/plugins/timelines/public/mock/test_providers.tsx b/x-pack/plugins/timelines/public/mock/test_providers.tsx index 12f8a5329af6a4..179b4e49cc9a96 100644 --- a/x-pack/plugins/timelines/public/mock/test_providers.tsx +++ b/x-pack/plugins/timelines/public/mock/test_providers.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { euiDarkVars } from '@kbn/ui-shared-deps-src/theme'; +import { euiDarkVars } from '@kbn/ui-theme'; import { I18nProvider } from '@kbn/i18n-react'; import React from 'react'; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row_messages_pane.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row_messages_pane.tsx index ce03d5989bc151..2783b204fff2dc 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row_messages_pane.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row_messages_pane.tsx @@ -10,7 +10,7 @@ import React, { useState } from 'react'; import { EuiSpacer, EuiBasicTable } from '@elastic/eui'; // @ts-ignore import { formatDate } from '@elastic/eui/lib/services/format'; -import { euiLightVars as theme } from '@kbn/ui-shared-deps-src/theme'; +import { euiLightVars as theme } from '@kbn/ui-theme'; import { i18n } from '@kbn/i18n'; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/execution_duration_chart.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/execution_duration_chart.tsx index 6cf5e172ff284b..b8c25eef938bb8 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/execution_duration_chart.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/execution_duration_chart.tsx @@ -17,7 +17,7 @@ import { EuiSelect, EuiLoadingChart, } from '@elastic/eui'; -import { euiLightVars as lightEuiTheme } from '@kbn/ui-shared-deps-src/theme'; +import { euiLightVars as lightEuiTheme } from '@kbn/ui-theme'; import { Axis, BarSeries, Chart, CurveType, LineSeries, Settings } from '@elastic/charts'; import { assign, fill } from 'lodash'; import moment from 'moment'; diff --git a/x-pack/plugins/uptime/public/contexts/uptime_theme_context.tsx b/x-pack/plugins/uptime/public/contexts/uptime_theme_context.tsx index 6df3879ef74077..2d25cf6e84e1b6 100644 --- a/x-pack/plugins/uptime/public/contexts/uptime_theme_context.tsx +++ b/x-pack/plugins/uptime/public/contexts/uptime_theme_context.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { euiLightVars, euiDarkVars } from '@kbn/ui-shared-deps-src/theme'; +import { euiLightVars, euiDarkVars } from '@kbn/ui-theme'; import React, { createContext, useMemo } from 'react'; import { EUI_CHARTS_THEME_DARK, EUI_CHARTS_THEME_LIGHT } from '@elastic/eui/dist/eui_charts_theme'; import { DARK_THEME, LIGHT_THEME, PartialTheme, Theme } from '@elastic/charts'; diff --git a/yarn.lock b/yarn.lock index 47a01e6cb8aeeb..2e4d6ddc987fb1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2950,6 +2950,10 @@ version "0.0.0" uid "" +"@kbn/flot-charts@link:bazel-bin/packages/kbn-flot-charts": + version "0.0.0" + uid "" + "@kbn/i18n-react@link:bazel-bin/packages/kbn-i18n-react": version "0.0.0" uid "" @@ -3114,6 +3118,10 @@ version "0.0.0" uid "" +"@kbn/ui-theme@link:bazel-bin/packages/kbn-ui-theme": + version "0.0.0" + uid "" + "@kbn/utility-types@link:bazel-bin/packages/kbn-utility-types": version "0.0.0" uid "" @@ -5960,6 +5968,14 @@ version "0.0.0" uid "" +"@types/kbn__ui-shared-deps-src@link:bazel-bin/packages/kbn-ui-shared-deps-src/npm_module_types": + version "0.0.0" + uid "" + +"@types/kbn__ui-theme@link:bazel-bin/packages/kbn-ui-theme/npm_module_types": + version "0.0.0" + uid "" + "@types/kbn__utility-types@link:bazel-bin/packages/kbn-utility-types/npm_module_types": version "0.0.0" uid "" From eb17b102039f358113a8f81e47ef278d90348cf4 Mon Sep 17 00:00:00 2001 From: Sandra G Date: Thu, 20 Jan 2022 17:13:23 -0500 Subject: [PATCH 105/108] [Stack Monitoring] compatibility for agent data streams (#119112) * update queries for elasticsearch package * fix unit test * add gitCcs helper function * modify rest of es queries * update logstash and kibana queries to use new createQuery * change beats and apm to use new createQuery * update changeQuery and remove old one * make getIndexPattern take request to check for ccs * fix unit test * fix unit tests * update queries and createQuery * don't add metric constant without dataset in query * fix types * fix type * comment out mb tests * fix unit test * fix unit test * fix * fix function param * change to getMetrics name * change to node_stats * comment out metricbeat tests * fix types * improve types and readability for test * remove passing of data stream type for now * add tests for createQuery changes * update getNewIndexPatterns to take one dataset * add unit test for getNewIndexPatterns * fix types * remove metrics from filter, update tests * update createNewIndexPatterns to accept new config instead of legacy * update alert queries to include datas stream index patterns * update comment * fix defaulting ccs to * for non cluster requests * update elasticsearch enterprise module * update unit test * remove data_stream.type from queries * change entsearch to metricbeat module name enterprisesearch * undo ccs cluster stats change * fix import * update alert queries * fix unit test * update unit test * change shard size query to use filter * change must to filter fix * update findSupportedBasicLicenseCluster index pattern * add ccs param to cluster request functions * update queries for ccs in get_clusters_from_request * update getBeatsForClusters query * update clusters apm query * update enterprisesearch query * move index pattern to query in fetch for alerts, fix ccs * remove metricbeat config from alert tests * fix ts * add metricset.name back to queries * comment tests back in * remove enterprise search checking for standalone cluster to fix test * update es index metricset name from index_stats to index for mb data * fix type * fetchClusters creates index pattern * fix type * remove monitoring.ui.metricbeat.index from config and usage in getCollectionStatus * fix type Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- x-pack/plugins/monitoring/common/ccs_utils.ts | 59 +---- x-pack/plugins/monitoring/common/constants.ts | 12 + .../monitoring/server/alerts/base_rule.ts | 25 +- .../alerts/ccr_read_exceptions_rule.test.ts | 1 - .../server/alerts/ccr_read_exceptions_rule.ts | 16 +- .../server/alerts/cluster_health_rule.test.ts | 1 - .../server/alerts/cluster_health_rule.ts | 23 +- .../server/alerts/cpu_usage_rule.test.ts | 1 - .../server/alerts/cpu_usage_rule.ts | 12 +- .../server/alerts/disk_usage_rule.test.ts | 1 - .../server/alerts/disk_usage_rule.ts | 12 +- ...lasticsearch_version_mismatch_rule.test.ts | 1 - .../elasticsearch_version_mismatch_rule.ts | 16 +- .../kibana_version_mismatch_rule.test.ts | 1 - .../alerts/kibana_version_mismatch_rule.ts | 16 +- .../alerts/large_shard_size_rule.test.ts | 1 - .../server/alerts/large_shard_size_rule.ts | 16 +- .../alerts/license_expiration_rule.test.ts | 1 - .../server/alerts/license_expiration_rule.ts | 17 +- .../logstash_version_mismatch_rule.test.ts | 1 - .../alerts/logstash_version_mismatch_rule.ts | 16 +- .../server/alerts/memory_usage_rule.test.ts | 1 - .../server/alerts/memory_usage_rule.ts | 16 +- .../missing_monitoring_data_rule.test.ts | 1 - .../alerts/missing_monitoring_data_rule.ts | 12 +- .../server/alerts/nodes_changed_rule.test.ts | 1 - .../server/alerts/nodes_changed_rule.ts | 18 +- .../thread_pool_rejections_rule_base.ts | 12 +- ...thread_pool_search_rejections_rule.test.ts | 1 - .../thread_pool_write_rejections_rule.test.ts | 1 - .../plugins/monitoring/server/config.test.ts | 3 - x-pack/plugins/monitoring/server/config.ts | 3 - .../collectors/get_usage_collector.ts | 5 +- .../server/lib/alerts/append_mb_index.ts | 12 - .../lib/alerts/create_dataset_query_filter.ts | 24 ++ .../lib/alerts/fetch_ccr_read_exceptions.ts | 19 +- .../lib/alerts/fetch_cluster_health.test.ts | 15 +- .../server/lib/alerts/fetch_cluster_health.ts | 19 +- .../server/lib/alerts/fetch_clusters.test.ts | 21 +- .../server/lib/alerts/fetch_clusters.ts | 18 +- .../alerts/fetch_cpu_usage_node_stats.test.ts | 34 ++- .../lib/alerts/fetch_cpu_usage_node_stats.ts | 20 +- .../fetch_disk_usage_node_stats.test.ts | 15 +- .../lib/alerts/fetch_disk_usage_node_stats.ts | 19 +- .../fetch_elasticsearch_versions.test.ts | 14 +- .../alerts/fetch_elasticsearch_versions.ts | 19 +- .../lib/alerts/fetch_index_shard_size.ts | 22 +- .../lib/alerts/fetch_kibana_versions.test.ts | 14 +- .../lib/alerts/fetch_kibana_versions.ts | 19 +- .../server/lib/alerts/fetch_licenses.test.ts | 12 + .../server/lib/alerts/fetch_licenses.ts | 19 +- .../alerts/fetch_logstash_versions.test.ts | 14 +- .../lib/alerts/fetch_logstash_versions.ts | 19 +- .../alerts/fetch_memory_usage_node_stats.ts | 19 +- .../fetch_missing_monitoring_data.test.ts | 17 +- .../alerts/fetch_missing_monitoring_data.ts | 13 +- .../alerts/fetch_nodes_from_cluster_stats.ts | 19 +- .../fetch_thread_pool_rejections_stats.ts | 19 +- .../server/lib/apm/create_apm_query.ts | 5 +- .../server/lib/apm/get_apms_for_clusters.ts | 21 +- .../server/lib/beats/create_beats_query.ts | 5 +- .../lib/beats/get_beats_for_clusters.ts | 19 +- .../lib/cluster/flag_supported_clusters.ts | 30 +-- .../server/lib/cluster/get_cluster_license.ts | 20 +- .../server/lib/cluster/get_cluster_stats.ts | 5 +- .../lib/cluster/get_clusters_from_request.ts | 39 +-- .../server/lib/cluster/get_clusters_state.ts | 18 +- .../lib/cluster/get_clusters_stats.test.js | 2 +- .../server/lib/cluster/get_clusters_stats.ts | 34 ++- .../lib/cluster/get_index_patterns.test.ts | 102 ++++++++ .../server/lib/cluster/get_index_patterns.ts | 89 ++++++- .../server/lib/create_query.test.js | 114 --------- .../server/lib/create_query.test.ts | 231 ++++++++++++++++++ .../monitoring/server/lib/create_query.ts | 38 ++- .../server/lib/details/get_metrics.test.js | 24 +- .../server/lib/details/get_metrics.ts | 7 +- .../server/lib/details/get_series.ts | 22 +- .../server/lib/elasticsearch/ccr.ts | 19 +- .../lib/elasticsearch/get_last_recovery.ts | 52 +++- .../server/lib/elasticsearch/get_ml_jobs.ts | 59 ++++- .../indices/get_index_summary.ts | 19 +- .../lib/elasticsearch/indices/get_indices.ts | 24 +- .../elasticsearch/nodes/get_node_summary.ts | 30 ++- .../nodes/get_nodes/get_node_ids.test.js | 15 ++ .../nodes/get_nodes/get_node_ids.ts | 16 +- .../nodes/get_nodes/get_nodes.ts | 22 +- .../get_nodes/get_paginated_nodes.test.js | 19 +- .../nodes/get_nodes/get_paginated_nodes.ts | 6 +- ...get_indices_unassigned_shard_stats.test.js | 16 +- .../get_indices_unassigned_shard_stats.ts | 29 ++- .../shards/get_nodes_shard_count.test.js | 16 +- .../shards/get_nodes_shard_count.ts | 33 +-- .../shards/get_shard_allocation.ts | 31 ++- .../elasticsearch/shards/get_shard_stats.ts | 20 +- .../shards/normalize_shard_objects.ts | 3 +- .../create_enterprise_search_query.ts | 22 +- .../get_enterprise_search_for_clusters.ts | 20 +- .../server/lib/enterprise_search/get_stats.ts | 20 +- .../server/lib/kibana/get_kibana_info.ts | 13 +- .../server/lib/kibana/get_kibanas.ts | 26 +- .../lib/kibana/get_kibanas_for_clusters.ts | 27 +- .../server/lib/logs/init_infra_source.ts | 2 +- .../server/lib/logstash/get_cluster_status.ts | 11 +- .../lib/logstash/get_logstash_for_clusters.ts | 25 +- .../server/lib/logstash/get_node_info.test.ts | 19 +- .../server/lib/logstash/get_node_info.ts | 17 +- .../server/lib/logstash/get_nodes.ts | 26 +- .../lib/logstash/get_paginated_pipelines.ts | 64 ++--- .../server/lib/logstash/get_pipeline.ts | 6 - .../server/lib/logstash/get_pipeline_ids.ts | 17 +- .../logstash/get_pipeline_state_document.ts | 19 +- .../get_pipeline_stats_aggregation.ts | 24 +- .../lib/logstash/get_pipeline_versions.ts | 22 +- .../lib/logstash/get_pipeline_vertex.ts | 6 - .../get_pipeline_vertex_stats_aggregation.ts | 23 +- .../collection/get_collection_status.test.js | 3 - .../setup/collection/get_collection_status.ts | 23 +- .../has_standalone_clusters.ts | 23 +- .../api/v1/apm/_get_apm_cluster_status.js | 4 +- .../server/routes/api/v1/apm/instance.js | 4 +- .../server/routes/api/v1/apm/overview.js | 8 +- .../server/routes/api/v1/beats/beat_detail.js | 4 +- .../server/routes/api/v1/beats/overview.js | 2 +- .../routes/api/v1/elasticsearch/ccr_shard.ts | 25 +- .../api/v1/elasticsearch/index_detail.js | 13 +- .../routes/api/v1/elasticsearch/indices.js | 19 +- .../routes/api/v1/elasticsearch/ml_jobs.js | 16 +- .../api/v1/elasticsearch/node_detail.js | 13 +- .../routes/api/v1/elasticsearch/nodes.js | 26 +- .../routes/api/v1/elasticsearch/overview.js | 36 +-- .../check/internal_monitoring.ts | 6 +- .../api/v1/enterprise_search/overview.js | 12 +- .../v1/kibana/_get_kibana_cluster_status.js | 6 +- .../server/routes/api/v1/kibana/instance.ts | 10 +- .../server/routes/api/v1/kibana/instances.js | 9 +- .../server/routes/api/v1/kibana/overview.js | 14 +- .../server/routes/api/v1/logstash/node.js | 13 +- .../server/routes/api/v1/logstash/nodes.js | 2 +- .../server/routes/api/v1/logstash/overview.js | 14 +- .../server/routes/api/v1/logstash/pipeline.js | 18 +- .../logstash/pipelines/cluster_pipelines.js | 9 +- .../v1/logstash/pipelines/node_pipelines.js | 9 +- .../apis/monitoring/apm/index.js | 6 +- .../apis/monitoring/beats/index.js | 6 +- .../apis/monitoring/cluster/index.js | 4 +- .../apis/monitoring/elasticsearch/index.js | 16 +- .../apis/monitoring/kibana/index.js | 6 +- .../apis/monitoring/logstash/index.js | 10 +- .../apis/monitoring/setup/collection/index.js | 8 +- .../data.json.gz | Bin 282109 -> 282241 bytes .../data.json.gz | Bin 229987 -> 229957 bytes 151 files changed, 1678 insertions(+), 1160 deletions(-) delete mode 100644 x-pack/plugins/monitoring/server/lib/alerts/append_mb_index.ts create mode 100644 x-pack/plugins/monitoring/server/lib/alerts/create_dataset_query_filter.ts create mode 100644 x-pack/plugins/monitoring/server/lib/cluster/get_index_patterns.test.ts delete mode 100644 x-pack/plugins/monitoring/server/lib/create_query.test.js create mode 100644 x-pack/plugins/monitoring/server/lib/create_query.test.ts diff --git a/x-pack/plugins/monitoring/common/ccs_utils.ts b/x-pack/plugins/monitoring/common/ccs_utils.ts index 7efe6e43ddbbd8..982189a1e4a977 100644 --- a/x-pack/plugins/monitoring/common/ccs_utils.ts +++ b/x-pack/plugins/monitoring/common/ccs_utils.ts @@ -13,32 +13,17 @@ type Config = Partial & { get?: (key: string) => any; }; -export function appendMetricbeatIndex( - config: Config, - indexPattern: string, - ccs?: string, - bypass: boolean = false -) { - if (bypass) { - return indexPattern; - } - // Leverage this function to also append the dynamic metricbeat index too - let mbIndex = null; +export function getConfigCcs(config: Config): boolean { + let ccsEnabled = false; // TODO: NP // This function is called with both NP config and LP config if (isFunction(config.get)) { - mbIndex = config.get('monitoring.ui.metricbeat.index'); + ccsEnabled = config.get('monitoring.ui.ccs.enabled'); } else { - mbIndex = get(config, 'ui.metricbeat.index'); - } - - if (ccs) { - mbIndex = `${mbIndex},${ccs}:${mbIndex}`; + ccsEnabled = get(config, 'ui.ccs.enabled'); } - - return `${indexPattern},${mbIndex}`; + return ccsEnabled; } - /** * Prefix all comma separated index patterns within the original {@code indexPattern}. * @@ -50,28 +35,10 @@ export function appendMetricbeatIndex( * @param {String} ccs The optional cluster-prefix to prepend. * @return {String} The index pattern with the {@code cluster} prefix appropriately prepended. */ -export function prefixIndexPattern( - config: Config, - indexPattern: string, - ccs?: string, - monitoringIndicesOnly: boolean = false -) { - let ccsEnabled = false; - // TODO: NP - // This function is called with both NP config and LP config - if (isFunction(config.get)) { - ccsEnabled = config.get('monitoring.ui.ccs.enabled'); - } else { - ccsEnabled = get(config, 'ui.ccs.enabled'); - } - +export function prefixIndexPattern(config: Config, indexPattern: string, ccs?: string) { + const ccsEnabled = getConfigCcs(config); if (!ccsEnabled || !ccs) { - return appendMetricbeatIndex( - config, - indexPattern, - ccsEnabled ? ccs : undefined, - monitoringIndicesOnly - ); + return indexPattern; } const patterns = indexPattern.split(','); @@ -79,15 +46,9 @@ export function prefixIndexPattern( // if a wildcard is used, then we also want to search the local indices if (ccs === '*') { - return appendMetricbeatIndex( - config, - `${prefixedPattern},${indexPattern}`, - ccs, - monitoringIndicesOnly - ); + return `${prefixedPattern},${indexPattern}`; } - - return appendMetricbeatIndex(config, prefixedPattern, ccs, monitoringIndicesOnly); + return prefixedPattern; } /** diff --git a/x-pack/plugins/monitoring/common/constants.ts b/x-pack/plugins/monitoring/common/constants.ts index 67cc86c013ca2d..96f66fc3d41778 100644 --- a/x-pack/plugins/monitoring/common/constants.ts +++ b/x-pack/plugins/monitoring/common/constants.ts @@ -132,6 +132,9 @@ export const INDEX_PATTERN_ELASTICSEARCH = '.monitoring-es-*'; // ECS-compliant patterns (metricbeat >8 and agent) export const INDEX_PATTERN_ELASTICSEARCH_ECS = '.monitoring-es-8-*'; export const INDEX_PATTERN_ENTERPRISE_SEARCH = '.monitoring-ent-search-*'; +export const DS_INDEX_PATTERN_METRICS = 'metrics'; +export const DS_INDEX_PATTERN_LOGS = 'logs'; +export const DS_INDEX_PATTERN_ES = 'elasticsearch'; // This is the unique token that exists in monitoring indices collected by metricbeat export const METRICBEAT_INDEX_NAME_UNIQUE_TOKEN = '-mb-'; @@ -586,3 +589,12 @@ export const ALERT_EMAIL_SERVICES = ['gmail', 'hotmail', 'icloud', 'outlook365', export const SAVED_OBJECT_TELEMETRY = 'monitoring-telemetry'; export const TELEMETRY_METRIC_BUTTON_CLICK = 'btnclick__'; + +export type INDEX_PATTERN_TYPES = + | 'elasticsearch' + | 'kibana' + | 'logstash' + | 'beats' + | 'enterprisesearch'; + +export type DS_INDEX_PATTERN_TYPES = typeof DS_INDEX_PATTERN_METRICS | typeof DS_INDEX_PATTERN_LOGS; diff --git a/x-pack/plugins/monitoring/server/alerts/base_rule.ts b/x-pack/plugins/monitoring/server/alerts/base_rule.ts index f05077ec4bb006..d13e6d9ed7f9b2 100644 --- a/x-pack/plugins/monitoring/server/alerts/base_rule.ts +++ b/x-pack/plugins/monitoring/server/alerts/base_rule.ts @@ -28,10 +28,7 @@ import { CommonAlertParams, } from '../../common/types/alerts'; import { fetchClusters } from '../lib/alerts/fetch_clusters'; -import { getCcsIndexPattern } from '../lib/alerts/get_ccs_index_pattern'; -import { INDEX_PATTERN_ELASTICSEARCH } from '../../common/constants'; import { AlertSeverity } from '../../common/enums'; -import { appendMetricbeatIndex } from '../lib/alerts/append_mb_index'; import { parseDuration } from '../../../alerting/common'; import { Globals } from '../static_globals'; @@ -226,23 +223,14 @@ export class BaseRule { ); const esClient = services.scopedClusterClient.asCurrentUser; - const availableCcs = Globals.app.config.ui.ccs.enabled; - const clusters = await this.fetchClusters(esClient, params as CommonAlertParams, availableCcs); - const data = await this.fetchData(params, esClient, clusters, availableCcs); + const clusters = await this.fetchClusters(esClient, params as CommonAlertParams); + const data = await this.fetchData(params, esClient, clusters); return await this.processData(data, clusters, services, state); } - protected async fetchClusters( - esClient: ElasticsearchClient, - params: CommonAlertParams, - ccs?: boolean - ) { - let esIndexPattern = appendMetricbeatIndex(Globals.app.config, INDEX_PATTERN_ELASTICSEARCH); - if (ccs) { - esIndexPattern = getCcsIndexPattern(esIndexPattern, ccs); - } + protected async fetchClusters(esClient: ElasticsearchClient, params: CommonAlertParams) { if (!params.limit) { - return await fetchClusters(esClient, esIndexPattern); + return await fetchClusters(esClient); } const limit = parseDuration(params.limit); const rangeFilter = this.ruleOptions.fetchClustersRange @@ -253,14 +241,13 @@ export class BaseRule { }, } : undefined; - return await fetchClusters(esClient, esIndexPattern, rangeFilter); + return await fetchClusters(esClient, rangeFilter); } protected async fetchData( params: CommonAlertParams | unknown, esClient: ElasticsearchClient, - clusters: AlertCluster[], - availableCcs: boolean + clusters: AlertCluster[] ): Promise> { throw new Error('Child classes must implement `fetchData`'); } diff --git a/x-pack/plugins/monitoring/server/alerts/ccr_read_exceptions_rule.test.ts b/x-pack/plugins/monitoring/server/alerts/ccr_read_exceptions_rule.test.ts index 8dd4623bfd7e43..ed4ba69b8e2547 100644 --- a/x-pack/plugins/monitoring/server/alerts/ccr_read_exceptions_rule.test.ts +++ b/x-pack/plugins/monitoring/server/alerts/ccr_read_exceptions_rule.test.ts @@ -39,7 +39,6 @@ jest.mock('../static_globals', () => ({ config: { ui: { ccs: { enabled: true }, - metricbeat: { index: 'metricbeat-*' }, container: { elasticsearch: { enabled: false } }, }, }, diff --git a/x-pack/plugins/monitoring/server/alerts/ccr_read_exceptions_rule.ts b/x-pack/plugins/monitoring/server/alerts/ccr_read_exceptions_rule.ts index 9b2f9b9fb3ed75..705d0c6b9c87f1 100644 --- a/x-pack/plugins/monitoring/server/alerts/ccr_read_exceptions_rule.ts +++ b/x-pack/plugins/monitoring/server/alerts/ccr_read_exceptions_rule.ts @@ -22,18 +22,12 @@ import { CCRReadExceptionsStats, } from '../../common/types/alerts'; import { AlertInstance } from '../../../alerting/server'; -import { - INDEX_PATTERN_ELASTICSEARCH, - RULE_CCR_READ_EXCEPTIONS, - RULE_DETAILS, -} from '../../common/constants'; +import { RULE_CCR_READ_EXCEPTIONS, RULE_DETAILS } from '../../common/constants'; import { fetchCCRReadExceptions } from '../lib/alerts/fetch_ccr_read_exceptions'; -import { getCcsIndexPattern } from '../lib/alerts/get_ccs_index_pattern'; import { AlertMessageTokenType, AlertSeverity } from '../../common/enums'; import { parseDuration } from '../../../alerting/common/parse_duration'; import { SanitizedAlert, RawAlertInstance } from '../../../alerting/common'; import { AlertingDefaults, createLink } from './alert_helpers'; -import { appendMetricbeatIndex } from '../lib/alerts/append_mb_index'; import { Globals } from '../static_globals'; export class CCRReadExceptionsRule extends BaseRule { @@ -72,20 +66,14 @@ export class CCRReadExceptionsRule extends BaseRule { protected async fetchData( params: CommonAlertParams, esClient: ElasticsearchClient, - clusters: AlertCluster[], - availableCcs: boolean + clusters: AlertCluster[] ): Promise { - let esIndexPattern = appendMetricbeatIndex(Globals.app.config, INDEX_PATTERN_ELASTICSEARCH); - if (availableCcs) { - esIndexPattern = getCcsIndexPattern(esIndexPattern, availableCcs); - } const { duration: durationString } = params; const duration = parseDuration(durationString); const endMs = +new Date(); const startMs = endMs - duration; const stats = await fetchCCRReadExceptions( esClient, - esIndexPattern, startMs, endMs, Globals.app.config.ui.max_bucket_size, diff --git a/x-pack/plugins/monitoring/server/alerts/cluster_health_rule.test.ts b/x-pack/plugins/monitoring/server/alerts/cluster_health_rule.test.ts index 5d209f7fc4a81f..85030657825c4f 100644 --- a/x-pack/plugins/monitoring/server/alerts/cluster_health_rule.test.ts +++ b/x-pack/plugins/monitoring/server/alerts/cluster_health_rule.test.ts @@ -21,7 +21,6 @@ jest.mock('../static_globals', () => ({ config: { ui: { ccs: { enabled: true }, - metricbeat: { index: 'metricbeat-*' }, }, }, }, diff --git a/x-pack/plugins/monitoring/server/alerts/cluster_health_rule.ts b/x-pack/plugins/monitoring/server/alerts/cluster_health_rule.ts index e85fb33cd76bda..b8810196c833a1 100644 --- a/x-pack/plugins/monitoring/server/alerts/cluster_health_rule.ts +++ b/x-pack/plugins/monitoring/server/alerts/cluster_health_rule.ts @@ -19,17 +19,10 @@ import { AlertInstanceState, } from '../../common/types/alerts'; import { AlertInstance } from '../../../alerting/server'; -import { - RULE_CLUSTER_HEALTH, - LEGACY_RULE_DETAILS, - INDEX_PATTERN_ELASTICSEARCH, -} from '../../common/constants'; +import { RULE_CLUSTER_HEALTH, LEGACY_RULE_DETAILS } from '../../common/constants'; import { AlertMessageTokenType, AlertClusterHealthType, AlertSeverity } from '../../common/enums'; import { AlertingDefaults } from './alert_helpers'; import { SanitizedAlert } from '../../../alerting/common'; -import { Globals } from '../static_globals'; -import { getCcsIndexPattern } from '../lib/alerts/get_ccs_index_pattern'; -import { appendMetricbeatIndex } from '../lib/alerts/append_mb_index'; import { fetchClusterHealth } from '../lib/alerts/fetch_cluster_health'; const RED_STATUS_MESSAGE = i18n.translate('xpack.monitoring.alerts.clusterHealth.redMessage', { @@ -66,19 +59,9 @@ export class ClusterHealthRule extends BaseRule { protected async fetchData( params: CommonAlertParams, esClient: ElasticsearchClient, - clusters: AlertCluster[], - availableCcs: boolean + clusters: AlertCluster[] ): Promise { - let esIndexPattern = appendMetricbeatIndex(Globals.app.config, INDEX_PATTERN_ELASTICSEARCH); - if (availableCcs) { - esIndexPattern = getCcsIndexPattern(esIndexPattern, availableCcs); - } - const healths = await fetchClusterHealth( - esClient, - clusters, - esIndexPattern, - params.filterQuery - ); + const healths = await fetchClusterHealth(esClient, clusters, params.filterQuery); return healths.map((clusterHealth) => { const shouldFire = clusterHealth.health !== AlertClusterHealthType.Green; const severity = diff --git a/x-pack/plugins/monitoring/server/alerts/cpu_usage_rule.test.ts b/x-pack/plugins/monitoring/server/alerts/cpu_usage_rule.test.ts index 9b19c1ddeb7d11..bcd2c0cbb58102 100644 --- a/x-pack/plugins/monitoring/server/alerts/cpu_usage_rule.test.ts +++ b/x-pack/plugins/monitoring/server/alerts/cpu_usage_rule.test.ts @@ -27,7 +27,6 @@ jest.mock('../static_globals', () => ({ config: { ui: { ccs: { enabled: true }, - metricbeat: { index: 'metricbeat-*' }, container: { elasticsearch: { enabled: false } }, }, }, diff --git a/x-pack/plugins/monitoring/server/alerts/cpu_usage_rule.ts b/x-pack/plugins/monitoring/server/alerts/cpu_usage_rule.ts index b41783d449c02b..fa4b64fd997c34 100644 --- a/x-pack/plugins/monitoring/server/alerts/cpu_usage_rule.ts +++ b/x-pack/plugins/monitoring/server/alerts/cpu_usage_rule.ts @@ -23,16 +23,14 @@ import { CommonAlertFilter, } from '../../common/types/alerts'; import { AlertInstance } from '../../../alerting/server'; -import { INDEX_PATTERN_ELASTICSEARCH, RULE_CPU_USAGE, RULE_DETAILS } from '../../common/constants'; +import { RULE_CPU_USAGE, RULE_DETAILS } from '../../common/constants'; // @ts-ignore import { ROUNDED_FLOAT } from '../../common/formatting'; import { fetchCpuUsageNodeStats } from '../lib/alerts/fetch_cpu_usage_node_stats'; -import { getCcsIndexPattern } from '../lib/alerts/get_ccs_index_pattern'; import { AlertMessageTokenType, AlertSeverity } from '../../common/enums'; import { RawAlertInstance, SanitizedAlert } from '../../../alerting/common'; import { parseDuration } from '../../../alerting/common/parse_duration'; import { AlertingDefaults, createLink } from './alert_helpers'; -import { appendMetricbeatIndex } from '../lib/alerts/append_mb_index'; import { Globals } from '../static_globals'; export class CpuUsageRule extends BaseRule { @@ -60,20 +58,14 @@ export class CpuUsageRule extends BaseRule { protected async fetchData( params: CommonAlertParams, esClient: ElasticsearchClient, - clusters: AlertCluster[], - availableCcs: boolean + clusters: AlertCluster[] ): Promise { - let esIndexPattern = appendMetricbeatIndex(Globals.app.config, INDEX_PATTERN_ELASTICSEARCH); - if (availableCcs) { - esIndexPattern = getCcsIndexPattern(esIndexPattern, availableCcs); - } const duration = parseDuration(params.duration); const endMs = +new Date(); const startMs = endMs - duration; const stats = await fetchCpuUsageNodeStats( esClient, clusters, - esIndexPattern, startMs, endMs, Globals.app.config.ui.max_bucket_size, diff --git a/x-pack/plugins/monitoring/server/alerts/disk_usage_rule.test.ts b/x-pack/plugins/monitoring/server/alerts/disk_usage_rule.test.ts index 63ff6a7ccab93a..daaded1c18c803 100644 --- a/x-pack/plugins/monitoring/server/alerts/disk_usage_rule.test.ts +++ b/x-pack/plugins/monitoring/server/alerts/disk_usage_rule.test.ts @@ -40,7 +40,6 @@ jest.mock('../static_globals', () => ({ config: { ui: { ccs: { enabled: true }, - metricbeat: { index: 'metricbeat-*' }, container: { elasticsearch: { enabled: false } }, }, }, diff --git a/x-pack/plugins/monitoring/server/alerts/disk_usage_rule.ts b/x-pack/plugins/monitoring/server/alerts/disk_usage_rule.ts index 17dff8ea6a9dd4..1e06f0649d1078 100644 --- a/x-pack/plugins/monitoring/server/alerts/disk_usage_rule.ts +++ b/x-pack/plugins/monitoring/server/alerts/disk_usage_rule.ts @@ -23,15 +23,13 @@ import { CommonAlertFilter, } from '../../common/types/alerts'; import { AlertInstance } from '../../../alerting/server'; -import { INDEX_PATTERN_ELASTICSEARCH, RULE_DISK_USAGE, RULE_DETAILS } from '../../common/constants'; +import { RULE_DISK_USAGE, RULE_DETAILS } from '../../common/constants'; // @ts-ignore import { ROUNDED_FLOAT } from '../../common/formatting'; import { fetchDiskUsageNodeStats } from '../lib/alerts/fetch_disk_usage_node_stats'; -import { getCcsIndexPattern } from '../lib/alerts/get_ccs_index_pattern'; import { AlertMessageTokenType, AlertSeverity } from '../../common/enums'; import { RawAlertInstance, SanitizedAlert } from '../../../alerting/common'; import { AlertingDefaults, createLink } from './alert_helpers'; -import { appendMetricbeatIndex } from '../lib/alerts/append_mb_index'; import { Globals } from '../static_globals'; export class DiskUsageRule extends BaseRule { @@ -59,18 +57,12 @@ export class DiskUsageRule extends BaseRule { protected async fetchData( params: CommonAlertParams, esClient: ElasticsearchClient, - clusters: AlertCluster[], - availableCcs: boolean + clusters: AlertCluster[] ): Promise { - let esIndexPattern = appendMetricbeatIndex(Globals.app.config, INDEX_PATTERN_ELASTICSEARCH); - if (availableCcs) { - esIndexPattern = getCcsIndexPattern(esIndexPattern, availableCcs); - } const { duration, threshold } = params; const stats = await fetchDiskUsageNodeStats( esClient, clusters, - esIndexPattern, duration as string, Globals.app.config.ui.max_bucket_size, params.filterQuery diff --git a/x-pack/plugins/monitoring/server/alerts/elasticsearch_version_mismatch_rule.test.ts b/x-pack/plugins/monitoring/server/alerts/elasticsearch_version_mismatch_rule.test.ts index 12fa54f34e3c4d..4531c5f0f1ffc1 100644 --- a/x-pack/plugins/monitoring/server/alerts/elasticsearch_version_mismatch_rule.test.ts +++ b/x-pack/plugins/monitoring/server/alerts/elasticsearch_version_mismatch_rule.test.ts @@ -28,7 +28,6 @@ jest.mock('../static_globals', () => ({ config: { ui: { ccs: { enabled: true }, - metricbeat: { index: 'metricbeat-*' }, container: { elasticsearch: { enabled: false } }, }, }, diff --git a/x-pack/plugins/monitoring/server/alerts/elasticsearch_version_mismatch_rule.ts b/x-pack/plugins/monitoring/server/alerts/elasticsearch_version_mismatch_rule.ts index b873a20c874b53..9d89f827f9b10d 100644 --- a/x-pack/plugins/monitoring/server/alerts/elasticsearch_version_mismatch_rule.ts +++ b/x-pack/plugins/monitoring/server/alerts/elasticsearch_version_mismatch_rule.ts @@ -18,17 +18,11 @@ import { AlertVersions, } from '../../common/types/alerts'; import { AlertInstance } from '../../../alerting/server'; -import { - RULE_ELASTICSEARCH_VERSION_MISMATCH, - LEGACY_RULE_DETAILS, - INDEX_PATTERN_ELASTICSEARCH, -} from '../../common/constants'; +import { RULE_ELASTICSEARCH_VERSION_MISMATCH, LEGACY_RULE_DETAILS } from '../../common/constants'; import { AlertSeverity } from '../../common/enums'; import { AlertingDefaults } from './alert_helpers'; import { SanitizedAlert } from '../../../alerting/common'; import { Globals } from '../static_globals'; -import { getCcsIndexPattern } from '../lib/alerts/get_ccs_index_pattern'; -import { appendMetricbeatIndex } from '../lib/alerts/append_mb_index'; import { fetchElasticsearchVersions } from '../lib/alerts/fetch_elasticsearch_versions'; export class ElasticsearchVersionMismatchRule extends BaseRule { @@ -55,17 +49,11 @@ export class ElasticsearchVersionMismatchRule extends BaseRule { protected async fetchData( params: CommonAlertParams, esClient: ElasticsearchClient, - clusters: AlertCluster[], - availableCcs: boolean + clusters: AlertCluster[] ): Promise { - let esIndexPattern = appendMetricbeatIndex(Globals.app.config, INDEX_PATTERN_ELASTICSEARCH); - if (availableCcs) { - esIndexPattern = getCcsIndexPattern(esIndexPattern, availableCcs); - } const elasticsearchVersions = await fetchElasticsearchVersions( esClient, clusters, - esIndexPattern, Globals.app.config.ui.max_bucket_size, params.filterQuery ); diff --git a/x-pack/plugins/monitoring/server/alerts/kibana_version_mismatch_rule.test.ts b/x-pack/plugins/monitoring/server/alerts/kibana_version_mismatch_rule.test.ts index 01016a7c02ae20..b4444c9088073c 100644 --- a/x-pack/plugins/monitoring/server/alerts/kibana_version_mismatch_rule.test.ts +++ b/x-pack/plugins/monitoring/server/alerts/kibana_version_mismatch_rule.test.ts @@ -28,7 +28,6 @@ jest.mock('../static_globals', () => ({ config: { ui: { ccs: { enabled: true }, - metricbeat: { index: 'metricbeat-*' }, container: { elasticsearch: { enabled: false } }, }, }, diff --git a/x-pack/plugins/monitoring/server/alerts/kibana_version_mismatch_rule.ts b/x-pack/plugins/monitoring/server/alerts/kibana_version_mismatch_rule.ts index 79f449f8e7ef72..24182c4a545d3d 100644 --- a/x-pack/plugins/monitoring/server/alerts/kibana_version_mismatch_rule.ts +++ b/x-pack/plugins/monitoring/server/alerts/kibana_version_mismatch_rule.ts @@ -18,17 +18,11 @@ import { AlertVersions, } from '../../common/types/alerts'; import { AlertInstance } from '../../../alerting/server'; -import { - RULE_KIBANA_VERSION_MISMATCH, - LEGACY_RULE_DETAILS, - INDEX_PATTERN_KIBANA, -} from '../../common/constants'; +import { RULE_KIBANA_VERSION_MISMATCH, LEGACY_RULE_DETAILS } from '../../common/constants'; import { AlertSeverity } from '../../common/enums'; import { AlertingDefaults } from './alert_helpers'; import { SanitizedAlert } from '../../../alerting/common'; import { Globals } from '../static_globals'; -import { getCcsIndexPattern } from '../lib/alerts/get_ccs_index_pattern'; -import { appendMetricbeatIndex } from '../lib/alerts/append_mb_index'; import { fetchKibanaVersions } from '../lib/alerts/fetch_kibana_versions'; export class KibanaVersionMismatchRule extends BaseRule { @@ -68,17 +62,11 @@ export class KibanaVersionMismatchRule extends BaseRule { protected async fetchData( params: CommonAlertParams, esClient: ElasticsearchClient, - clusters: AlertCluster[], - availableCcs: boolean + clusters: AlertCluster[] ): Promise { - let kibanaIndexPattern = appendMetricbeatIndex(Globals.app.config, INDEX_PATTERN_KIBANA); - if (availableCcs) { - kibanaIndexPattern = getCcsIndexPattern(kibanaIndexPattern, availableCcs); - } const kibanaVersions = await fetchKibanaVersions( esClient, clusters, - kibanaIndexPattern, Globals.app.config.ui.max_bucket_size, params.filterQuery ); diff --git a/x-pack/plugins/monitoring/server/alerts/large_shard_size_rule.test.ts b/x-pack/plugins/monitoring/server/alerts/large_shard_size_rule.test.ts index f7d6081edd306c..0460064b4f7c55 100644 --- a/x-pack/plugins/monitoring/server/alerts/large_shard_size_rule.test.ts +++ b/x-pack/plugins/monitoring/server/alerts/large_shard_size_rule.test.ts @@ -40,7 +40,6 @@ jest.mock('../static_globals', () => ({ config: { ui: { ccs: { enabled: true }, - metricbeat: { index: 'metricbeat-*' }, container: { elasticsearch: { enabled: false } }, }, }, diff --git a/x-pack/plugins/monitoring/server/alerts/large_shard_size_rule.ts b/x-pack/plugins/monitoring/server/alerts/large_shard_size_rule.ts index 3009995e2f292f..92be43b9c06c0f 100644 --- a/x-pack/plugins/monitoring/server/alerts/large_shard_size_rule.ts +++ b/x-pack/plugins/monitoring/server/alerts/large_shard_size_rule.ts @@ -22,17 +22,11 @@ import { IndexShardSizeStats, } from '../../common/types/alerts'; import { AlertInstance } from '../../../alerting/server'; -import { - INDEX_PATTERN_ELASTICSEARCH, - RULE_LARGE_SHARD_SIZE, - RULE_DETAILS, -} from '../../common/constants'; +import { RULE_LARGE_SHARD_SIZE, RULE_DETAILS } from '../../common/constants'; import { fetchIndexShardSize } from '../lib/alerts/fetch_index_shard_size'; -import { getCcsIndexPattern } from '../lib/alerts/get_ccs_index_pattern'; import { AlertMessageTokenType, AlertSeverity } from '../../common/enums'; import { SanitizedAlert, RawAlertInstance } from '../../../alerting/common'; import { AlertingDefaults, createLink } from './alert_helpers'; -import { appendMetricbeatIndex } from '../lib/alerts/append_mb_index'; import { Globals } from '../static_globals'; export class LargeShardSizeRule extends BaseRule { @@ -60,19 +54,13 @@ export class LargeShardSizeRule extends BaseRule { protected async fetchData( params: CommonAlertParams & { indexPattern: string }, esClient: ElasticsearchClient, - clusters: AlertCluster[], - availableCcs: boolean + clusters: AlertCluster[] ): Promise { - let esIndexPattern = appendMetricbeatIndex(Globals.app.config, INDEX_PATTERN_ELASTICSEARCH); - if (availableCcs) { - esIndexPattern = getCcsIndexPattern(esIndexPattern, availableCcs); - } const { threshold, indexPattern: shardIndexPatterns } = params; const stats = await fetchIndexShardSize( esClient, clusters, - esIndexPattern, threshold!, shardIndexPatterns, Globals.app.config.ui.max_bucket_size, diff --git a/x-pack/plugins/monitoring/server/alerts/license_expiration_rule.test.ts b/x-pack/plugins/monitoring/server/alerts/license_expiration_rule.test.ts index b29a5fc4661d74..86a6f666fcf87c 100644 --- a/x-pack/plugins/monitoring/server/alerts/license_expiration_rule.test.ts +++ b/x-pack/plugins/monitoring/server/alerts/license_expiration_rule.test.ts @@ -34,7 +34,6 @@ jest.mock('../static_globals', () => ({ ui: { show_license_expiration: true, ccs: { enabled: true }, - metricbeat: { index: 'metricbeat-*' }, container: { elasticsearch: { enabled: false } }, }, }, diff --git a/x-pack/plugins/monitoring/server/alerts/license_expiration_rule.ts b/x-pack/plugins/monitoring/server/alerts/license_expiration_rule.ts index fc050bd6780129..3a837a125a523b 100644 --- a/x-pack/plugins/monitoring/server/alerts/license_expiration_rule.ts +++ b/x-pack/plugins/monitoring/server/alerts/license_expiration_rule.ts @@ -21,17 +21,11 @@ import { AlertLicenseState, } from '../../common/types/alerts'; import { AlertExecutorOptions, AlertInstance } from '../../../alerting/server'; -import { - RULE_LICENSE_EXPIRATION, - LEGACY_RULE_DETAILS, - INDEX_PATTERN_ELASTICSEARCH, -} from '../../common/constants'; +import { RULE_LICENSE_EXPIRATION, LEGACY_RULE_DETAILS } from '../../common/constants'; import { AlertMessageTokenType, AlertSeverity } from '../../common/enums'; import { AlertingDefaults } from './alert_helpers'; import { SanitizedAlert } from '../../../alerting/common'; import { Globals } from '../static_globals'; -import { getCcsIndexPattern } from '../lib/alerts/get_ccs_index_pattern'; -import { appendMetricbeatIndex } from '../lib/alerts/append_mb_index'; import { fetchLicenses } from '../lib/alerts/fetch_licenses'; const EXPIRES_DAYS = [60, 30, 14, 7]; @@ -80,14 +74,9 @@ export class LicenseExpirationRule extends BaseRule { protected async fetchData( params: CommonAlertParams, esClient: ElasticsearchClient, - clusters: AlertCluster[], - availableCcs: boolean + clusters: AlertCluster[] ): Promise { - let esIndexPattern = appendMetricbeatIndex(Globals.app.config, INDEX_PATTERN_ELASTICSEARCH); - if (availableCcs) { - esIndexPattern = getCcsIndexPattern(esIndexPattern, availableCcs); - } - const licenses = await fetchLicenses(esClient, clusters, esIndexPattern, params.filterQuery); + const licenses = await fetchLicenses(esClient, clusters, params.filterQuery); return licenses.map((license) => { const { clusterUuid, type, expiryDateMS, status, ccs } = license; diff --git a/x-pack/plugins/monitoring/server/alerts/logstash_version_mismatch_rule.test.ts b/x-pack/plugins/monitoring/server/alerts/logstash_version_mismatch_rule.test.ts index 20f64b65ba1f05..857a9bf5bfa791 100644 --- a/x-pack/plugins/monitoring/server/alerts/logstash_version_mismatch_rule.test.ts +++ b/x-pack/plugins/monitoring/server/alerts/logstash_version_mismatch_rule.test.ts @@ -29,7 +29,6 @@ jest.mock('../static_globals', () => ({ ui: { show_license_expiration: true, ccs: { enabled: true }, - metricbeat: { index: 'metricbeat-*' }, container: { elasticsearch: { enabled: false } }, }, }, diff --git a/x-pack/plugins/monitoring/server/alerts/logstash_version_mismatch_rule.ts b/x-pack/plugins/monitoring/server/alerts/logstash_version_mismatch_rule.ts index 6d7c06c1c1e07c..ee3e5838d7d35c 100644 --- a/x-pack/plugins/monitoring/server/alerts/logstash_version_mismatch_rule.ts +++ b/x-pack/plugins/monitoring/server/alerts/logstash_version_mismatch_rule.ts @@ -18,17 +18,11 @@ import { AlertVersions, } from '../../common/types/alerts'; import { AlertInstance } from '../../../alerting/server'; -import { - RULE_LOGSTASH_VERSION_MISMATCH, - LEGACY_RULE_DETAILS, - INDEX_PATTERN_LOGSTASH, -} from '../../common/constants'; +import { RULE_LOGSTASH_VERSION_MISMATCH, LEGACY_RULE_DETAILS } from '../../common/constants'; import { AlertSeverity } from '../../common/enums'; import { AlertingDefaults } from './alert_helpers'; import { SanitizedAlert } from '../../../alerting/common'; import { Globals } from '../static_globals'; -import { getCcsIndexPattern } from '../lib/alerts/get_ccs_index_pattern'; -import { appendMetricbeatIndex } from '../lib/alerts/append_mb_index'; import { fetchLogstashVersions } from '../lib/alerts/fetch_logstash_versions'; export class LogstashVersionMismatchRule extends BaseRule { @@ -55,17 +49,11 @@ export class LogstashVersionMismatchRule extends BaseRule { protected async fetchData( params: CommonAlertParams, esClient: ElasticsearchClient, - clusters: AlertCluster[], - availableCcs: boolean + clusters: AlertCluster[] ): Promise { - let logstashIndexPattern = appendMetricbeatIndex(Globals.app.config, INDEX_PATTERN_LOGSTASH); - if (availableCcs) { - logstashIndexPattern = getCcsIndexPattern(logstashIndexPattern, availableCcs); - } const logstashVersions = await fetchLogstashVersions( esClient, clusters, - logstashIndexPattern, Globals.app.config.ui.max_bucket_size, params.filterQuery ); diff --git a/x-pack/plugins/monitoring/server/alerts/memory_usage_rule.test.ts b/x-pack/plugins/monitoring/server/alerts/memory_usage_rule.test.ts index 8547f126a02d6e..6e7aff2ae8fb4e 100644 --- a/x-pack/plugins/monitoring/server/alerts/memory_usage_rule.test.ts +++ b/x-pack/plugins/monitoring/server/alerts/memory_usage_rule.test.ts @@ -27,7 +27,6 @@ jest.mock('../static_globals', () => ({ config: { ui: { ccs: { enabled: true }, - metricbeat: { index: 'metricbeat-*' }, container: { elasticsearch: { enabled: false } }, }, }, diff --git a/x-pack/plugins/monitoring/server/alerts/memory_usage_rule.ts b/x-pack/plugins/monitoring/server/alerts/memory_usage_rule.ts index 25b12379f8d3a5..06ecf4bb450c87 100644 --- a/x-pack/plugins/monitoring/server/alerts/memory_usage_rule.ts +++ b/x-pack/plugins/monitoring/server/alerts/memory_usage_rule.ts @@ -23,19 +23,13 @@ import { CommonAlertFilter, } from '../../common/types/alerts'; import { AlertInstance } from '../../../alerting/server'; -import { - INDEX_PATTERN_ELASTICSEARCH, - RULE_MEMORY_USAGE, - RULE_DETAILS, -} from '../../common/constants'; +import { RULE_MEMORY_USAGE, RULE_DETAILS } from '../../common/constants'; // @ts-ignore import { ROUNDED_FLOAT } from '../../common/formatting'; import { fetchMemoryUsageNodeStats } from '../lib/alerts/fetch_memory_usage_node_stats'; -import { getCcsIndexPattern } from '../lib/alerts/get_ccs_index_pattern'; import { AlertMessageTokenType, AlertSeverity } from '../../common/enums'; import { RawAlertInstance, SanitizedAlert } from '../../../alerting/common'; import { AlertingDefaults, createLink } from './alert_helpers'; -import { appendMetricbeatIndex } from '../lib/alerts/append_mb_index'; import { parseDuration } from '../../../alerting/common/parse_duration'; import { Globals } from '../static_globals'; @@ -64,13 +58,8 @@ export class MemoryUsageRule extends BaseRule { protected async fetchData( params: CommonAlertParams, esClient: ElasticsearchClient, - clusters: AlertCluster[], - availableCcs: boolean + clusters: AlertCluster[] ): Promise { - let esIndexPattern = appendMetricbeatIndex(Globals.app.config, INDEX_PATTERN_ELASTICSEARCH); - if (availableCcs) { - esIndexPattern = getCcsIndexPattern(esIndexPattern, availableCcs); - } const { duration, threshold } = params; const parsedDuration = parseDuration(duration as string); const endMs = +new Date(); @@ -79,7 +68,6 @@ export class MemoryUsageRule extends BaseRule { const stats = await fetchMemoryUsageNodeStats( esClient, clusters, - esIndexPattern, startMs, endMs, Globals.app.config.ui.max_bucket_size, diff --git a/x-pack/plugins/monitoring/server/alerts/missing_monitoring_data_rule.test.ts b/x-pack/plugins/monitoring/server/alerts/missing_monitoring_data_rule.test.ts index 66259b9fffac92..a8a96a61a4b251 100644 --- a/x-pack/plugins/monitoring/server/alerts/missing_monitoring_data_rule.test.ts +++ b/x-pack/plugins/monitoring/server/alerts/missing_monitoring_data_rule.test.ts @@ -29,7 +29,6 @@ jest.mock('../static_globals', () => ({ ui: { show_license_expiration: true, ccs: { enabled: true }, - metricbeat: { index: 'metricbeat-*' }, container: { elasticsearch: { enabled: false } }, }, }, diff --git a/x-pack/plugins/monitoring/server/alerts/missing_monitoring_data_rule.ts b/x-pack/plugins/monitoring/server/alerts/missing_monitoring_data_rule.ts index 50ba9fa9e35864..fa7cbe009712a0 100644 --- a/x-pack/plugins/monitoring/server/alerts/missing_monitoring_data_rule.ts +++ b/x-pack/plugins/monitoring/server/alerts/missing_monitoring_data_rule.ts @@ -20,12 +20,10 @@ import { AlertNodeState, } from '../../common/types/alerts'; import { AlertInstance } from '../../../alerting/server'; -import { INDEX_PATTERN, RULE_MISSING_MONITORING_DATA, RULE_DETAILS } from '../../common/constants'; -import { getCcsIndexPattern } from '../lib/alerts/get_ccs_index_pattern'; +import { RULE_MISSING_MONITORING_DATA, RULE_DETAILS } from '../../common/constants'; import { AlertMessageTokenType, AlertSeverity } from '../../common/enums'; import { RawAlertInstance, SanitizedAlert } from '../../../alerting/common'; import { parseDuration } from '../../../alerting/common/parse_duration'; -import { appendMetricbeatIndex } from '../lib/alerts/append_mb_index'; import { fetchMissingMonitoringData } from '../lib/alerts/fetch_missing_monitoring_data'; import { AlertingDefaults, createLink } from './alert_helpers'; import { Globals } from '../static_globals'; @@ -59,20 +57,14 @@ export class MissingMonitoringDataRule extends BaseRule { protected async fetchData( params: CommonAlertParams, esClient: ElasticsearchClient, - clusters: AlertCluster[], - availableCcs: boolean + clusters: AlertCluster[] ): Promise { - let indexPattern = appendMetricbeatIndex(Globals.app.config, INDEX_PATTERN); - if (availableCcs) { - indexPattern = getCcsIndexPattern(indexPattern, availableCcs); - } const duration = parseDuration(params.duration); const limit = parseDuration(params.limit!); const now = +new Date(); const missingData = await fetchMissingMonitoringData( esClient, clusters, - indexPattern, Globals.app.config.ui.max_bucket_size, now, now - limit - LIMIT_BUFFER, diff --git a/x-pack/plugins/monitoring/server/alerts/nodes_changed_rule.test.ts b/x-pack/plugins/monitoring/server/alerts/nodes_changed_rule.test.ts index 5145a4e8476af3..3e24df3a6ef151 100644 --- a/x-pack/plugins/monitoring/server/alerts/nodes_changed_rule.test.ts +++ b/x-pack/plugins/monitoring/server/alerts/nodes_changed_rule.test.ts @@ -34,7 +34,6 @@ jest.mock('../static_globals', () => ({ config: { ui: { ccs: { enabled: true }, - metricbeat: { index: 'metricbeat-*' }, container: { elasticsearch: { enabled: false } }, }, }, diff --git a/x-pack/plugins/monitoring/server/alerts/nodes_changed_rule.ts b/x-pack/plugins/monitoring/server/alerts/nodes_changed_rule.ts index 545d6331d225e2..82cf91e91b52a9 100644 --- a/x-pack/plugins/monitoring/server/alerts/nodes_changed_rule.ts +++ b/x-pack/plugins/monitoring/server/alerts/nodes_changed_rule.ts @@ -20,19 +20,11 @@ import { AlertNodesChangedState, } from '../../common/types/alerts'; import { AlertInstance } from '../../../alerting/server'; -import { - RULE_NODES_CHANGED, - LEGACY_RULE_DETAILS, - INDEX_PATTERN_ELASTICSEARCH, -} from '../../common/constants'; +import { RULE_NODES_CHANGED, LEGACY_RULE_DETAILS } from '../../common/constants'; import { AlertingDefaults } from './alert_helpers'; import { SanitizedAlert } from '../../../alerting/common'; -import { Globals } from '../static_globals'; import { fetchNodesFromClusterStats } from '../lib/alerts/fetch_nodes_from_cluster_stats'; -import { getCcsIndexPattern } from '../lib/alerts/get_ccs_index_pattern'; -import { appendMetricbeatIndex } from '../lib/alerts/append_mb_index'; import { AlertSeverity } from '../../common/enums'; - interface AlertNodesChangedStates { removed: AlertClusterStatsNode[]; added: AlertClusterStatsNode[]; @@ -104,17 +96,11 @@ export class NodesChangedRule extends BaseRule { protected async fetchData( params: CommonAlertParams, esClient: ElasticsearchClient, - clusters: AlertCluster[], - availableCcs: boolean + clusters: AlertCluster[] ): Promise { - let esIndexPattern = appendMetricbeatIndex(Globals.app.config, INDEX_PATTERN_ELASTICSEARCH); - if (availableCcs) { - esIndexPattern = getCcsIndexPattern(esIndexPattern, availableCcs); - } const nodesFromClusterStats = await fetchNodesFromClusterStats( esClient, clusters, - esIndexPattern, params.filterQuery ); return nodesFromClusterStats.map((nodes) => { diff --git a/x-pack/plugins/monitoring/server/alerts/thread_pool_rejections_rule_base.ts b/x-pack/plugins/monitoring/server/alerts/thread_pool_rejections_rule_base.ts index e6c2002eaff87f..0cca5eb81c95f2 100644 --- a/x-pack/plugins/monitoring/server/alerts/thread_pool_rejections_rule_base.ts +++ b/x-pack/plugins/monitoring/server/alerts/thread_pool_rejections_rule_base.ts @@ -21,13 +21,10 @@ import { AlertThreadPoolRejectionsStats, } from '../../common/types/alerts'; import { AlertInstance } from '../../../alerting/server'; -import { INDEX_PATTERN_ELASTICSEARCH } from '../../common/constants'; import { fetchThreadPoolRejectionStats } from '../lib/alerts/fetch_thread_pool_rejections_stats'; -import { getCcsIndexPattern } from '../lib/alerts/get_ccs_index_pattern'; import { AlertMessageTokenType, AlertSeverity } from '../../common/enums'; import { Alert, RawAlertInstance } from '../../../alerting/common'; import { AlertingDefaults, createLink } from './alert_helpers'; -import { appendMetricbeatIndex } from '../lib/alerts/append_mb_index'; import { Globals } from '../static_globals'; type ActionVariables = Array<{ name: string; description: string }>; @@ -70,20 +67,13 @@ export class ThreadPoolRejectionsRuleBase extends BaseRule { protected async fetchData( params: ThreadPoolRejectionsAlertParams, esClient: ElasticsearchClient, - clusters: AlertCluster[], - availableCcs: boolean + clusters: AlertCluster[] ): Promise { - let esIndexPattern = appendMetricbeatIndex(Globals.app.config, INDEX_PATTERN_ELASTICSEARCH); - if (availableCcs) { - esIndexPattern = getCcsIndexPattern(esIndexPattern, availableCcs); - } - const { threshold, duration } = params; const stats = await fetchThreadPoolRejectionStats( esClient, clusters, - esIndexPattern, Globals.app.config.ui.max_bucket_size, this.threadPoolType, duration, diff --git a/x-pack/plugins/monitoring/server/alerts/thread_pool_search_rejections_rule.test.ts b/x-pack/plugins/monitoring/server/alerts/thread_pool_search_rejections_rule.test.ts index 351980d3f385df..63a02088b9b659 100644 --- a/x-pack/plugins/monitoring/server/alerts/thread_pool_search_rejections_rule.test.ts +++ b/x-pack/plugins/monitoring/server/alerts/thread_pool_search_rejections_rule.test.ts @@ -29,7 +29,6 @@ jest.mock('../static_globals', () => ({ ui: { show_license_expiration: true, ccs: { enabled: true }, - metricbeat: { index: 'metricbeat-*' }, container: { elasticsearch: { enabled: false } }, }, }, diff --git a/x-pack/plugins/monitoring/server/alerts/thread_pool_write_rejections_rule.test.ts b/x-pack/plugins/monitoring/server/alerts/thread_pool_write_rejections_rule.test.ts index 79896d11da2c31..da4c7ffaeffa09 100644 --- a/x-pack/plugins/monitoring/server/alerts/thread_pool_write_rejections_rule.test.ts +++ b/x-pack/plugins/monitoring/server/alerts/thread_pool_write_rejections_rule.test.ts @@ -29,7 +29,6 @@ jest.mock('../static_globals', () => ({ ui: { show_license_expiration: true, ccs: { enabled: true }, - metricbeat: { index: 'metricbeat-*' }, container: { elasticsearch: { enabled: false } }, }, }, diff --git a/x-pack/plugins/monitoring/server/config.test.ts b/x-pack/plugins/monitoring/server/config.test.ts index 036ade38607e97..22e7b74368ebfa 100644 --- a/x-pack/plugins/monitoring/server/config.test.ts +++ b/x-pack/plugins/monitoring/server/config.test.ts @@ -102,9 +102,6 @@ describe('config schema', () => { "index": "filebeat-*", }, "max_bucket_size": 10000, - "metricbeat": Object { - "index": "metricbeat-*", - }, "min_interval_seconds": 10, "show_license_expiration": true, }, diff --git a/x-pack/plugins/monitoring/server/config.ts b/x-pack/plugins/monitoring/server/config.ts index 835ad30de7cbe7..3facfd97319f2c 100644 --- a/x-pack/plugins/monitoring/server/config.ts +++ b/x-pack/plugins/monitoring/server/config.ts @@ -32,9 +32,6 @@ export const configSchema = schema.object({ logs: schema.object({ index: schema.string({ defaultValue: 'filebeat-*' }), }), - metricbeat: schema.object({ - index: schema.string({ defaultValue: 'metricbeat-*' }), - }), max_bucket_size: schema.number({ defaultValue: 10000 }), elasticsearch: monitoringElasticsearchConfigSchema, container: schema.object({ diff --git a/x-pack/plugins/monitoring/server/kibana_monitoring/collectors/get_usage_collector.ts b/x-pack/plugins/monitoring/server/kibana_monitoring/collectors/get_usage_collector.ts index 4c454637bf8bb3..cbbfe64f5e3e22 100644 --- a/x-pack/plugins/monitoring/server/kibana_monitoring/collectors/get_usage_collector.ts +++ b/x-pack/plugins/monitoring/server/kibana_monitoring/collectors/get_usage_collector.ts @@ -11,8 +11,6 @@ import { MonitoringConfig } from '../../config'; import { getStackProductsUsage } from './lib/get_stack_products_usage'; import { fetchLicenseType } from './lib/fetch_license_type'; import { MonitoringUsage, StackProductUsage, MonitoringClusterStackProductUsage } from './types'; -import { INDEX_PATTERN_ELASTICSEARCH } from '../../../common/constants'; -import { getCcsIndexPattern } from '../../lib/alerts/get_ccs_index_pattern'; import { fetchClusters } from '../../lib/alerts/fetch_clusters'; export function getMonitoringUsageCollector( @@ -106,8 +104,7 @@ export function getMonitoringUsageCollector( : getClient().asInternalUser; const usageClusters: MonitoringClusterStackProductUsage[] = []; const availableCcs = config.ui.ccs.enabled; - const elasticsearchIndex = getCcsIndexPattern(INDEX_PATTERN_ELASTICSEARCH, availableCcs); - const clusters = await fetchClusters(callCluster, elasticsearchIndex); + const clusters = await fetchClusters(callCluster); for (const cluster of clusters) { const license = await fetchLicenseType(callCluster, availableCcs, cluster.clusterUuid); const stackProducts = await getStackProductsUsage( diff --git a/x-pack/plugins/monitoring/server/lib/alerts/append_mb_index.ts b/x-pack/plugins/monitoring/server/lib/alerts/append_mb_index.ts deleted file mode 100644 index c8713f70ea5cf9..00000000000000 --- a/x-pack/plugins/monitoring/server/lib/alerts/append_mb_index.ts +++ /dev/null @@ -1,12 +0,0 @@ -/* - * 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 { MonitoringConfig } from '../../config'; - -export function appendMetricbeatIndex(config: MonitoringConfig, indexPattern: string) { - return `${indexPattern},${config.ui.metricbeat.index}`; -} diff --git a/x-pack/plugins/monitoring/server/lib/alerts/create_dataset_query_filter.ts b/x-pack/plugins/monitoring/server/lib/alerts/create_dataset_query_filter.ts new file mode 100644 index 00000000000000..7d23240bc1e943 --- /dev/null +++ b/x-pack/plugins/monitoring/server/lib/alerts/create_dataset_query_filter.ts @@ -0,0 +1,24 @@ +/* + * 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 const createDatasetFilter = (legacyType: string, dataset: string) => ({ + bool: { + should: [ + { + term: { + type: legacyType, + }, + }, + { + term: { + 'data_stream.dataset': dataset, + }, + }, + ], + minimum_should_match: 1, + }, +}); diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_ccr_read_exceptions.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_ccr_read_exceptions.ts index e7a5923207d604..d9dd035b92c4d5 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_ccr_read_exceptions.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_ccr_read_exceptions.ts @@ -8,17 +8,26 @@ import { ElasticsearchClient } from 'kibana/server'; import { get } from 'lodash'; import { CCRReadExceptionsStats } from '../../../common/types/alerts'; +import { getNewIndexPatterns } from '../cluster/get_index_patterns'; +import { createDatasetFilter } from './create_dataset_query_filter'; +import { Globals } from '../../static_globals'; +import { getConfigCcs } from '../../../common/ccs_utils'; export async function fetchCCRReadExceptions( esClient: ElasticsearchClient, - index: string, startMs: number, endMs: number, size: number, filterQuery?: string ): Promise { + const indexPatterns = getNewIndexPatterns({ + config: Globals.app.config, + moduleType: 'elasticsearch', + dataset: 'ccr', + ccs: getConfigCcs(Globals.app.config) ? '*' : undefined, + }); const params = { - index, + index: indexPatterns, filter_path: ['aggregations.remote_clusters.buckets'], body: { size: 0, @@ -35,11 +44,7 @@ export async function fetchCCRReadExceptions( }, }, }, - { - term: { - type: 'ccr_stats', - }, - }, + createDatasetFilter('ccr_stats', 'elasticsearch.ccr'), { range: { timestamp: { diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_cluster_health.test.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_cluster_health.test.ts index 2739e23245bdee..ea87608a14ef03 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_cluster_health.test.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_cluster_health.test.ts @@ -10,6 +10,18 @@ import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { elasticsearchClientMock } from '../../../../../../src/core/server/elasticsearch/client/mocks'; import { fetchClusterHealth } from './fetch_cluster_health'; +jest.mock('../../static_globals', () => ({ + Globals: { + app: { + config: { + ui: { + ccs: { enabled: true }, + }, + }, + }, + }, +})); + describe('fetchClusterHealth', () => { it('should return the cluster health', async () => { const status = 'green'; @@ -34,9 +46,8 @@ describe('fetchClusterHealth', () => { ); const clusters = [{ clusterUuid, clusterName: 'foo' }]; - const index = '.monitoring-es-*'; - const health = await fetchClusterHealth(esClient, clusters, index); + const health = await fetchClusterHealth(esClient, clusters); expect(health).toEqual([ { health: status, diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_cluster_health.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_cluster_health.ts index b2004f0c7c7106..59fd379344b4c9 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_cluster_health.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_cluster_health.ts @@ -7,15 +7,24 @@ import { ElasticsearchClient } from 'kibana/server'; import { AlertCluster, AlertClusterHealth } from '../../../common/types/alerts'; import { ElasticsearchSource, ElasticsearchResponse } from '../../../common/types/es'; +import { createDatasetFilter } from './create_dataset_query_filter'; +import { Globals } from '../../static_globals'; +import { getConfigCcs } from '../../../common/ccs_utils'; +import { getNewIndexPatterns } from '../cluster/get_index_patterns'; export async function fetchClusterHealth( esClient: ElasticsearchClient, clusters: AlertCluster[], - index: string, filterQuery?: string ): Promise { + const indexPatterns = getNewIndexPatterns({ + config: Globals.app.config, + moduleType: 'elasticsearch', + dataset: 'cluster_stats', + ccs: getConfigCcs(Globals.app.config) ? '*' : undefined, + }); const params = { - index, + index: indexPatterns, filter_path: [ 'hits.hits._source.cluster_state.status', 'hits.hits._source.cluster_uuid', @@ -39,11 +48,7 @@ export async function fetchClusterHealth( cluster_uuid: clusters.map((cluster) => cluster.clusterUuid), }, }, - { - term: { - type: 'cluster_stats', - }, - }, + createDatasetFilter('cluster_stats', 'elasticsearch.cluster_stats'), { range: { timestamp: { diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_clusters.test.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_clusters.test.ts index c46ec424b2cd37..fa4fa0269fb1b2 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_clusters.test.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_clusters.test.ts @@ -11,6 +11,18 @@ import { elasticsearchClientMock } from 'src/core/server/elasticsearch/client/mo import { elasticsearchServiceMock } from 'src/core/server/mocks'; import { fetchClusters } from './fetch_clusters'; +jest.mock('../../static_globals', () => ({ + Globals: { + app: { + config: { + ui: { + ccs: { enabled: true }, + }, + }, + }, + }, +})); + describe('fetchClusters', () => { const clusterUuid = '1sdfds734'; const clusterName = 'monitoring'; @@ -31,8 +43,7 @@ describe('fetchClusters', () => { }, } as estypes.SearchResponse) ); - const index = '.monitoring-es-*'; - const result = await fetchClusters(esClient, index); + const result = await fetchClusters(esClient); expect(result).toEqual([{ clusterUuid, clusterName }]); }); @@ -60,15 +71,13 @@ describe('fetchClusters', () => { }, } as estypes.SearchResponse) ); - const index = '.monitoring-es-*'; - const result = await fetchClusters(esClient, index); + const result = await fetchClusters(esClient); expect(result).toEqual([{ clusterUuid, clusterName: metadataName }]); }); it('should limit the time period in the query', async () => { const esClient = elasticsearchServiceMock.createScopedClusterClient().asCurrentUser; - const index = '.monitoring-es-*'; - await fetchClusters(esClient, index); + await fetchClusters(esClient); const params = esClient.search.mock.calls[0][0] as any; expect(params?.body?.query.bool.filter[1].range.timestamp.gte).toBe('now-2m'); }); diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_clusters.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_clusters.ts index 984cdee4e1b7b4..76bd81c24145f4 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_clusters.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_clusters.ts @@ -8,6 +8,10 @@ import { ElasticsearchClient } from 'kibana/server'; import { get } from 'lodash'; import { AlertCluster } from '../../../common/types/alerts'; +import { getNewIndexPatterns } from '../cluster/get_index_patterns'; +import { createDatasetFilter } from './create_dataset_query_filter'; +import { Globals } from '../../static_globals'; +import { getConfigCcs } from '../../../common/ccs_utils'; interface RangeFilter { [field: string]: { @@ -18,11 +22,15 @@ interface RangeFilter { export async function fetchClusters( esClient: ElasticsearchClient, - index: string, rangeFilter: RangeFilter = { timestamp: { gte: 'now-2m' } } ): Promise { + const indexPatterns = getNewIndexPatterns({ + config: Globals.app.config, + moduleType: 'elasticsearch', + ccs: getConfigCcs(Globals.app.config) ? '*' : undefined, + }); const params = { - index, + index: indexPatterns, filter_path: [ 'hits.hits._source.cluster_settings.cluster.metadata.display_name', 'hits.hits._source.cluster_uuid', @@ -33,11 +41,7 @@ export async function fetchClusters( query: { bool: { filter: [ - { - term: { - type: 'cluster_stats', - }, - }, + createDatasetFilter('cluster_stats', 'elasticsearch.cluster_stats'), { range: rangeFilter, }, diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_cpu_usage_node_stats.test.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_cpu_usage_node_stats.test.ts index a67a5e679cc334..fd7b61b5f92fff 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_cpu_usage_node_stats.test.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_cpu_usage_node_stats.test.ts @@ -10,6 +10,18 @@ import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { elasticsearchClientMock } from '../../../../../../src/core/server/elasticsearch/client/mocks'; import { fetchCpuUsageNodeStats } from './fetch_cpu_usage_node_stats'; +jest.mock('../../static_globals', () => ({ + Globals: { + app: { + config: { + ui: { + ccs: { enabled: true }, + }, + }, + }, + }, +})); + describe('fetchCpuUsageNodeStats', () => { const esClient = elasticsearchClientMock.createScopedClusterClient().asCurrentUser; const clusters = [ @@ -18,7 +30,6 @@ describe('fetchCpuUsageNodeStats', () => { clusterName: 'test', }, ]; - const index = '.monitoring-es-*'; const startMs = 0; const endMs = 0; const size = 10; @@ -62,7 +73,7 @@ describe('fetchCpuUsageNodeStats', () => { }, }) ); - const result = await fetchCpuUsageNodeStats(esClient, clusters, index, startMs, endMs, size); + const result = await fetchCpuUsageNodeStats(esClient, clusters, startMs, endMs, size); expect(result).toEqual([ { clusterUuid: clusters[0].clusterUuid, @@ -129,7 +140,7 @@ describe('fetchCpuUsageNodeStats', () => { }, }) ); - const result = await fetchCpuUsageNodeStats(esClient, clusters, index, startMs, endMs, size); + const result = await fetchCpuUsageNodeStats(esClient, clusters, startMs, endMs, size); expect(result).toEqual([ { clusterUuid: clusters[0].clusterUuid, @@ -189,7 +200,7 @@ describe('fetchCpuUsageNodeStats', () => { }, }) ); - const result = await fetchCpuUsageNodeStats(esClient, clusters, index, startMs, endMs, size); + const result = await fetchCpuUsageNodeStats(esClient, clusters, startMs, endMs, size); expect(result[0].ccs).toBe('foo'); }); @@ -203,9 +214,10 @@ describe('fetchCpuUsageNodeStats', () => { }); const filterQuery = '{"bool":{"should":[{"exists":{"field":"cluster_uuid"}}],"minimum_should_match":1}}'; - await fetchCpuUsageNodeStats(esClient, clusters, index, startMs, endMs, size, filterQuery); + await fetchCpuUsageNodeStats(esClient, clusters, startMs, endMs, size, filterQuery); expect(params).toStrictEqual({ - index: '.monitoring-es-*', + index: + '*:.monitoring-es-*,.monitoring-es-*,*:metrics-elasticsearch.node_stats-*,metrics-elasticsearch.node_stats-*', filter_path: ['aggregations'], body: { size: 0, @@ -213,7 +225,15 @@ describe('fetchCpuUsageNodeStats', () => { bool: { filter: [ { terms: { cluster_uuid: ['abc123'] } }, - { term: { type: 'node_stats' } }, + { + bool: { + should: [ + { term: { type: 'node_stats' } }, + { term: { 'data_stream.dataset': 'elasticsearch.node_stats' } }, + ], + minimum_should_match: 1, + }, + }, { range: { timestamp: { format: 'epoch_millis', gte: 0, lte: 0 } } }, { bool: { should: [{ exists: { field: 'cluster_uuid' } }], minimum_should_match: 1 }, diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_cpu_usage_node_stats.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_cpu_usage_node_stats.ts index 2ad42870e99587..99fc9db7d097bb 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_cpu_usage_node_stats.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_cpu_usage_node_stats.ts @@ -10,6 +10,10 @@ import { get } from 'lodash'; import moment from 'moment'; import { NORMALIZED_DERIVATIVE_UNIT } from '../../../common/constants'; import { AlertCluster, AlertCpuUsageNodeStats } from '../../../common/types/alerts'; +import { createDatasetFilter } from './create_dataset_query_filter'; +import { getNewIndexPatterns } from '../cluster/get_index_patterns'; +import { Globals } from '../../static_globals'; +import { getConfigCcs } from '../../../common/ccs_utils'; interface NodeBucketESResponse { key: string; @@ -26,7 +30,6 @@ interface ClusterBucketESResponse { export async function fetchCpuUsageNodeStats( esClient: ElasticsearchClient, clusters: AlertCluster[], - index: string, startMs: number, endMs: number, size: number, @@ -35,8 +38,15 @@ export async function fetchCpuUsageNodeStats( // Using pure MS didn't seem to work well with the date_histogram interval // but minutes does const intervalInMinutes = moment.duration(endMs - startMs).asMinutes(); + + const indexPatterns = getNewIndexPatterns({ + config: Globals.app.config, + moduleType: 'elasticsearch', + dataset: 'node_stats', + ccs: getConfigCcs(Globals.app.config) ? '*' : undefined, + }); const params = { - index, + index: indexPatterns, filter_path: ['aggregations'], body: { size: 0, @@ -48,11 +58,7 @@ export async function fetchCpuUsageNodeStats( cluster_uuid: clusters.map((cluster) => cluster.clusterUuid), }, }, - { - term: { - type: 'node_stats', - }, - }, + createDatasetFilter('node_stats', 'elasticsearch.node_stats'), { range: { timestamp: { diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_disk_usage_node_stats.test.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_disk_usage_node_stats.test.ts index 4766400891af55..d4bbbe71e9c418 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_disk_usage_node_stats.test.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_disk_usage_node_stats.test.ts @@ -10,6 +10,18 @@ import { elasticsearchClientMock } from '../../../../../../src/core/server/elast import { elasticsearchServiceMock } from 'src/core/server/mocks'; import { fetchDiskUsageNodeStats } from './fetch_disk_usage_node_stats'; +jest.mock('../../static_globals', () => ({ + Globals: { + app: { + config: { + ui: { + ccs: { enabled: true }, + }, + }, + }, + }, +})); + describe('fetchDiskUsageNodeStats', () => { const esClient = elasticsearchServiceMock.createScopedClusterClient().asCurrentUser; @@ -19,7 +31,6 @@ describe('fetchDiskUsageNodeStats', () => { clusterName: 'test-cluster', }, ]; - const index = '.monitoring-es-*'; const duration = '5m'; const size = 10; @@ -63,7 +74,7 @@ describe('fetchDiskUsageNodeStats', () => { }) ); - const result = await fetchDiskUsageNodeStats(esClient, clusters, index, duration, size); + const result = await fetchDiskUsageNodeStats(esClient, clusters, duration, size); expect(result).toEqual([ { clusterUuid: clusters[0].clusterUuid, diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_disk_usage_node_stats.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_disk_usage_node_stats.ts index 2d4872c0bd8958..9116d477278549 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_disk_usage_node_stats.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_disk_usage_node_stats.ts @@ -8,18 +8,27 @@ import { ElasticsearchClient } from 'kibana/server'; import { get } from 'lodash'; import { AlertCluster, AlertDiskUsageNodeStats } from '../../../common/types/alerts'; +import { createDatasetFilter } from './create_dataset_query_filter'; +import { Globals } from '../../static_globals'; +import { getConfigCcs } from '../../../common/ccs_utils'; +import { getNewIndexPatterns } from '../cluster/get_index_patterns'; export async function fetchDiskUsageNodeStats( esClient: ElasticsearchClient, clusters: AlertCluster[], - index: string, duration: string, size: number, filterQuery?: string ): Promise { const clustersIds = clusters.map((cluster) => cluster.clusterUuid); + const indexPatterns = getNewIndexPatterns({ + config: Globals.app.config, + moduleType: 'elasticsearch', + dataset: 'node_stats', + ccs: getConfigCcs(Globals.app.config) ? '*' : undefined, + }); const params = { - index, + index: indexPatterns, filter_path: ['aggregations'], body: { size: 0, @@ -31,11 +40,7 @@ export async function fetchDiskUsageNodeStats( cluster_uuid: clustersIds, }, }, - { - term: { - type: 'node_stats', - }, - }, + createDatasetFilter('node_stats', 'elasticsearch.node_stats'), { range: { timestamp: { diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_elasticsearch_versions.test.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_elasticsearch_versions.test.ts index 515fa3b2442d3e..c8505a82614dbe 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_elasticsearch_versions.test.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_elasticsearch_versions.test.ts @@ -11,6 +11,18 @@ import { elasticsearchServiceMock } from 'src/core/server/mocks'; import { fetchElasticsearchVersions } from './fetch_elasticsearch_versions'; import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +jest.mock('../../static_globals', () => ({ + Globals: { + app: { + config: { + ui: { + ccs: { enabled: true }, + }, + }, + }, + }, +})); + describe('fetchElasticsearchVersions', () => { const esClient = elasticsearchServiceMock.createScopedClusterClient().asCurrentUser; @@ -45,7 +57,7 @@ describe('fetchElasticsearchVersions', () => { } as estypes.SearchResponse) ); - const result = await fetchElasticsearchVersions(esClient, clusters, index, size); + const result = await fetchElasticsearchVersions(esClient, clusters, size); expect(result).toEqual([ { clusterUuid: clusters[0].clusterUuid, diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_elasticsearch_versions.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_elasticsearch_versions.ts index 6ca2e89048df97..16c7f67851f3db 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_elasticsearch_versions.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_elasticsearch_versions.ts @@ -7,16 +7,25 @@ import { ElasticsearchClient } from 'kibana/server'; import { AlertCluster, AlertVersions } from '../../../common/types/alerts'; import { ElasticsearchSource, ElasticsearchResponse } from '../../../common/types/es'; +import { createDatasetFilter } from './create_dataset_query_filter'; +import { Globals } from '../../static_globals'; +import { getConfigCcs } from '../../../common/ccs_utils'; +import { getNewIndexPatterns } from '../cluster/get_index_patterns'; export async function fetchElasticsearchVersions( esClient: ElasticsearchClient, clusters: AlertCluster[], - index: string, size: number, filterQuery?: string ): Promise { + const indexPatterns = getNewIndexPatterns({ + config: Globals.app.config, + moduleType: 'elasticsearch', + dataset: 'cluster_stats', + ccs: getConfigCcs(Globals.app.config) ? '*' : undefined, + }); const params = { - index, + index: indexPatterns, filter_path: [ 'hits.hits._source.cluster_stats.nodes.versions', 'hits.hits._index', @@ -40,11 +49,7 @@ export async function fetchElasticsearchVersions( cluster_uuid: clusters.map((cluster) => cluster.clusterUuid), }, }, - { - term: { - type: 'cluster_stats', - }, - }, + createDatasetFilter('cluster_stats', 'elasticsearch.cluster_stats'), { range: { timestamp: { diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_index_shard_size.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_index_shard_size.ts index 9259adc63e5463..65ed31f5db5107 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_index_shard_size.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_index_shard_size.ts @@ -9,7 +9,10 @@ import { ElasticsearchClient } from 'kibana/server'; import { AlertCluster, IndexShardSizeStats } from '../../../common/types/alerts'; import { ElasticsearchIndexStats, ElasticsearchResponseHit } from '../../../common/types/es'; import { ESGlobPatterns, RegExPatterns } from '../../../common/es_glob_patterns'; +import { createDatasetFilter } from './create_dataset_query_filter'; import { Globals } from '../../static_globals'; +import { getConfigCcs } from '../../../common/ccs_utils'; +import { getNewIndexPatterns } from '../cluster/get_index_patterns'; type TopHitType = ElasticsearchResponseHit & { _source: { index_stats?: Partial }; @@ -28,25 +31,26 @@ const gbMultiplier = 1000000000; export async function fetchIndexShardSize( esClient: ElasticsearchClient, clusters: AlertCluster[], - index: string, threshold: number, shardIndexPatterns: string, size: number, filterQuery?: string ): Promise { + const indexPatterns = getNewIndexPatterns({ + config: Globals.app.config, + moduleType: 'elasticsearch', + dataset: 'index', + ccs: getConfigCcs(Globals.app.config) ? '*' : undefined, + }); const params = { - index, + index: indexPatterns, filter_path: ['aggregations.clusters.buckets'], body: { size: 0, query: { bool: { - must: [ - { - match: { - type: 'index_stats', - }, - }, + filter: [ + createDatasetFilter('index_stats', 'elasticsearch.index'), { range: { timestamp: { @@ -102,7 +106,7 @@ export async function fetchIndexShardSize( try { if (filterQuery) { const filterQueryObject = JSON.parse(filterQuery); - params.body.query.bool.must.push(filterQueryObject); + params.body.query.bool.filter.push(filterQueryObject); } } catch (e) { // meh diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_kibana_versions.test.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_kibana_versions.test.ts index f9a03bb73d5fcd..6bdecaf6f83edc 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_kibana_versions.test.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_kibana_versions.test.ts @@ -10,6 +10,18 @@ import { fetchKibanaVersions } from './fetch_kibana_versions'; import { elasticsearchClientMock } from '../../../../../../src/core/server/elasticsearch/client/mocks'; import { elasticsearchServiceMock } from 'src/core/server/mocks'; +jest.mock('../../static_globals', () => ({ + Globals: { + app: { + config: { + ui: { + ccs: { enabled: true }, + }, + }, + }, + }, +})); + describe('fetchKibanaVersions', () => { const esClient = elasticsearchServiceMock.createScopedClusterClient().asCurrentUser; const clusters = [ @@ -66,7 +78,7 @@ describe('fetchKibanaVersions', () => { }) ); - const result = await fetchKibanaVersions(esClient, clusters, index, size); + const result = await fetchKibanaVersions(esClient, clusters, size); expect(result).toEqual([ { clusterUuid: clusters[0].clusterUuid, diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_kibana_versions.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_kibana_versions.ts index 71813f3a526dee..48465954e8afb3 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_kibana_versions.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_kibana_versions.ts @@ -7,6 +7,10 @@ import { ElasticsearchClient } from 'kibana/server'; import { get } from 'lodash'; import { AlertCluster, AlertVersions } from '../../../common/types/alerts'; +import { createDatasetFilter } from './create_dataset_query_filter'; +import { Globals } from '../../static_globals'; +import { getConfigCcs } from '../../../common/ccs_utils'; +import { getNewIndexPatterns } from '../cluster/get_index_patterns'; interface ESAggResponse { key: string; @@ -15,12 +19,17 @@ interface ESAggResponse { export async function fetchKibanaVersions( esClient: ElasticsearchClient, clusters: AlertCluster[], - index: string, size: number, filterQuery?: string ): Promise { + const indexPatterns = getNewIndexPatterns({ + config: Globals.app.config, + moduleType: 'kibana', + dataset: 'stats', + ccs: getConfigCcs(Globals.app.config) ? '*' : undefined, + }); const params = { - index, + index: indexPatterns, filter_path: ['aggregations'], body: { size: 0, @@ -32,11 +41,7 @@ export async function fetchKibanaVersions( cluster_uuid: clusters.map((cluster) => cluster.clusterUuid), }, }, - { - term: { - type: 'kibana_stats', - }, - }, + createDatasetFilter('kibana_stats', 'kibana.stats'), { range: { timestamp: { diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_licenses.test.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_licenses.test.ts index 538e24a7642769..fbfe6ba58d5401 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_licenses.test.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_licenses.test.ts @@ -10,6 +10,18 @@ import { elasticsearchClientMock } from '../../../../../../src/core/server/elast import { elasticsearchServiceMock } from 'src/core/server/mocks'; import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +jest.mock('../../static_globals', () => ({ + Globals: { + app: { + config: { + ui: { + ccs: { enabled: true }, + }, + }, + }, + }, +})); + describe('fetchLicenses', () => { const clusterName = 'MyCluster'; const clusterUuid = 'clusterA'; diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_licenses.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_licenses.ts index b7bdf2fb6be724..0d21227112ecf8 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_licenses.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_licenses.ts @@ -7,15 +7,24 @@ import { ElasticsearchClient } from 'kibana/server'; import { AlertLicense, AlertCluster } from '../../../common/types/alerts'; import { ElasticsearchSource } from '../../../common/types/es'; +import { createDatasetFilter } from './create_dataset_query_filter'; +import { Globals } from '../../static_globals'; +import { getConfigCcs } from '../../../common/ccs_utils'; +import { getNewIndexPatterns } from '../cluster/get_index_patterns'; export async function fetchLicenses( esClient: ElasticsearchClient, clusters: AlertCluster[], - index: string, filterQuery?: string ): Promise { + const indexPatterns = getNewIndexPatterns({ + config: Globals.app.config, + moduleType: 'elasticsearch', + dataset: 'cluster_stats', + ccs: getConfigCcs(Globals.app.config) ? '*' : undefined, + }); const params = { - index, + index: indexPatterns, filter_path: [ 'hits.hits._source.license.*', 'hits.hits._source.cluster_uuid', @@ -39,11 +48,7 @@ export async function fetchLicenses( cluster_uuid: clusters.map((cluster) => cluster.clusterUuid), }, }, - { - term: { - type: 'cluster_stats', - }, - }, + createDatasetFilter('cluster_stats', 'elasticsearch.cluster_stats'), { range: { timestamp: { diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_logstash_versions.test.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_logstash_versions.test.ts index 5732fc00f009b5..a1df1a56ad3b54 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_logstash_versions.test.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_logstash_versions.test.ts @@ -10,6 +10,18 @@ import { fetchLogstashVersions } from './fetch_logstash_versions'; import { elasticsearchClientMock } from '../../../../../../src/core/server/elasticsearch/client/mocks'; import { elasticsearchServiceMock } from 'src/core/server/mocks'; +jest.mock('../../static_globals', () => ({ + Globals: { + app: { + config: { + ui: { + ccs: { enabled: true }, + }, + }, + }, + }, +})); + describe('fetchLogstashVersions', () => { const esClient = elasticsearchServiceMock.createScopedClusterClient().asCurrentUser; const clusters = [ @@ -66,7 +78,7 @@ describe('fetchLogstashVersions', () => { }) ); - const result = await fetchLogstashVersions(esClient, clusters, index, size); + const result = await fetchLogstashVersions(esClient, clusters, size); expect(result).toEqual([ { clusterUuid: clusters[0].clusterUuid, diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_logstash_versions.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_logstash_versions.ts index 112c2fe798b100..3527223c3b07a3 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_logstash_versions.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_logstash_versions.ts @@ -7,6 +7,10 @@ import { ElasticsearchClient } from 'kibana/server'; import { get } from 'lodash'; import { AlertCluster, AlertVersions } from '../../../common/types/alerts'; +import { createDatasetFilter } from './create_dataset_query_filter'; +import { Globals } from '../../static_globals'; +import { getConfigCcs } from '../../../common/ccs_utils'; +import { getNewIndexPatterns } from '../cluster/get_index_patterns'; interface ESAggResponse { key: string; @@ -15,12 +19,17 @@ interface ESAggResponse { export async function fetchLogstashVersions( esClient: ElasticsearchClient, clusters: AlertCluster[], - index: string, size: number, filterQuery?: string ): Promise { + const indexPatterns = getNewIndexPatterns({ + config: Globals.app.config, + moduleType: 'logstash', + dataset: 'node_stats', + ccs: getConfigCcs(Globals.app.config) ? '*' : undefined, + }); const params = { - index, + index: indexPatterns, filter_path: ['aggregations'], body: { size: 0, @@ -32,11 +41,7 @@ export async function fetchLogstashVersions( cluster_uuid: clusters.map((cluster) => cluster.clusterUuid), }, }, - { - term: { - type: 'logstash_stats', - }, - }, + createDatasetFilter('logstash_stats', 'logstash.node_stats'), { range: { timestamp: { diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_memory_usage_node_stats.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_memory_usage_node_stats.ts index 9403ae5d79a70f..96462462ada6b7 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_memory_usage_node_stats.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_memory_usage_node_stats.ts @@ -8,19 +8,28 @@ import { ElasticsearchClient } from 'kibana/server'; import { get } from 'lodash'; import { AlertCluster, AlertMemoryUsageNodeStats } from '../../../common/types/alerts'; +import { createDatasetFilter } from './create_dataset_query_filter'; +import { Globals } from '../../static_globals'; +import { getConfigCcs } from '../../../common/ccs_utils'; +import { getNewIndexPatterns } from '../cluster/get_index_patterns'; export async function fetchMemoryUsageNodeStats( esClient: ElasticsearchClient, clusters: AlertCluster[], - index: string, startMs: number, endMs: number, size: number, filterQuery?: string ): Promise { const clustersIds = clusters.map((cluster) => cluster.clusterUuid); + const indexPatterns = getNewIndexPatterns({ + config: Globals.app.config, + moduleType: 'elasticsearch', + dataset: 'node_stats', + ccs: getConfigCcs(Globals.app.config) ? '*' : undefined, + }); const params = { - index, + index: indexPatterns, filter_path: ['aggregations'], body: { size: 0, @@ -32,11 +41,7 @@ export async function fetchMemoryUsageNodeStats( cluster_uuid: clustersIds, }, }, - { - term: { - type: 'node_stats', - }, - }, + createDatasetFilter('node_stats', 'elasticsearch.node_stats'), { range: { timestamp: { diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_missing_monitoring_data.test.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_missing_monitoring_data.test.ts index 980adb009ff8f6..a51cced18fd7ba 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_missing_monitoring_data.test.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_missing_monitoring_data.test.ts @@ -9,6 +9,18 @@ import { elasticsearchClientMock } from '../../../../../../src/core/server/elasticsearch/client/mocks'; import { fetchMissingMonitoringData } from './fetch_missing_monitoring_data'; +jest.mock('../../static_globals', () => ({ + Globals: { + app: { + config: { + ui: { + ccs: { enabled: true }, + }, + }, + }, + }, +})); + function getResponse( index: string, products: Array<{ @@ -42,7 +54,6 @@ function getResponse( describe('fetchMissingMonitoringData', () => { const esClient = elasticsearchClientMock.createScopedClusterClient().asCurrentUser; - const index = '.monitoring-*'; const startMs = 100; const size = 10; @@ -87,7 +98,7 @@ describe('fetchMissingMonitoringData', () => { }, }) ); - const result = await fetchMissingMonitoringData(esClient, clusters, index, size, now, startMs); + const result = await fetchMissingMonitoringData(esClient, clusters, size, now, startMs); expect(result).toEqual([ { nodeId: 'nodeUuid1', @@ -137,7 +148,7 @@ describe('fetchMissingMonitoringData', () => { }, }) ); - const result = await fetchMissingMonitoringData(esClient, clusters, index, size, now, startMs); + const result = await fetchMissingMonitoringData(esClient, clusters, size, now, startMs); expect(result).toEqual([ { nodeId: 'nodeUuid1', diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_missing_monitoring_data.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_missing_monitoring_data.ts index cdf0f21b52b09d..93ad44a5fd44bf 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_missing_monitoring_data.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_missing_monitoring_data.ts @@ -8,6 +8,9 @@ import { ElasticsearchClient } from 'kibana/server'; import { get } from 'lodash'; import { AlertCluster, AlertMissingData } from '../../../common/types/alerts'; +import { Globals } from '../../static_globals'; +import { getConfigCcs } from '../../../common/ccs_utils'; +import { getNewIndexPatterns } from '../cluster/get_index_patterns'; interface ClusterBucketESResponse { key: string; @@ -44,15 +47,21 @@ interface TopHitESResponse { export async function fetchMissingMonitoringData( esClient: ElasticsearchClient, clusters: AlertCluster[], - index: string, size: number, nowInMs: number, startMs: number, filterQuery?: string ): Promise { const endMs = nowInMs; + // changing this to only search ES because of changes related to https://github.com/elastic/kibana/issues/83309 + const indexPatterns = getNewIndexPatterns({ + config: Globals.app.config, + moduleType: 'elasticsearch', + dataset: 'node_stats', + ccs: getConfigCcs(Globals.app.config) ? '*' : undefined, + }); const params = { - index, + index: indexPatterns, filter_path: ['aggregations.clusters.buckets'], body: { size: 0, diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_nodes_from_cluster_stats.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_nodes_from_cluster_stats.ts index 3dc3e315318fcb..b67d071afcc0df 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_nodes_from_cluster_stats.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_nodes_from_cluster_stats.ts @@ -7,6 +7,10 @@ import { ElasticsearchClient } from 'kibana/server'; import { AlertCluster, AlertClusterStatsNodes } from '../../../common/types/alerts'; import { ElasticsearchSource } from '../../../common/types/es'; +import { createDatasetFilter } from './create_dataset_query_filter'; +import { Globals } from '../../static_globals'; +import { getConfigCcs } from '../../../common/ccs_utils'; +import { getNewIndexPatterns } from '../cluster/get_index_patterns'; function formatNode( nodes: NonNullable['nodes']> | undefined @@ -26,11 +30,16 @@ function formatNode( export async function fetchNodesFromClusterStats( esClient: ElasticsearchClient, clusters: AlertCluster[], - index: string, filterQuery?: string ): Promise { + const indexPatterns = getNewIndexPatterns({ + config: Globals.app.config, + moduleType: 'elasticsearch', + dataset: 'cluster_stats', + ccs: getConfigCcs(Globals.app.config) ? '*' : undefined, + }); const params = { - index, + index: indexPatterns, filter_path: ['aggregations.clusters.buckets'], body: { size: 0, @@ -45,11 +54,7 @@ export async function fetchNodesFromClusterStats( query: { bool: { filter: [ - { - term: { - type: 'cluster_stats', - }, - }, + createDatasetFilter('cluster_stats', 'elasticsearch.cluster_stats'), { range: { timestamp: { diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_thread_pool_rejections_stats.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_thread_pool_rejections_stats.ts index 0d1d052b5f8663..472bf0e955a2d2 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_thread_pool_rejections_stats.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_thread_pool_rejections_stats.ts @@ -8,6 +8,10 @@ import { ElasticsearchClient } from 'kibana/server'; import { get } from 'lodash'; import { AlertCluster, AlertThreadPoolRejectionsStats } from '../../../common/types/alerts'; +import { createDatasetFilter } from './create_dataset_query_filter'; +import { Globals } from '../../static_globals'; +import { getConfigCcs } from '../../../common/ccs_utils'; +import { getNewIndexPatterns } from '../cluster/get_index_patterns'; const invalidNumberValue = (value: number) => { return isNaN(value) || value === undefined || value === null; @@ -33,15 +37,20 @@ const getTopHits = (threadType: string, order: 'asc' | 'desc') => ({ export async function fetchThreadPoolRejectionStats( esClient: ElasticsearchClient, clusters: AlertCluster[], - index: string, size: number, threadType: string, duration: string, filterQuery?: string ): Promise { const clustersIds = clusters.map((cluster) => cluster.clusterUuid); + const indexPatterns = getNewIndexPatterns({ + config: Globals.app.config, + moduleType: 'elasticsearch', + dataset: 'node_stats', + ccs: getConfigCcs(Globals.app.config) ? '*' : undefined, + }); const params = { - index, + index: indexPatterns, filter_path: ['aggregations'], body: { size: 0, @@ -53,11 +62,7 @@ export async function fetchThreadPoolRejectionStats( cluster_uuid: clustersIds, }, }, - { - term: { - type: 'node_stats', - }, - }, + createDatasetFilter('node_stats', 'elasticsearch.node_stats'), { range: { timestamp: { diff --git a/x-pack/plugins/monitoring/server/lib/apm/create_apm_query.ts b/x-pack/plugins/monitoring/server/lib/apm/create_apm_query.ts index 63c56607a68e6b..1dc0f7a31e9a7c 100644 --- a/x-pack/plugins/monitoring/server/lib/apm/create_apm_query.ts +++ b/x-pack/plugins/monitoring/server/lib/apm/create_apm_query.ts @@ -25,7 +25,9 @@ export function createApmQuery(options: { const opts = { filters: [] as any[], metric: ApmMetric.getMetricFields(), - types: ['stats', 'beats_stats'], + type: 'beats_stats', + metricset: 'stats', + dsDataset: 'beats.stats', ...(options ?? {}), }; @@ -38,6 +40,5 @@ export function createApmQuery(options: { }, }, }); - return createQuery(opts); } diff --git a/x-pack/plugins/monitoring/server/lib/apm/get_apms_for_clusters.ts b/x-pack/plugins/monitoring/server/lib/apm/get_apms_for_clusters.ts index e99ce0da1ef102..77b5e447549990 100644 --- a/x-pack/plugins/monitoring/server/lib/apm/get_apms_for_clusters.ts +++ b/x-pack/plugins/monitoring/server/lib/apm/get_apms_for_clusters.ts @@ -6,12 +6,13 @@ */ import { LegacyRequest, Cluster } from '../../types'; -import { checkParam } from '../error_missing_required'; import { createApmQuery } from './create_apm_query'; import { ApmMetric } from '../metrics'; import { apmAggResponseHandler, apmUuidsAgg, apmAggFilterPath } from './_apm_stats'; import { getTimeOfLastEvent } from './_get_time_of_last_event'; import { ElasticsearchResponse } from '../../../common/types/es'; +import { getLegacyIndexPattern } from '../cluster/get_index_patterns'; +import { Globals } from '../../static_globals'; export function handleResponse(clusterUuid: string, response: ElasticsearchResponse) { const { apmTotal, totalEvents, memRss, versions } = apmAggResponseHandler(response); @@ -32,24 +33,24 @@ export function handleResponse(clusterUuid: string, response: ElasticsearchRespo }; } -export function getApmsForClusters( - req: LegacyRequest, - apmIndexPattern: string, - clusters: Cluster[] -) { - checkParam(apmIndexPattern, 'apmIndexPattern in apms/getApmsForClusters'); - +export function getApmsForClusters(req: LegacyRequest, clusters: Cluster[], ccs?: string) { const start = req.payload.timeRange.min; const end = req.payload.timeRange.max; const config = req.server.config(); const maxBucketSize = config.get('monitoring.ui.max_bucket_size'); const cgroup = config.get('monitoring.ui.container.apm.enabled'); + const indexPatterns = getLegacyIndexPattern({ + moduleType: 'beats', + ccs: ccs || req.payload.ccs, + config: Globals.app.config, + }); + return Promise.all( clusters.map(async (cluster) => { const clusterUuid = cluster.elasticsearch?.cluster?.id ?? cluster.cluster_uuid; const params = { - index: apmIndexPattern, + index: indexPatterns, size: 0, ignore_unavailable: true, filter_path: apmAggFilterPath, @@ -70,7 +71,7 @@ export function getApmsForClusters( getTimeOfLastEvent({ req, callWithRequest, - apmIndexPattern, + apmIndexPattern: indexPatterns, start, end, clusterUuid, diff --git a/x-pack/plugins/monitoring/server/lib/beats/create_beats_query.ts b/x-pack/plugins/monitoring/server/lib/beats/create_beats_query.ts index b013cd8234c406..6f56a95c8cbb95 100644 --- a/x-pack/plugins/monitoring/server/lib/beats/create_beats_query.ts +++ b/x-pack/plugins/monitoring/server/lib/beats/create_beats_query.ts @@ -26,9 +26,12 @@ export function createBeatsQuery(options: { end?: number; }) { const opts = { + moduleType: 'beats', filters: [] as any[], metric: BeatsMetric.getMetricFields(), - types: ['stats', 'beats_stats'], + type: 'beats_stats', + metricset: 'stats', + dsDataset: 'beats.stats', ...(options ?? {}), }; diff --git a/x-pack/plugins/monitoring/server/lib/beats/get_beats_for_clusters.ts b/x-pack/plugins/monitoring/server/lib/beats/get_beats_for_clusters.ts index 3a0720f7ca1956..ae723fa99bbded 100644 --- a/x-pack/plugins/monitoring/server/lib/beats/get_beats_for_clusters.ts +++ b/x-pack/plugins/monitoring/server/lib/beats/get_beats_for_clusters.ts @@ -5,12 +5,13 @@ * 2.0. */ -import { checkParam } from '../error_missing_required'; import { BeatsClusterMetric } from '../metrics'; import { createBeatsQuery } from './create_beats_query'; import { beatsAggFilterPath, beatsUuidsAgg, beatsAggResponseHandler } from './_beats_stats'; import type { ElasticsearchResponse } from '../../../common/types/es'; import { LegacyRequest, Cluster } from '../../types'; +import { getLegacyIndexPattern } from '../cluster/get_index_patterns'; +import { Globals } from '../../static_globals'; export function handleResponse(clusterUuid: string, response: ElasticsearchResponse) { const { beatTotal, beatTypes, totalEvents, bytesSent } = beatsAggResponseHandler(response); @@ -31,23 +32,21 @@ export function handleResponse(clusterUuid: string, response: ElasticsearchRespo }; } -export function getBeatsForClusters( - req: LegacyRequest, - beatsIndexPattern: string, - clusters: Cluster[] -) { - checkParam(beatsIndexPattern, 'beatsIndexPattern in beats/getBeatsForClusters'); - +export function getBeatsForClusters(req: LegacyRequest, clusters: Cluster[], ccs: string) { const start = req.payload.timeRange.min; const end = req.payload.timeRange.max; const config = req.server.config(); const maxBucketSize = config.get('monitoring.ui.max_bucket_size'); - + const indexPatterns = getLegacyIndexPattern({ + moduleType: 'beats', + ccs, + config: Globals.app.config, + }); return Promise.all( clusters.map(async (cluster) => { const clusterUuid = cluster.elasticsearch?.cluster?.id ?? cluster.cluster_uuid; const params = { - index: beatsIndexPattern, + index: indexPatterns, size: 0, ignore_unavailable: true, filter_path: beatsAggFilterPath, diff --git a/x-pack/plugins/monitoring/server/lib/cluster/flag_supported_clusters.ts b/x-pack/plugins/monitoring/server/lib/cluster/flag_supported_clusters.ts index 820b1bf24c6a13..9ead8833dce462 100644 --- a/x-pack/plugins/monitoring/server/lib/cluster/flag_supported_clusters.ts +++ b/x-pack/plugins/monitoring/server/lib/cluster/flag_supported_clusters.ts @@ -10,15 +10,24 @@ import { checkParam } from '../error_missing_required'; import { STANDALONE_CLUSTER_CLUSTER_UUID } from '../../../common/constants'; import { ElasticsearchResponse, ElasticsearchModifiedSource } from '../../../common/types/es'; import { LegacyRequest } from '../../types'; +import { getNewIndexPatterns } from './get_index_patterns'; +import { Globals } from '../../static_globals'; async function findSupportedBasicLicenseCluster( req: LegacyRequest, clusters: ElasticsearchModifiedSource[], - kbnIndexPattern: string, + ccs: string, kibanaUuid: string, serverLog: (message: string) => void ) { - checkParam(kbnIndexPattern, 'kbnIndexPattern in cluster/findSupportedBasicLicenseCluster'); + const dataset = 'stats'; + const moduleType = 'kibana'; + const indexPatterns = getNewIndexPatterns({ + config: Globals.app.config, + moduleType, + dataset, + ccs, + }); serverLog( `Detected all clusters in monitoring data have basic license. Checking for supported admin cluster UUID for Kibana ${kibanaUuid}.` @@ -28,7 +37,7 @@ async function findSupportedBasicLicenseCluster( const gte = req.payload.timeRange.min; const lte = req.payload.timeRange.max; const kibanaDataResult: ElasticsearchResponse = (await callWithRequest(req, 'search', { - index: kbnIndexPattern, + index: indexPatterns, size: 1, ignore_unavailable: true, filter_path: ['hits.hits._source.cluster_uuid', 'hits.hits._source.cluster.id'], @@ -41,7 +50,7 @@ async function findSupportedBasicLicenseCluster( bool: { should: [ { term: { type: 'kibana_stats' } }, - { term: { 'metricset.name': 'stats' } }, + { term: { 'data_stream.dataset': 'kibana.stats' } }, ], }, }, @@ -58,7 +67,6 @@ async function findSupportedBasicLicenseCluster( cluster.isSupported = true; } } - serverLog( `Found basic license admin cluster UUID for Monitoring UI support: ${supportedClusterUuid}.` ); @@ -80,9 +88,7 @@ async function findSupportedBasicLicenseCluster( * Non-Basic license clusters and any cluster in a single-cluster environment * are also flagged as supported in this method. */ -export function flagSupportedClusters(req: LegacyRequest, kbnIndexPattern: string) { - checkParam(kbnIndexPattern, 'kbnIndexPattern in cluster/flagSupportedClusters'); - +export function flagSupportedClusters(req: LegacyRequest, ccs: string) { const config = req.server.config(); const serverLog = (message: string) => req.getLogger('supported-clusters').debug(message); const flagAllSupported = (clusters: ElasticsearchModifiedSource[]) => { @@ -124,13 +130,7 @@ export function flagSupportedClusters(req: LegacyRequest, kbnIndexPattern: strin // if all linked are basic licenses if (linkedClusterCount === basicLicenseCount) { const kibanaUuid = config.get('server.uuid') as string; - return await findSupportedBasicLicenseCluster( - req, - clusters, - kbnIndexPattern, - kibanaUuid, - serverLog - ); + return await findSupportedBasicLicenseCluster(req, clusters, ccs, kibanaUuid, serverLog); } // if some non-basic licenses diff --git a/x-pack/plugins/monitoring/server/lib/cluster/get_cluster_license.ts b/x-pack/plugins/monitoring/server/lib/cluster/get_cluster_license.ts index 8ed5578e574a0c..108e88529bf7c7 100644 --- a/x-pack/plugins/monitoring/server/lib/cluster/get_cluster_license.ts +++ b/x-pack/plugins/monitoring/server/lib/cluster/get_cluster_license.ts @@ -13,19 +13,31 @@ import { createQuery } from '../create_query'; import { ElasticsearchMetric } from '../metrics'; import { ElasticsearchResponse } from '../../../common/types/es'; import { LegacyRequest } from '../../types'; +import { getNewIndexPatterns } from './get_index_patterns'; +import { Globals } from '../../static_globals'; -export function getClusterLicense(req: LegacyRequest, esIndexPattern: string, clusterUuid: string) { - checkParam(esIndexPattern, 'esIndexPattern in getClusterLicense'); +// is this being used anywhere? not called within the app +export function getClusterLicense(req: LegacyRequest, clusterUuid: string) { + const dataset = 'cluster_stats'; + const moduleType = 'elasticsearch'; + const indexPattern = getNewIndexPatterns({ + config: Globals.app.config, + moduleType, + dataset, + ccs: req.payload.ccs, + }); const params = { - index: esIndexPattern, + index: indexPattern, size: 1, ignore_unavailable: true, filter_path: ['hits.hits._source.license'], body: { sort: { timestamp: { order: 'desc', unmapped_type: 'long' } }, query: createQuery({ - type: 'cluster_stats', + type: dataset, + dsDataset: `${moduleType}.${dataset}`, + metricset: dataset, clusterUuid, metric: ElasticsearchMetric.getMetricFields(), }), diff --git a/x-pack/plugins/monitoring/server/lib/cluster/get_cluster_stats.ts b/x-pack/plugins/monitoring/server/lib/cluster/get_cluster_stats.ts index c671765a445486..97eebd678a975e 100644 --- a/x-pack/plugins/monitoring/server/lib/cluster/get_cluster_stats.ts +++ b/x-pack/plugins/monitoring/server/lib/cluster/get_cluster_stats.ts @@ -14,11 +14,10 @@ import { getClustersStats } from './get_clusters_stats'; * This will fetch the cluster stats and cluster state as a single object for the cluster specified by the {@code req}. * * @param {Object} req The incoming user's request - * @param {String} esIndexPattern The Elasticsearch index pattern * @param {String} clusterUuid The requested cluster's UUID * @return {Promise} The object cluster response. */ -export function getClusterStats(req: LegacyRequest, esIndexPattern: string, clusterUuid: string) { +export function getClusterStats(req: LegacyRequest, clusterUuid: string) { if (!clusterUuid) { throw badRequest( i18n.translate('xpack.monitoring.clusterStats.uuidNotSpecifiedErrorMessage', { @@ -29,7 +28,7 @@ export function getClusterStats(req: LegacyRequest, esIndexPattern: string, clus } // passing clusterUuid so `get_clusters` will filter for single cluster - return getClustersStats(req, esIndexPattern, clusterUuid).then((clusters) => { + return getClustersStats(req, clusterUuid).then((clusters) => { if (!clusters || clusters.length === 0) { throw notFound( i18n.translate('xpack.monitoring.clusterStats.uuidNotFoundErrorMessage', { diff --git a/x-pack/plugins/monitoring/server/lib/cluster/get_clusters_from_request.ts b/x-pack/plugins/monitoring/server/lib/cluster/get_clusters_from_request.ts index 6e28070cdbfaaf..570d6fadfeb903 100644 --- a/x-pack/plugins/monitoring/server/lib/cluster/get_clusters_from_request.ts +++ b/x-pack/plugins/monitoring/server/lib/cluster/get_clusters_from_request.ts @@ -52,15 +52,7 @@ export async function getClustersFromRequest( codePaths, }: { clusterUuid: string; start: number; end: number; codePaths: string[] } ) { - const { - esIndexPattern, - kbnIndexPattern, - lsIndexPattern, - beatsIndexPattern, - apmIndexPattern, - enterpriseSearchIndexPattern, - filebeatIndexPattern, - } = indexPatterns; + const { filebeatIndexPattern } = indexPatterns; const config = req.server.config(); const isStandaloneCluster = clusterUuid === STANDALONE_CLUSTER_CLUSTER_UUID; @@ -71,18 +63,11 @@ export async function getClustersFromRequest( clusters.push(getStandaloneClusterDefinition()); } else { // get clusters with stats and cluster state - clusters = await getClustersStats(req, esIndexPattern, clusterUuid); + clusters = await getClustersStats(req, clusterUuid, '*'); } if (!clusterUuid && !isStandaloneCluster) { - const indexPatternsToCheckForNonClusters = [ - lsIndexPattern, - beatsIndexPattern, - apmIndexPattern, - enterpriseSearchIndexPattern, - ]; - - if (await hasStandaloneClusters(req, indexPatternsToCheckForNonClusters)) { + if (await hasStandaloneClusters(req, '*')) { clusters.push(getStandaloneClusterDefinition()); } } @@ -106,7 +91,7 @@ export async function getClustersFromRequest( // add ml jobs and alerts data const mlJobs = isInCodePath(codePaths, [CODE_PATH_ML]) - ? await getMlJobsForCluster(req, esIndexPattern, cluster) + ? await getMlJobsForCluster(req, cluster, '*') : null; if (mlJobs !== null) { cluster.ml = { jobs: mlJobs }; @@ -128,7 +113,7 @@ export async function getClustersFromRequest( } // update clusters with license check results - const getSupportedClusters = flagSupportedClusters(req, kbnIndexPattern); + const getSupportedClusters = flagSupportedClusters(req, '*'); clusters = await getSupportedClusters(clusters); // add alerts data @@ -184,7 +169,7 @@ export async function getClustersFromRequest( // add kibana data const kibanas = isInCodePath(codePaths, [CODE_PATH_KIBANA]) && !isStandaloneCluster - ? await getKibanasForClusters(req, kbnIndexPattern, clusters) + ? await getKibanasForClusters(req, clusters, '*') : []; // add the kibana data to each cluster kibanas.forEach((kibana) => { @@ -197,8 +182,8 @@ export async function getClustersFromRequest( // add logstash data if (isInCodePath(codePaths, [CODE_PATH_LOGSTASH])) { - const logstashes = await getLogstashForClusters(req, lsIndexPattern, clusters); - const pipelines = await getLogstashPipelineIds({ req, lsIndexPattern, clusterUuid, size: 1 }); + const logstashes = await getLogstashForClusters(req, clusters, '*'); + const pipelines = await getLogstashPipelineIds({ req, clusterUuid, size: 1, ccs: '*' }); logstashes.forEach((logstash) => { const clusterIndex = clusters.findIndex( (cluster) => @@ -214,7 +199,7 @@ export async function getClustersFromRequest( // add beats data const beatsByCluster = isInCodePath(codePaths, [CODE_PATH_BEATS]) - ? await getBeatsForClusters(req, beatsIndexPattern, clusters) + ? await getBeatsForClusters(req, clusters, '*') : []; beatsByCluster.forEach((beats) => { const clusterIndex = clusters.findIndex( @@ -226,7 +211,7 @@ export async function getClustersFromRequest( // add apm data const apmsByCluster = isInCodePath(codePaths, [CODE_PATH_APM]) - ? await getApmsForClusters(req, apmIndexPattern, clusters) + ? await getApmsForClusters(req, clusters, '*') : []; apmsByCluster.forEach((apm) => { const clusterIndex = clusters.findIndex( @@ -244,7 +229,7 @@ export async function getClustersFromRequest( // add Enterprise Search data const enterpriseSearchByCluster = isInCodePath(codePaths, [CODE_PATH_ENTERPRISE_SEARCH]) - ? await getEnterpriseSearchForClusters(req, enterpriseSearchIndexPattern, clusters) + ? await getEnterpriseSearchForClusters(req, clusters, '*') : []; enterpriseSearchByCluster.forEach((entSearch) => { const clusterIndex = clusters.findIndex( @@ -259,7 +244,7 @@ export async function getClustersFromRequest( }); // check ccr configuration - const isCcrEnabled = await checkCcrEnabled(req, esIndexPattern); + const isCcrEnabled = await checkCcrEnabled(req, '*'); const kibanaUuid = config.get('server.uuid')!; diff --git a/x-pack/plugins/monitoring/server/lib/cluster/get_clusters_state.ts b/x-pack/plugins/monitoring/server/lib/cluster/get_clusters_state.ts index d732b43bc203b4..fab74ef1d979fd 100644 --- a/x-pack/plugins/monitoring/server/lib/cluster/get_clusters_state.ts +++ b/x-pack/plugins/monitoring/server/lib/cluster/get_clusters_state.ts @@ -10,6 +10,8 @@ import { find } from 'lodash'; import { checkParam } from '../error_missing_required'; import { ElasticsearchResponse, ElasticsearchModifiedSource } from '../../../common/types/es'; import { LegacyRequest } from '../../types'; +import { getNewIndexPatterns } from './get_index_patterns'; +import { Globals } from '../../static_globals'; /** * Augment the {@clusters} with their cluster state's from the {@code response}. @@ -46,13 +48,7 @@ export function handleResponse( * * If there is no cluster state available for any cluster, then it will be returned without any cluster state information. */ -export function getClustersState( - req: LegacyRequest, - esIndexPattern: string, - clusters: ElasticsearchModifiedSource[] -) { - checkParam(esIndexPattern, 'esIndexPattern in cluster/getClustersHealth'); - +export function getClustersState(req: LegacyRequest, clusters: ElasticsearchModifiedSource[]) { const clusterUuids = clusters .filter((cluster) => !cluster.cluster_state || !cluster.elasticsearch?.cluster?.stats?.state) .map((cluster) => cluster.cluster_uuid || cluster.elasticsearch?.cluster?.id); @@ -63,8 +59,14 @@ export function getClustersState( return Promise.resolve(clusters); } + const indexPatterns = getNewIndexPatterns({ + config: Globals.app.config, + moduleType: 'elasticsearch', + ccs: req.payload.ccs, + }); + const params = { - index: esIndexPattern, + index: indexPatterns, size: clusterUuids.length, ignore_unavailable: true, filter_path: [ diff --git a/x-pack/plugins/monitoring/server/lib/cluster/get_clusters_stats.test.js b/x-pack/plugins/monitoring/server/lib/cluster/get_clusters_stats.test.js index a8f7423c45100c..db4339a23e88c9 100644 --- a/x-pack/plugins/monitoring/server/lib/cluster/get_clusters_stats.test.js +++ b/x-pack/plugins/monitoring/server/lib/cluster/get_clusters_stats.test.js @@ -43,7 +43,7 @@ describe('handleClusterStats', () => { }, }; - const clusters = handleClusterStats(response, { log: () => undefined }); + const clusters = handleClusterStats(response); expect(clusters.length).toEqual(1); expect(clusters[0].ccs).toEqual('cluster_one'); diff --git a/x-pack/plugins/monitoring/server/lib/cluster/get_clusters_stats.ts b/x-pack/plugins/monitoring/server/lib/cluster/get_clusters_stats.ts index a2201ca958e355..80fe5ce3806a67 100644 --- a/x-pack/plugins/monitoring/server/lib/cluster/get_clusters_stats.ts +++ b/x-pack/plugins/monitoring/server/lib/cluster/get_clusters_stats.ts @@ -16,21 +16,22 @@ import { parseCrossClusterPrefix } from '../../../common/ccs_utils'; import { getClustersState } from './get_clusters_state'; import { ElasticsearchResponse, ElasticsearchModifiedSource } from '../../../common/types/es'; import { LegacyRequest } from '../../types'; +import { getNewIndexPatterns } from './get_index_patterns'; +import { Globals } from '../../static_globals'; /** * This will fetch the cluster stats and cluster state as a single object per cluster. * * @param {Object} req The incoming user's request - * @param {String} esIndexPattern The Elasticsearch index pattern * @param {String} clusterUuid (optional) If not undefined, getClusters will filter for a single cluster * @return {Promise} A promise containing an array of clusters. */ -export function getClustersStats(req: LegacyRequest, esIndexPattern: string, clusterUuid: string) { +export function getClustersStats(req: LegacyRequest, clusterUuid: string, ccs?: string) { return ( - fetchClusterStats(req, esIndexPattern, clusterUuid) + fetchClusterStats(req, clusterUuid, ccs) .then((response) => handleClusterStats(response)) // augment older documents (e.g., from 2.x - 5.4) with their cluster_state - .then((clusters) => getClustersState(req, esIndexPattern, clusters)) + .then((clusters) => getClustersState(req, clusters)) ); } @@ -38,12 +39,19 @@ export function getClustersStats(req: LegacyRequest, esIndexPattern: string, clu * Query cluster_stats for all the cluster data * * @param {Object} req (required) - server request - * @param {String} esIndexPattern (required) - index pattern to use in searching for cluster_stats data * @param {String} clusterUuid (optional) - if not undefined, getClusters filters for a single clusterUuid * @return {Promise} Object representing each cluster. */ -function fetchClusterStats(req: LegacyRequest, esIndexPattern: string, clusterUuid: string) { - checkParam(esIndexPattern, 'esIndexPattern in getClusters'); +function fetchClusterStats(req: LegacyRequest, clusterUuid: string, ccs?: string) { + const dataset = 'cluster_stats'; + const moduleType = 'elasticsearch'; + const indexPattern = getNewIndexPatterns({ + config: Globals.app.config, + moduleType, + dataset, + // this is will be either *, a request value, or null + ccs: ccs || req.payload.ccs, + }); const config = req.server.config(); // Get the params from the POST body for the request @@ -51,7 +59,7 @@ function fetchClusterStats(req: LegacyRequest, esIndexPattern: string, clusterUu const end = req.payload.timeRange.max; const metric = ElasticsearchMetric.getMetricFields(); const params = { - index: esIndexPattern, + index: indexPattern, size: config.get('monitoring.ui.max_bucket_size'), ignore_unavailable: true, filter_path: [ @@ -80,7 +88,15 @@ function fetchClusterStats(req: LegacyRequest, esIndexPattern: string, clusterUu 'hits.hits._source.cluster_settings.cluster.metadata.display_name', ], body: { - query: createQuery({ type: 'cluster_stats', start, end, metric, clusterUuid }), + query: createQuery({ + type: dataset, + dsDataset: `${moduleType}.${dataset}`, + metricset: dataset, + start, + end, + metric, + clusterUuid, + }), collapse: { field: 'cluster_uuid', }, diff --git a/x-pack/plugins/monitoring/server/lib/cluster/get_index_patterns.test.ts b/x-pack/plugins/monitoring/server/lib/cluster/get_index_patterns.test.ts new file mode 100644 index 00000000000000..015bdd4c65ccfe --- /dev/null +++ b/x-pack/plugins/monitoring/server/lib/cluster/get_index_patterns.test.ts @@ -0,0 +1,102 @@ +/* + * 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 { MonitoringConfig } from '../..'; +import { getNewIndexPatterns } from './get_index_patterns'; + +const getConfigWithCcs = (ccsEnabled: boolean) => { + return { + ui: { + ccs: { + enabled: ccsEnabled, + }, + }, + } as MonitoringConfig; +}; + +describe('getNewIndexPatterns', () => { + beforeEach(() => { + jest.resetModules(); + }); + it('returns local elasticsearch index patterns when ccs is enabled (default true) and no ccs payload', () => { + const indexPatterns = getNewIndexPatterns({ + config: getConfigWithCcs(true), + moduleType: 'elasticsearch', + }); + expect(indexPatterns).toBe('.monitoring-es-*,metrics-elasticsearch.*-*'); + }); + it('returns ecs only elasticsearch index patterns when specifying ecsLegacyOnly: true', () => { + const indexPatterns = getNewIndexPatterns({ + config: getConfigWithCcs(true), + moduleType: 'elasticsearch', + ecsLegacyOnly: true, + }); + expect(indexPatterns).toBe('.monitoring-es-8-*,metrics-elasticsearch.*-*'); + }); + it('returns local kibana index patterns when ccs is enabled with no ccs payload', () => { + const indexPatterns = getNewIndexPatterns({ + config: getConfigWithCcs(true), + moduleType: 'kibana', + }); + expect(indexPatterns).toBe('.monitoring-kibana-*,metrics-kibana.*-*'); + }); + it('returns logstash index patterns when ccs is enabled and no ccs payload', () => { + const indexPatterns = getNewIndexPatterns({ + config: getConfigWithCcs(true), + moduleType: 'logstash', + }); + expect(indexPatterns).toBe('.monitoring-logstash-*,metrics-logstash.*-*'); + }); + it('returns beats index patterns when ccs is enabled and no ccs payload', () => { + const indexPatterns = getNewIndexPatterns({ + config: getConfigWithCcs(true), + moduleType: 'beats', + }); + expect(indexPatterns).toBe('.monitoring-beats-*,metrics-beats.*-*'); + }); + it('returns elasticsearch index patterns with dataset', () => { + const indexPatterns = getNewIndexPatterns({ + config: getConfigWithCcs(true), + moduleType: 'elasticsearch', + dataset: 'cluster_stats', + }); + expect(indexPatterns).toBe('.monitoring-es-*,metrics-elasticsearch.cluster_stats-*'); + }); + it('returns elasticsearch index patterns without ccs prefixes when ccs is disabled', () => { + const indexPatterns = getNewIndexPatterns({ + config: getConfigWithCcs(false), + moduleType: 'elasticsearch', + }); + expect(indexPatterns).toBe('.monitoring-es-*,metrics-elasticsearch.*-*'); + }); + it('returns elasticsearch index patterns without ccs prefixes when ccs is disabled but ccs request payload has a value', () => { + const indexPatterns = getNewIndexPatterns({ + config: getConfigWithCcs(false), + ccs: 'myccs', + moduleType: 'elasticsearch', + }); + expect(indexPatterns).toBe('.monitoring-es-*,metrics-elasticsearch.*-*'); + }); + it('returns elasticsearch index patterns with custom ccs prefixes when ccs is enabled and ccs request payload has a value', () => { + const indexPatterns = getNewIndexPatterns({ + config: getConfigWithCcs(true), + ccs: 'myccs', + moduleType: 'elasticsearch', + }); + expect(indexPatterns).toBe('myccs:.monitoring-es-*,myccs:metrics-elasticsearch.*-*'); + }); + it('returns elasticsearch index patterns with ccs prefixes and local index patterns when ccs is enabled and ccs request payload value is *', () => { + const indexPatterns = getNewIndexPatterns({ + config: getConfigWithCcs(true), + ccs: '*', + moduleType: 'elasticsearch', + }); + expect(indexPatterns).toBe( + '*:.monitoring-es-*,.monitoring-es-*,*:metrics-elasticsearch.*-*,metrics-elasticsearch.*-*' + ); + }); +}); diff --git a/x-pack/plugins/monitoring/server/lib/cluster/get_index_patterns.ts b/x-pack/plugins/monitoring/server/lib/cluster/get_index_patterns.ts index 5f7e55cf94c5a5..fe9a319780db5b 100644 --- a/x-pack/plugins/monitoring/server/lib/cluster/get_index_patterns.ts +++ b/x-pack/plugins/monitoring/server/lib/cluster/get_index_patterns.ts @@ -9,12 +9,17 @@ import { LegacyServer } from '../../types'; import { prefixIndexPattern } from '../../../common/ccs_utils'; import { INDEX_PATTERN_ELASTICSEARCH, + INDEX_PATTERN_ELASTICSEARCH_ECS, INDEX_PATTERN_KIBANA, INDEX_PATTERN_LOGSTASH, INDEX_PATTERN_BEATS, INDEX_ALERTS, + DS_INDEX_PATTERN_TYPES, + DS_INDEX_PATTERN_METRICS, + INDEX_PATTERN_TYPES, INDEX_PATTERN_ENTERPRISE_SEARCH, } from '../../../common/constants'; +import { MonitoringConfig } from '../..'; export function getIndexPatterns( server: LegacyServer, @@ -44,10 +49,90 @@ export function getIndexPatterns( ...Object.keys(additionalPatterns).reduce((accum, varName) => { return { ...accum, - [varName]: prefixIndexPattern(config, additionalPatterns[varName], ccs, true), + [varName]: prefixIndexPattern(config, additionalPatterns[varName], ccs), }; }, {}), }; - return indexPatterns; } +// calling legacy index patterns those that are .monitoring +export function getLegacyIndexPattern({ + moduleType, + ecsLegacyOnly = false, + config, + ccs, +}: { + moduleType: INDEX_PATTERN_TYPES; + ecsLegacyOnly?: boolean; + config: MonitoringConfig; + ccs?: string; +}) { + let indexPattern = ''; + switch (moduleType) { + case 'elasticsearch': + // there may be cases where we only want the legacy ecs version index pattern (>=8.0) + indexPattern = ecsLegacyOnly ? INDEX_PATTERN_ELASTICSEARCH_ECS : INDEX_PATTERN_ELASTICSEARCH; + break; + case 'kibana': + indexPattern = INDEX_PATTERN_KIBANA; + break; + case 'logstash': + indexPattern = INDEX_PATTERN_LOGSTASH; + break; + case 'beats': + indexPattern = INDEX_PATTERN_BEATS; + break; + case 'enterprisesearch': + indexPattern = INDEX_PATTERN_ENTERPRISE_SEARCH; + break; + default: + throw new Error(`invalid module type to create index pattern: ${moduleType}`); + } + return prefixIndexPattern(config, indexPattern, ccs); +} + +export function getDsIndexPattern({ + type = DS_INDEX_PATTERN_METRICS, + moduleType, + dataset, + namespace = '*', + config, + ccs, +}: { + type?: string; + dataset?: string; + moduleType: INDEX_PATTERN_TYPES; + namespace?: string; + config: MonitoringConfig; + ccs?: string; +}): string { + let datasetsPattern = ''; + if (dataset) { + datasetsPattern = `${moduleType}.${dataset}`; + } else { + datasetsPattern = `${moduleType}.*`; + } + return prefixIndexPattern(config, `${type}-${datasetsPattern}-${namespace}`, ccs); +} + +export function getNewIndexPatterns({ + config, + moduleType, + type = DS_INDEX_PATTERN_METRICS, + dataset, + namespace = '*', + ccs, + ecsLegacyOnly, +}: { + config: MonitoringConfig; + moduleType: INDEX_PATTERN_TYPES; + type?: DS_INDEX_PATTERN_TYPES; + dataset?: string; + namespace?: string; + ccs?: string; + ecsLegacyOnly?: boolean; +}): string { + const legacyIndexPattern = getLegacyIndexPattern({ moduleType, ecsLegacyOnly, config, ccs }); + const dsIndexPattern = getDsIndexPattern({ type, moduleType, dataset, namespace, config, ccs }); + return `${legacyIndexPattern},${dsIndexPattern}`; +} diff --git a/x-pack/plugins/monitoring/server/lib/create_query.test.js b/x-pack/plugins/monitoring/server/lib/create_query.test.js deleted file mode 100644 index 60fa6faa79e443..00000000000000 --- a/x-pack/plugins/monitoring/server/lib/create_query.test.js +++ /dev/null @@ -1,114 +0,0 @@ -/* - * 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 { set } from '@elastic/safer-lodash-set'; -import { MissingRequiredError } from './error_missing_required'; -import { ElasticsearchMetric } from './metrics'; -import { createQuery } from './create_query'; - -let metric; - -describe('Create Query', () => { - beforeEach(() => { - metric = ElasticsearchMetric.getMetricFields(); - }); - - it('Allows UUID to not be passed', () => { - const options = { metric }; - const result = createQuery(options); - const expected = set({}, 'bool.filter', []); - expect(result).toEqual(expected); - }); - - it('Uses Elasticsearch timestamp field for start and end time range by default', () => { - const options = { - uuid: 'abc123', - start: '2016-03-01 10:00:00', - end: '2016-03-01 10:00:01', - metric, - }; - const result = createQuery(options); - let expected = {}; - expected = set(expected, 'bool.filter[0].term', { - 'source_node.uuid': 'abc123', - }); - expected = set(expected, 'bool.filter[1].range.timestamp', { - format: 'epoch_millis', - gte: 1456826400000, - lte: 1456826401000, - }); - expect(result).toEqual(expected); - }); - - it('Injects uuid and timestamp fields dynamically, based on metric', () => { - const options = { - uuid: 'abc123', - start: '2016-03-01 10:00:00', - end: '2016-03-01 10:00:01', - metric: { - uuidField: 'testUuidField', - timestampField: 'testTimestampField', - }, - }; - const result = createQuery(options); - let expected = set({}, 'bool.filter[0].term.testUuidField', 'abc123'); - expected = set(expected, 'bool.filter[1].range.testTimestampField', { - format: 'epoch_millis', - gte: 1456826400000, - lte: 1456826401000, - }); - expect(result).toEqual(expected); - }); - - it('Throws if missing metric.timestampField', () => { - function callCreateQuery() { - const options = {}; // missing metric object - return createQuery(options); - } - expect(callCreateQuery).toThrowError(MissingRequiredError); - }); - - it('Throws if given uuid but missing metric.uuidField', () => { - function callCreateQuery() { - const options = { uuid: 'abc123', metric }; - delete options.metric.uuidField; - return createQuery(options); - } - expect(callCreateQuery).toThrowError(MissingRequiredError); - }); - - // TODO: tests were not running and need to be updated to pass - it.skip('Uses `type` option to add type filter with minimal fields', () => { - const options = { type: 'test-type-yay', metric }; - const result = createQuery(options); - let expected = {}; - expected = set(expected, 'bool.filter[0].term', { type: 'test-type-yay' }); - expect(result).to.be.eql(expected); - }); - - it.skip('Uses `type` option to add type filter with all other option fields', () => { - const options = { - type: 'test-type-yay', - uuid: 'abc123', - start: '2016-03-01 10:00:00', - end: '2016-03-01 10:00:01', - metric, - }; - const result = createQuery(options); - let expected = {}; - expected = set(expected, 'bool.filter[0].term', { type: 'test-type-yay' }); - expected = set(expected, 'bool.filter[1].term', { - 'source_node.uuid': 'abc123', - }); - expected = set(expected, 'bool.filter[2].range.timestamp', { - format: 'epoch_millis', - gte: 1456826400000, - lte: 1456826401000, - }); - expect(result).to.be.eql(expected); - }); -}); diff --git a/x-pack/plugins/monitoring/server/lib/create_query.test.ts b/x-pack/plugins/monitoring/server/lib/create_query.test.ts new file mode 100644 index 00000000000000..0e78889ca71fa7 --- /dev/null +++ b/x-pack/plugins/monitoring/server/lib/create_query.test.ts @@ -0,0 +1,231 @@ +/* + * 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 { MissingRequiredError } from './error_missing_required'; +import { ElasticsearchMetric } from './metrics'; +import { createQuery } from './create_query'; + +interface Metric { + uuidField?: string; + timestampField: string; +} +let metric: Metric; + +describe('Create Query', () => { + beforeEach(() => { + metric = ElasticsearchMetric.getMetricFields(); + }); + + it('Allows UUID to not be passed', () => { + const options = { metric, clusterUuid: 'cuid123' }; + expect(createQuery(options)).toEqual({ + bool: { filter: [{ term: { cluster_uuid: 'cuid123' } }] }, + }); + }); + + it('Uses Elasticsearch timestamp field for start and end time range by default', () => { + const options = { + clusterUuid: 'cuid123', + uuid: 'abc123', + start: 1456826400000, + end: 14568264010000, + metric, + }; + expect(createQuery(options)).toEqual({ + bool: { + filter: [ + { term: { cluster_uuid: 'cuid123' } }, + { term: { 'source_node.uuid': 'abc123' } }, + { + range: { + timestamp: { format: 'epoch_millis', gte: 1456826400000, lte: 14568264010000 }, + }, + }, + ], + }, + }); + }); + + it('Injects uuid and timestamp fields dynamically, based on metric', () => { + const options = { + clusterUuid: 'cuid123', + uuid: 'abc123', + start: 1456826400000, + end: 14568264010000, + metric: { + uuidField: 'testUuidField', + timestampField: 'testTimestampField', + }, + }; + expect(createQuery(options)).toEqual({ + bool: { + filter: [ + { term: { cluster_uuid: 'cuid123' } }, + { term: { testUuidField: 'abc123' } }, + { + range: { + testTimestampField: { + format: 'epoch_millis', + gte: 1456826400000, + lte: 14568264010000, + }, + }, + }, + ], + }, + }); + }); + + it('Throws if missing metric.timestampField', () => { + function callCreateQuery() { + const options = { clusterUuid: 'cuid123' }; // missing metric object + return createQuery(options); + } + expect(callCreateQuery).toThrowError(MissingRequiredError); + }); + + it('Throws if given uuid but missing metric.uuidField', () => { + function callCreateQuery() { + const options = { uuid: 'abc123', clusterUuid: 'cuid123', metric }; + delete options.metric.uuidField; + return createQuery(options); + } + expect(callCreateQuery).toThrowError(MissingRequiredError); + }); + + it('Uses `type` option to add type filter with minimal fields', () => { + const options = { type: 'cluster_stats', clusterUuid: 'cuid123', metric }; + expect(createQuery(options)).toEqual({ + bool: { + filter: [ + { bool: { should: [{ term: { type: 'cluster_stats' } }] } }, + { term: { cluster_uuid: 'cuid123' } }, + ], + }, + }); + }); + + it('Uses `type` option to add type filter with all other option fields and no data stream fields', () => { + const options = { + type: 'cluster_stats', + clusterUuid: 'cuid123', + uuid: 'abc123', + start: 1456826400000, + end: 14568264000000, + metric, + }; + expect(createQuery(options)).toEqual({ + bool: { + filter: [ + { bool: { should: [{ term: { type: 'cluster_stats' } }] } }, + { term: { cluster_uuid: 'cuid123' } }, + { term: { 'source_node.uuid': 'abc123' } }, + { + range: { + timestamp: { format: 'epoch_millis', gte: 1456826400000, lte: 14568264000000 }, + }, + }, + ], + }, + }); + }); + + it('Uses `dsType` option to add filter with all other option fields', () => { + const options = { + dsDataset: 'elasticsearch.cluster_stats', + clusterUuid: 'cuid123', + uuid: 'abc123', + start: 1456826400000, + end: 14568264000000, + metric, + }; + expect(createQuery(options)).toEqual({ + bool: { + filter: [ + { + bool: { + should: [{ term: { 'data_stream.dataset': 'elasticsearch.cluster_stats' } }], + }, + }, + { term: { cluster_uuid: 'cuid123' } }, + { term: { 'source_node.uuid': 'abc123' } }, + { + range: { + timestamp: { format: 'epoch_millis', gte: 1456826400000, lte: 14568264000000 }, + }, + }, + ], + }, + }); + }); + + it('Uses legacy `type`, `dsDataset`, `metricset` options to add type filters and data stream filters with minimal fields that defaults to `metrics` data_stream', () => { + const options = { + type: 'cluster_stats', + metricset: 'cluster_stats', + dsDataset: 'elasticsearch.cluster_stats', + clusterUuid: 'cuid123', + metric, + }; + expect(createQuery(options)).toEqual({ + bool: { + filter: [ + { + bool: { + should: [ + { + term: { + 'data_stream.dataset': 'elasticsearch.cluster_stats', + }, + }, + { + term: { + 'metricset.name': 'cluster_stats', + }, + }, + { term: { type: 'cluster_stats' } }, + ], + }, + }, + { term: { cluster_uuid: 'cuid123' } }, + ], + }, + }); + }); + + it('Uses legacy `type`, `metricset`, `dsDataset`, and `filters` options', () => { + const options = { + type: 'cluster_stats', + metricset: 'cluster_stats', + dsDataset: 'elasticsearch.cluster_stats', + clusterUuid: 'cuid123', + metric, + filters: [ + { + term: { 'source_node.uuid': `nuid123` }, + }, + ], + }; + expect(createQuery(options)).toEqual({ + bool: { + filter: [ + { + bool: { + should: [ + { term: { 'data_stream.dataset': 'elasticsearch.cluster_stats' } }, + { term: { 'metricset.name': 'cluster_stats' } }, + { term: { type: 'cluster_stats' } }, + ], + }, + }, + { term: { cluster_uuid: 'cuid123' } }, + { term: { 'source_node.uuid': 'nuid123' } }, + ], + }, + }); + }); +}); diff --git a/x-pack/plugins/monitoring/server/lib/create_query.ts b/x-pack/plugins/monitoring/server/lib/create_query.ts index 8dead521d24fb4..051b0ed6b4f9ce 100644 --- a/x-pack/plugins/monitoring/server/lib/create_query.ts +++ b/x-pack/plugins/monitoring/server/lib/create_query.ts @@ -56,7 +56,9 @@ export function createTimeFilter(options: { * document UUIDs, start time and end time, and injecting additional filters. * * Options object: - * @param {String} options.type - `type` field value of the documents + * @param {string} options.type - `type` field value of the documents in legay .monitoring indices + * @param {string} options.dsDataset - `data_stream.dataset` field values of the documents + * @param {string} options.metricset - `metricset.name` field values of the documents * @param {Array} options.filters - additional filters to add to the `bool` section of the query. Default: [] * @param {string} options.clusterUuid - a UUID of the cluster. Required. * @param {string} options.uuid - a UUID of the metric to filter for, or `null` if UUID should not be part of the query @@ -64,30 +66,44 @@ export function createTimeFilter(options: { * @param {Date} options.end - numeric timestamp (optional) * @param {Metric} options.metric - Metric instance or metric fields object @see ElasticsearchMetric.getMetricFields */ -export function createQuery(options: { + +interface CreateQueryOptions { type?: string; - types?: string[]; + dsDataset?: string; + metricset?: string; filters?: any[]; clusterUuid: string; uuid?: string; start?: number; end?: number; metric?: { uuidField?: string; timestampField: string }; -}) { - const { type, types, clusterUuid, uuid, filters } = defaults(options, { filters: [] }); +} +export function createQuery(options: CreateQueryOptions) { + const { type, metricset, dsDataset, clusterUuid, uuid, filters } = defaults(options, { + filters: [], + }); const isFromStandaloneCluster = clusterUuid === STANDALONE_CLUSTER_CLUSTER_UUID; + const terms = []; let typeFilter: any; + + // data_stream.dataset matches agent integration data streams + if (dsDataset) { + terms.push({ term: { 'data_stream.dataset': dsDataset } }); + } + // metricset.name matches standalone beats + if (metricset) { + terms.push({ term: { 'metricset.name': metricset } }); + } + // type matches legacy data if (type) { - typeFilter = { bool: { should: [{ term: { type } }, { term: { 'metricset.name': type } }] } }; - } else if (types) { + terms.push({ term: { type } }); + } + if (terms.length) { typeFilter = { bool: { - should: [ - ...types.map((t) => ({ term: { type: t } })), - ...types.map((t) => ({ term: { 'metricset.name': t } })), - ], + should: [...terms], }, }; } diff --git a/x-pack/plugins/monitoring/server/lib/details/get_metrics.test.js b/x-pack/plugins/monitoring/server/lib/details/get_metrics.test.js index 80234ee369aeef..5ba7fd1207448a 100644 --- a/x-pack/plugins/monitoring/server/lib/details/get_metrics.test.js +++ b/x-pack/plugins/monitoring/server/lib/details/get_metrics.test.js @@ -16,6 +16,18 @@ import aggMetricsBuckets from './__fixtures__/agg_metrics_buckets'; const min = 1498968000000; // 2017-07-02T04:00:00.000Z const max = 1499054399999; // 2017-07-03T03:59:59.999Z +jest.mock('../../static_globals', () => ({ + Globals: { + app: { + config: { + ui: { + ccs: { enabled: true }, + }, + }, + }, + }, +})); + function getMockReq(metricsBuckets = []) { const config = { get: sinon.stub(), @@ -59,27 +71,25 @@ function getMockReq(metricsBuckets = []) { }; } -const indexPattern = []; - describe('getMetrics and getSeries', () => { it('should return metrics with non-derivative metric', async () => { const req = getMockReq(nonDerivMetricsBuckets); const metricSet = ['node_cpu_utilization']; - const result = await getMetrics(req, indexPattern, metricSet); + const result = await getMetrics(req, 'elasticsearch', metricSet); expect(result).toMatchSnapshot(); }); it('should return metrics with derivative metric', async () => { const req = getMockReq(derivMetricsBuckets); const metricSet = ['cluster_search_request_rate']; - const result = await getMetrics(req, indexPattern, metricSet); + const result = await getMetrics(req, 'elasticsearch', metricSet); expect(result).toMatchSnapshot(); }); it('should return metrics with metric containing custom aggs', async () => { const req = getMockReq(aggMetricsBuckets); const metricSet = ['cluster_index_latency']; - const result = await getMetrics(req, indexPattern, metricSet); + const result = await getMetrics(req, 'elasticsearch', metricSet); expect(result).toMatchSnapshot(); }); @@ -91,14 +101,14 @@ describe('getMetrics and getSeries', () => { keys: ['index_mem_fixed_bit_set', 'index_mem_versions'], }, ]; - const result = await getMetrics(req, indexPattern, metricSet); + const result = await getMetrics(req, 'elasticsearch', metricSet); expect(result).toMatchSnapshot(); }); it('should return metrics with metric that uses default calculation', async () => { const req = getMockReq(nonDerivMetricsBuckets); const metricSet = ['kibana_max_response_times']; - const result = await getMetrics(req, indexPattern, metricSet); + const result = await getMetrics(req, 'elasticsearch', metricSet); expect(result).toMatchSnapshot(); }); }); diff --git a/x-pack/plugins/monitoring/server/lib/details/get_metrics.ts b/x-pack/plugins/monitoring/server/lib/details/get_metrics.ts index a8a1117839dfe8..efca0b84b0d65c 100644 --- a/x-pack/plugins/monitoring/server/lib/details/get_metrics.ts +++ b/x-pack/plugins/monitoring/server/lib/details/get_metrics.ts @@ -11,20 +11,21 @@ import { getSeries } from './get_series'; import { calculateTimeseriesInterval } from '../calculate_timeseries_interval'; import { getTimezone } from '../get_timezone'; import { LegacyRequest } from '../../types'; +import { INDEX_PATTERN_TYPES } from '../../../common/constants'; type Metric = string | { keys: string | string[]; name: string }; // TODO: Switch to an options object argument here export async function getMetrics( req: LegacyRequest, - indexPattern: string, + moduleType: INDEX_PATTERN_TYPES, metricSet: Metric[] = [], filters: Array> = [], metricOptions: Record = {}, numOfBuckets: number = 0, groupBy: string | Record | null = null ) { - checkParam(indexPattern, 'indexPattern in details/getMetrics'); + checkParam(moduleType, 'moduleType in details/getMetrics'); checkParam(metricSet, 'metricSet in details/getMetrics'); const config = req.server.config(); @@ -53,7 +54,7 @@ export async function getMetrics( return Promise.all( metricNames.map((metricName) => { - return getSeries(req, indexPattern, metricName, metricOptions, filters, groupBy, { + return getSeries(req, moduleType, metricName, metricOptions, filters, groupBy, { min, max, bucketSize, diff --git a/x-pack/plugins/monitoring/server/lib/details/get_series.ts b/x-pack/plugins/monitoring/server/lib/details/get_series.ts index 99652cbff3ffd8..3a053b16aad7cd 100644 --- a/x-pack/plugins/monitoring/server/lib/details/get_series.ts +++ b/x-pack/plugins/monitoring/server/lib/details/get_series.ts @@ -16,9 +16,12 @@ import { formatTimestampToDuration } from '../../../common'; import { NORMALIZED_DERIVATIVE_UNIT, CALCULATE_DURATION_UNTIL, + INDEX_PATTERN_TYPES, STANDALONE_CLUSTER_CLUSTER_UUID, } from '../../../common/constants'; import { formatUTCTimestampForTimezone } from '../format_timezone'; +import { getNewIndexPatterns } from '../cluster/get_index_patterns'; +import { Globals } from '../../static_globals'; type SeriesBucket = Bucket & { metric_mb_deriv?: { normalized_value: number } }; @@ -117,7 +120,7 @@ function createMetricAggs(metric: Metric) { async function fetchSeries( req: LegacyRequest, - indexPattern: string, + moduleType: INDEX_PATTERN_TYPES, metric: Metric, metricOptions: any, groupBy: string | Record | null, @@ -175,8 +178,14 @@ async function fetchSeries( }; } + const indexPatterns = getNewIndexPatterns({ + config: Globals.app.config, + moduleType, + ccs: req.payload.ccs, + }); + const params = { - index: indexPattern, + index: indexPatterns, size: 0, ignore_unavailable: true, body: { @@ -327,14 +336,15 @@ function handleSeries( * TODO: This should be expanded to accept multiple metrics in a single request to allow a single date histogram to be used. * * @param {Object} req The incoming user's request. - * @param {String} indexPattern The relevant index pattern (not just for Elasticsearch!). + * @param {String} moduleType The relevant module eg: elasticsearch, kibana, logstash. * @param {String} metricName The name of the metric being plotted. * @param {Array} filters Any filters that should be applied to the query. * @return {Promise} The object response containing the {@code timeRange}, {@code metric}, and {@code data}. */ + export async function getSeries( req: LegacyRequest, - indexPattern: string, + moduleType: INDEX_PATTERN_TYPES, metricName: string, metricOptions: Record, filters: Array>, @@ -346,7 +356,7 @@ export async function getSeries( timezone, }: { min: string | number; max: string | number; bucketSize: number; timezone: string } ) { - checkParam(indexPattern, 'indexPattern in details/getSeries'); + checkParam(moduleType, 'moduleType in details/getSeries'); const metric = metrics[metricName]; if (!metric) { @@ -354,7 +364,7 @@ export async function getSeries( } const response = await fetchSeries( req, - indexPattern, + moduleType, metric, metricOptions, groupBy, diff --git a/x-pack/plugins/monitoring/server/lib/elasticsearch/ccr.ts b/x-pack/plugins/monitoring/server/lib/elasticsearch/ccr.ts index 17dc48d0b237e7..902e4bf784a096 100644 --- a/x-pack/plugins/monitoring/server/lib/elasticsearch/ccr.ts +++ b/x-pack/plugins/monitoring/server/lib/elasticsearch/ccr.ts @@ -14,9 +14,18 @@ import { ElasticsearchMetric } from '../metrics'; import { createQuery } from '../create_query'; import { ElasticsearchResponse } from '../../../common/types/es'; import { LegacyRequest } from '../../types'; +import { getNewIndexPatterns } from '../cluster/get_index_patterns'; +import { Globals } from '../../static_globals'; -export async function checkCcrEnabled(req: LegacyRequest, esIndexPattern: string) { - checkParam(esIndexPattern, 'esIndexPattern in checkCcrEnabled'); +export async function checkCcrEnabled(req: LegacyRequest, ccs: string) { + const dataset = 'cluster_stats'; + const moduleType = 'elasticsearch'; + const indexPatterns = getNewIndexPatterns({ + config: Globals.app.config, + moduleType, + dataset, + ccs, + }); const start = moment.utc(req.payload.timeRange.min).valueOf(); const end = moment.utc(req.payload.timeRange.max).valueOf(); @@ -25,12 +34,14 @@ export async function checkCcrEnabled(req: LegacyRequest, esIndexPattern: string const metricFields = ElasticsearchMetric.getMetricFields(); const params = { - index: esIndexPattern, + index: indexPatterns, size: 1, ignore_unavailable: true, body: { query: createQuery({ - type: 'cluster_stats', + type: dataset, + dsDataset: `${moduleType}.${dataset}`, + metricset: dataset, start, end, clusterUuid, diff --git a/x-pack/plugins/monitoring/server/lib/elasticsearch/get_last_recovery.ts b/x-pack/plugins/monitoring/server/lib/elasticsearch/get_last_recovery.ts index 52c5b5b97f77b4..7f6eea717be763 100644 --- a/x-pack/plugins/monitoring/server/lib/elasticsearch/get_last_recovery.ts +++ b/x-pack/plugins/monitoring/server/lib/elasticsearch/get_last_recovery.ts @@ -19,6 +19,8 @@ import { ElasticsearchResponseHit, } from '../../../common/types/es'; import { LegacyRequest } from '../../types'; +import { getNewIndexPatterns } from '../cluster/get_index_patterns'; +import { Globals } from '../../static_globals'; /** * Filter out shard activity that we do not care about. @@ -86,37 +88,63 @@ export function handleMbLastRecoveries(resp: ElasticsearchResponse, start: numbe return filtered; } -export async function getLastRecovery( - req: LegacyRequest, - esIndexPattern: string, - esIndexPatternEcs: string, - size: number -) { - checkParam(esIndexPattern, 'esIndexPattern in elasticsearch/getLastRecovery'); - +export async function getLastRecovery(req: LegacyRequest, size: number) { const start = req.payload.timeRange.min; const end = req.payload.timeRange.max; const clusterUuid = req.params.clusterUuid; const metric = ElasticsearchMetric.getMetricFields(); + + const dataset = 'index_recovery'; + const moduleType = 'elasticsearch'; + const indexPattern = getNewIndexPatterns({ + config: Globals.app.config, + moduleType, + dataset, + ccs: req.payload.ccs, + }); + const legacyParams = { - index: esIndexPattern, + index: indexPattern, size: 1, ignore_unavailable: true, body: { _source: ['index_recovery.shards'], sort: { timestamp: { order: 'desc', unmapped_type: 'long' } }, - query: createQuery({ type: 'index_recovery', start, end, clusterUuid, metric }), + query: createQuery({ + type: dataset, + metricset: dataset, + start, + end, + clusterUuid, + metric, + }), }, }; + + const indexPatternEcs = getNewIndexPatterns({ + config: Globals.app.config, + moduleType, + dataset, + ccs: req.payload.ccs, + ecsLegacyOnly: true, + }); const ecsParams = { - index: esIndexPatternEcs, + index: indexPatternEcs, size, ignore_unavailable: true, body: { _source: ['elasticsearch.index.recovery', '@timestamp'], sort: { timestamp: { order: 'desc', unmapped_type: 'long' } }, - query: createQuery({ type: 'index_recovery', start, end, clusterUuid, metric }), + query: createQuery({ + type: dataset, + dsDataset: `${moduleType}.${dataset}`, + metricset: dataset, + start, + end, + clusterUuid, + metric, + }), aggs: { max_timestamp: { max: { diff --git a/x-pack/plugins/monitoring/server/lib/elasticsearch/get_ml_jobs.ts b/x-pack/plugins/monitoring/server/lib/elasticsearch/get_ml_jobs.ts index b0c82bdc0f5023..f321326ee090a5 100644 --- a/x-pack/plugins/monitoring/server/lib/elasticsearch/get_ml_jobs.ts +++ b/x-pack/plugins/monitoring/server/lib/elasticsearch/get_ml_jobs.ts @@ -15,6 +15,8 @@ import { ElasticsearchMetric } from '../metrics'; import { ML_SUPPORTED_LICENSES } from '../../../common/constants'; import { ElasticsearchResponse, ElasticsearchSource } from '../../../common/types/es'; import { LegacyRequest } from '../../types'; +import { getNewIndexPatterns } from '../cluster/get_index_patterns'; +import { Globals } from '../../static_globals'; /* * Get a listing of jobs along with some metric data to use for the listing @@ -37,17 +39,26 @@ export function handleResponse(response: ElasticsearchResponse) { export type MLJobs = ReturnType; -export function getMlJobs(req: LegacyRequest, esIndexPattern: string) { - checkParam(esIndexPattern, 'esIndexPattern in getMlJobs'); - +export function getMlJobs(req: LegacyRequest) { const config = req.server.config(); const maxBucketSize = config.get('monitoring.ui.max_bucket_size'); const start = req.payload.timeRange.min; // no wrapping in moment :) const end = req.payload.timeRange.max; const clusterUuid = req.params.clusterUuid; const metric = ElasticsearchMetric.getMetricFields(); + + const dataset = 'ml_job'; + const type = 'job_stats'; + const moduleType = 'elasticsearch'; + const indexPatterns = getNewIndexPatterns({ + config: Globals.app.config, + ccs: req.payload.ccs, + moduleType, + dataset, + }); + const params = { - index: esIndexPattern, + index: indexPatterns, size: maxBucketSize, ignore_unavailable: true, filter_path: [ @@ -69,7 +80,15 @@ export function getMlJobs(req: LegacyRequest, esIndexPattern: string) { body: { sort: { timestamp: { order: 'desc', unmapped_type: 'long' } }, collapse: { field: 'job_stats.job_id' }, - query: createQuery({ types: ['ml_job', 'job_stats'], start, end, clusterUuid, metric }), + query: createQuery({ + type, + dsDataset: `${moduleType}.${dataset}`, + metricset: dataset, + start, + end, + clusterUuid, + metric, + }), }, }; @@ -81,11 +100,7 @@ export function getMlJobs(req: LegacyRequest, esIndexPattern: string) { * cardinality isn't guaranteed to be accurate is the issue * but it will be as long as the precision threshold is >= the actual value */ -export function getMlJobsForCluster( - req: LegacyRequest, - esIndexPattern: string, - cluster: ElasticsearchSource -) { +export function getMlJobsForCluster(req: LegacyRequest, cluster: ElasticsearchSource, ccs: string) { const license = cluster.license ?? cluster.elasticsearch?.cluster?.stats?.license ?? {}; if (license.status === 'active' && includes(ML_SUPPORTED_LICENSES, license.type)) { @@ -94,19 +109,37 @@ export function getMlJobsForCluster( const end = req.payload.timeRange.max; const clusterUuid = req.params.clusterUuid; const metric = ElasticsearchMetric.getMetricFields(); + + const type = 'job_stats'; + const dataset = 'ml_job'; + const moduleType = 'elasticsearch'; + const indexPatterns = getNewIndexPatterns({ + config: Globals.app.config, + moduleType, + dataset, + ccs, + }); + const params = { - index: esIndexPattern, + index: indexPatterns, size: 0, ignore_unavailable: true, filter_path: 'aggregations.jobs_count.value', body: { - query: createQuery({ types: ['ml_job', 'job_stats'], start, end, clusterUuid, metric }), + query: createQuery({ + type, + dsDataset: `${moduleType}.${dataset}`, + metricset: dataset, + start, + end, + clusterUuid, + metric, + }), aggs: { jobs_count: { cardinality: { field: 'job_stats.job_id' } }, }, }, }; - const { callWithRequest } = req.server.plugins.elasticsearch.getCluster('monitoring'); return callWithRequest(req, 'search', params).then((response: ElasticsearchResponse) => { diff --git a/x-pack/plugins/monitoring/server/lib/elasticsearch/indices/get_index_summary.ts b/x-pack/plugins/monitoring/server/lib/elasticsearch/indices/get_index_summary.ts index 8a03027a93a565..388c3a364c77af 100644 --- a/x-pack/plugins/monitoring/server/lib/elasticsearch/indices/get_index_summary.ts +++ b/x-pack/plugins/monitoring/server/lib/elasticsearch/indices/get_index_summary.ts @@ -15,6 +15,8 @@ import { createQuery } from '../../create_query'; import { ElasticsearchMetric } from '../../metrics'; import { ElasticsearchResponse } from '../../../../common/types/es'; import { LegacyRequest } from '../../../types'; +import { getNewIndexPatterns } from '../../cluster/get_index_patterns'; +import { Globals } from '../../../static_globals'; export function handleResponse(shardStats: any, indexUuid: string) { return (response: ElasticsearchResponse) => { @@ -64,7 +66,6 @@ export function handleResponse(shardStats: any, indexUuid: string) { export function getIndexSummary( req: LegacyRequest, - esIndexPattern: string, shardStats: any, { clusterUuid, @@ -73,7 +74,15 @@ export function getIndexSummary( end, }: { clusterUuid: string; indexUuid: string; start: number; end: number } ) { - checkParam(esIndexPattern, 'esIndexPattern in elasticsearch/getIndexSummary'); + const dataset = 'index'; // data_stream.dataset + const type = 'index_stats'; // legacy + const moduleType = 'elasticsearch'; + const indexPatterns = getNewIndexPatterns({ + config: Globals.app.config, + dataset, + moduleType, + ccs: req.payload.ccs, + }); const metric = ElasticsearchMetric.getMetricFields(); const filters = [ @@ -87,13 +96,15 @@ export function getIndexSummary( }, ]; const params = { - index: esIndexPattern, + index: indexPatterns, size: 1, ignore_unavailable: true, body: { sort: { timestamp: { order: 'desc', unmapped_type: 'long' } }, query: createQuery({ - types: ['index', 'index_stats'], + type, + dsDataset: `${moduleType}.${dataset}`, + metricset: dataset, start, end, clusterUuid, diff --git a/x-pack/plugins/monitoring/server/lib/elasticsearch/indices/get_indices.ts b/x-pack/plugins/monitoring/server/lib/elasticsearch/indices/get_indices.ts index a43feb8fc84a3b..85e49f463526a6 100644 --- a/x-pack/plugins/monitoring/server/lib/elasticsearch/indices/get_indices.ts +++ b/x-pack/plugins/monitoring/server/lib/elasticsearch/indices/get_indices.ts @@ -19,6 +19,8 @@ import { calculateRate } from '../../calculate_rate'; import { getUnassignedShards } from '../shards'; import { ElasticsearchResponse } from '../../../../common/types/es'; import { LegacyRequest } from '../../../types'; +import { getNewIndexPatterns } from '../../cluster/get_index_patterns'; +import { Globals } from '../../../static_globals'; export function handleResponse( resp: ElasticsearchResponse, @@ -95,7 +97,7 @@ export function handleResponse( } export function buildGetIndicesQuery( - esIndexPattern: string, + req: LegacyRequest, clusterUuid: string, { start, @@ -113,9 +115,18 @@ export function buildGetIndicesQuery( }); } const metricFields = ElasticsearchMetric.getMetricFields(); + const dataset = 'index'; // data_stream.dataset + const type = 'index_stats'; // legacy + const moduleType = 'elasticsearch'; + const indexPatterns = getNewIndexPatterns({ + config: Globals.app.config, + ccs: req.payload.ccs, + dataset, + moduleType, + }); return { - index: esIndexPattern, + index: indexPatterns, size, ignore_unavailable: true, filter_path: [ @@ -145,7 +156,9 @@ export function buildGetIndicesQuery( ], body: { query: createQuery({ - types: ['index', 'index_stats'], + type, + dsDataset: `${moduleType}.${dataset}`, + metricset: dataset, start, end, clusterUuid, @@ -167,17 +180,14 @@ export function buildGetIndicesQuery( export function getIndices( req: LegacyRequest, - esIndexPattern: string, showSystemIndices: boolean = false, shardStats: any ) { - checkParam(esIndexPattern, 'esIndexPattern in elasticsearch/getIndices'); - const { min: start, max: end } = req.payload.timeRange; const clusterUuid = req.params.clusterUuid; const config = req.server.config(); - const params = buildGetIndicesQuery(esIndexPattern, clusterUuid, { + const params = buildGetIndicesQuery(req, clusterUuid, { start, end, showSystemIndices, diff --git a/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_node_summary.ts b/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_node_summary.ts index aed6b40675e459..a422ccf95527c4 100644 --- a/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_node_summary.ts +++ b/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_node_summary.ts @@ -24,6 +24,8 @@ import { ElasticsearchLegacySource, } from '../../../../common/types/es'; import { LegacyRequest } from '../../../types'; +import { getNewIndexPatterns } from '../../cluster/get_index_patterns'; +import { Globals } from '../../../static_globals'; export function handleResponse( clusterState: ElasticsearchSource['cluster_state'], @@ -100,7 +102,6 @@ export function handleResponse( export function getNodeSummary( req: LegacyRequest, - esIndexPattern: string, clusterState: ElasticsearchSource['cluster_state'], shardStats: any, { @@ -110,25 +111,40 @@ export function getNodeSummary( end, }: { clusterUuid: string; nodeUuid: string; start: number; end: number } ) { - checkParam(esIndexPattern, 'esIndexPattern in elasticsearch/getNodeSummary'); - - // Build up the Elasticsearch request const metric = ElasticsearchMetric.getMetricFields(); const filters = [ { term: { 'source_node.uuid': nodeUuid }, }, ]; + + const dataset = 'node_stats'; + const moduleType = 'elasticsearch'; + const indexPatterns = getNewIndexPatterns({ + config: Globals.app.config, + ccs: req.payload.ccs, + dataset, + moduleType, + }); + const params = { - index: esIndexPattern, + index: indexPatterns, size: 1, ignore_unavailable: true, body: { sort: { timestamp: { order: 'desc', unmapped_type: 'long' } }, - query: createQuery({ type: 'node_stats', start, end, clusterUuid, metric, filters }), + query: createQuery({ + type: dataset, + dsDataset: `${moduleType}.${dataset}`, + metricset: dataset, + start, + end, + clusterUuid, + metric, + filters, + }), }, }; - const { callWithRequest } = req.server.plugins.elasticsearch.getCluster('monitoring'); return callWithRequest(req, 'search', params).then( handleResponse(clusterState, shardStats, nodeUuid) diff --git a/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_node_ids.test.js b/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_node_ids.test.js index e6f04e3c649e54..738ea9ecc6a367 100644 --- a/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_node_ids.test.js +++ b/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_node_ids.test.js @@ -7,6 +7,18 @@ import { getNodeIds } from './get_node_ids'; +jest.mock('../../../../static_globals', () => ({ + Globals: { + app: { + config: { + ui: { + ccs: { enabled: true }, + }, + }, + }, + }, +})); + describe('getNodeIds', () => { it('should return a list of ids and uuids', async () => { const callWithRequest = jest.fn().mockReturnValue({ @@ -37,6 +49,9 @@ describe('getNodeIds', () => { }, }, server: { + config: () => ({ + get: () => true, + }), plugins: { elasticsearch: { getCluster: () => ({ diff --git a/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_node_ids.ts b/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_node_ids.ts index 03524eebd12e8c..58f4a0b8aca56c 100644 --- a/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_node_ids.ts +++ b/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_node_ids.ts @@ -10,16 +10,26 @@ import { get } from 'lodash'; import { ElasticsearchMetric } from '../../../metrics'; import { createQuery } from '../../../create_query'; import { LegacyRequest, Bucket } from '../../../../types'; +import { getNewIndexPatterns } from '../../../cluster/get_index_patterns'; +import { Globals } from '../../../../static_globals'; export async function getNodeIds( req: LegacyRequest, - indexPattern: string, { clusterUuid }: { clusterUuid: string }, size: number ) { const start = moment.utc(req.payload.timeRange.min).valueOf(); const end = moment.utc(req.payload.timeRange.max).valueOf(); + const dataset = 'node_stats'; + const moduleType = 'elasticsearch'; + const indexPattern = getNewIndexPatterns({ + config: Globals.app.config, + ccs: req.payload.ccs, + moduleType, + dataset, + }); + const params = { index: indexPattern, size: 0, @@ -27,7 +37,9 @@ export async function getNodeIds( filter_path: ['aggregations.composite_data.buckets'], body: { query: createQuery({ - type: 'node_stats', + type: dataset, + dsDataset: `${moduleType}.${dataset}`, + metricset: dataset, start, end, metric: ElasticsearchMetric.getMetricFields(), diff --git a/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_nodes.ts b/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_nodes.ts index 0b5c0337e6c475..2bd7078fa00a4f 100644 --- a/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_nodes.ts +++ b/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_nodes.ts @@ -6,7 +6,6 @@ */ import moment from 'moment'; -import { checkParam } from '../../../error_missing_required'; import { createQuery } from '../../../create_query'; import { calculateAuto } from '../../../calculate_auto'; import { ElasticsearchMetric } from '../../../metrics'; @@ -15,6 +14,8 @@ import { handleResponse } from './handle_response'; import { LISTING_METRICS_NAMES, LISTING_METRICS_PATHS } from './nodes_listing_metrics'; import { LegacyRequest } from '../../../../types'; import { ElasticsearchModifiedSource } from '../../../../../common/types/es'; +import { getNewIndexPatterns } from '../../../cluster/get_index_patterns'; +import { Globals } from '../../../../static_globals'; /* Run an aggregation on node_stats to get stat data for the selected time * range for all the active nodes. Every option is a key to a configuration @@ -35,13 +36,10 @@ import { ElasticsearchModifiedSource } from '../../../../../common/types/es'; */ export async function getNodes( req: LegacyRequest, - esIndexPattern: string, pageOfNodes: Array<{ uuid: string }>, clusterStats: ElasticsearchModifiedSource, nodesShardCount: { nodes: { [nodeId: string]: { shardCount: number } } } ) { - checkParam(esIndexPattern, 'esIndexPattern in getNodes'); - const start = moment.utc(req.payload.timeRange.min).valueOf(); const orgStart = start; const end = moment.utc(req.payload.timeRange.max).valueOf(); @@ -67,13 +65,24 @@ export async function getNodes( }, ]; + const dataset = 'node_stats'; + const moduleType = 'elasticsearch'; + const indexPatterns = getNewIndexPatterns({ + config: Globals.app.config, + ccs: req.payload.ccs, + moduleType, + dataset, + }); + const params = { - index: esIndexPattern, + index: indexPatterns, size: config.get('monitoring.ui.max_bucket_size'), ignore_unavailable: true, body: { query: createQuery({ - type: 'node_stats', + type: dataset, + dsDataset: `${moduleType}.${dataset}`, + metricset: dataset, start, end, clusterUuid, @@ -112,7 +121,6 @@ export async function getNodes( ...LISTING_METRICS_PATHS, ], }; - const { callWithRequest } = req.server.plugins.elasticsearch.getCluster('monitoring'); const response = await callWithRequest(req, 'search', params); diff --git a/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_paginated_nodes.test.js b/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_paginated_nodes.test.js index c7939027a0fb32..f96cb8e7a18539 100644 --- a/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_paginated_nodes.test.js +++ b/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_paginated_nodes.test.js @@ -47,7 +47,6 @@ describe('getPaginatedNodes', () => { }), }, }; - const esIndexPattern = '.monitoring-es-*'; const clusterUuid = '1abc'; const metricSet = ['foo', 'bar']; const pagination = { index: 0, size: 10 }; @@ -74,7 +73,6 @@ describe('getPaginatedNodes', () => { it('should return a subset based on the pagination parameters', async () => { const nodes = await getPaginatedNodes( req, - esIndexPattern, { clusterUuid }, metricSet, pagination, @@ -94,7 +92,6 @@ describe('getPaginatedNodes', () => { it('should return a sorted subset', async () => { const nodes = await getPaginatedNodes( req, - esIndexPattern, { clusterUuid }, metricSet, pagination, @@ -111,17 +108,11 @@ describe('getPaginatedNodes', () => { }); }); - it('should return a filterd subset', async () => { - const nodes = await getPaginatedNodes( - req, - esIndexPattern, - { clusterUuid }, - metricSet, - pagination, - sort, - 'tw', - { clusterStats, nodesShardCount } - ); + it('should return a filtered subset', async () => { + const nodes = await getPaginatedNodes(req, { clusterUuid }, metricSet, pagination, sort, 'tw', { + clusterStats, + nodesShardCount, + }); expect(nodes).toEqual({ pageOfNodes: [{ name: 'two', uuid: 2, isOnline: false, shardCount: 5, foo: 12 }], totalNodeCount: 1, diff --git a/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_paginated_nodes.ts b/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_paginated_nodes.ts index 118140fe3f9cd2..d353ea844cdf92 100644 --- a/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_paginated_nodes.ts +++ b/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_paginated_nodes.ts @@ -41,7 +41,6 @@ interface Node { export async function getPaginatedNodes( req: LegacyRequest, - esIndexPattern: string, { clusterUuid }: { clusterUuid: string }, metricSet: string[], pagination: { index: number; size: number }, @@ -59,7 +58,7 @@ export async function getPaginatedNodes( ) { const config = req.server.config(); const size = Number(config.get('monitoring.ui.max_bucket_size')); - const nodes: Node[] = await getNodeIds(req, esIndexPattern, { clusterUuid }, size); + const nodes: Node[] = await getNodeIds(req, { clusterUuid }, size); // Add `isOnline` and shards from the cluster state and shard stats const clusterState = clusterStats?.cluster_state ?? { nodes: {} }; @@ -87,13 +86,14 @@ export async function getPaginatedNodes( }; const metricSeriesData = await getMetrics( req, - esIndexPattern, + 'elasticsearch', metricSet, filters, { nodes }, 4, groupBy ); + for (const metricName in metricSeriesData) { if (!metricSeriesData.hasOwnProperty(metricName)) { continue; diff --git a/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_indices_unassigned_shard_stats.test.js b/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_indices_unassigned_shard_stats.test.js index 6521f1f435cbc7..6a9e01166ea875 100644 --- a/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_indices_unassigned_shard_stats.test.js +++ b/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_indices_unassigned_shard_stats.test.js @@ -7,6 +7,18 @@ import { getIndicesUnassignedShardStats } from './get_indices_unassigned_shard_stats'; +jest.mock('../../../static_globals', () => ({ + Globals: { + app: { + config: { + ui: { + ccs: { enabled: true }, + }, + }, + }, + }, +})); + describe('getIndicesUnassignedShardStats', () => { it('should return the unassigned shard stats for indices', async () => { const indices = { @@ -16,6 +28,7 @@ describe('getIndicesUnassignedShardStats', () => { }; const req = { + payload: {}, server: { config: () => ({ get: () => {}, @@ -52,9 +65,8 @@ describe('getIndicesUnassignedShardStats', () => { }, }, }; - const esIndexPattern = '*'; const cluster = {}; - const stats = await getIndicesUnassignedShardStats(req, esIndexPattern, cluster); + const stats = await getIndicesUnassignedShardStats(req, cluster); expect(stats.indices).toEqual(indices); }); }); diff --git a/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_indices_unassigned_shard_stats.ts b/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_indices_unassigned_shard_stats.ts index 87f79ff5b9b44d..b0ba916b53eb8e 100644 --- a/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_indices_unassigned_shard_stats.ts +++ b/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_indices_unassigned_shard_stats.ts @@ -16,12 +16,10 @@ import { ElasticsearchMetric } from '../../metrics'; import { calculateIndicesTotals } from './calculate_shard_stat_indices_totals'; import { LegacyRequest } from '../../../types'; import { ElasticsearchModifiedSource } from '../../../../common/types/es'; +import { getNewIndexPatterns } from '../../cluster/get_index_patterns'; +import { Globals } from '../../../static_globals'; -async function getUnassignedShardData( - req: LegacyRequest, - esIndexPattern: string, - cluster: ElasticsearchModifiedSource -) { +async function getUnassignedShardData(req: LegacyRequest, cluster: ElasticsearchModifiedSource) { const config = req.server.config(); const maxBucketSize = config.get('monitoring.ui.max_bucket_size'); const metric = ElasticsearchMetric.getMetricFields(); @@ -38,14 +36,26 @@ async function getUnassignedShardData( }); } + const dataset = 'shard'; // data_stream.dataset + const type = 'shards'; // legacy + const moduleType = 'elasticsearch'; + const indexPattern = getNewIndexPatterns({ + config: Globals.app.config, + ccs: req.payload.ccs, + moduleType, + dataset, + }); + const params = { - index: esIndexPattern, + index: indexPattern, size: 0, ignore_unavailable: true, body: { sort: { timestamp: { order: 'desc', unmapped_type: 'long' } }, query: createQuery({ - types: ['shard', 'shards'], + type, + dsDataset: `${moduleType}.${dataset}`, + metricset: dataset, clusterUuid: cluster.cluster_uuid ?? cluster.elasticsearch?.cluster?.id, metric, filters, @@ -84,12 +94,9 @@ async function getUnassignedShardData( export async function getIndicesUnassignedShardStats( req: LegacyRequest, - esIndexPattern: string, cluster: ElasticsearchModifiedSource ) { - checkParam(esIndexPattern, 'esIndexPattern in elasticsearch/getShardStats'); - - const response = await getUnassignedShardData(req, esIndexPattern, cluster); + const response = await getUnassignedShardData(req, cluster); const indices = get(response, 'aggregations.indices.buckets', []).reduce( (accum: any, bucket: any) => { const index = bucket.key; diff --git a/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_nodes_shard_count.test.js b/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_nodes_shard_count.test.js index 16d8693ca931dd..c5c77ef389427c 100644 --- a/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_nodes_shard_count.test.js +++ b/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_nodes_shard_count.test.js @@ -7,6 +7,18 @@ import { getNodesShardCount } from './get_nodes_shard_count'; +jest.mock('../../../static_globals', () => ({ + Globals: { + app: { + config: { + ui: { + ccs: { enabled: true }, + }, + }, + }, + }, +})); + describe('getNodeShardCount', () => { it('should return the shard count per node', async () => { const nodes = { @@ -16,6 +28,7 @@ describe('getNodeShardCount', () => { }; const req = { + payload: {}, server: { config: () => ({ get: () => {}, @@ -38,9 +51,8 @@ describe('getNodeShardCount', () => { }, }, }; - const esIndexPattern = '*'; const cluster = {}; - const counts = await getNodesShardCount(req, esIndexPattern, cluster); + const counts = await getNodesShardCount(req, cluster); expect(counts.nodes).toEqual(nodes); }); }); diff --git a/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_nodes_shard_count.ts b/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_nodes_shard_count.ts index 12ce144ebf5c5a..a8ce0d429f06c2 100644 --- a/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_nodes_shard_count.ts +++ b/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_nodes_shard_count.ts @@ -14,12 +14,10 @@ import { createQuery } from '../../create_query'; import { ElasticsearchMetric } from '../../metrics'; import { LegacyRequest } from '../../../types'; import { ElasticsearchModifiedSource } from '../../../../common/types/es'; +import { getNewIndexPatterns } from '../../cluster/get_index_patterns'; +import { Globals } from '../../../static_globals'; -async function getShardCountPerNode( - req: LegacyRequest, - esIndexPattern: string, - cluster: ElasticsearchModifiedSource -) { +async function getShardCountPerNode(req: LegacyRequest, cluster: ElasticsearchModifiedSource) { const config = req.server.config(); const maxBucketSize = config.get('monitoring.ui.max_bucket_size'); const metric = ElasticsearchMetric.getMetricFields(); @@ -35,15 +33,26 @@ async function getShardCountPerNode( }, }); } + const dataset = 'shard'; // data_stream.dataset + const type = 'shards'; // legacy + const moduleType = 'elasticsearch'; + const indexPattern = getNewIndexPatterns({ + config: Globals.app.config, + ccs: req.payload.ccs, + moduleType, + dataset, + }); const params = { - index: esIndexPattern, + index: indexPattern, size: 0, ignore_unavailable: true, body: { sort: { timestamp: { order: 'desc', unmapped_type: 'long' } }, query: createQuery({ - types: ['shard', 'shards'], + type, + dsDataset: `${moduleType}.${dataset}`, + metricset: dataset, clusterUuid: cluster.cluster_uuid ?? cluster.elasticsearch?.cluster?.id, metric, filters, @@ -63,14 +72,8 @@ async function getShardCountPerNode( return await callWithRequest(req, 'search', params); } -export async function getNodesShardCount( - req: LegacyRequest, - esIndexPattern: string, - cluster: ElasticsearchModifiedSource -) { - checkParam(esIndexPattern, 'esIndexPattern in elasticsearch/getShardStats'); - - const response = await getShardCountPerNode(req, esIndexPattern, cluster); +export async function getNodesShardCount(req: LegacyRequest, cluster: ElasticsearchModifiedSource) { + const response = await getShardCountPerNode(req, cluster); const nodes = get(response, 'aggregations.nodes.buckets', []).reduce( (accum: any, bucket: any) => { accum[bucket.key] = { shardCount: bucket.doc_count }; diff --git a/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_shard_allocation.ts b/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_shard_allocation.ts index 26a1f88c719cf6..cede4bf921419b 100644 --- a/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_shard_allocation.ts +++ b/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_shard_allocation.ts @@ -6,13 +6,16 @@ */ // @ts-ignore -import { checkParam } from '../../error_missing_required'; +import { StringOptions } from '@kbn/config-schema/target_types/types'; // @ts-ignore import { createQuery } from '../../create_query'; // @ts-ignore import { ElasticsearchMetric } from '../../metrics'; import { ElasticsearchResponse, ElasticsearchLegacySource } from '../../../../common/types/es'; import { LegacyRequest } from '../../../types'; +import { getNewIndexPatterns } from '../../cluster/get_index_patterns'; +import { Globals } from '../../../static_globals'; + export function handleResponse(response: ElasticsearchResponse) { const hits = response.hits?.hits; if (!hits) { @@ -57,15 +60,12 @@ export function handleResponse(response: ElasticsearchResponse) { export function getShardAllocation( req: LegacyRequest, - esIndexPattern: string, { shardFilter, stateUuid, showSystemIndices = false, }: { shardFilter: any; stateUuid: string; showSystemIndices: boolean } ) { - checkParam(esIndexPattern, 'esIndexPattern in elasticsearch/getShardAllocation'); - const filters = [ { bool: { @@ -100,15 +100,32 @@ export function getShardAllocation( const config = req.server.config(); const clusterUuid = req.params.clusterUuid; const metric = ElasticsearchMetric.getMetricFields(); + + const dataset = 'shard'; // data_stream.dataset + const type = 'shards'; // legacy + const moduleType = 'elasticsearch'; + const indexPatterns = getNewIndexPatterns({ + config: Globals.app.config, + ccs: req.payload.ccs, + dataset, + moduleType, + }); + const params = { - index: esIndexPattern, + index: indexPatterns, size: config.get('monitoring.ui.max_bucket_size'), ignore_unavailable: true, body: { - query: createQuery({ types: ['shard', 'shards'], clusterUuid, metric, filters }), + query: createQuery({ + type, + dsDataset: `${moduleType}.${dataset}`, + metricset: dataset, + clusterUuid, + metric, + filters, + }), }, }; - const { callWithRequest } = req.server.plugins.elasticsearch.getCluster('monitoring'); return callWithRequest(req, 'search', params).then(handleResponse); } diff --git a/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_shard_stats.ts b/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_shard_stats.ts index 0ee047b2b938b3..29cbcb9ac0567b 100644 --- a/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_shard_stats.ts +++ b/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_shard_stats.ts @@ -20,6 +20,8 @@ import { getShardAggs } from './get_shard_stat_aggs'; import { calculateIndicesTotals } from './calculate_shard_stat_indices_totals'; import { LegacyRequest } from '../../../types'; import { ElasticsearchResponse, ElasticsearchModifiedSource } from '../../../../common/types/es'; +import { getNewIndexPatterns } from '../../cluster/get_index_patterns'; +import { Globals } from '../../../static_globals'; export function handleResponse( resp: ElasticsearchResponse, @@ -55,11 +57,18 @@ export function handleResponse( export function getShardStats( req: LegacyRequest, - esIndexPattern: string, cluster: ElasticsearchModifiedSource, { includeNodes = false, includeIndices = false, indexName = null, nodeUuid = null } = {} ) { - checkParam(esIndexPattern, 'esIndexPattern in elasticsearch/getShardStats'); + const dataset = 'shard'; // data_stream.dataset + const type = 'shards'; // legacy + const moduleType = 'elasticsearch'; + const indexPatterns = getNewIndexPatterns({ + config: Globals.app.config, + ccs: req.payload.ccs, + moduleType, + dataset, + }); const config = req.server.config(); const metric = ElasticsearchMetric.getMetricFields(); @@ -95,13 +104,15 @@ export function getShardStats( }); } const params = { - index: esIndexPattern, + index: indexPatterns, size: 0, ignore_unavailable: true, body: { sort: { timestamp: { order: 'desc', unmapped_type: 'long' } }, query: createQuery({ - types: ['shard', 'shards'], + type, + dsDataset: `${moduleType}.${dataset}`, + metricset: dataset, clusterUuid: cluster.cluster_uuid ?? cluster.elasticsearch?.cluster?.id, metric, filters, @@ -111,7 +122,6 @@ export function getShardStats( }, }, }; - const { callWithRequest } = req.server.plugins.elasticsearch.getCluster('monitoring'); return callWithRequest(req, 'search', params).then((resp) => { return handleResponse(resp, includeNodes, includeIndices, cluster); diff --git a/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/normalize_shard_objects.ts b/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/normalize_shard_objects.ts index 6aa84a0809e963..c6f38c7ac795f8 100644 --- a/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/normalize_shard_objects.ts +++ b/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/normalize_shard_objects.ts @@ -48,7 +48,8 @@ export function normalizeNodeShards(masterNode: string) { [node.key]: { shardCount: node.doc_count, indexCount: node.index_count.value, - name: node.node_names.buckets[0].key, + // this field is always missing, problem with package? elasticsearch.node.name ECS field doesn't exist + name: node.node_names.buckets[0]?.key || 'NO NAME', node_ids: nodeIds, type: calculateNodeType(_node, masterNode), // put the "star" icon on the node link in the shard allocator }, diff --git a/x-pack/plugins/monitoring/server/lib/enterprise_search/create_enterprise_search_query.ts b/x-pack/plugins/monitoring/server/lib/enterprise_search/create_enterprise_search_query.ts index 3a418e010e1f74..5e5c972d2ba460 100644 --- a/x-pack/plugins/monitoring/server/lib/enterprise_search/create_enterprise_search_query.ts +++ b/x-pack/plugins/monitoring/server/lib/enterprise_search/create_enterprise_search_query.ts @@ -16,7 +16,6 @@ import { STANDALONE_CLUSTER_CLUSTER_UUID } from '../../../common/constants'; */ export function createEnterpriseSearchQuery(options: { filters?: any[]; - types?: string[]; metric?: EnterpriseSearchMetricFields; uuid?: string; start?: number; @@ -25,7 +24,6 @@ export function createEnterpriseSearchQuery(options: { const opts = { filters: [] as any[], metric: EnterpriseSearchMetric.getMetricFields(), - types: ['health', 'stats'], clusterUuid: STANDALONE_CLUSTER_CLUSTER_UUID, // This is to disable the stack monitoring clusterUuid filter ...(options ?? {}), }; @@ -33,6 +31,26 @@ export function createEnterpriseSearchQuery(options: { opts.filters.push({ bool: { should: [ + { + term: { + type: 'health', + }, + }, + { + term: { + type: 'stats', + }, + }, + { + term: { + 'metricset.name': 'health', + }, + }, + { + term: { + 'metricset.name': 'stats', + }, + }, { term: { 'event.dataset': 'enterprisesearch.health' } }, { term: { 'event.dataset': 'enterprisesearch.stats' } }, ], diff --git a/x-pack/plugins/monitoring/server/lib/enterprise_search/get_enterprise_search_for_clusters.ts b/x-pack/plugins/monitoring/server/lib/enterprise_search/get_enterprise_search_for_clusters.ts index 96ba1d18dc9e80..d46853fe48d3f1 100644 --- a/x-pack/plugins/monitoring/server/lib/enterprise_search/get_enterprise_search_for_clusters.ts +++ b/x-pack/plugins/monitoring/server/lib/enterprise_search/get_enterprise_search_for_clusters.ts @@ -7,7 +7,6 @@ import { ElasticsearchResponse } from '../../../common/types/es'; import { LegacyRequest, Cluster } from '../../types'; -import { checkParam } from '../error_missing_required'; import { createEnterpriseSearchQuery } from './create_enterprise_search_query'; import { EnterpriseSearchMetric } from '../metrics'; import { @@ -15,6 +14,8 @@ import { entSearchAggResponseHandler, entSearchUuidsAgg, } from './_enterprise_search_stats'; +import { getLegacyIndexPattern } from '../cluster/get_index_patterns'; +import { Globals } from '../../static_globals'; function handleResponse(clusterUuid: string, response: ElasticsearchResponse) { const stats = entSearchAggResponseHandler(response); @@ -27,24 +28,25 @@ function handleResponse(clusterUuid: string, response: ElasticsearchResponse) { export function getEnterpriseSearchForClusters( req: LegacyRequest, - entSearchIndexPattern: string, - clusters: Cluster[] + clusters: Cluster[], + ccs: string ) { - checkParam( - entSearchIndexPattern, - 'entSearchIndexPattern in enterprise_earch/getEnterpriseSearchForClusters' - ); - const start = req.payload.timeRange.min; const end = req.payload.timeRange.max; const config = req.server.config(); const maxBucketSize = config.get('monitoring.ui.max_bucket_size'); + const indexPatterns = getLegacyIndexPattern({ + moduleType: 'enterprisesearch', + ccs, + config: Globals.app.config, + }); + return Promise.all( clusters.map(async (cluster) => { const clusterUuid = cluster.elasticsearch?.cluster?.id ?? cluster.cluster_uuid; const params = { - index: entSearchIndexPattern, + index: indexPatterns, size: 0, ignore_unavailable: true, filter_path: entSearchAggFilterPath, diff --git a/x-pack/plugins/monitoring/server/lib/enterprise_search/get_stats.ts b/x-pack/plugins/monitoring/server/lib/enterprise_search/get_stats.ts index bcb5617e0c9d87..73bd33daeac34d 100644 --- a/x-pack/plugins/monitoring/server/lib/enterprise_search/get_stats.ts +++ b/x-pack/plugins/monitoring/server/lib/enterprise_search/get_stats.ts @@ -8,28 +8,30 @@ import moment from 'moment'; import { ElasticsearchResponse } from '../../../common/types/es'; import { LegacyRequest } from '../../types'; -import { checkParam } from '../error_missing_required'; import { createEnterpriseSearchQuery } from './create_enterprise_search_query'; import { entSearchAggFilterPath, entSearchUuidsAgg, entSearchAggResponseHandler, } from './_enterprise_search_stats'; +import { getLegacyIndexPattern } from '../cluster/get_index_patterns'; +import { Globals } from '../../static_globals'; -export async function getStats( - req: LegacyRequest, - entSearchIndexPattern: string, - clusterUuid: string -) { - checkParam(entSearchIndexPattern, 'entSearchIndexPattern in getStats'); - +export async function getStats(req: LegacyRequest, clusterUuid: string) { const config = req.server.config(); const start = moment.utc(req.payload.timeRange.min).valueOf(); const end = moment.utc(req.payload.timeRange.max).valueOf(); const maxBucketSize = config.get('monitoring.ui.max_bucket_size'); + // just get the legacy pattern since no integration exists yet + const indexPattern = getLegacyIndexPattern({ + moduleType: 'enterprisesearch', + config: Globals.app.config, + ccs: req.payload.ccs, + }); + const params = { - index: entSearchIndexPattern, + index: indexPattern, filter_path: entSearchAggFilterPath, size: 0, ignore_unavailable: true, diff --git a/x-pack/plugins/monitoring/server/lib/kibana/get_kibana_info.ts b/x-pack/plugins/monitoring/server/lib/kibana/get_kibana_info.ts index 81a653d370c0b1..4116e9e5b86acc 100644 --- a/x-pack/plugins/monitoring/server/lib/kibana/get_kibana_info.ts +++ b/x-pack/plugins/monitoring/server/lib/kibana/get_kibana_info.ts @@ -12,6 +12,8 @@ import { checkParam, MissingRequiredError } from '../error_missing_required'; import { calculateAvailability } from '../calculate_availability'; import { LegacyRequest } from '../../types'; import { ElasticsearchResponse } from '../../../common/types/es'; +import { getNewIndexPatterns } from '../cluster/get_index_patterns'; +import { Globals } from '../../static_globals'; import { buildKibanaInfo } from './build_kibana_info'; export function handleResponse(resp: ElasticsearchResponse) { @@ -32,13 +34,16 @@ export function handleResponse(resp: ElasticsearchResponse) { export function getKibanaInfo( req: LegacyRequest, - kbnIndexPattern: string, { clusterUuid, kibanaUuid }: { clusterUuid: string; kibanaUuid: string } ) { - checkParam(kbnIndexPattern, 'kbnIndexPattern in getKibanaInfo'); - + const moduleType = 'kibana'; + const indexPatterns = getNewIndexPatterns({ + config: Globals.app.config, + ccs: req.payload.ccs, + moduleType, + }); const params = { - index: kbnIndexPattern, + index: indexPatterns, size: 1, ignore_unavailable: true, filter_path: [ diff --git a/x-pack/plugins/monitoring/server/lib/kibana/get_kibanas.ts b/x-pack/plugins/monitoring/server/lib/kibana/get_kibanas.ts index 6e55bf83bbd02c..a476baa9c45d2b 100644 --- a/x-pack/plugins/monitoring/server/lib/kibana/get_kibanas.ts +++ b/x-pack/plugins/monitoring/server/lib/kibana/get_kibanas.ts @@ -15,6 +15,8 @@ import { calculateAvailability } from '../calculate_availability'; // @ts-ignore import { KibanaMetric } from '../metrics'; import { LegacyRequest } from '../../types'; +import { getNewIndexPatterns } from '../cluster/get_index_patterns'; +import { Globals } from '../../static_globals'; import { ElasticsearchResponse, ElasticsearchResponseHit } from '../../../common/types/es'; import { KibanaInfo, buildKibanaInfo } from './build_kibana_info'; @@ -52,24 +54,28 @@ interface Kibana { * - requests * - response times */ -export async function getKibanas( - req: LegacyRequest, - kbnIndexPattern: string, - { clusterUuid }: { clusterUuid: string } -) { - checkParam(kbnIndexPattern, 'kbnIndexPattern in getKibanas'); - +export async function getKibanas(req: LegacyRequest, { clusterUuid }: { clusterUuid: string }) { const config = req.server.config(); const start = moment.utc(req.payload.timeRange.min).valueOf(); const end = moment.utc(req.payload.timeRange.max).valueOf(); - + const moduleType = 'kibana'; + const type = 'kibana_stats'; + const dataset = 'stats'; + const indexPatterns = getNewIndexPatterns({ + config: Globals.app.config, + ccs: req.payload.ccs, + moduleType, + dataset, + }); const params = { - index: kbnIndexPattern, + index: indexPatterns, size: config.get('monitoring.ui.max_bucket_size'), ignore_unavailable: true, body: { query: createQuery({ - types: ['kibana_stats', 'stats'], + type, + dsDataset: `${moduleType}.${dataset}`, + metricset: dataset, start, end, clusterUuid, diff --git a/x-pack/plugins/monitoring/server/lib/kibana/get_kibanas_for_clusters.ts b/x-pack/plugins/monitoring/server/lib/kibana/get_kibanas_for_clusters.ts index 5326976ec99acf..883ca17c98c5bd 100644 --- a/x-pack/plugins/monitoring/server/lib/kibana/get_kibanas_for_clusters.ts +++ b/x-pack/plugins/monitoring/server/lib/kibana/get_kibanas_for_clusters.ts @@ -7,9 +7,10 @@ import { chain, find } from 'lodash'; import { LegacyRequest, Cluster, Bucket } from '../../types'; -import { checkParam } from '../error_missing_required'; import { createQuery } from '../create_query'; import { KibanaClusterMetric } from '../metrics'; +import { getNewIndexPatterns } from '../cluster/get_index_patterns'; +import { Globals } from '../../static_globals'; /* * Get high-level info for Kibanas in a set of clusters @@ -24,28 +25,34 @@ import { KibanaClusterMetric } from '../metrics'; * - number of instances * - combined health */ -export function getKibanasForClusters( - req: LegacyRequest, - kbnIndexPattern: string, - clusters: Cluster[] -) { - checkParam(kbnIndexPattern, 'kbnIndexPattern in kibana/getKibanasForClusters'); - +export function getKibanasForClusters(req: LegacyRequest, clusters: Cluster[], ccs: string) { const config = req.server.config(); const start = req.payload.timeRange.min; const end = req.payload.timeRange.max; + const moduleType = 'kibana'; + const type = 'kibana_stats'; + const dataset = 'stats'; + const indexPatterns = getNewIndexPatterns({ + config: Globals.app.config, + moduleType, + dataset, + ccs, + }); + return Promise.all( clusters.map((cluster) => { const clusterUuid = cluster.elasticsearch?.cluster?.id ?? cluster.cluster_uuid; const metric = KibanaClusterMetric.getMetricFields(); const params = { - index: kbnIndexPattern, + index: indexPatterns, size: 0, ignore_unavailable: true, body: { query: createQuery({ - types: ['stats', 'kibana_stats'], + type, + dsDataset: `${moduleType}.${dataset}`, + metricset: dataset, start, end, clusterUuid, diff --git a/x-pack/plugins/monitoring/server/lib/logs/init_infra_source.ts b/x-pack/plugins/monitoring/server/lib/logs/init_infra_source.ts index 727e47b62bc922..72a794db76183a 100644 --- a/x-pack/plugins/monitoring/server/lib/logs/init_infra_source.ts +++ b/x-pack/plugins/monitoring/server/lib/logs/init_infra_source.ts @@ -13,7 +13,7 @@ import { InfraPluginSetup } from '../../../../infra/server'; export const initInfraSource = (config: MonitoringConfig, infraPlugin: InfraPluginSetup) => { if (infraPlugin) { - const filebeatIndexPattern = prefixIndexPattern(config, config.ui.logs.index, '*', true); + const filebeatIndexPattern = prefixIndexPattern(config, config.ui.logs.index, '*'); infraPlugin.defineInternalSourceConfiguration(INFRA_SOURCE_ID, { name: 'Elastic Stack Logs', logIndices: { diff --git a/x-pack/plugins/monitoring/server/lib/logstash/get_cluster_status.ts b/x-pack/plugins/monitoring/server/lib/logstash/get_cluster_status.ts index dfd1eaa1550691..308a750f6ef020 100644 --- a/x-pack/plugins/monitoring/server/lib/logstash/get_cluster_status.ts +++ b/x-pack/plugins/monitoring/server/lib/logstash/get_cluster_status.ts @@ -6,7 +6,6 @@ */ import { get } from 'lodash'; -import { checkParam } from '../error_missing_required'; import { getLogstashForClusters } from './get_logstash_for_clusters'; import { LegacyRequest } from '../../types'; @@ -16,18 +15,12 @@ import { LegacyRequest } from '../../types'; * Shared functionality between the different routes. * * @param {Object} req The incoming request. - * @param {String} lsIndexPattern The Logstash pattern to query for the current time range. * @param {String} clusterUuid The cluster UUID for the associated Elasticsearch cluster. * @returns {Promise} The cluster status object. */ -export function getClusterStatus( - req: LegacyRequest, - lsIndexPattern: string, - { clusterUuid }: { clusterUuid: string } -) { - checkParam(lsIndexPattern, 'lsIndexPattern in logstash/getClusterStatus'); +export function getClusterStatus(req: LegacyRequest, { clusterUuid }: { clusterUuid: string }) { const clusters = [{ cluster_uuid: clusterUuid }]; - return getLogstashForClusters(req, lsIndexPattern, clusters).then((clusterStatus) => + return getLogstashForClusters(req, clusters).then((clusterStatus) => get(clusterStatus, '[0].stats') ); } diff --git a/x-pack/plugins/monitoring/server/lib/logstash/get_logstash_for_clusters.ts b/x-pack/plugins/monitoring/server/lib/logstash/get_logstash_for_clusters.ts index 20e611a5ee3dad..a0be8efe5ebdf7 100644 --- a/x-pack/plugins/monitoring/server/lib/logstash/get_logstash_for_clusters.ts +++ b/x-pack/plugins/monitoring/server/lib/logstash/get_logstash_for_clusters.ts @@ -8,9 +8,10 @@ import { get } from 'lodash'; import { LegacyRequest, Cluster, Bucket } from '../../types'; import { LOGSTASH } from '../../../common/constants'; -import { checkParam } from '../error_missing_required'; import { createQuery } from '../create_query'; import { LogstashClusterMetric } from '../metrics'; +import { getNewIndexPatterns } from '../cluster/get_index_patterns'; +import { Globals } from '../../static_globals'; const { MEMORY, PERSISTED } = LOGSTASH.QUEUE_TYPES; @@ -38,25 +39,35 @@ const getQueueTypes = (queueBuckets: Array + clusters: Array<{ cluster_uuid: string } | Cluster>, + ccs?: string ) { - checkParam(lsIndexPattern, 'lsIndexPattern in logstash/getLogstashForClusters'); - const start = req.payload.timeRange.min; const end = req.payload.timeRange.max; const config = req.server.config(); + const dataset = 'node_stats'; + const type = 'logstash_stats'; + const moduleType = 'logstash'; + const indexPatterns = getNewIndexPatterns({ + config: Globals.app.config, + ccs: ccs || req.payload.ccs, + moduleType, + dataset, + }); + return Promise.all( clusters.map((cluster) => { const clusterUuid = get(cluster, 'elasticsearch.cluster.id', cluster.cluster_uuid); const params = { - index: lsIndexPattern, + index: indexPatterns, size: 0, ignore_unavailable: true, body: { query: createQuery({ - types: ['node_stats', 'logstash_stats'], + type, + dsDataset: `${moduleType}.${dataset}`, + metricset: dataset, start, end, clusterUuid, diff --git a/x-pack/plugins/monitoring/server/lib/logstash/get_node_info.test.ts b/x-pack/plugins/monitoring/server/lib/logstash/get_node_info.test.ts index cee6c144c866ea..a43eb9a7cd09fe 100644 --- a/x-pack/plugins/monitoring/server/lib/logstash/get_node_info.test.ts +++ b/x-pack/plugins/monitoring/server/lib/logstash/get_node_info.test.ts @@ -18,6 +18,18 @@ interface HitParams { value?: string; } +jest.mock('../../static_globals', () => ({ + Globals: { + app: { + config: { + ui: { + ccs: { enabled: true }, + }, + }, + }, + }, +})); + // deletes, adds, or updates the properties based on a default object function createResponseObjHit(params?: HitParams[]): ElasticsearchResponseHit { const defaultResponseObj: ElasticsearchResponseHit = { @@ -189,7 +201,11 @@ describe('get_logstash_info', () => { then: jest.fn(), }); const req = { + payload: {}, server: { + config: () => ({ + get: () => undefined, + }), plugins: { elasticsearch: { getCluster: () => ({ @@ -199,7 +215,8 @@ describe('get_logstash_info', () => { }, }, } as unknown as LegacyRequest; - await getNodeInfo(req, '.monitoring-logstash-*', { + + await getNodeInfo(req, { clusterUuid: STANDALONE_CLUSTER_CLUSTER_UUID, logstashUuid: 'logstash_uuid', }); diff --git a/x-pack/plugins/monitoring/server/lib/logstash/get_node_info.ts b/x-pack/plugins/monitoring/server/lib/logstash/get_node_info.ts index ebd1128dce3646..92e2a836e08ff8 100644 --- a/x-pack/plugins/monitoring/server/lib/logstash/get_node_info.ts +++ b/x-pack/plugins/monitoring/server/lib/logstash/get_node_info.ts @@ -6,12 +6,14 @@ */ import { merge } from 'lodash'; -import { checkParam, MissingRequiredError } from '../error_missing_required'; +import { MissingRequiredError } from '../error_missing_required'; import { calculateAvailability } from '../calculate_availability'; import { LegacyRequest } from '../../types'; import { ElasticsearchResponse } from '../../../common/types/es'; import { STANDALONE_CLUSTER_CLUSTER_UUID } from '../../../common/constants'; import { standaloneClusterFilter } from '../standalone_clusters/standalone_cluster_query_filter'; +import { getNewIndexPatterns } from '../cluster/get_index_patterns'; +import { Globals } from '../../static_globals'; export function handleResponse(resp: ElasticsearchResponse) { const legacyStats = resp.hits?.hits[0]?._source?.logstash_stats; @@ -33,18 +35,25 @@ export function handleResponse(resp: ElasticsearchResponse) { export function getNodeInfo( req: LegacyRequest, - lsIndexPattern: string, { clusterUuid, logstashUuid }: { clusterUuid: string; logstashUuid: string } ) { - checkParam(lsIndexPattern, 'lsIndexPattern in getNodeInfo'); const isStandaloneCluster = clusterUuid === STANDALONE_CLUSTER_CLUSTER_UUID; const clusterFilter = isStandaloneCluster ? standaloneClusterFilter : { term: { cluster_uuid: clusterUuid } }; + const dataset = 'node_stats'; + const moduleType = 'logstash'; + const indexPatterns = getNewIndexPatterns({ + config: Globals.app.config, + ccs: req.payload.ccs, + moduleType, + dataset, + }); + const params = { - index: lsIndexPattern, + index: indexPatterns, size: 1, ignore_unavailable: true, filter_path: [ diff --git a/x-pack/plugins/monitoring/server/lib/logstash/get_nodes.ts b/x-pack/plugins/monitoring/server/lib/logstash/get_nodes.ts index a25b57ab445e32..d7c490b1d2fd6d 100644 --- a/x-pack/plugins/monitoring/server/lib/logstash/get_nodes.ts +++ b/x-pack/plugins/monitoring/server/lib/logstash/get_nodes.ts @@ -6,12 +6,13 @@ */ import moment from 'moment'; -import { checkParam } from '../error_missing_required'; import { createQuery } from '../create_query'; import { calculateAvailability } from '../calculate_availability'; import { LogstashMetric } from '../metrics'; import { LegacyRequest } from '../../types'; import { ElasticsearchResponse } from '../../../common/types/es'; +import { getNewIndexPatterns } from '../cluster/get_index_patterns'; +import { Globals } from '../../static_globals'; interface Logstash { jvm?: { @@ -64,28 +65,35 @@ interface Logstash { * - events * - config reloads */ -export async function getNodes( - req: LegacyRequest, - lsIndexPattern: string, - { clusterUuid }: { clusterUuid: string } -) { - checkParam(lsIndexPattern, 'lsIndexPattern in getNodes'); +export async function getNodes(req: LegacyRequest, { clusterUuid }: { clusterUuid: string }) { + const dataset = 'node_stats'; + const type = 'logstash_stats'; + const moduleType = 'logstash'; + + const indexPatterns = getNewIndexPatterns({ + config: Globals.app.config, + ccs: req.payload.ccs, + moduleType, + dataset, + }); const config = req.server.config(); const start = moment.utc(req.payload.timeRange.min).valueOf(); const end = moment.utc(req.payload.timeRange.max).valueOf(); const params = { - index: lsIndexPattern, + index: indexPatterns, size: config.get('monitoring.ui.max_bucket_size'), // FIXME ignore_unavailable: true, body: { query: createQuery({ + type, + dsDataset: `${moduleType}.${dataset}`, + metricset: dataset, start, end, clusterUuid, metric: LogstashMetric.getMetricFields(), - types: ['node_stats', 'logstash_stats'], }), collapse: { field: 'logstash_stats.logstash.uuid', diff --git a/x-pack/plugins/monitoring/server/lib/logstash/get_paginated_pipelines.ts b/x-pack/plugins/monitoring/server/lib/logstash/get_paginated_pipelines.ts index f8f993874a1814..42c6a684234c45 100644 --- a/x-pack/plugins/monitoring/server/lib/logstash/get_paginated_pipelines.ts +++ b/x-pack/plugins/monitoring/server/lib/logstash/get_paginated_pipelines.ts @@ -42,7 +42,6 @@ import { interface GetPaginatedPipelinesParams { req: LegacyRequest; - lsIndexPattern: string; clusterUuid: string; logstashUuid?: string; metrics: { @@ -55,7 +54,6 @@ interface GetPaginatedPipelinesParams { } export async function getPaginatedPipelines({ req, - lsIndexPattern, clusterUuid, logstashUuid, metrics, @@ -70,16 +68,15 @@ export async function getPaginatedPipelines({ const size = config.get('monitoring.ui.max_bucket_size') as unknown as number; let pipelines = await getLogstashPipelineIds({ req, - lsIndexPattern, clusterUuid, logstashUuid, size, }); // this is needed for sorting if (sortField === throughputMetric) { - pipelines = await getPaginatedThroughputData(pipelines, req, lsIndexPattern, throughputMetric); + pipelines = await getPaginatedThroughputData(pipelines, req, throughputMetric); } else if (sortField === nodesCountMetric) { - pipelines = await getPaginatedNodesData(pipelines, req, lsIndexPattern, nodesCountMetric); + pipelines = await getPaginatedNodesData(pipelines, req, nodesCountMetric); } const filteredPipelines = filter(pipelines, queryText, ['id']); // We only support filtering by id right now @@ -91,7 +88,6 @@ export async function getPaginatedPipelines({ const response = { pipelines: await getPipelines({ req, - lsIndexPattern, pipelines: pageOfPipelines, throughputMetric, nodesCountMetric, @@ -131,9 +127,10 @@ function processPipelinesAPIResponse( async function getPaginatedThroughputData( pipelines: Pipeline[], req: LegacyRequest, - lsIndexPattern: string, throughputMetric: PipelineThroughputMetricKey ): Promise { + const dataset = 'node_stats'; + const moduleType = 'logstash'; const metricSeriesData: any = Object.values( await Promise.all( pipelines.map((pipeline) => { @@ -141,22 +138,19 @@ async function getPaginatedThroughputData( try { const data = await getMetrics( req, - lsIndexPattern, + moduleType, [throughputMetric], [ { bool: { should: [ + { term: { 'data_stream.dataset': `${moduleType}.${dataset}` } }, + { term: { 'metricset.name': dataset } }, { term: { type: 'logstash_stats', }, }, - { - term: { - 'metricset.name': 'node_stats', - }, - }, ], }, }, @@ -197,20 +191,22 @@ async function getPaginatedThroughputData( async function getPaginatedNodesData( pipelines: Pipeline[], req: LegacyRequest, - lsIndexPattern: string, nodesCountMetric: PipelineNodeCountMetricKey ): Promise { + const dataset = 'node_stats'; + const moduleType = 'logstash'; const pipelineWithMetrics = cloneDeep(pipelines); const metricSeriesData = await getMetrics( req, - lsIndexPattern, + moduleType, [nodesCountMetric], [ { bool: { should: [ + { term: { 'data_stream.dataset': `${moduleType}.${dataset}` } }, + { term: { 'metricset.name': dataset } }, { term: { type: 'logstash_stats' } }, - { term: { 'metricset.name': 'node_stats' } }, ], }, }, @@ -231,29 +227,17 @@ async function getPaginatedNodesData( async function getPipelines({ req, - lsIndexPattern, pipelines, throughputMetric, nodesCountMetric, }: { req: LegacyRequest; - lsIndexPattern: string; pipelines: Pipeline[]; throughputMetric: PipelineThroughputMetricKey; nodesCountMetric: PipelineNodeCountMetricKey; }): Promise { - const throughputPipelines = await getThroughputPipelines( - req, - lsIndexPattern, - pipelines, - throughputMetric - ); - const nodeCountPipelines = await getNodePipelines( - req, - lsIndexPattern, - pipelines, - nodesCountMetric - ); + const throughputPipelines = await getThroughputPipelines(req, pipelines, throughputMetric); + const nodeCountPipelines = await getNodePipelines(req, pipelines, nodesCountMetric); const finalPipelines = pipelines.map(({ id }) => { const matchThroughputPipeline = throughputPipelines.find((p) => p.id === id); const matchNodesCountPipeline = nodeCountPipelines.find((p) => p.id === id); @@ -276,32 +260,30 @@ async function getPipelines({ async function getThroughputPipelines( req: LegacyRequest, - lsIndexPattern: string, pipelines: Pipeline[], throughputMetric: string ): Promise { + const dataset = 'node_stats'; + const moduleType = 'logstash'; const metricsResponse = await Promise.all( pipelines.map((pipeline) => { return new Promise(async (resolve, reject) => { try { const data = await getMetrics( req, - lsIndexPattern, + moduleType, [throughputMetric], [ { bool: { should: [ + { term: { 'data_stream.dataset': `${moduleType}.${dataset}` } }, + { term: { 'metricset.name': dataset } }, { term: { type: 'logstash_stats', }, }, - { - term: { - 'metricset.name': 'node_stats', - }, - }, ], }, }, @@ -322,20 +304,22 @@ async function getThroughputPipelines( async function getNodePipelines( req: LegacyRequest, - lsIndexPattern: string, pipelines: Pipeline[], nodesCountMetric: string ): Promise { + const moduleType = 'logstash'; + const dataset = 'node_stats'; const metricData = await getMetrics( req, - lsIndexPattern, + moduleType, [nodesCountMetric], [ { bool: { should: [ + { term: { 'data_stream.dataset': `${moduleType}.${dataset}` } }, + { term: { 'metricset.name': dataset } }, { term: { type: 'logstash_stats' } }, - { term: { 'metricset.name': 'node_stats' } }, ], }, }, diff --git a/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline.ts b/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline.ts index 1e8eb94df4836b..16a96b132483f7 100644 --- a/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline.ts +++ b/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline.ts @@ -7,7 +7,6 @@ import boom from '@hapi/boom'; import { get } from 'lodash'; -import { checkParam } from '../error_missing_required'; import { getPipelineStateDocument } from './get_pipeline_state_document'; import { getPipelineStatsAggregation } from './get_pipeline_stats_aggregation'; import { calculateTimeseriesInterval } from '../calculate_timeseries_interval'; @@ -122,13 +121,10 @@ export function _enrichStateWithStatsAggregation( export async function getPipeline( req: LegacyRequest, config: { get: (key: string) => string | undefined }, - lsIndexPattern: string, clusterUuid: string, pipelineId: string, version: PipelineVersion ) { - checkParam(lsIndexPattern, 'lsIndexPattern in getPipeline'); - // Determine metrics' timeseries interval based on version's timespan const minIntervalSeconds = Math.max(Number(config.get('monitoring.ui.min_interval_seconds')), 30); const timeseriesInterval = calculateTimeseriesInterval( @@ -140,14 +136,12 @@ export async function getPipeline( const [stateDocument, statsAggregation] = await Promise.all([ getPipelineStateDocument({ req, - logstashIndexPattern: lsIndexPattern, clusterUuid, pipelineId, version, }), getPipelineStatsAggregation({ req, - logstashIndexPattern: lsIndexPattern, timeseriesInterval, clusterUuid, pipelineId, diff --git a/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_ids.ts b/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_ids.ts index c9b7a3adfc18e7..7654ed551b63b4 100644 --- a/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_ids.ts +++ b/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_ids.ts @@ -10,20 +10,22 @@ import { get } from 'lodash'; import { LegacyRequest, Bucket, Pipeline } from '../../types'; import { createQuery } from '../create_query'; import { LogstashMetric } from '../metrics'; +import { getNewIndexPatterns } from '../cluster/get_index_patterns'; +import { Globals } from '../../static_globals'; interface GetLogstashPipelineIdsParams { req: LegacyRequest; - lsIndexPattern: string; clusterUuid: string; size: number; logstashUuid?: string; + ccs?: string; } export async function getLogstashPipelineIds({ req, - lsIndexPattern, clusterUuid, logstashUuid, size, + ccs, }: GetLogstashPipelineIdsParams): Promise { const start = moment.utc(req.payload.timeRange.min).valueOf(); const end = moment.utc(req.payload.timeRange.max).valueOf(); @@ -33,8 +35,17 @@ export async function getLogstashPipelineIds({ filters.push({ term: { 'logstash_stats.logstash.uuid': logstashUuid } }); } + const dataset = 'node_stats'; + const moduleType = 'logstash'; + const indexPatterns = getNewIndexPatterns({ + config: Globals.app.config, + ccs: ccs || req.payload.ccs, + moduleType, + dataset, + }); + const params = { - index: lsIndexPattern, + index: indexPatterns, size: 0, ignore_unavailable: true, filter_path: ['aggregations.nest.id.buckets', 'aggregations.nest_mb.id.buckets'], diff --git a/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_state_document.ts b/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_state_document.ts index f62d4de1219ecf..6c2504efe29ff3 100644 --- a/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_state_document.ts +++ b/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_state_document.ts @@ -9,20 +9,29 @@ import { createQuery } from '../create_query'; import { LogstashMetric } from '../metrics'; import { LegacyRequest, PipelineVersion } from '../../types'; import { ElasticsearchResponse } from '../../../common/types/es'; +import { getNewIndexPatterns } from '../cluster/get_index_patterns'; +import { Globals } from '../../static_globals'; export async function getPipelineStateDocument({ req, - logstashIndexPattern, clusterUuid, pipelineId, version, }: { req: LegacyRequest; - logstashIndexPattern: string; clusterUuid: string; pipelineId: string; version: PipelineVersion; }) { + const dataset = 'node'; + const type = 'logstash_state'; + const moduleType = 'logstash'; + const indexPatterns = getNewIndexPatterns({ + config: Globals.app.config, + ccs: req.payload.ccs, + moduleType, + dataset, + }); const { callWithRequest } = req.server.plugins?.elasticsearch.getCluster('monitoring'); const filters = [ { term: { 'logstash_state.pipeline.id': pipelineId } }, @@ -35,14 +44,16 @@ export async function getPipelineStateDocument({ // This is important because a user may pick a very narrow time picker window. If we were to use a start/end value // that could result in us being unable to render the graph // Use the logstash_stats documents to determine whether the instance is up/down - types: ['logstash_state', 'node'], + type, + dsDataset: `${moduleType}.${dataset}`, + metricset: dataset, metric: LogstashMetric.getMetricFields(), clusterUuid, filters, }); const params = { - index: logstashIndexPattern, + index: indexPatterns, size: 1, ignore_unavailable: true, body: { diff --git a/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_stats_aggregation.ts b/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_stats_aggregation.ts index 70f856b25f8c85..31cfa4b4a02911 100644 --- a/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_stats_aggregation.ts +++ b/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_stats_aggregation.ts @@ -6,8 +6,10 @@ */ import { LegacyRequest, PipelineVersion } from '../../types'; +import { getNewIndexPatterns } from '../cluster/get_index_patterns'; import { createQuery } from '../create_query'; import { LogstashMetric } from '../metrics'; +import { Globals } from '../../static_globals'; function scalarCounterAggregation( field: string, @@ -111,16 +113,23 @@ function createScopedAgg(pipelineId: string, pipelineHash: string, maxBucketSize function fetchPipelineLatestStats( query: object, - logstashIndexPattern: string, pipelineId: string, version: PipelineVersion, maxBucketSize: string, callWithRequest: any, req: LegacyRequest ) { + const dataset = 'node_stats'; + const moduleType = 'logstash'; + const indexPatterns = getNewIndexPatterns({ + config: Globals.app.config, + ccs: req.payload.ccs, + moduleType, + dataset, + }); const pipelineAggregation = createScopedAgg(pipelineId, version.hash, maxBucketSize); const params = { - index: logstashIndexPattern, + index: indexPatterns, size: 0, ignore_unavailable: true, filter_path: [ @@ -149,14 +158,12 @@ function fetchPipelineLatestStats( export function getPipelineStatsAggregation({ req, - logstashIndexPattern, timeseriesInterval, clusterUuid, pipelineId, version, }: { req: LegacyRequest; - logstashIndexPattern: string; timeseriesInterval: number; clusterUuid: string; pipelineId: string; @@ -197,8 +204,14 @@ export function getPipelineStatsAggregation({ const start = version.lastSeen - timeseriesInterval * 1000; const end = version.lastSeen; + const dataset = 'node_stats'; + const type = 'logstash_stats'; + const moduleType = 'logstash'; + const query = createQuery({ - types: ['node_stats', 'logstash_stats'], + type, + dsDataset: `${moduleType}.${dataset}`, + metricset: dataset, start, end, metric: LogstashMetric.getMetricFields(), @@ -210,7 +223,6 @@ export function getPipelineStatsAggregation({ return fetchPipelineLatestStats( query, - logstashIndexPattern, pipelineId, version, // @ts-ignore not undefined, need to get correct config diff --git a/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_versions.ts b/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_versions.ts index 0dbbf26b331e2f..eecc4388f89470 100644 --- a/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_versions.ts +++ b/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_versions.ts @@ -8,7 +8,8 @@ import { get, orderBy } from 'lodash'; import { createQuery } from '../create_query'; import { LogstashMetric } from '../metrics'; -import { checkParam } from '../error_missing_required'; +import { getNewIndexPatterns } from '../cluster/get_index_patterns'; +import { Globals } from '../../static_globals'; import { LegacyRequest, PipelineVersion } from '../../types'; import { mergePipelineVersions } from './merge_pipeline_versions'; @@ -61,17 +62,23 @@ const createScopedAgg = (pipelineId: string, maxBucketSize: number) => { function fetchPipelineVersions({ req, - lsIndexPattern, clusterUuid, pipelineId, }: { req: LegacyRequest; - lsIndexPattern: string; clusterUuid: string; pipelineId: string; }) { + const dataset = 'node_stats'; + const type = 'logstash_stats'; + const moduleType = 'logstash'; + const indexPatterns = getNewIndexPatterns({ + config: Globals.app.config, + ccs: req.payload.ccs, + moduleType, + dataset, + }); const config = req.server.config(); - checkParam(lsIndexPattern, 'logstashIndexPattern in getPipelineVersions'); const { callWithRequest } = req.server.plugins.elasticsearch.getCluster('monitoring'); const filters = [ @@ -105,7 +112,9 @@ function fetchPipelineVersions({ }, ]; const query = createQuery({ - types: ['node_stats', 'logstash_stats'], + type, + dsDataset: `${moduleType}.${dataset}`, + metricset: dataset, metric: LogstashMetric.getMetricFields(), clusterUuid, filters, @@ -121,7 +130,7 @@ function fetchPipelineVersions({ }; const params = { - index: lsIndexPattern, + index: indexPatterns, size: 0, ignore_unavailable: true, body: { @@ -159,7 +168,6 @@ export function _handleResponse(response: any) { export async function getPipelineVersions(args: { req: LegacyRequest; - lsIndexPattern: string; clusterUuid: string; pipelineId: string; }) { diff --git a/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_vertex.ts b/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_vertex.ts index 75b82787ef3d0d..5605b23b8988bd 100644 --- a/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_vertex.ts +++ b/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_vertex.ts @@ -7,7 +7,6 @@ import boom from '@hapi/boom'; import { get } from 'lodash'; -import { checkParam } from '../error_missing_required'; import { getPipelineStateDocument } from './get_pipeline_state_document'; import { getPipelineVertexStatsAggregation } from './get_pipeline_vertex_stats_aggregation'; import { calculateTimeseriesInterval } from '../calculate_timeseries_interval'; @@ -137,14 +136,11 @@ export function _enrichVertexStateWithStatsAggregation( export async function getPipelineVertex( req: LegacyRequest, config: { get: (key: string) => string | undefined }, - lsIndexPattern: string, clusterUuid: string, pipelineId: string, version: PipelineVersion, vertexId: string ) { - checkParam(lsIndexPattern, 'lsIndexPattern in getPipeline'); - // Determine metrics' timeseries interval based on version's timespan const minIntervalSeconds = Math.max(Number(config.get('monitoring.ui.min_interval_seconds')), 30); const timeseriesInterval = calculateTimeseriesInterval( @@ -156,14 +152,12 @@ export async function getPipelineVertex( const [stateDocument, statsAggregation] = await Promise.all([ getPipelineStateDocument({ req, - logstashIndexPattern: lsIndexPattern, clusterUuid, pipelineId, version, }), getPipelineVertexStatsAggregation({ req, - logstashIndexPattern: lsIndexPattern, timeSeriesIntervalInSeconds: timeseriesInterval, clusterUuid, pipelineId, diff --git a/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_vertex_stats_aggregation.ts b/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_vertex_stats_aggregation.ts index bfd803f0a86d58..8b26f5d44855b0 100644 --- a/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_vertex_stats_aggregation.ts +++ b/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_vertex_stats_aggregation.ts @@ -6,8 +6,10 @@ */ import { LegacyRequest, PipelineVersion } from '../../types'; +import { getNewIndexPatterns } from '../cluster/get_index_patterns'; import { createQuery } from '../create_query'; import { LogstashMetric } from '../metrics'; +import { Globals } from '../../static_globals'; function scalarCounterAggregation( field: string, @@ -147,7 +149,6 @@ function createTimeSeriesAgg(timeSeriesIntervalInSeconds: number, ...aggsList: o function fetchPipelineVertexTimeSeriesStats({ query, - logstashIndexPattern, pipelineId, version, vertexId, @@ -157,7 +158,6 @@ function fetchPipelineVertexTimeSeriesStats({ req, }: { query: object; - logstashIndexPattern: string; pipelineId: string; version: PipelineVersion; vertexId: string; @@ -174,8 +174,14 @@ function fetchPipelineVertexTimeSeriesStats({ }), }; + const indexPatterns = getNewIndexPatterns({ + config: Globals.app.config, + ccs: req.payload.ccs, + moduleType: 'logstash', + }); + const params = { - index: logstashIndexPattern, + index: indexPatterns, size: 0, ignore_unavailable: true, filter_path: [ @@ -202,7 +208,6 @@ function fetchPipelineVertexTimeSeriesStats({ export function getPipelineVertexStatsAggregation({ req, - logstashIndexPattern, timeSeriesIntervalInSeconds, clusterUuid, pipelineId, @@ -210,7 +215,6 @@ export function getPipelineVertexStatsAggregation({ vertexId, }: { req: LegacyRequest; - logstashIndexPattern: string; timeSeriesIntervalInSeconds: number; clusterUuid: string; pipelineId: string; @@ -252,8 +256,14 @@ export function getPipelineVertexStatsAggregation({ const start = version.firstSeen; const end = version.lastSeen; + const moduleType = 'logstash'; + const dataset = 'node_stats'; + const type = 'logstash_stats'; + const query = createQuery({ - types: ['node_stats', 'logstash_stats'], + type, + dsDataset: `${moduleType}.${dataset}`, + metricset: dataset, start, end, metric: LogstashMetric.getMetricFields(), @@ -265,7 +275,6 @@ export function getPipelineVertexStatsAggregation({ return fetchPipelineVertexTimeSeriesStats({ query, - logstashIndexPattern, pipelineId, version, vertexId, diff --git a/x-pack/plugins/monitoring/server/lib/setup/collection/get_collection_status.test.js b/x-pack/plugins/monitoring/server/lib/setup/collection/get_collection_status.test.js index 1029f00455c690..bbcedf7fdd33d2 100644 --- a/x-pack/plugins/monitoring/server/lib/setup/collection/get_collection_status.test.js +++ b/x-pack/plugins/monitoring/server/lib/setup/collection/get_collection_status.test.js @@ -34,9 +34,6 @@ const mockReq = ( if (prop === 'server.uuid') { return 'kibana-1234'; } - if (prop === 'monitoring.ui.metricbeat.index') { - return 'metricbeat-*'; - } }), }; }, diff --git a/x-pack/plugins/monitoring/server/lib/setup/collection/get_collection_status.ts b/x-pack/plugins/monitoring/server/lib/setup/collection/get_collection_status.ts index eda9315842040b..463ccf547d5dbc 100644 --- a/x-pack/plugins/monitoring/server/lib/setup/collection/get_collection_status.ts +++ b/x-pack/plugins/monitoring/server/lib/setup/collection/get_collection_status.ts @@ -291,16 +291,6 @@ function getUuidBucketName(productName: string) { } } -function matchesMetricbeatIndex(metricbeatIndex: string, index: string) { - if (index.includes(metricbeatIndex)) { - return true; - } - if (metricbeatIndex.includes('*')) { - return new RegExp(metricbeatIndex).test(index); - } - return false; -} - function isBeatFromAPM(bucket: Bucket) { const beatType = get(bucket, 'single_type.beat_type'); if (!beatType) { @@ -443,7 +433,6 @@ export const getCollectionStatus = async ( ) => { const config = req.server.config(); const kibanaUuid = config.get('server.uuid'); - const metricbeatIndex = config.get('monitoring.ui.metricbeat.index')!; const size = config.get('monitoring.ui.max_bucket_size'); const hasPermissions = await hasNecessaryPermissions(req); @@ -484,11 +473,6 @@ export const getCollectionStatus = async ( if (bucket.key.includes(token)) { return true; } - if (matchesMetricbeatIndex(metricbeatIndex, bucket.key)) { - if (get(bucket, `${uuidBucketName}.buckets`, []).length) { - return true; - } - } return false; }); @@ -512,9 +496,7 @@ export const getCollectionStatus = async ( // If there is a single bucket, then they are fully migrated or fully on the internal collector else if (indexBuckets.length === 1) { const singleIndexBucket = indexBuckets[0]; - const isFullyMigrated = - singleIndexBucket.key.includes(METRICBEAT_INDEX_NAME_UNIQUE_TOKEN) || - matchesMetricbeatIndex(metricbeatIndex, singleIndexBucket.key); + const isFullyMigrated = singleIndexBucket.key.includes(METRICBEAT_INDEX_NAME_UNIQUE_TOKEN); const map = isFullyMigrated ? fullyMigratedUuidsMap : internalCollectorsUuidsMap; const uuidBuckets = get(singleIndexBucket, `${uuidBucketName}.buckets`, []); @@ -594,8 +576,7 @@ export const getCollectionStatus = async ( for (const indexBucket of indexBuckets) { const isFullyMigrated = considerAllInstancesMigrated || - indexBucket.key.includes(METRICBEAT_INDEX_NAME_UNIQUE_TOKEN) || - matchesMetricbeatIndex(metricbeatIndex, indexBucket.key); + indexBucket.key.includes(METRICBEAT_INDEX_NAME_UNIQUE_TOKEN); const map = isFullyMigrated ? fullyMigratedUuidsMap : internalCollectorsUuidsMap; const otherMap = !isFullyMigrated ? fullyMigratedUuidsMap : internalCollectorsUuidsMap; diff --git a/x-pack/plugins/monitoring/server/lib/standalone_clusters/has_standalone_clusters.ts b/x-pack/plugins/monitoring/server/lib/standalone_clusters/has_standalone_clusters.ts index 4aacc6d14d0f99..1859c66e9e7132 100644 --- a/x-pack/plugins/monitoring/server/lib/standalone_clusters/has_standalone_clusters.ts +++ b/x-pack/plugins/monitoring/server/lib/standalone_clusters/has_standalone_clusters.ts @@ -9,8 +9,22 @@ import moment from 'moment'; import { get } from 'lodash'; import { LegacyRequest } from '../../types'; import { standaloneClusterFilter } from './'; +import { Globals } from '../../static_globals'; +import { getLegacyIndexPattern, getNewIndexPatterns } from '../cluster/get_index_patterns'; -export async function hasStandaloneClusters(req: LegacyRequest, indexPatterns: string[]) { +export async function hasStandaloneClusters(req: LegacyRequest, ccs: string) { + const lsIndexPatterns = getNewIndexPatterns({ + config: Globals.app.config, + moduleType: 'logstash', + ccs, + }); + // use legacy because no integration exists for beats + const beatsIndexPatterns = getLegacyIndexPattern({ + moduleType: 'beats', + config: Globals.app.config, + ccs, + }); + const indexPatterns = [lsIndexPatterns, beatsIndexPatterns]; const indexPatternList = indexPatterns.reduce((list, patterns) => { list.push(...patterns.split(',')); return list; @@ -28,7 +42,12 @@ export async function hasStandaloneClusters(req: LegacyRequest, indexPatterns: s }, { terms: { - 'event.dataset': ['logstash.node.stats', 'logstash.node', 'beat.stats', 'beat.state'], + 'metricset.name': ['node', 'node_stats', 'stats', 'state'], + }, + }, + { + terms: { + 'data_stream.dataset': ['node', 'node_stats', 'stats', 'state'], }, }, ], diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/apm/_get_apm_cluster_status.js b/x-pack/plugins/monitoring/server/routes/api/v1/apm/_get_apm_cluster_status.js index a28312de78af0b..bd0198ffcc3b24 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/apm/_get_apm_cluster_status.js +++ b/x-pack/plugins/monitoring/server/routes/api/v1/apm/_get_apm_cluster_status.js @@ -7,9 +7,9 @@ import { getApmsForClusters } from '../../../../lib/apm/get_apms_for_clusters'; -export const getApmClusterStatus = (req, apmIndexPattern, { clusterUuid }) => { +export const getApmClusterStatus = (req, { clusterUuid }) => { const clusters = [{ cluster_uuid: clusterUuid }]; - return getApmsForClusters(req, apmIndexPattern, clusters).then((apms) => { + return getApmsForClusters(req, clusters).then((apms) => { const [{ stats, config }] = apms; return { ...stats, diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/apm/instance.js b/x-pack/plugins/monitoring/server/routes/api/v1/apm/instance.js index a0b00167101fe4..4fa0de7d399d99 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/apm/instance.js +++ b/x-pack/plugins/monitoring/server/routes/api/v1/apm/instance.js @@ -47,9 +47,7 @@ export function apmInstanceRoute(server) { try { const [metrics, apmSummary] = await Promise.all([ - getMetrics(req, apmIndexPattern, metricSet, [ - { term: { 'beats_stats.beat.uuid': apmUuid } }, - ]), + getMetrics(req, 'beats', metricSet, [{ term: { 'beats_stats.beat.uuid': apmUuid } }]), getApmInfo(req, apmIndexPattern, { clusterUuid, apmUuid }), ]); diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/apm/overview.js b/x-pack/plugins/monitoring/server/routes/api/v1/apm/overview.js index ea7f3f41b842e8..b773cfd7b0fb97 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/apm/overview.js +++ b/x-pack/plugins/monitoring/server/routes/api/v1/apm/overview.js @@ -6,12 +6,10 @@ */ import { schema } from '@kbn/config-schema'; -import { prefixIndexPattern } from '../../../../../common/ccs_utils'; import { getMetrics } from '../../../../lib/details/get_metrics'; import { metricSet } from './metric_set_overview'; import { handleError } from '../../../../lib/errors'; import { getApmClusterStatus } from './_get_apm_cluster_status'; -import { INDEX_PATTERN_BEATS } from '../../../../../common/constants'; export function apmOverviewRoute(server) { server.route({ @@ -33,9 +31,7 @@ export function apmOverviewRoute(server) { }, async handler(req) { const config = server.config(); - const ccs = req.payload.ccs; const clusterUuid = req.params.clusterUuid; - const apmIndexPattern = prefixIndexPattern(config, INDEX_PATTERN_BEATS, ccs); const showCgroupMetrics = config.get('monitoring.ui.container.apm.enabled'); if (showCgroupMetrics) { @@ -45,8 +41,8 @@ export function apmOverviewRoute(server) { try { const [stats, metrics] = await Promise.all([ - getApmClusterStatus(req, apmIndexPattern, { clusterUuid }), - getMetrics(req, apmIndexPattern, metricSet), + getApmClusterStatus(req, { clusterUuid }), + getMetrics(req, 'beats', metricSet), ]); return { diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/beats/beat_detail.js b/x-pack/plugins/monitoring/server/routes/api/v1/beats/beat_detail.js index 851380fede77dc..d9454b7ae62cf6 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/beats/beat_detail.js +++ b/x-pack/plugins/monitoring/server/routes/api/v1/beats/beat_detail.js @@ -49,9 +49,7 @@ export function beatsDetailRoute(server) { try { const [summary, metrics] = await Promise.all([ getBeatSummary(req, beatsIndexPattern, summaryOptions), - getMetrics(req, beatsIndexPattern, metricSet, [ - { term: { 'beats_stats.beat.uuid': beatUuid } }, - ]), + getMetrics(req, 'beats', metricSet, [{ term: { 'beats_stats.beat.uuid': beatUuid } }]), ]); return { diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/beats/overview.js b/x-pack/plugins/monitoring/server/routes/api/v1/beats/overview.js index 4abf46b3ad1cee..12349c8b855712 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/beats/overview.js +++ b/x-pack/plugins/monitoring/server/routes/api/v1/beats/overview.js @@ -41,7 +41,7 @@ export function beatsOverviewRoute(server) { const [latest, stats, metrics] = await Promise.all([ getLatestStats(req, beatsIndexPattern, clusterUuid), getStats(req, beatsIndexPattern, clusterUuid), - getMetrics(req, beatsIndexPattern, metricSet), + getMetrics(req, 'beats', metricSet), ]); return { diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/ccr_shard.ts b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/ccr_shard.ts index d07a6602224077..a1d76fe5ccd0d2 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/ccr_shard.ts +++ b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/ccr_shard.ts @@ -13,9 +13,10 @@ import { handleError } from '../../../../lib/errors/handle_error'; import { prefixIndexPattern } from '../../../../../common/ccs_utils'; // @ts-ignore import { getMetrics } from '../../../../lib/details/get_metrics'; -import { INDEX_PATTERN_ELASTICSEARCH } from '../../../../../common/constants'; import { ElasticsearchResponse } from '../../../../../common/types/es'; import { LegacyRequest } from '../../../../types'; +import { getNewIndexPatterns } from '../../../../lib/cluster/get_index_patterns'; +import { Globals } from '../../../../static_globals'; function getFormattedLeaderIndex(leaderIndex: string) { let leader = leaderIndex; @@ -98,27 +99,33 @@ export function ccrShardRoute(server: { route: (p: any) => void; config: () => { }, }, async handler(req: LegacyRequest) { - const config = server.config(); const index = req.params.index; const shardId = req.params.shardId; - const ccs = req.payload.ccs; - const esIndexPattern = prefixIndexPattern(config, INDEX_PATTERN_ELASTICSEARCH, ccs); + const moduleType = 'elasticsearch'; + const dataset = 'ccr'; + const esIndexPattern = getNewIndexPatterns({ + config: Globals.app.config, + ccs: req.payload.ccs, + moduleType, + dataset, + }); const filters = [ { bool: { should: [ + { term: { 'data_stream.dataset': { value: `${moduleType}.${dataset}` } } }, { term: { - type: { - value: 'ccr_stats', + 'metricset.name': { + value: dataset, }, }, }, { term: { - 'metricset.name': { - value: 'ccr', + type: { + value: 'ccr_stats', }, }, }, @@ -145,7 +152,7 @@ export function ccrShardRoute(server: { route: (p: any) => void; config: () => { const [metrics, ccrResponse]: [unknown, ElasticsearchResponse] = await Promise.all([ getMetrics( req, - esIndexPattern, + 'elasticsearch', [ { keys: ['ccr_sync_lag_time'], name: 'ccr_sync_lag_time' }, { keys: ['ccr_sync_lag_ops'], name: 'ccr_sync_lag_ops' }, diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/index_detail.js b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/index_detail.js index e99ae04ab282c6..6c6b1487da1064 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/index_detail.js +++ b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/index_detail.js @@ -14,7 +14,6 @@ import { getShardAllocation, getShardStats } from '../../../../lib/elasticsearch import { handleError } from '../../../../lib/errors/handle_error'; import { prefixIndexPattern } from '../../../../../common/ccs_utils'; import { metricSet } from './metric_set_index_detail'; -import { INDEX_PATTERN_ELASTICSEARCH } from '../../../../../common/constants'; import { getLogs } from '../../../../lib/logs/get_logs'; const { advanced: metricSetAdvanced, overview: metricSetOverview } = metricSet; @@ -42,12 +41,10 @@ export function esIndexRoute(server) { handler: async (req) => { try { const config = server.config(); - const ccs = req.payload.ccs; const clusterUuid = req.params.clusterUuid; const indexUuid = req.params.id; const start = req.payload.timeRange.min; const end = req.payload.timeRange.max; - const esIndexPattern = prefixIndexPattern(config, INDEX_PATTERN_ELASTICSEARCH, ccs); const filebeatIndexPattern = prefixIndexPattern( config, config.get('monitoring.ui.logs.index'), @@ -57,21 +54,21 @@ export function esIndexRoute(server) { const isAdvanced = req.payload.is_advanced; const metricSet = isAdvanced ? metricSetAdvanced : metricSetOverview; - const cluster = await getClusterStats(req, esIndexPattern, clusterUuid); + const cluster = await getClusterStats(req, clusterUuid); const showSystemIndices = true; // hardcode to true, because this could be a system index - const shardStats = await getShardStats(req, esIndexPattern, cluster, { + const shardStats = await getShardStats(req, cluster, { includeNodes: true, includeIndices: true, indexName: indexUuid, }); - const indexSummary = await getIndexSummary(req, esIndexPattern, shardStats, { + const indexSummary = await getIndexSummary(req, shardStats, { clusterUuid, indexUuid, start, end, }); - const metrics = await getMetrics(req, esIndexPattern, metricSet, [ + const metrics = await getMetrics(req, 'elasticsearch', metricSet, [ { term: { 'index_stats.index': indexUuid } }, ]); @@ -97,7 +94,7 @@ export function esIndexRoute(server) { stateUuid, showSystemIndices, }; - const shards = await getShardAllocation(req, esIndexPattern, allocationOptions); + const shards = await getShardAllocation(req, allocationOptions); logs = await getLogs(config, req, filebeatIndexPattern, { clusterUuid, diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/indices.js b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/indices.js index 76e769ac030bac..ea490a15471164 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/indices.js +++ b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/indices.js @@ -10,8 +10,6 @@ import { getClusterStats } from '../../../../lib/cluster/get_cluster_stats'; import { getClusterStatus } from '../../../../lib/cluster/get_cluster_status'; import { getIndices } from '../../../../lib/elasticsearch/indices'; import { handleError } from '../../../../lib/errors/handle_error'; -import { prefixIndexPattern } from '../../../../../common/ccs_utils'; -import { INDEX_PATTERN_ELASTICSEARCH } from '../../../../../common/constants'; import { getIndicesUnassignedShardStats } from '../../../../lib/elasticsearch/shards/get_indices_unassigned_shard_stats'; export function esIndicesRoute(server) { @@ -36,25 +34,14 @@ export function esIndicesRoute(server) { }, }, async handler(req) { - const config = server.config(); const { clusterUuid } = req.params; const { show_system_indices: showSystemIndices } = req.query; const { ccs } = req.payload; - const esIndexPattern = prefixIndexPattern(config, INDEX_PATTERN_ELASTICSEARCH, ccs); try { - const clusterStats = await getClusterStats(req, esIndexPattern, clusterUuid); - const indicesUnassignedShardStats = await getIndicesUnassignedShardStats( - req, - esIndexPattern, - clusterStats - ); - const indices = await getIndices( - req, - esIndexPattern, - showSystemIndices, - indicesUnassignedShardStats - ); + const clusterStats = await getClusterStats(req, clusterUuid, ccs); + const indicesUnassignedShardStats = await getIndicesUnassignedShardStats(req, clusterStats); + const indices = await getIndices(req, showSystemIndices, indicesUnassignedShardStats); return { clusterStatus: getClusterStatus(clusterStats, indicesUnassignedShardStats), diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/ml_jobs.js b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/ml_jobs.js index 5853cc3d6ee9d1..d27ec8ce3cc83e 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/ml_jobs.js +++ b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/ml_jobs.js @@ -10,8 +10,6 @@ import { getClusterStats } from '../../../../lib/cluster/get_cluster_stats'; import { getClusterStatus } from '../../../../lib/cluster/get_cluster_status'; import { getMlJobs } from '../../../../lib/elasticsearch/get_ml_jobs'; import { handleError } from '../../../../lib/errors/handle_error'; -import { prefixIndexPattern } from '../../../../../common/ccs_utils'; -import { INDEX_PATTERN_ELASTICSEARCH } from '../../../../../common/constants'; import { getIndicesUnassignedShardStats } from '../../../../lib/elasticsearch/shards/get_indices_unassigned_shard_stats'; export function mlJobRoute(server) { @@ -33,20 +31,12 @@ export function mlJobRoute(server) { }, }, async handler(req) { - const config = server.config(); - const ccs = req.payload.ccs; const clusterUuid = req.params.clusterUuid; - const esIndexPattern = prefixIndexPattern(config, INDEX_PATTERN_ELASTICSEARCH, ccs); try { - const clusterStats = await getClusterStats(req, esIndexPattern, clusterUuid); - const indicesUnassignedShardStats = await getIndicesUnassignedShardStats( - req, - esIndexPattern, - clusterStats - ); - const rows = await getMlJobs(req, esIndexPattern); - + const clusterStats = await getClusterStats(req, clusterUuid); + const indicesUnassignedShardStats = await getIndicesUnassignedShardStats(req, clusterStats); + const rows = await getMlJobs(req); return { clusterStatus: getClusterStatus(clusterStats, indicesUnassignedShardStats), rows, diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/node_detail.js b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/node_detail.js index 5f77d0394a4f19..86048ed1765abb 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/node_detail.js +++ b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/node_detail.js @@ -14,7 +14,6 @@ import { getMetrics } from '../../../../lib/details/get_metrics'; import { handleError } from '../../../../lib/errors/handle_error'; import { prefixIndexPattern } from '../../../../../common/ccs_utils'; import { metricSets } from './metric_set_node_detail'; -import { INDEX_PATTERN_ELASTICSEARCH } from '../../../../../common/constants'; import { getLogs } from '../../../../lib/logs/get_logs'; const { advanced: metricSetAdvanced, overview: metricSetOverview } = metricSets; @@ -48,7 +47,6 @@ export function esNodeRoute(server) { const nodeUuid = req.params.nodeUuid; const start = req.payload.timeRange.min; const end = req.payload.timeRange.max; - const esIndexPattern = prefixIndexPattern(config, INDEX_PATTERN_ELASTICSEARCH, ccs); const filebeatIndexPattern = prefixIndexPattern( config, config.get('monitoring.ui.logs.index'), @@ -75,25 +73,26 @@ export function esNodeRoute(server) { } try { - const cluster = await getClusterStats(req, esIndexPattern, clusterUuid); + const cluster = await getClusterStats(req, clusterUuid, ccs); const clusterState = get( cluster, 'cluster_state', get(cluster, 'elasticsearch.cluster.stats.state') ); - const shardStats = await getShardStats(req, esIndexPattern, cluster, { + + const shardStats = await getShardStats(req, cluster, { includeIndices: true, includeNodes: true, nodeUuid, }); - const nodeSummary = await getNodeSummary(req, esIndexPattern, clusterState, shardStats, { + const nodeSummary = await getNodeSummary(req, clusterState, shardStats, { clusterUuid, nodeUuid, start, end, }); - const metrics = await getMetrics(req, esIndexPattern, metricSet, [ + const metrics = await getMetrics(req, 'elasticsearch', metricSet, [ { term: { 'source_node.uuid': nodeUuid } }, ]); let logs; @@ -118,7 +117,7 @@ export function esNodeRoute(server) { stateUuid, showSystemIndices, }; - const shards = await getShardAllocation(req, esIndexPattern, allocationOptions); + const shards = await getShardAllocation(req, allocationOptions); shardAllocation = { shards, diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/nodes.js b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/nodes.js index 7ea2e6e1e14404..d6cff7ecd9ae9a 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/nodes.js +++ b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/nodes.js @@ -11,8 +11,6 @@ import { getClusterStatus } from '../../../../lib/cluster/get_cluster_status'; import { getNodes } from '../../../../lib/elasticsearch/nodes'; import { getNodesShardCount } from '../../../../lib/elasticsearch/shards/get_nodes_shard_count'; import { handleError } from '../../../../lib/errors/handle_error'; -import { prefixIndexPattern } from '../../../../../common/ccs_utils'; -import { INDEX_PATTERN_ELASTICSEARCH } from '../../../../../common/constants'; import { getPaginatedNodes } from '../../../../lib/elasticsearch/nodes/get_nodes/get_paginated_nodes'; import { LISTING_METRICS_NAMES } from '../../../../lib/elasticsearch/nodes/get_nodes/nodes_listing_metrics'; import { getIndicesUnassignedShardStats } from '../../../../lib/elasticsearch/shards/get_indices_unassigned_shard_stats'; @@ -45,25 +43,18 @@ export function esNodesRoute(server) { }, }, async handler(req) { - const config = server.config(); const { ccs, pagination, sort, queryText } = req.payload; const clusterUuid = req.params.clusterUuid; - const esIndexPattern = prefixIndexPattern(config, INDEX_PATTERN_ELASTICSEARCH, ccs); try { - const clusterStats = await getClusterStats(req, esIndexPattern, clusterUuid); - const nodesShardCount = await getNodesShardCount(req, esIndexPattern, clusterStats); - const indicesUnassignedShardStats = await getIndicesUnassignedShardStats( - req, - esIndexPattern, - clusterStats - ); + const clusterStats = await getClusterStats(req, clusterUuid); + const nodesShardCount = await getNodesShardCount(req, clusterStats); + const indicesUnassignedShardStats = await getIndicesUnassignedShardStats(req, clusterStats); const clusterStatus = getClusterStatus(clusterStats, indicesUnassignedShardStats); const metricSet = LISTING_METRICS_NAMES; const { pageOfNodes, totalNodeCount } = await getPaginatedNodes( req, - esIndexPattern, { clusterUuid }, metricSet, pagination, @@ -72,16 +63,11 @@ export function esNodesRoute(server) { { clusterStats, nodesShardCount, - } + }, + ccs ); - const nodes = await getNodes( - req, - esIndexPattern, - pageOfNodes, - clusterStats, - nodesShardCount - ); + const nodes = await getNodes(req, pageOfNodes, clusterStats, nodesShardCount); return { clusterStatus, nodes, totalNodeCount }; } catch (err) { throw handleError(err, req); diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/overview.js b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/overview.js index a84ca61a9396b0..6c74f9dd872d27 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/overview.js +++ b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/overview.js @@ -13,10 +13,6 @@ import { getMetrics } from '../../../../lib/details/get_metrics'; import { handleError } from '../../../../lib/errors/handle_error'; import { prefixIndexPattern } from '../../../../../common/ccs_utils'; import { metricSet } from './metric_set_overview'; -import { - INDEX_PATTERN_ELASTICSEARCH, - INDEX_PATTERN_ELASTICSEARCH_ECS, -} from '../../../../../common/constants'; import { getLogs } from '../../../../lib/logs'; import { getIndicesUnassignedShardStats } from '../../../../lib/elasticsearch/shards/get_indices_unassigned_shard_stats'; @@ -40,22 +36,7 @@ export function esOverviewRoute(server) { }, async handler(req) { const config = server.config(); - const ccs = req.payload.ccs; const clusterUuid = req.params.clusterUuid; - const esIndexPattern = prefixIndexPattern(config, INDEX_PATTERN_ELASTICSEARCH, ccs); - const esLegacyIndexPattern = prefixIndexPattern( - config, - INDEX_PATTERN_ELASTICSEARCH, - ccs, - true - ); - const esEcsIndexPattern = prefixIndexPattern( - config, - INDEX_PATTERN_ELASTICSEARCH_ECS, - ccs, - true - ); - const filebeatIndexPattern = prefixIndexPattern( config, config.get('monitoring.ui.logs.index'), @@ -68,21 +49,12 @@ export function esOverviewRoute(server) { try { const [clusterStats, metrics, shardActivity, logs] = await Promise.all([ - getClusterStats(req, esIndexPattern, clusterUuid), - getMetrics(req, esIndexPattern, metricSet), - getLastRecovery( - req, - esLegacyIndexPattern, - esEcsIndexPattern, - config.get('monitoring.ui.max_bucket_size') - ), + getClusterStats(req, clusterUuid), + getMetrics(req, 'elasticsearch', metricSet), + getLastRecovery(req, config.get('monitoring.ui.max_bucket_size')), getLogs(config, req, filebeatIndexPattern, { clusterUuid, start, end }), ]); - const indicesUnassignedShardStats = await getIndicesUnassignedShardStats( - req, - esIndexPattern, - clusterStats - ); + const indicesUnassignedShardStats = await getIndicesUnassignedShardStats(req, clusterStats); const result = { clusterStatus: getClusterStatus(clusterStats, indicesUnassignedShardStats), diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch_settings/check/internal_monitoring.ts b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch_settings/check/internal_monitoring.ts index eee6ba98e62c77..46626066005adf 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch_settings/check/internal_monitoring.ts +++ b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch_settings/check/internal_monitoring.ts @@ -89,9 +89,9 @@ export function internalMonitoringCheckRoute(server: LegacyServer, npRoute: Rout const config = server.config(); const { ccs } = request.body; - const esIndexPattern = prefixIndexPattern(config, INDEX_PATTERN_ELASTICSEARCH, ccs, true); - const kbnIndexPattern = prefixIndexPattern(config, INDEX_PATTERN_KIBANA, ccs, true); - const lsIndexPattern = prefixIndexPattern(config, INDEX_PATTERN_LOGSTASH, ccs, true); + const esIndexPattern = prefixIndexPattern(config, INDEX_PATTERN_ELASTICSEARCH, ccs); + const kbnIndexPattern = prefixIndexPattern(config, INDEX_PATTERN_KIBANA, ccs); + const lsIndexPattern = prefixIndexPattern(config, INDEX_PATTERN_LOGSTASH, ccs); const indexCounts = await Promise.all([ checkLatestMonitoringIsLegacy(context, esIndexPattern), checkLatestMonitoringIsLegacy(context, kbnIndexPattern), diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/enterprise_search/overview.js b/x-pack/plugins/monitoring/server/routes/api/v1/enterprise_search/overview.js index b9bc0f49bc99d4..97ab818a829920 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/enterprise_search/overview.js +++ b/x-pack/plugins/monitoring/server/routes/api/v1/enterprise_search/overview.js @@ -6,11 +6,9 @@ */ import { schema } from '@kbn/config-schema'; -import { prefixIndexPattern } from '../../../../../common/ccs_utils'; import { getMetrics } from '../../../../lib/details/get_metrics'; import { metricSet } from './metric_set_overview'; import { handleError } from '../../../../lib/errors'; -import { INDEX_PATTERN_ENTERPRISE_SEARCH } from '../../../../../common/constants'; import { getStats } from '../../../../lib/enterprise_search'; export function entSearchOverviewRoute(server) { @@ -34,16 +32,10 @@ export function entSearchOverviewRoute(server) { async handler(req) { const clusterUuid = req.params.clusterUuid; - const entSearchIndexPattern = prefixIndexPattern( - server.config(), - INDEX_PATTERN_ENTERPRISE_SEARCH, - req.payload.ccs - ); - try { const [stats, metrics] = await Promise.all([ - getStats(req, entSearchIndexPattern, clusterUuid), - getMetrics(req, entSearchIndexPattern, metricSet, [], { + getStats(req, clusterUuid), + getMetrics(req, 'enterprisesearch', metricSet, [], { skipClusterUuidFilter: true, }), ]); diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/kibana/_get_kibana_cluster_status.js b/x-pack/plugins/monitoring/server/routes/api/v1/kibana/_get_kibana_cluster_status.js index 6a54e19d3493b0..373ab2cbde9b06 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/kibana/_get_kibana_cluster_status.js +++ b/x-pack/plugins/monitoring/server/routes/api/v1/kibana/_get_kibana_cluster_status.js @@ -8,9 +8,7 @@ import { get } from 'lodash'; import { getKibanasForClusters } from '../../../../lib/kibana/get_kibanas_for_clusters'; -export const getKibanaClusterStatus = (req, kbnIndexPattern, { clusterUuid }) => { +export const getKibanaClusterStatus = (req, { clusterUuid }) => { const clusters = [{ cluster_uuid: clusterUuid }]; - return getKibanasForClusters(req, kbnIndexPattern, clusters).then((kibanas) => - get(kibanas, '[0].stats') - ); + return getKibanasForClusters(req, clusters).then((kibanas) => get(kibanas, '[0].stats')); }; diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/kibana/instance.ts b/x-pack/plugins/monitoring/server/routes/api/v1/kibana/instance.ts index 613ca39275c2de..dfbd8e82bb29bf 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/kibana/instance.ts +++ b/x-pack/plugins/monitoring/server/routes/api/v1/kibana/instance.ts @@ -12,10 +12,7 @@ import { handleError } from '../../../../lib/errors'; // @ts-ignore import { getMetrics } from '../../../../lib/details/get_metrics'; // @ts-ignore -import { prefixIndexPattern } from '../../../../../common/ccs_utils'; -// @ts-ignore import { metricSet } from './metric_set_instance'; -import { INDEX_PATTERN_KIBANA } from '../../../../../common/constants'; import { LegacyRequest, LegacyServer } from '../../../../types'; /** @@ -44,16 +41,13 @@ export function kibanaInstanceRoute(server: LegacyServer) { }, }, async handler(req: LegacyRequest) { - const config = server.config(); - const ccs = req.payload.ccs; const clusterUuid = req.params.clusterUuid; const kibanaUuid = req.params.kibanaUuid; - const kbnIndexPattern = prefixIndexPattern(config, INDEX_PATTERN_KIBANA, ccs); try { const [metrics, kibanaSummary] = await Promise.all([ - getMetrics(req, kbnIndexPattern, metricSet), - getKibanaInfo(req, kbnIndexPattern, { clusterUuid, kibanaUuid }), + getMetrics(req, 'kibana', metricSet), + getKibanaInfo(req, { clusterUuid, kibanaUuid }), ]); return { diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/kibana/instances.js b/x-pack/plugins/monitoring/server/routes/api/v1/kibana/instances.js index f9b3498cd684eb..f1e872d6436f28 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/kibana/instances.js +++ b/x-pack/plugins/monitoring/server/routes/api/v1/kibana/instances.js @@ -6,11 +6,9 @@ */ import { schema } from '@kbn/config-schema'; -import { prefixIndexPattern } from '../../../../../common/ccs_utils'; import { getKibanaClusterStatus } from './_get_kibana_cluster_status'; import { getKibanas } from '../../../../lib/kibana/get_kibanas'; import { handleError } from '../../../../lib/errors'; -import { INDEX_PATTERN_KIBANA } from '../../../../../common/constants'; export function kibanaInstancesRoute(server) { /** @@ -34,15 +32,12 @@ export function kibanaInstancesRoute(server) { }, }, async handler(req) { - const config = server.config(); - const ccs = req.payload.ccs; const clusterUuid = req.params.clusterUuid; - const kbnIndexPattern = prefixIndexPattern(config, INDEX_PATTERN_KIBANA, ccs); try { const [clusterStatus, kibanas] = await Promise.all([ - getKibanaClusterStatus(req, kbnIndexPattern, { clusterUuid }), - getKibanas(req, kbnIndexPattern, { clusterUuid }), + getKibanaClusterStatus(req, { clusterUuid }), + getKibanas(req, { clusterUuid }), ]); return { diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/kibana/overview.js b/x-pack/plugins/monitoring/server/routes/api/v1/kibana/overview.js index f9a9443c3533b6..8f77dea99868ab 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/kibana/overview.js +++ b/x-pack/plugins/monitoring/server/routes/api/v1/kibana/overview.js @@ -6,12 +6,10 @@ */ import { schema } from '@kbn/config-schema'; -import { prefixIndexPattern } from '../../../../../common/ccs_utils'; import { getKibanaClusterStatus } from './_get_kibana_cluster_status'; import { getMetrics } from '../../../../lib/details/get_metrics'; import { metricSet } from './metric_set_overview'; import { handleError } from '../../../../lib/errors'; -import { INDEX_PATTERN_KIBANA } from '../../../../../common/constants'; export function kibanaOverviewRoute(server) { /** @@ -35,20 +33,20 @@ export function kibanaOverviewRoute(server) { }, }, async handler(req) { - const config = server.config(); - const ccs = req.payload.ccs; const clusterUuid = req.params.clusterUuid; - const kbnIndexPattern = prefixIndexPattern(config, INDEX_PATTERN_KIBANA, ccs); try { + const moduleType = 'kibana'; + const dsDataset = 'stats'; const [clusterStatus, metrics] = await Promise.all([ - getKibanaClusterStatus(req, kbnIndexPattern, { clusterUuid }), - getMetrics(req, kbnIndexPattern, metricSet, [ + getKibanaClusterStatus(req, { clusterUuid }), + getMetrics(req, moduleType, metricSet, [ { bool: { should: [ + { term: { 'data_stream.dataset': `${moduleType}.${dsDataset}` } }, + { term: { 'metricset.name': dsDataset } }, { term: { type: 'kibana_stats' } }, - { term: { 'metricset.name': 'stats' } }, ], }, }, diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/logstash/node.js b/x-pack/plugins/monitoring/server/routes/api/v1/logstash/node.js index 6c0ec3f0af374c..9c7749bf74903a 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/logstash/node.js +++ b/x-pack/plugins/monitoring/server/routes/api/v1/logstash/node.js @@ -9,9 +9,7 @@ import { schema } from '@kbn/config-schema'; import { getNodeInfo } from '../../../../lib/logstash/get_node_info'; import { handleError } from '../../../../lib/errors'; import { getMetrics } from '../../../../lib/details/get_metrics'; -import { prefixIndexPattern } from '../../../../../common/ccs_utils'; import { metricSets } from './metric_set_node'; -import { INDEX_PATTERN_LOGSTASH } from '../../../../../common/constants'; const { advanced: metricSetAdvanced, overview: metricSetOverview } = metricSets; @@ -50,9 +48,7 @@ export function logstashNodeRoute(server) { }, async handler(req) { const config = server.config(); - const ccs = req.payload.ccs; const clusterUuid = req.params.clusterUuid; - const lsIndexPattern = prefixIndexPattern(config, INDEX_PATTERN_LOGSTASH, ccs); const logstashUuid = req.params.logstashUuid; let metricSet; @@ -71,18 +67,21 @@ export function logstashNodeRoute(server) { } try { + const moduleType = 'logstash'; + const dsDataset = 'node_stats'; const [metrics, nodeSummary] = await Promise.all([ - getMetrics(req, lsIndexPattern, metricSet, [ + getMetrics(req, 'logstash', metricSet, [ { bool: { should: [ + { term: { 'data_stream.dataset': `${moduleType}.${dsDataset}` } }, + { term: { 'metricset.name': dsDataset } }, { term: { type: 'logstash_stats' } }, - { term: { 'metricset.name': 'node_stats' } }, ], }, }, ]), - getNodeInfo(req, lsIndexPattern, { clusterUuid, logstashUuid }), + getNodeInfo(req, { clusterUuid, logstashUuid }), ]); return { diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/logstash/nodes.js b/x-pack/plugins/monitoring/server/routes/api/v1/logstash/nodes.js index 051fb7d38fd417..cca02519aa7c42 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/logstash/nodes.js +++ b/x-pack/plugins/monitoring/server/routes/api/v1/logstash/nodes.js @@ -51,7 +51,7 @@ export function logstashNodesRoute(server) { try { const [clusterStatus, nodes] = await Promise.all([ - getClusterStatus(req, lsIndexPattern, { clusterUuid }), + getClusterStatus(req, { clusterUuid }), getNodes(req, lsIndexPattern, { clusterUuid }), ]); diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/logstash/overview.js b/x-pack/plugins/monitoring/server/routes/api/v1/logstash/overview.js index 7ecd09a9d993ea..81d64e8fcdc2b9 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/logstash/overview.js +++ b/x-pack/plugins/monitoring/server/routes/api/v1/logstash/overview.js @@ -9,9 +9,7 @@ import { schema } from '@kbn/config-schema'; import { getClusterStatus } from '../../../../lib/logstash/get_cluster_status'; import { getMetrics } from '../../../../lib/details/get_metrics'; import { handleError } from '../../../../lib/errors'; -import { prefixIndexPattern } from '../../../../../common/ccs_utils'; import { metricSet } from './metric_set_overview'; -import { INDEX_PATTERN_LOGSTASH } from '../../../../../common/constants'; /* * Logstash Overview route. @@ -45,24 +43,24 @@ export function logstashOverviewRoute(server) { }, }, async handler(req) { - const config = server.config(); - const ccs = req.payload.ccs; const clusterUuid = req.params.clusterUuid; - const lsIndexPattern = prefixIndexPattern(config, INDEX_PATTERN_LOGSTASH, ccs); try { + const moduleType = 'logstash'; + const dsDataset = 'node_stats'; const [metrics, clusterStatus] = await Promise.all([ - getMetrics(req, lsIndexPattern, metricSet, [ + getMetrics(req, moduleType, metricSet, [ { bool: { should: [ + { term: { 'data_stream.dataset': `${moduleType}.${dsDataset}` } }, + { term: { 'metricset.name': dsDataset } }, { term: { type: 'logstash_stats' } }, - { term: { 'metricset.name': 'node_stats' } }, ], }, }, ]), - getClusterStatus(req, lsIndexPattern, { clusterUuid }), + getClusterStatus(req, { clusterUuid }), ]); return { diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/logstash/pipeline.js b/x-pack/plugins/monitoring/server/routes/api/v1/logstash/pipeline.js index 6b81059f0c2564..59f91b82ca4973 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/logstash/pipeline.js +++ b/x-pack/plugins/monitoring/server/routes/api/v1/logstash/pipeline.js @@ -10,8 +10,6 @@ import { handleError } from '../../../../lib/errors'; import { getPipelineVersions } from '../../../../lib/logstash/get_pipeline_versions'; import { getPipeline } from '../../../../lib/logstash/get_pipeline'; import { getPipelineVertex } from '../../../../lib/logstash/get_pipeline_vertex'; -import { prefixIndexPattern } from '../../../../../common/ccs_utils'; -import { INDEX_PATTERN_LOGSTASH } from '../../../../../common/constants'; function getPipelineVersion(versions, pipelineHash) { return pipelineHash ? versions.find(({ hash }) => hash === pipelineHash) : versions[0]; @@ -48,10 +46,8 @@ export function logstashPipelineRoute(server) { }, handler: async (req) => { const config = server.config(); - const ccs = req.payload.ccs; const clusterUuid = req.params.clusterUuid; const detailVertexId = req.payload.detailVertexId; - const lsIndexPattern = prefixIndexPattern(config, INDEX_PATTERN_LOGSTASH, ccs); const pipelineId = req.params.pipelineId; // Optional params default to empty string, set to null to be more explicit. @@ -62,8 +58,6 @@ export function logstashPipelineRoute(server) { try { versions = await getPipelineVersions({ req, - config, - lsIndexPattern, clusterUuid, pipelineId, }); @@ -72,18 +66,10 @@ export function logstashPipelineRoute(server) { } const version = getPipelineVersion(versions, pipelineHash); - const promises = [getPipeline(req, config, lsIndexPattern, clusterUuid, pipelineId, version)]; + const promises = [getPipeline(req, config, clusterUuid, pipelineId, version)]; if (detailVertexId) { promises.push( - getPipelineVertex( - req, - config, - lsIndexPattern, - clusterUuid, - pipelineId, - version, - detailVertexId - ) + getPipelineVertex(req, config, clusterUuid, pipelineId, version, detailVertexId) ); } diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/logstash/pipelines/cluster_pipelines.js b/x-pack/plugins/monitoring/server/routes/api/v1/logstash/pipelines/cluster_pipelines.js index b7d86e86e7a074..ace5661b9bf988 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/logstash/pipelines/cluster_pipelines.js +++ b/x-pack/plugins/monitoring/server/routes/api/v1/logstash/pipelines/cluster_pipelines.js @@ -8,8 +8,6 @@ import { schema } from '@kbn/config-schema'; import { getClusterStatus } from '../../../../../lib/logstash/get_cluster_status'; import { handleError } from '../../../../../lib/errors'; -import { prefixIndexPattern } from '../../../../../../common/ccs_utils'; -import { INDEX_PATTERN_LOGSTASH } from '../../../../../../common/constants'; import { getPaginatedPipelines } from '../../../../../lib/logstash/get_paginated_pipelines'; /** @@ -45,10 +43,8 @@ export function logstashClusterPipelinesRoute(server) { }, }, handler: async (req) => { - const config = server.config(); - const { ccs, pagination, sort, queryText } = req.payload; + const { pagination, sort, queryText } = req.payload; const clusterUuid = req.params.clusterUuid; - const lsIndexPattern = prefixIndexPattern(config, INDEX_PATTERN_LOGSTASH, ccs); const throughputMetric = 'logstash_cluster_pipeline_throughput'; const nodesCountMetric = 'logstash_cluster_pipeline_nodes_count'; @@ -64,7 +60,6 @@ export function logstashClusterPipelinesRoute(server) { try { const response = await getPaginatedPipelines({ req, - lsIndexPattern, clusterUuid, metrics: { throughputMetric, nodesCountMetric }, pagination, @@ -74,7 +69,7 @@ export function logstashClusterPipelinesRoute(server) { return { ...response, - clusterStatus: await getClusterStatus(req, lsIndexPattern, { clusterUuid }), + clusterStatus: await getClusterStatus(req, { clusterUuid }), }; } catch (err) { throw handleError(err, req); diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/logstash/pipelines/node_pipelines.js b/x-pack/plugins/monitoring/server/routes/api/v1/logstash/pipelines/node_pipelines.js index f31e88b5b8b081..c232da925e74cc 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/logstash/pipelines/node_pipelines.js +++ b/x-pack/plugins/monitoring/server/routes/api/v1/logstash/pipelines/node_pipelines.js @@ -8,8 +8,6 @@ import { schema } from '@kbn/config-schema'; import { getNodeInfo } from '../../../../../lib/logstash/get_node_info'; import { handleError } from '../../../../../lib/errors'; -import { prefixIndexPattern } from '../../../../../../common/ccs_utils'; -import { INDEX_PATTERN_LOGSTASH } from '../../../../../../common/constants'; import { getPaginatedPipelines } from '../../../../../lib/logstash/get_paginated_pipelines'; /** @@ -46,10 +44,8 @@ export function logstashNodePipelinesRoute(server) { }, }, handler: async (req) => { - const config = server.config(); - const { ccs, pagination, sort, queryText } = req.payload; + const { pagination, sort, queryText } = req.payload; const { clusterUuid, logstashUuid } = req.params; - const lsIndexPattern = prefixIndexPattern(config, INDEX_PATTERN_LOGSTASH, ccs); const throughputMetric = 'logstash_node_pipeline_throughput'; const nodesCountMetric = 'logstash_node_pipeline_nodes_count'; @@ -66,7 +62,6 @@ export function logstashNodePipelinesRoute(server) { try { const response = await getPaginatedPipelines({ req, - lsIndexPattern, clusterUuid, logstashUuid, metrics: { throughputMetric, nodesCountMetric }, @@ -77,7 +72,7 @@ export function logstashNodePipelinesRoute(server) { return { ...response, - nodeSummary: await getNodeInfo(req, lsIndexPattern, { clusterUuid, logstashUuid }), + nodeSummary: await getNodeInfo(req, { clusterUuid, logstashUuid }), }; } catch (err) { throw handleError(err, req); diff --git a/x-pack/test/api_integration/apis/monitoring/apm/index.js b/x-pack/test/api_integration/apis/monitoring/apm/index.js index ae0623054dc6bf..b56a26d71a83aa 100644 --- a/x-pack/test/api_integration/apis/monitoring/apm/index.js +++ b/x-pack/test/api_integration/apis/monitoring/apm/index.js @@ -8,10 +8,10 @@ export default function ({ loadTestFile }) { describe('APM', () => { loadTestFile(require.resolve('./overview')); - loadTestFile(require.resolve('./overview_mb')); + // loadTestFile(require.resolve('./overview_mb')); loadTestFile(require.resolve('./instances')); - loadTestFile(require.resolve('./instances_mb')); + // loadTestFile(require.resolve('./instances_mb')); loadTestFile(require.resolve('./instance')); - loadTestFile(require.resolve('./instance_mb')); + // loadTestFile(require.resolve('./instance_mb')); }); } diff --git a/x-pack/test/api_integration/apis/monitoring/beats/index.js b/x-pack/test/api_integration/apis/monitoring/beats/index.js index 8fe09e457f685c..235afdc7fe6b21 100644 --- a/x-pack/test/api_integration/apis/monitoring/beats/index.js +++ b/x-pack/test/api_integration/apis/monitoring/beats/index.js @@ -8,10 +8,10 @@ export default function ({ loadTestFile }) { describe('Beats', () => { loadTestFile(require.resolve('./overview')); - loadTestFile(require.resolve('./overview_mb')); + // loadTestFile(require.resolve('./overview_mb')); loadTestFile(require.resolve('./list')); - loadTestFile(require.resolve('./list_mb')); + // loadTestFile(require.resolve('./list_mb')); loadTestFile(require.resolve('./detail')); - loadTestFile(require.resolve('./detail_mb')); + // loadTestFile(require.resolve('./detail_mb')); }); } diff --git a/x-pack/test/api_integration/apis/monitoring/cluster/index.js b/x-pack/test/api_integration/apis/monitoring/cluster/index.js index fb99f5e0b96056..59af14b049aa7a 100644 --- a/x-pack/test/api_integration/apis/monitoring/cluster/index.js +++ b/x-pack/test/api_integration/apis/monitoring/cluster/index.js @@ -8,8 +8,8 @@ export default function ({ loadTestFile }) { describe('cluster', () => { loadTestFile(require.resolve('./list')); - loadTestFile(require.resolve('./list_mb')); + // loadTestFile(require.resolve('./list_mb')); loadTestFile(require.resolve('./overview')); - loadTestFile(require.resolve('./overview_mb')); + // loadTestFile(require.resolve('./overview_mb')); }); } diff --git a/x-pack/test/api_integration/apis/monitoring/elasticsearch/index.js b/x-pack/test/api_integration/apis/monitoring/elasticsearch/index.js index ad864979a15fe7..167da3e360c166 100644 --- a/x-pack/test/api_integration/apis/monitoring/elasticsearch/index.js +++ b/x-pack/test/api_integration/apis/monitoring/elasticsearch/index.js @@ -8,20 +8,20 @@ export default function ({ loadTestFile }) { describe('Elasticsearch', () => { loadTestFile(require.resolve('./overview')); - loadTestFile(require.resolve('./overview_mb')); + // loadTestFile(require.resolve('./overview_mb')); loadTestFile(require.resolve('./nodes')); - loadTestFile(require.resolve('./nodes_mb')); + // loadTestFile(require.resolve('./nodes_mb')); loadTestFile(require.resolve('./node_detail')); - loadTestFile(require.resolve('./node_detail_mb')); + // loadTestFile(require.resolve('./node_detail_mb')); loadTestFile(require.resolve('./node_detail_advanced')); - loadTestFile(require.resolve('./node_detail_advanced_mb')); + // loadTestFile(require.resolve('./node_detail_advanced_mb')); loadTestFile(require.resolve('./indices')); - loadTestFile(require.resolve('./indices_mb')); + // loadTestFile(require.resolve('./indices_mb')); loadTestFile(require.resolve('./index_detail')); - loadTestFile(require.resolve('./index_detail_mb')); + // loadTestFile(require.resolve('./index_detail_mb')); loadTestFile(require.resolve('./ccr')); - loadTestFile(require.resolve('./ccr_mb')); + // loadTestFile(require.resolve('./ccr_mb')); loadTestFile(require.resolve('./ccr_shard')); - loadTestFile(require.resolve('./ccr_shard_mb')); + // loadTestFile(require.resolve('./ccr_shard_mb')); }); } diff --git a/x-pack/test/api_integration/apis/monitoring/kibana/index.js b/x-pack/test/api_integration/apis/monitoring/kibana/index.js index b54b09102bc1b2..f953104d915e8d 100644 --- a/x-pack/test/api_integration/apis/monitoring/kibana/index.js +++ b/x-pack/test/api_integration/apis/monitoring/kibana/index.js @@ -8,10 +8,10 @@ export default function ({ loadTestFile }) { describe('Kibana', () => { loadTestFile(require.resolve('./overview')); - loadTestFile(require.resolve('./overview_mb')); + // loadTestFile(require.resolve('./overview_mb')); loadTestFile(require.resolve('./listing')); - loadTestFile(require.resolve('./listing_mb')); + // loadTestFile(require.resolve('./listing_mb')); loadTestFile(require.resolve('./instance')); - loadTestFile(require.resolve('./instance_mb')); + // loadTestFile(require.resolve('./instance_mb')); }); } diff --git a/x-pack/test/api_integration/apis/monitoring/logstash/index.js b/x-pack/test/api_integration/apis/monitoring/logstash/index.js index 0caf7e360ef3a8..1a8baacacf066a 100644 --- a/x-pack/test/api_integration/apis/monitoring/logstash/index.js +++ b/x-pack/test/api_integration/apis/monitoring/logstash/index.js @@ -8,14 +8,14 @@ export default function ({ loadTestFile }) { describe('Logstash', () => { loadTestFile(require.resolve('./overview')); - loadTestFile(require.resolve('./overview_mb')); + // loadTestFile(require.resolve('./overview_mb')); loadTestFile(require.resolve('./nodes')); - loadTestFile(require.resolve('./nodes_mb')); + // loadTestFile(require.resolve('./nodes_mb')); loadTestFile(require.resolve('./node_detail')); - loadTestFile(require.resolve('./node_detail_mb')); + // loadTestFile(require.resolve('./node_detail_mb')); loadTestFile(require.resolve('./multicluster_pipelines')); - loadTestFile(require.resolve('./multicluster_pipelines_mb')); + // loadTestFile(require.resolve('./multicluster_pipelines_mb')); loadTestFile(require.resolve('./pipelines')); - loadTestFile(require.resolve('./pipelines_mb')); + // loadTestFile(require.resolve('./pipelines_mb')); }); } diff --git a/x-pack/test/api_integration/apis/monitoring/setup/collection/index.js b/x-pack/test/api_integration/apis/monitoring/setup/collection/index.js index 4690b6d6371d89..1898aedfcab0d7 100644 --- a/x-pack/test/api_integration/apis/monitoring/setup/collection/index.js +++ b/x-pack/test/api_integration/apis/monitoring/setup/collection/index.js @@ -8,13 +8,13 @@ export default function ({ loadTestFile }) { describe('Collection', () => { loadTestFile(require.resolve('./kibana')); - loadTestFile(require.resolve('./kibana_mb')); + // loadTestFile(require.resolve('./kibana_mb')); loadTestFile(require.resolve('./kibana_exclusive')); - loadTestFile(require.resolve('./kibana_exclusive_mb')); + // loadTestFile(require.resolve('./kibana_exclusive_mb')); loadTestFile(require.resolve('./es_and_kibana')); - loadTestFile(require.resolve('./es_and_kibana_mb')); + // loadTestFile(require.resolve('./es_and_kibana_mb')); loadTestFile(require.resolve('./es_and_kibana_exclusive')); - loadTestFile(require.resolve('./es_and_kibana_exclusive_mb')); + // loadTestFile(require.resolve('./es_and_kibana_exclusive_mb')); loadTestFile(require.resolve('./detect_beats')); loadTestFile(require.resolve('./detect_beats_management')); loadTestFile(require.resolve('./detect_logstash')); diff --git a/x-pack/test/functional/es_archives/monitoring/singlecluster_red_platinum_mb/data.json.gz b/x-pack/test/functional/es_archives/monitoring/singlecluster_red_platinum_mb/data.json.gz index 163ed932c541351b8f63d2b0b9445e5fb4e11292..d82f05dd3eb4304717516fecb1401aa8f3f4a4ea 100644 GIT binary patch literal 282241 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

+wKqbn2O{GDQn`BtgJS_!UwN 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 PQ&KBW>~M322f=>l%u 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�VUe7aU|T_7hH+za5C<3d|sZXUJ|s?>QsvMHgdE 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

    qvAxi@V; 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

    sKZ*yeqp(H=hs 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

    -LAtHM3 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

      ChyH~yioMU z{?(YYgG+^B z_#MGKiOcP?(ZzR>2$&|aG+jP0RM+7)Cs zQ}px+O~>+eO-qe!dgM-F>7H;bv#u)7NYxqTK*sf7r&-WAzrAmru!sJL?D#F2_ynkO zw{NrrxpEc=b0B_~&^K?U*mN(1KGNgn&Phb}*jupkvnb)FZKF?|22wxhv8!P+yS~hzm*2Rtrzks^$H#t;bub`b!qQ?n$AS&!gOS z)q0uOcREp4aFHn;R$;IB`8OvP*X(u?uN~=sg(V($YN@*6#xwM->a@C_OoCOS8$8!zDvpvJUA-dXme^MClo4)CMtsZJws@=BFU7+nJ+XHsYdoy%H OuzH>rUj4xt>3;#Na+rMp diff --git a/x-pack/test/functional/es_archives/monitoring/singlecluster_three_nodes_shard_relocation_mb/data.json.gz b/x-pack/test/functional/es_archives/monitoring/singlecluster_three_nodes_shard_relocation_mb/data.json.gz index e2f6380f1010a2acf6b64e671d93a2874c0f86c9..4f66d024a65b96e9d35feae31f575f3508292901 100644 GIT binary patch delta 212613 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%0AO2`;+!ACfKf7>G@T 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

      !T<_8r_{wwjKoWnmo#4RR(M+b+sOVeLkT8d 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%0Dp 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 H8bSPjlsUsB From 72559010f7d649c5ecab7926be0420473280e8db Mon Sep 17 00:00:00 2001 From: Spencer Date: Thu, 20 Jan 2022 15:19:13 -0700 Subject: [PATCH 106/108] [plugin-helpers/tests] filter out ci-stats warnings (#123510) --- .../kbn-plugin-helpers/src/integration_tests/build.test.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/kbn-plugin-helpers/src/integration_tests/build.test.ts b/packages/kbn-plugin-helpers/src/integration_tests/build.test.ts index 65cbdaf88034c3..71a3fbe6037182 100644 --- a/packages/kbn-plugin-helpers/src/integration_tests/build.test.ts +++ b/packages/kbn-plugin-helpers/src/integration_tests/build.test.ts @@ -60,7 +60,12 @@ it('builds a generated plugin into a viable archive', async () => { } ); - expect(buildProc.all).toMatchInlineSnapshot(` + expect( + buildProc.all + ?.split('\n') + .filter((l) => !l.includes('failed to reach ci-stats service')) + .join('\n') + ).toMatchInlineSnapshot(` " info deleting the build and target directories info running @kbn/optimizer │ info initialized, 0 bundles cached From 735948de4dd94c0fc4d639fe44afc635572d420e Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Fri, 21 Jan 2022 00:17:38 +0000 Subject: [PATCH 107/108] chore(NA): splits types from code on @kbn/io-ts-utils (#123431) * chore(NA): splits types from code on @kbn/io-ts-utils * chore(NA): missing import keys Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .eslintrc.js | 4 -- package.json | 1 + packages/BUILD.bazel | 1 + packages/kbn-io-ts-utils/BUILD.bazel | 37 +++++++++++-------- .../deep_exact_rt/package.json | 4 -- .../iso_to_epoch_rt/package.json | 4 -- packages/kbn-io-ts-utils/json_rt/package.json | 4 -- .../kbn-io-ts-utils/merge_rt/package.json | 4 -- .../non_empty_string_rt/package.json | 4 -- packages/kbn-io-ts-utils/package.json | 1 - .../parseable_types/package.json | 4 -- .../props_to_schema/package.json | 4 -- packages/kbn-io-ts-utils/src/index.ts | 2 + .../strict_keys_rt/package.json | 4 -- .../to_boolean_rt/package.json | 4 -- .../to_json_schema/package.json | 4 -- .../kbn-io-ts-utils/to_number_rt/package.json | 4 -- .../kbn-server-route-repository/BUILD.bazel | 2 +- .../src/decode_request_params.test.ts | 2 +- .../src/decode_request_params.ts | 2 +- .../kbn-typed-react-router-config/BUILD.bazel | 2 +- .../src/create_router.test.tsx | 2 +- .../src/create_router.ts | 3 +- x-pack/plugins/apm/common/environment_rt.ts | 2 +- .../public/components/routing/home/index.tsx | 2 +- .../routing/service_detail/index.tsx | 2 +- .../register_apm_server_routes.test.ts | 2 +- .../apm_routes/register_apm_server_routes.ts | 3 +- .../apm/server/routes/backends/route.ts | 2 +- .../apm/server/routes/correlations/route.ts | 2 +- .../apm/server/routes/default_api_types.ts | 2 +- .../plugins/apm/server/routes/errors/route.ts | 3 +- .../routes/latency_distribution/route.ts | 2 +- .../routes/observability_overview/route.ts | 2 +- .../apm/server/routes/rum_client/route.ts | 2 +- .../apm/server/routes/services/route.ts | 4 +- .../settings/agent_configuration/route.ts | 2 +- .../apm/server/routes/source_maps/route.ts | 2 +- .../apm/server/routes/transactions/route.ts | 3 +- yarn.lock | 4 ++ 40 files changed, 52 insertions(+), 92 deletions(-) delete mode 100644 packages/kbn-io-ts-utils/deep_exact_rt/package.json delete mode 100644 packages/kbn-io-ts-utils/iso_to_epoch_rt/package.json delete mode 100644 packages/kbn-io-ts-utils/json_rt/package.json delete mode 100644 packages/kbn-io-ts-utils/merge_rt/package.json delete mode 100644 packages/kbn-io-ts-utils/non_empty_string_rt/package.json delete mode 100644 packages/kbn-io-ts-utils/parseable_types/package.json delete mode 100644 packages/kbn-io-ts-utils/props_to_schema/package.json delete mode 100644 packages/kbn-io-ts-utils/strict_keys_rt/package.json delete mode 100644 packages/kbn-io-ts-utils/to_boolean_rt/package.json delete mode 100644 packages/kbn-io-ts-utils/to_json_schema/package.json delete mode 100644 packages/kbn-io-ts-utils/to_number_rt/package.json diff --git a/.eslintrc.js b/.eslintrc.js index 5ee75d186eb240..f3d3e700fec30c 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -226,10 +226,6 @@ const RESTRICTED_IMPORTS = [ name: 'react-use', message: 'Please use react-use/lib/{method} instead.', }, - { - name: '@kbn/io-ts-utils', - message: `Import directly from @kbn/io-ts-utils/{method} submodules`, - }, ]; module.exports = { diff --git a/package.json b/package.json index 4e7044b458a44f..2dd2e411bdcfb8 100644 --- a/package.json +++ b/package.json @@ -578,6 +578,7 @@ "@types/kbn__i18n": "link:bazel-bin/packages/kbn-i18n/npm_module_types", "@types/kbn__i18n-react": "link:bazel-bin/packages/kbn-i18n-react/npm_module_types", "@types/kbn__interpreter": "link:bazel-bin/packages/kbn-interpreter/npm_module_types", + "@types/kbn__io-ts-utils": "link:bazel-bin/packages/kbn-io-ts-utils/npm_module_types", "@types/kbn__mapbox-gl": "link:bazel-bin/packages/kbn-mapbox-gl/npm_module_types", "@types/kbn__monaco": "link:bazel-bin/packages/kbn-monaco/npm_module_types", "@types/kbn__optimizer": "link:bazel-bin/packages/kbn-optimizer/npm_module_types", diff --git a/packages/BUILD.bazel b/packages/BUILD.bazel index be4d1087bc21a2..936091a3b85c2a 100644 --- a/packages/BUILD.bazel +++ b/packages/BUILD.bazel @@ -97,6 +97,7 @@ filegroup( "//packages/kbn-i18n:build_types", "//packages/kbn-i18n-react:build_types", "//packages/kbn-interpreter:build_types", + "//packages/kbn-io-ts-utils:build_types", "//packages/kbn-mapbox-gl:build_types", "//packages/kbn-monaco:build_types", "//packages/kbn-optimizer:build_types", diff --git a/packages/kbn-io-ts-utils/BUILD.bazel b/packages/kbn-io-ts-utils/BUILD.bazel index dd81e8318e9d98..5ecfc0acc55e8e 100644 --- a/packages/kbn-io-ts-utils/BUILD.bazel +++ b/packages/kbn-io-ts-utils/BUILD.bazel @@ -1,9 +1,10 @@ -load("@npm//@bazel/typescript:index.bzl", "ts_config", "ts_project") -load("@build_bazel_rules_nodejs//:index.bzl", "js_library", "pkg_npm") -load("//src/dev/bazel:index.bzl", "jsts_transpiler") +load("@npm//@bazel/typescript:index.bzl", "ts_config") +load("@build_bazel_rules_nodejs//:index.bzl", "js_library") +load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") PKG_BASE_NAME = "kbn-io-ts-utils" PKG_REQUIRE_NAME = "@kbn/io-ts-utils" +TYPES_PKG_REQUIRE_NAME = "@types/kbn__io-ts-utils" SOURCE_FILES = glob( [ @@ -23,17 +24,6 @@ filegroup( NPM_MODULE_EXTRA_FILES = [ "package.json", - "deep_exact_rt/package.json", - "iso_to_epoch_rt/package.json", - "json_rt/package.json", - "merge_rt/package.json", - "non_empty_string_rt/package.json", - "parseable_types/package.json", - "props_to_schema/package.json", - "strict_keys_rt/package.json", - "to_boolean_rt/package.json", - "to_json_schema/package.json", - "to_number_rt/package.json", ] RUNTIME_DEPS = [ @@ -86,7 +76,7 @@ ts_project( js_library( name = PKG_BASE_NAME, srcs = NPM_MODULE_EXTRA_FILES, - deps = RUNTIME_DEPS + [":target_node", ":tsc_types"], + deps = RUNTIME_DEPS + [":target_node"], package_name = PKG_REQUIRE_NAME, visibility = ["//visibility:public"], ) @@ -105,3 +95,20 @@ filegroup( ], visibility = ["//visibility:public"], ) + +pkg_npm_types( + name = "npm_module_types", + srcs = SRCS, + deps = [":tsc_types"], + package_name = TYPES_PKG_REQUIRE_NAME, + tsconfig = ":tsconfig", + visibility = ["//visibility:public"], +) + +filegroup( + name = "build_types", + srcs = [ + ":npm_module_types", + ], + visibility = ["//visibility:public"], +) diff --git a/packages/kbn-io-ts-utils/deep_exact_rt/package.json b/packages/kbn-io-ts-utils/deep_exact_rt/package.json deleted file mode 100644 index b42591a2e82d04..00000000000000 --- a/packages/kbn-io-ts-utils/deep_exact_rt/package.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "main": "../target_node/deep_exact_rt", - "types": "../target_types/deep_exact_rt" -} \ No newline at end of file diff --git a/packages/kbn-io-ts-utils/iso_to_epoch_rt/package.json b/packages/kbn-io-ts-utils/iso_to_epoch_rt/package.json deleted file mode 100644 index e96c50b9fbf4ec..00000000000000 --- a/packages/kbn-io-ts-utils/iso_to_epoch_rt/package.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "main": "../target_node/iso_to_epoch_rt", - "types": "../target_types/iso_to_epoch_rt" -} \ No newline at end of file diff --git a/packages/kbn-io-ts-utils/json_rt/package.json b/packages/kbn-io-ts-utils/json_rt/package.json deleted file mode 100644 index f896827cf99a40..00000000000000 --- a/packages/kbn-io-ts-utils/json_rt/package.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "main": "../target_node/json_rt", - "types": "../target_types/json_rt" -} \ No newline at end of file diff --git a/packages/kbn-io-ts-utils/merge_rt/package.json b/packages/kbn-io-ts-utils/merge_rt/package.json deleted file mode 100644 index f7773688068e03..00000000000000 --- a/packages/kbn-io-ts-utils/merge_rt/package.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "main": "../target_node/merge_rt", - "types": "../target_types/merge_rt" -} \ No newline at end of file diff --git a/packages/kbn-io-ts-utils/non_empty_string_rt/package.json b/packages/kbn-io-ts-utils/non_empty_string_rt/package.json deleted file mode 100644 index 6348f6d7280599..00000000000000 --- a/packages/kbn-io-ts-utils/non_empty_string_rt/package.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "main": "../target_node/non_empty_string_rt", - "types": "../target_types/non_empty_string_rt" -} \ No newline at end of file diff --git a/packages/kbn-io-ts-utils/package.json b/packages/kbn-io-ts-utils/package.json index fb1179b06bf45a..2dc3532e05d966 100644 --- a/packages/kbn-io-ts-utils/package.json +++ b/packages/kbn-io-ts-utils/package.json @@ -1,7 +1,6 @@ { "name": "@kbn/io-ts-utils", "main": "./target_node/index.js", - "types": "./target_types/index.d.ts", "version": "1.0.0", "license": "SSPL-1.0 OR Elastic License 2.0", "private": true diff --git a/packages/kbn-io-ts-utils/parseable_types/package.json b/packages/kbn-io-ts-utils/parseable_types/package.json deleted file mode 100644 index 6dab2a5ee156e6..00000000000000 --- a/packages/kbn-io-ts-utils/parseable_types/package.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "main": "../target_node/parseable_types", - "types": "../target_types/parseable_types" -} \ No newline at end of file diff --git a/packages/kbn-io-ts-utils/props_to_schema/package.json b/packages/kbn-io-ts-utils/props_to_schema/package.json deleted file mode 100644 index 478de84d17f819..00000000000000 --- a/packages/kbn-io-ts-utils/props_to_schema/package.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "main": "../target_node/props_to_schema", - "types": "../target_types/props_to_schema" -} \ No newline at end of file diff --git a/packages/kbn-io-ts-utils/src/index.ts b/packages/kbn-io-ts-utils/src/index.ts index 88cfc063f738a9..a01e6c41d79d64 100644 --- a/packages/kbn-io-ts-utils/src/index.ts +++ b/packages/kbn-io-ts-utils/src/index.ts @@ -6,6 +6,8 @@ * Side Public License, v 1. */ +export type { NonEmptyStringBrand } from './non_empty_string_rt'; + export { deepExactRt } from './deep_exact_rt'; export { jsonRt } from './json_rt'; export { mergeRt } from './merge_rt'; diff --git a/packages/kbn-io-ts-utils/strict_keys_rt/package.json b/packages/kbn-io-ts-utils/strict_keys_rt/package.json deleted file mode 100644 index 68823d97a5d008..00000000000000 --- a/packages/kbn-io-ts-utils/strict_keys_rt/package.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "main": "../target_node/strict_keys_rt", - "types": "../target_types/strict_keys_rt" -} \ No newline at end of file diff --git a/packages/kbn-io-ts-utils/to_boolean_rt/package.json b/packages/kbn-io-ts-utils/to_boolean_rt/package.json deleted file mode 100644 index 5e801a65291531..00000000000000 --- a/packages/kbn-io-ts-utils/to_boolean_rt/package.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "main": "../target_node/to_boolean_rt", - "types": "../target_types/to_boolean_rt" -} \ No newline at end of file diff --git a/packages/kbn-io-ts-utils/to_json_schema/package.json b/packages/kbn-io-ts-utils/to_json_schema/package.json deleted file mode 100644 index 366f3243b1156f..00000000000000 --- a/packages/kbn-io-ts-utils/to_json_schema/package.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "main": "../target_node/to_json_schema", - "types": "../target_types/to_json_schema" -} \ No newline at end of file diff --git a/packages/kbn-io-ts-utils/to_number_rt/package.json b/packages/kbn-io-ts-utils/to_number_rt/package.json deleted file mode 100644 index f5da955cb97759..00000000000000 --- a/packages/kbn-io-ts-utils/to_number_rt/package.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "main": "../target_node/to_number_rt", - "types": "../target_types/to_number_rt" -} \ No newline at end of file diff --git a/packages/kbn-server-route-repository/BUILD.bazel b/packages/kbn-server-route-repository/BUILD.bazel index 103f15bbf5d6a6..a0e1cf41dcf8f1 100644 --- a/packages/kbn-server-route-repository/BUILD.bazel +++ b/packages/kbn-server-route-repository/BUILD.bazel @@ -38,7 +38,7 @@ RUNTIME_DEPS = [ TYPES_DEPS = [ "//packages/kbn-config-schema:npm_module_types", - "//packages/kbn-io-ts-utils", + "//packages/kbn-io-ts-utils:npm_module_types", "@npm//@hapi/boom", "@npm//fp-ts", "@npm//utility-types", diff --git a/packages/kbn-server-route-repository/src/decode_request_params.test.ts b/packages/kbn-server-route-repository/src/decode_request_params.test.ts index a5c1a2b49eb191..96035bc3e00112 100644 --- a/packages/kbn-server-route-repository/src/decode_request_params.test.ts +++ b/packages/kbn-server-route-repository/src/decode_request_params.test.ts @@ -5,7 +5,7 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ -import { jsonRt } from '@kbn/io-ts-utils/json_rt'; +import { jsonRt } from '@kbn/io-ts-utils'; import * as t from 'io-ts'; import { decodeRequestParams } from './decode_request_params'; diff --git a/packages/kbn-server-route-repository/src/decode_request_params.ts b/packages/kbn-server-route-repository/src/decode_request_params.ts index 4df6fa3333c503..00492d69b8ac5e 100644 --- a/packages/kbn-server-route-repository/src/decode_request_params.ts +++ b/packages/kbn-server-route-repository/src/decode_request_params.ts @@ -10,7 +10,7 @@ import { omitBy, isPlainObject, isEmpty } from 'lodash'; import { isLeft } from 'fp-ts/lib/Either'; import { PathReporter } from 'io-ts/lib/PathReporter'; import Boom from '@hapi/boom'; -import { strictKeysRt } from '@kbn/io-ts-utils/strict_keys_rt'; +import { strictKeysRt } from '@kbn/io-ts-utils'; import { RouteParamsRT } from './typings'; interface KibanaRequestParams { diff --git a/packages/kbn-typed-react-router-config/BUILD.bazel b/packages/kbn-typed-react-router-config/BUILD.bazel index d759948a6c5763..6f4e53e58fff76 100644 --- a/packages/kbn-typed-react-router-config/BUILD.bazel +++ b/packages/kbn-typed-react-router-config/BUILD.bazel @@ -37,7 +37,7 @@ RUNTIME_DEPS = [ ] TYPES_DEPS = [ - "//packages/kbn-io-ts-utils", + "//packages/kbn-io-ts-utils:npm_module_types", "@npm//query-string", "@npm//utility-types", "@npm//@types/jest", diff --git a/packages/kbn-typed-react-router-config/src/create_router.test.tsx b/packages/kbn-typed-react-router-config/src/create_router.test.tsx index ac337f8bb5b877..9837d45ddd8690 100644 --- a/packages/kbn-typed-react-router-config/src/create_router.test.tsx +++ b/packages/kbn-typed-react-router-config/src/create_router.test.tsx @@ -7,7 +7,7 @@ */ import React from 'react'; import * as t from 'io-ts'; -import { toNumberRt } from '@kbn/io-ts-utils/to_number_rt'; +import { toNumberRt } from '@kbn/io-ts-utils'; import { createRouter } from './create_router'; import { createMemoryHistory } from 'history'; import { route } from './route'; diff --git a/packages/kbn-typed-react-router-config/src/create_router.ts b/packages/kbn-typed-react-router-config/src/create_router.ts index 89ff4fc6b0c6cf..27a4f1dd5de023 100644 --- a/packages/kbn-typed-react-router-config/src/create_router.ts +++ b/packages/kbn-typed-react-router-config/src/create_router.ts @@ -15,8 +15,7 @@ import { } from 'react-router-config'; import qs from 'query-string'; import { findLastIndex, merge, compact } from 'lodash'; -import { mergeRt } from '@kbn/io-ts-utils/merge_rt'; -import { deepExactRt } from '@kbn/io-ts-utils/deep_exact_rt'; +import { deepExactRt, mergeRt } from '@kbn/io-ts-utils'; import { FlattenRoutesOf, Route, Router } from './types'; function toReactRouterPath(path: string) { diff --git a/x-pack/plugins/apm/common/environment_rt.ts b/x-pack/plugins/apm/common/environment_rt.ts index 67d1a6ce6fa648..dd07bb9f47318a 100644 --- a/x-pack/plugins/apm/common/environment_rt.ts +++ b/x-pack/plugins/apm/common/environment_rt.ts @@ -5,7 +5,7 @@ * 2.0. */ import * as t from 'io-ts'; -import { nonEmptyStringRt } from '@kbn/io-ts-utils/non_empty_string_rt'; +import { nonEmptyStringRt } from '@kbn/io-ts-utils'; import { ENVIRONMENT_ALL, ENVIRONMENT_NOT_DEFINED, diff --git a/x-pack/plugins/apm/public/components/routing/home/index.tsx b/x-pack/plugins/apm/public/components/routing/home/index.tsx index e70cb31eef88f0..25a68592d2b119 100644 --- a/x-pack/plugins/apm/public/components/routing/home/index.tsx +++ b/x-pack/plugins/apm/public/components/routing/home/index.tsx @@ -8,7 +8,7 @@ import { i18n } from '@kbn/i18n'; import { Outlet } from '@kbn/typed-react-router-config'; import * as t from 'io-ts'; import React from 'react'; -import { toBooleanRt } from '@kbn/io-ts-utils/to_boolean_rt'; +import { toBooleanRt } from '@kbn/io-ts-utils'; import { RedirectTo } from '../redirect_to'; import { comparisonTypeRt } from '../../../../common/runtime_types/comparison_type_rt'; import { ENVIRONMENT_ALL } from '../../../../common/environment_filter_values'; diff --git a/x-pack/plugins/apm/public/components/routing/service_detail/index.tsx b/x-pack/plugins/apm/public/components/routing/service_detail/index.tsx index 713292c6338912..f8206f273abd4c 100644 --- a/x-pack/plugins/apm/public/components/routing/service_detail/index.tsx +++ b/x-pack/plugins/apm/public/components/routing/service_detail/index.tsx @@ -8,7 +8,7 @@ import * as t from 'io-ts'; import { i18n } from '@kbn/i18n'; import React from 'react'; import { Outlet } from '@kbn/typed-react-router-config'; -import { toBooleanRt } from '@kbn/io-ts-utils/to_boolean_rt'; +import { toBooleanRt } from '@kbn/io-ts-utils'; import { comparisonTypeRt } from '../../../../common/runtime_types/comparison_type_rt'; import { ENVIRONMENT_ALL } from '../../../../common/environment_filter_values'; import { environmentRt } from '../../../../common/environment_rt'; diff --git a/x-pack/plugins/apm/server/routes/apm_routes/register_apm_server_routes.test.ts b/x-pack/plugins/apm/server/routes/apm_routes/register_apm_server_routes.test.ts index 371652cdab9576..c2391967f1cd29 100644 --- a/x-pack/plugins/apm/server/routes/apm_routes/register_apm_server_routes.test.ts +++ b/x-pack/plugins/apm/server/routes/apm_routes/register_apm_server_routes.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { jsonRt } from '@kbn/io-ts-utils/json_rt'; +import { jsonRt } from '@kbn/io-ts-utils'; import { createServerRouteRepository } from '@kbn/server-route-repository'; import { ServerRoute } from '@kbn/server-route-repository'; import * as t from 'io-ts'; diff --git a/x-pack/plugins/apm/server/routes/apm_routes/register_apm_server_routes.ts b/x-pack/plugins/apm/server/routes/apm_routes/register_apm_server_routes.ts index a7a43569236550..e84f97c70691ba 100644 --- a/x-pack/plugins/apm/server/routes/apm_routes/register_apm_server_routes.ts +++ b/x-pack/plugins/apm/server/routes/apm_routes/register_apm_server_routes.ts @@ -17,8 +17,7 @@ import { parseEndpoint, routeValidationObject, } from '@kbn/server-route-repository'; -import { mergeRt } from '@kbn/io-ts-utils/merge_rt'; -import { jsonRt } from '@kbn/io-ts-utils/json_rt'; +import { jsonRt, mergeRt } from '@kbn/io-ts-utils'; import { pickKeys } from '../../../common/utils/pick_keys'; import { APMRouteHandlerResources, TelemetryUsageCounter } from '../typings'; import type { ApmPluginRequestHandlerContext } from '../typings'; diff --git a/x-pack/plugins/apm/server/routes/backends/route.ts b/x-pack/plugins/apm/server/routes/backends/route.ts index 58160477994bdd..4f8d404fc529f6 100644 --- a/x-pack/plugins/apm/server/routes/backends/route.ts +++ b/x-pack/plugins/apm/server/routes/backends/route.ts @@ -6,7 +6,7 @@ */ import * as t from 'io-ts'; -import { toNumberRt } from '@kbn/io-ts-utils/to_number_rt'; +import { toNumberRt } from '@kbn/io-ts-utils'; import { setupRequest } from '../../lib/helpers/setup_request'; import { environmentRt, diff --git a/x-pack/plugins/apm/server/routes/correlations/route.ts b/x-pack/plugins/apm/server/routes/correlations/route.ts index 377fedf9d18133..af267cd7294ebd 100644 --- a/x-pack/plugins/apm/server/routes/correlations/route.ts +++ b/x-pack/plugins/apm/server/routes/correlations/route.ts @@ -9,7 +9,7 @@ import * as t from 'io-ts'; import Boom from '@hapi/boom'; import { i18n } from '@kbn/i18n'; -import { toNumberRt } from '@kbn/io-ts-utils/to_number_rt'; +import { toNumberRt } from '@kbn/io-ts-utils'; import { isActivePlatinumLicense } from '../../../common/license_check'; diff --git a/x-pack/plugins/apm/server/routes/default_api_types.ts b/x-pack/plugins/apm/server/routes/default_api_types.ts index b31de8e53dad2b..5622b12e1b099b 100644 --- a/x-pack/plugins/apm/server/routes/default_api_types.ts +++ b/x-pack/plugins/apm/server/routes/default_api_types.ts @@ -6,7 +6,7 @@ */ import * as t from 'io-ts'; -import { isoToEpochRt } from '@kbn/io-ts-utils/iso_to_epoch_rt'; +import { isoToEpochRt } from '@kbn/io-ts-utils'; export { environmentRt } from '../../common/environment_rt'; diff --git a/x-pack/plugins/apm/server/routes/errors/route.ts b/x-pack/plugins/apm/server/routes/errors/route.ts index f4e5ac172d5b04..2ead97f74d3736 100644 --- a/x-pack/plugins/apm/server/routes/errors/route.ts +++ b/x-pack/plugins/apm/server/routes/errors/route.ts @@ -5,8 +5,7 @@ * 2.0. */ -import { toNumberRt } from '@kbn/io-ts-utils/to_number_rt'; -import { jsonRt } from '@kbn/io-ts-utils/json_rt'; +import { jsonRt, toNumberRt } from '@kbn/io-ts-utils'; import * as t from 'io-ts'; import { createApmServerRoute } from '../apm_routes/create_apm_server_route'; import { getErrorDistribution } from './distribution/get_distribution'; diff --git a/x-pack/plugins/apm/server/routes/latency_distribution/route.ts b/x-pack/plugins/apm/server/routes/latency_distribution/route.ts index f30e98dd8c7b8f..675429df9df3f0 100644 --- a/x-pack/plugins/apm/server/routes/latency_distribution/route.ts +++ b/x-pack/plugins/apm/server/routes/latency_distribution/route.ts @@ -6,7 +6,7 @@ */ import * as t from 'io-ts'; -import { toNumberRt } from '@kbn/io-ts-utils/to_number_rt'; +import { toNumberRt } from '@kbn/io-ts-utils'; import { getOverallLatencyDistribution } from './get_overall_latency_distribution'; import { setupRequest } from '../../lib/helpers/setup_request'; import { createApmServerRoute } from '../apm_routes/create_apm_server_route'; diff --git a/x-pack/plugins/apm/server/routes/observability_overview/route.ts b/x-pack/plugins/apm/server/routes/observability_overview/route.ts index c99586638c3de6..b94fcf2f32a02a 100644 --- a/x-pack/plugins/apm/server/routes/observability_overview/route.ts +++ b/x-pack/plugins/apm/server/routes/observability_overview/route.ts @@ -6,7 +6,7 @@ */ import * as t from 'io-ts'; -import { toNumberRt } from '@kbn/io-ts-utils/to_number_rt'; +import { toNumberRt } from '@kbn/io-ts-utils'; import { setupRequest } from '../../lib/helpers/setup_request'; import { getServiceCount } from './get_service_count'; import { getTransactionsPerMinute } from './get_transactions_per_minute'; diff --git a/x-pack/plugins/apm/server/routes/rum_client/route.ts b/x-pack/plugins/apm/server/routes/rum_client/route.ts index 482dcc0799ed00..1b1b87f5d11985 100644 --- a/x-pack/plugins/apm/server/routes/rum_client/route.ts +++ b/x-pack/plugins/apm/server/routes/rum_client/route.ts @@ -6,7 +6,7 @@ */ import * as t from 'io-ts'; import { Logger } from 'kibana/server'; -import { isoToEpochRt } from '@kbn/io-ts-utils/iso_to_epoch_rt'; +import { isoToEpochRt } from '@kbn/io-ts-utils'; import { setupRequest, Setup } from '../../lib/helpers/setup_request'; import { getClientMetrics } from './get_client_metrics'; import { getJSErrors } from './get_js_errors'; diff --git a/x-pack/plugins/apm/server/routes/services/route.ts b/x-pack/plugins/apm/server/routes/services/route.ts index 2b7a71ba13acf8..de5f457f18deca 100644 --- a/x-pack/plugins/apm/server/routes/services/route.ts +++ b/x-pack/plugins/apm/server/routes/services/route.ts @@ -6,9 +6,7 @@ */ import Boom from '@hapi/boom'; -import { jsonRt } from '@kbn/io-ts-utils/json_rt'; -import { isoToEpochRt } from '@kbn/io-ts-utils/iso_to_epoch_rt'; -import { toNumberRt } from '@kbn/io-ts-utils/to_number_rt'; +import { isoToEpochRt, jsonRt, toNumberRt } from '@kbn/io-ts-utils'; import * as t from 'io-ts'; import { uniq } from 'lodash'; import { latencyAggregationTypeRt } from '../../../common/latency_aggregation_types'; diff --git a/x-pack/plugins/apm/server/routes/settings/agent_configuration/route.ts b/x-pack/plugins/apm/server/routes/settings/agent_configuration/route.ts index 26a9eaefc04135..b8245a8efaa94e 100644 --- a/x-pack/plugins/apm/server/routes/settings/agent_configuration/route.ts +++ b/x-pack/plugins/apm/server/routes/settings/agent_configuration/route.ts @@ -7,7 +7,7 @@ import * as t from 'io-ts'; import Boom from '@hapi/boom'; -import { toBooleanRt } from '@kbn/io-ts-utils/to_boolean_rt'; +import { toBooleanRt } from '@kbn/io-ts-utils'; import { maxSuggestions } from '../../../../../observability/common'; import { setupRequest } from '../../../lib/helpers/setup_request'; import { getServiceNames } from './get_service_names'; diff --git a/x-pack/plugins/apm/server/routes/source_maps/route.ts b/x-pack/plugins/apm/server/routes/source_maps/route.ts index b0b7eb5134fcf5..a60c59c03589dd 100644 --- a/x-pack/plugins/apm/server/routes/source_maps/route.ts +++ b/x-pack/plugins/apm/server/routes/source_maps/route.ts @@ -7,7 +7,7 @@ import Boom from '@hapi/boom'; import * as t from 'io-ts'; import { SavedObjectsClientContract } from 'kibana/server'; -import { jsonRt } from '@kbn/io-ts-utils/json_rt'; +import { jsonRt } from '@kbn/io-ts-utils'; import { createApmArtifact, deleteApmArtifact, diff --git a/x-pack/plugins/apm/server/routes/transactions/route.ts b/x-pack/plugins/apm/server/routes/transactions/route.ts index cad1c3b8f353b8..49c50f5a9100d1 100644 --- a/x-pack/plugins/apm/server/routes/transactions/route.ts +++ b/x-pack/plugins/apm/server/routes/transactions/route.ts @@ -5,8 +5,7 @@ * 2.0. */ -import { jsonRt } from '@kbn/io-ts-utils/json_rt'; -import { toNumberRt } from '@kbn/io-ts-utils/to_number_rt'; +import { jsonRt, toNumberRt } from '@kbn/io-ts-utils'; import * as t from 'io-ts'; import { LatencyAggregationType, diff --git a/yarn.lock b/yarn.lock index 2e4d6ddc987fb1..f840945352c913 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5864,6 +5864,10 @@ version "0.0.0" uid "" +"@types/kbn__io-ts-utils@link:bazel-bin/packages/kbn-io-ts-utils/npm_module_types": + version "0.0.0" + uid "" + "@types/kbn__mapbox-gl@link:bazel-bin/packages/kbn-mapbox-gl/npm_module_types": version "0.0.0" uid "" From 48693d1fd6d558465e93995328282e0788eb1319 Mon Sep 17 00:00:00 2001 From: Garrett Spong Date: Thu, 20 Jan 2022 18:47:36 -0700 Subject: [PATCH 108/108] [RAC][Alerting][Security Solution] Adds Rule Execution UUID (#113058) ## Summary Resolves: https://github.com/elastic/kibana/issues/110135 This PR is for introducing a new UUID (`kibana.alert.rule.execution.uuid` as defined in the AAD schema) for identifying individual rule executions. This id is introduced as a `private readonly` member of the [alerting server task_manager](https://github.com/elastic/kibana/blob/a993668663dd4fc25d3336e2d474101ed8d1b74d/x-pack/plugins/alerting/server/task_runner/task_runner.ts#L123), and plumbed through the `executionHandler` and to all appropriate alert event and event-log touch points. For persistence when writing alerts within the RuleRegistry, `kibana.alert.rule.execution.uuid` is plumbed through [`getCommonAlertFields()`](https://github.com/elastic/kibana/blob/c81341c325edcb0eaca1dab2521b2a86fea18389/x-pack/plugins/rule_registry/server/utils/get_common_alert_fields.ts#L52) so it is grouped with like fields and is picked up by both the [`createPersistenceRuleTypeWrapper`](https://github.com/elastic/kibana/blob/c81341c325edcb0eaca1dab2521b2a86fea18389/x-pack/plugins/rule_registry/server/utils/create_persistence_rule_type_wrapper.ts#L38) used by Security Solution, and [`createLifecycleExecutor`](https://github.com/elastic/kibana/blob/d152ca5b6bf7f56fcba1d1d8c2cfee5404a821de/x-pack/plugins/rule_registry/server/utils/create_lifecycle_executor.ts#L157) used by Observability rules. Additionally on the Security Solution side, `kibana.alert.rule.execution.uuid` was plumbed through the `RuleExecutionLog` so that all events written to the event-log will now include this id so individual rule status events/metrics can be correlated with specific rule executions. No UI facing changes were made, however `kibana.alert.rule.execution.uuid` is now available within the Alerts Table FieldBrowser, and can be toggled and viewed alongside alerts:

      As visible when exploring `event-log` in Discover:

      ### Checklist Delete any items that are not applicable to this PR. - [ ] [Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html) was added for features that require explanation or tutorials - Will need to sync with Doc folks on updates here. - [X] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios --- .../src/technical_field_names.ts | 3 + ...eate_alert_event_log_record_object.test.ts | 24 + .../create_alert_event_log_record_object.ts | 25 +- .../server/rules_client/tests/disable.test.ts | 4 + .../create_execution_handler.test.ts | 8 + .../task_runner/create_execution_handler.ts | 3 + .../server/task_runner/task_runner.test.ts | 445 ++++++++++++++++++ .../server/task_runner/task_runner.ts | 23 + .../task_runner/task_runner_cancel.test.ts | 88 ++++ x-pack/plugins/alerting/server/types.ts | 1 + .../metric_threshold_executor.test.ts | 1 + .../field_maps/technical_rule_field_map.ts | 5 + .../utils/create_lifecycle_rule_type.test.ts | 3 + .../server/utils/get_common_alert_fields.ts | 3 + .../server/utils/rule_executor_test_utils.ts | 1 + .../detection_alerts/alerts_details.spec.ts | 2 +- ...gacy_rules_notification_alert_type.test.ts | 1 + .../get_signals_template.test.ts.snap | 7 + .../routes/index/signals_mapping.json | 7 + .../routes/rules/preview_rules_route.ts | 1 + .../__mocks__/rule_execution_log_client.ts | 1 + .../rule_execution_events/events_writer.ts | 7 +- .../rule_execution_logger/logger.ts | 8 +- .../rule_execution_logger/logger_interface.ts | 1 + .../create_security_rule_type_wrapper.ts | 3 + .../factories/build_rule_message_factory.ts | 4 +- .../rule_types/factories/utils/build_alert.ts | 2 + .../detection_engine/signals/utils.test.ts | 1 - .../alert_types/es_query/alert_type.test.ts | 6 + .../index_threshold/alert_type.test.ts | 3 + .../common/lib/get_event_log.ts | 6 +- .../tests/alerting/event_log_alerts.ts | 19 + .../security_and_spaces/tests/create_ml.ts | 2 + .../spaces_only/tests/trial/create_rule.ts | 10 +- 34 files changed, 716 insertions(+), 12 deletions(-) diff --git a/packages/kbn-rule-data-utils/src/technical_field_names.ts b/packages/kbn-rule-data-utils/src/technical_field_names.ts index c6edd30549a76e..e49b47c7127803 100644 --- a/packages/kbn-rule-data-utils/src/technical_field_names.ts +++ b/packages/kbn-rule-data-utils/src/technical_field_names.ts @@ -47,6 +47,7 @@ const ALERT_RULE_CREATED_AT = `${ALERT_RULE_NAMESPACE}.created_at` as const; const ALERT_RULE_CREATED_BY = `${ALERT_RULE_NAMESPACE}.created_by` as const; const ALERT_RULE_DESCRIPTION = `${ALERT_RULE_NAMESPACE}.description` as const; const ALERT_RULE_ENABLED = `${ALERT_RULE_NAMESPACE}.enabled` as const; +const ALERT_RULE_EXECUTION_UUID = `${ALERT_RULE_NAMESPACE}.execution.uuid` as const; const ALERT_RULE_FROM = `${ALERT_RULE_NAMESPACE}.from` as const; const ALERT_RULE_INTERVAL = `${ALERT_RULE_NAMESPACE}.interval` as const; const ALERT_RULE_LICENSE = `${ALERT_RULE_NAMESPACE}.license` as const; @@ -103,6 +104,7 @@ const fields = { ALERT_RULE_CREATED_BY, ALERT_RULE_DESCRIPTION, ALERT_RULE_ENABLED, + ALERT_RULE_EXECUTION_UUID, ALERT_RULE_FROM, ALERT_RULE_INTERVAL, ALERT_RULE_LICENSE, @@ -156,6 +158,7 @@ export { ALERT_RULE_CREATED_BY, ALERT_RULE_DESCRIPTION, ALERT_RULE_ENABLED, + ALERT_RULE_EXECUTION_UUID, ALERT_RULE_FROM, ALERT_RULE_INTERVAL, ALERT_RULE_LICENSE, diff --git a/x-pack/plugins/alerting/server/lib/create_alert_event_log_record_object.test.ts b/x-pack/plugins/alerting/server/lib/create_alert_event_log_record_object.test.ts index a7a00034e70647..3895c90d4a6c20 100644 --- a/x-pack/plugins/alerting/server/lib/create_alert_event_log_record_object.test.ts +++ b/x-pack/plugins/alerting/server/lib/create_alert_event_log_record_object.test.ts @@ -25,6 +25,7 @@ describe('createAlertEventLogRecordObject', () => { test('created alert event "execute-start"', async () => { expect( createAlertEventLogRecordObject({ + executionId: '7a7065d7-6e8b-4aae-8d20-c93613dec9fb', ruleId: '1', ruleType, action: 'execute-start', @@ -50,6 +51,13 @@ describe('createAlertEventLogRecordObject', () => { kind: 'alert', }, kibana: { + alert: { + rule: { + execution: { + uuid: '7a7065d7-6e8b-4aae-8d20-c93613dec9fb', + }, + }, + }, saved_objects: [ { id: '1', @@ -76,6 +84,7 @@ describe('createAlertEventLogRecordObject', () => { test('created alert event "recovered-instance"', async () => { expect( createAlertEventLogRecordObject({ + executionId: '7a7065d7-6e8b-4aae-8d20-c93613dec9fb', ruleId: '1', ruleName: 'test name', ruleType, @@ -109,6 +118,13 @@ describe('createAlertEventLogRecordObject', () => { start: '1970-01-01T00:00:00.000Z', }, kibana: { + alert: { + rule: { + execution: { + uuid: '7a7065d7-6e8b-4aae-8d20-c93613dec9fb', + }, + }, + }, alerting: { action_group_id: 'group 1', action_subgroup: 'subgroup value', @@ -138,6 +154,7 @@ describe('createAlertEventLogRecordObject', () => { test('created alert event "execute-action"', async () => { expect( createAlertEventLogRecordObject({ + executionId: '7a7065d7-6e8b-4aae-8d20-c93613dec9fb', ruleId: '1', ruleName: 'test name', ruleType, @@ -176,6 +193,13 @@ describe('createAlertEventLogRecordObject', () => { start: '1970-01-01T00:00:00.000Z', }, kibana: { + alert: { + rule: { + execution: { + uuid: '7a7065d7-6e8b-4aae-8d20-c93613dec9fb', + }, + }, + }, alerting: { action_group_id: 'group 1', action_subgroup: 'subgroup value', diff --git a/x-pack/plugins/alerting/server/lib/create_alert_event_log_record_object.ts b/x-pack/plugins/alerting/server/lib/create_alert_event_log_record_object.ts index e06b5bf893bac1..95e33d394fbd2b 100644 --- a/x-pack/plugins/alerting/server/lib/create_alert_event_log_record_object.ts +++ b/x-pack/plugins/alerting/server/lib/create_alert_event_log_record_object.ts @@ -12,6 +12,7 @@ import { UntypedNormalizedRuleType } from '../rule_type_registry'; export type Event = Exclude; interface CreateAlertEventLogRecordParams { + executionId?: string; ruleId: string; ruleType: UntypedNormalizedRuleType; action: string; @@ -36,7 +37,18 @@ interface CreateAlertEventLogRecordParams { } export function createAlertEventLogRecordObject(params: CreateAlertEventLogRecordParams): Event { - const { ruleType, action, state, message, task, ruleId, group, subgroup, namespace } = params; + const { + executionId, + ruleType, + action, + state, + message, + task, + ruleId, + group, + subgroup, + namespace, + } = params; const alerting = params.instanceId || group || subgroup ? { @@ -59,6 +71,17 @@ export function createAlertEventLogRecordObject(params: CreateAlertEventLogRecor }, kibana: { ...(alerting ? alerting : {}), + ...(executionId + ? { + alert: { + rule: { + execution: { + uuid: executionId, + }, + }, + }, + } + : {}), saved_objects: params.savedObjects.map((so) => ({ ...(so.relation ? { rel: so.relation } : {}), type: so.type, diff --git a/x-pack/plugins/alerting/server/rules_client/tests/disable.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/disable.test.ts index a5b9f1d928e818..9c3e5872c76e1b 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/disable.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/disable.test.ts @@ -21,6 +21,10 @@ import { getBeforeSetup, setGlobalDate } from './lib'; import { eventLoggerMock } from '../../../../event_log/server/event_logger.mock'; import { TaskStatus } from '../../../../task_manager/server'; +jest.mock('uuid', () => ({ + v4: () => '5f6aa57d-3e22-484e-bae8-cbed868f4d28', +})); + const taskManager = taskManagerMock.createStart(); const ruleTypeRegistry = ruleTypeRegistryMock.create(); const unsecuredSavedObjectsClient = savedObjectsClientMock.create(); diff --git a/x-pack/plugins/alerting/server/task_runner/create_execution_handler.test.ts b/x-pack/plugins/alerting/server/task_runner/create_execution_handler.test.ts index 69b094585d7030..71ec12e29a9ddb 100644 --- a/x-pack/plugins/alerting/server/task_runner/create_execution_handler.test.ts +++ b/x-pack/plugins/alerting/server/task_runner/create_execution_handler.test.ts @@ -73,6 +73,7 @@ const createExecutionHandlerParams: jest.Mocked< spaceId: 'test1', ruleId: '1', ruleName: 'name-of-alert', + executionId: '5f6aa57d-3e22-484e-bae8-cbed868f4d28', tags: ['tag-A', 'tag-B'], apiKey: 'MTIzOmFiYw==', kibanaBaseUrl: 'http://localhost:5601', @@ -173,6 +174,13 @@ test('enqueues execution per selected action', async () => { "kind": "alert", }, "kibana": Object { + "alert": Object { + "rule": Object { + "execution": Object { + "uuid": "5f6aa57d-3e22-484e-bae8-cbed868f4d28", + }, + }, + }, "alerting": Object { "action_group_id": "default", "instance_id": "2", diff --git a/x-pack/plugins/alerting/server/task_runner/create_execution_handler.ts b/x-pack/plugins/alerting/server/task_runner/create_execution_handler.ts index 112cb949e3ad76..58f8089890c87a 100644 --- a/x-pack/plugins/alerting/server/task_runner/create_execution_handler.ts +++ b/x-pack/plugins/alerting/server/task_runner/create_execution_handler.ts @@ -36,6 +36,7 @@ export interface CreateExecutionHandlerOptions< > { ruleId: string; ruleName: string; + executionId: string; tags?: string[]; actionsPlugin: ActionsPluginStartContract; actions: AlertAction[]; @@ -83,6 +84,7 @@ export function createExecutionHandler< logger, ruleId, ruleName, + executionId, tags, actionsPlugin, actions: ruleActions, @@ -206,6 +208,7 @@ export function createExecutionHandler< ruleId, ruleType: ruleType as UntypedNormalizedRuleType, action: EVENT_LOG_ACTIONS.executeAction, + executionId, instanceId: alertId, group: actionGroup, subgroup: actionSubgroup, diff --git a/x-pack/plugins/alerting/server/task_runner/task_runner.test.ts b/x-pack/plugins/alerting/server/task_runner/task_runner.test.ts index 61d41e674c209f..a466583cd3bd39 100644 --- a/x-pack/plugins/alerting/server/task_runner/task_runner.test.ts +++ b/x-pack/plugins/alerting/server/task_runner/task_runner.test.ts @@ -41,6 +41,10 @@ import { UntypedNormalizedRuleType } from '../rule_type_registry'; import { ruleTypeRegistryMock } from '../rule_type_registry.mock'; import { ExecuteOptions } from '../../../actions/server/create_execute_function'; +jest.mock('uuid', () => ({ + v4: () => '5f6aa57d-3e22-484e-bae8-cbed868f4d28', +})); + const ruleType: jest.Mocked = { id: 'test', name: 'My test rule', @@ -323,6 +327,13 @@ describe('Task Runner', () => { "kind": "alert", }, "kibana": Object { + "alert": Object { + "rule": Object { + "execution": Object { + "uuid": "5f6aa57d-3e22-484e-bae8-cbed868f4d28", + }, + }, + }, "saved_objects": Array [ Object { "id": "1", @@ -484,6 +495,13 @@ describe('Task Runner', () => { kind: 'alert', }, kibana: { + alert: { + rule: { + execution: { + uuid: '5f6aa57d-3e22-484e-bae8-cbed868f4d28', + }, + }, + }, task: { schedule_delay: 0, scheduled: '1970-01-01T00:00:00.000Z', @@ -515,6 +533,13 @@ describe('Task Runner', () => { start: '1970-01-01T00:00:00.000Z', }, kibana: { + alert: { + rule: { + execution: { + uuid: '5f6aa57d-3e22-484e-bae8-cbed868f4d28', + }, + }, + }, alerting: { action_group_id: 'default', action_subgroup: 'subDefault', @@ -549,6 +574,13 @@ describe('Task Runner', () => { start: '1970-01-01T00:00:00.000Z', }, kibana: { + alert: { + rule: { + execution: { + uuid: '5f6aa57d-3e22-484e-bae8-cbed868f4d28', + }, + }, + }, alerting: { action_group_id: 'default', action_subgroup: 'subDefault', @@ -576,6 +608,13 @@ describe('Task Runner', () => { kind: 'alert', }, kibana: { + alert: { + rule: { + execution: { + uuid: '5f6aa57d-3e22-484e-bae8-cbed868f4d28', + }, + }, + }, alerting: { instance_id: '1', action_group_id: 'default', @@ -611,6 +650,13 @@ describe('Task Runner', () => { expect(eventLogger.logEvent).toHaveBeenNthCalledWith(5, { event: { action: 'execute', category: ['alerts'], kind: 'alert', outcome: 'success' }, kibana: { + alert: { + rule: { + execution: { + uuid: '5f6aa57d-3e22-484e-bae8-cbed868f4d28', + }, + }, + }, alerting: { status: 'active', }, @@ -707,6 +753,13 @@ describe('Task Runner', () => { schedule_delay: 0, scheduled: '1970-01-01T00:00:00.000Z', }, + alert: { + rule: { + execution: { + uuid: '5f6aa57d-3e22-484e-bae8-cbed868f4d28', + }, + }, + }, saved_objects: [ { id: '1', @@ -734,6 +787,13 @@ describe('Task Runner', () => { start: '1970-01-01T00:00:00.000Z', }, kibana: { + alert: { + rule: { + execution: { + uuid: '5f6aa57d-3e22-484e-bae8-cbed868f4d28', + }, + }, + }, alerting: { action_group_id: 'default', instance_id: '1', @@ -767,6 +827,13 @@ describe('Task Runner', () => { start: '1970-01-01T00:00:00.000Z', }, kibana: { + alert: { + rule: { + execution: { + uuid: '5f6aa57d-3e22-484e-bae8-cbed868f4d28', + }, + }, + }, alerting: { instance_id: '1', action_group_id: 'default', @@ -799,6 +866,13 @@ describe('Task Runner', () => { outcome: 'success', }, kibana: { + alert: { + rule: { + execution: { + uuid: '5f6aa57d-3e22-484e-bae8-cbed868f4d28', + }, + }, + }, alerting: { status: 'active', }, @@ -963,6 +1037,13 @@ describe('Task Runner', () => { "kind": "alert", }, "kibana": Object { + "alert": Object { + "rule": Object { + "execution": Object { + "uuid": "5f6aa57d-3e22-484e-bae8-cbed868f4d28", + }, + }, + }, "saved_objects": Array [ Object { "id": "1", @@ -998,6 +1079,13 @@ describe('Task Runner', () => { "start": "1969-12-31T00:00:00.000Z", }, "kibana": Object { + "alert": Object { + "rule": Object { + "execution": Object { + "uuid": "5f6aa57d-3e22-484e-bae8-cbed868f4d28", + }, + }, + }, "alerting": Object { "action_group_id": "default", "instance_id": "1", @@ -1033,6 +1121,13 @@ describe('Task Runner', () => { "outcome": "success", }, "kibana": Object { + "alert": Object { + "rule": Object { + "execution": Object { + "uuid": "5f6aa57d-3e22-484e-bae8-cbed868f4d28", + }, + }, + }, "alerting": Object { "status": "active", }, @@ -1302,6 +1397,13 @@ describe('Task Runner', () => { "kind": "alert", }, "kibana": Object { + "alert": Object { + "rule": Object { + "execution": Object { + "uuid": "5f6aa57d-3e22-484e-bae8-cbed868f4d28", + }, + }, + }, "saved_objects": Array [ Object { "id": "1", @@ -1337,6 +1439,13 @@ describe('Task Runner', () => { "start": "1970-01-01T00:00:00.000Z", }, "kibana": Object { + "alert": Object { + "rule": Object { + "execution": Object { + "uuid": "5f6aa57d-3e22-484e-bae8-cbed868f4d28", + }, + }, + }, "alerting": Object { "action_group_id": "default", "instance_id": "1", @@ -1373,6 +1482,13 @@ describe('Task Runner', () => { "start": "1970-01-01T00:00:00.000Z", }, "kibana": Object { + "alert": Object { + "rule": Object { + "execution": Object { + "uuid": "5f6aa57d-3e22-484e-bae8-cbed868f4d28", + }, + }, + }, "alerting": Object { "action_group_id": "default", "instance_id": "1", @@ -1407,6 +1523,13 @@ describe('Task Runner', () => { "kind": "alert", }, "kibana": Object { + "alert": Object { + "rule": Object { + "execution": Object { + "uuid": "5f6aa57d-3e22-484e-bae8-cbed868f4d28", + }, + }, + }, "alerting": Object { "action_group_id": "default", "instance_id": "1", @@ -1448,6 +1571,13 @@ describe('Task Runner', () => { "outcome": "success", }, "kibana": Object { + "alert": Object { + "rule": Object { + "execution": Object { + "uuid": "5f6aa57d-3e22-484e-bae8-cbed868f4d28", + }, + }, + }, "alerting": Object { "status": "active", }, @@ -1597,6 +1727,13 @@ describe('Task Runner', () => { "kind": "alert", }, "kibana": Object { + "alert": Object { + "rule": Object { + "execution": Object { + "uuid": "5f6aa57d-3e22-484e-bae8-cbed868f4d28", + }, + }, + }, "saved_objects": Array [ Object { "id": "1", @@ -1633,6 +1770,13 @@ describe('Task Runner', () => { "start": "1969-12-31T06:00:00.000Z", }, "kibana": Object { + "alert": Object { + "rule": Object { + "execution": Object { + "uuid": "5f6aa57d-3e22-484e-bae8-cbed868f4d28", + }, + }, + }, "alerting": Object { "instance_id": "2", }, @@ -1668,6 +1812,13 @@ describe('Task Runner', () => { "start": "1969-12-31T00:00:00.000Z", }, "kibana": Object { + "alert": Object { + "rule": Object { + "execution": Object { + "uuid": "5f6aa57d-3e22-484e-bae8-cbed868f4d28", + }, + }, + }, "alerting": Object { "action_group_id": "default", "instance_id": "1", @@ -1702,6 +1853,13 @@ describe('Task Runner', () => { "kind": "alert", }, "kibana": Object { + "alert": Object { + "rule": Object { + "execution": Object { + "uuid": "5f6aa57d-3e22-484e-bae8-cbed868f4d28", + }, + }, + }, "alerting": Object { "action_group_id": "recovered", "instance_id": "2", @@ -1742,6 +1900,13 @@ describe('Task Runner', () => { "kind": "alert", }, "kibana": Object { + "alert": Object { + "rule": Object { + "execution": Object { + "uuid": "5f6aa57d-3e22-484e-bae8-cbed868f4d28", + }, + }, + }, "alerting": Object { "action_group_id": "default", "instance_id": "1", @@ -1783,6 +1948,13 @@ describe('Task Runner', () => { "outcome": "success", }, "kibana": Object { + "alert": Object { + "rule": Object { + "execution": Object { + "uuid": "5f6aa57d-3e22-484e-bae8-cbed868f4d28", + }, + }, + }, "alerting": Object { "status": "active", }, @@ -2165,6 +2337,13 @@ describe('Task Runner', () => { "kind": "alert", }, "kibana": Object { + "alert": Object { + "rule": Object { + "execution": Object { + "uuid": "5f6aa57d-3e22-484e-bae8-cbed868f4d28", + }, + }, + }, "saved_objects": Array [ Object { "id": "1", @@ -2201,6 +2380,13 @@ describe('Task Runner', () => { "start": "1969-12-31T06:00:00.000Z", }, "kibana": Object { + "alert": Object { + "rule": Object { + "execution": Object { + "uuid": "5f6aa57d-3e22-484e-bae8-cbed868f4d28", + }, + }, + }, "alerting": Object { "action_group_id": "default", "instance_id": "2", @@ -2237,6 +2423,13 @@ describe('Task Runner', () => { "start": "1969-12-31T00:00:00.000Z", }, "kibana": Object { + "alert": Object { + "rule": Object { + "execution": Object { + "uuid": "5f6aa57d-3e22-484e-bae8-cbed868f4d28", + }, + }, + }, "alerting": Object { "action_group_id": "default", "instance_id": "1", @@ -2272,6 +2465,13 @@ describe('Task Runner', () => { "outcome": "success", }, "kibana": Object { + "alert": Object { + "rule": Object { + "execution": Object { + "uuid": "5f6aa57d-3e22-484e-bae8-cbed868f4d28", + }, + }, + }, "alerting": Object { "status": "active", }, @@ -2546,6 +2746,13 @@ describe('Task Runner', () => { "kind": "alert", }, "kibana": Object { + "alert": Object { + "rule": Object { + "execution": Object { + "uuid": "5f6aa57d-3e22-484e-bae8-cbed868f4d28", + }, + }, + }, "saved_objects": Array [ Object { "id": "1", @@ -2584,6 +2791,13 @@ describe('Task Runner', () => { "reason": "execute", }, "kibana": Object { + "alert": Object { + "rule": Object { + "execution": Object { + "uuid": "5f6aa57d-3e22-484e-bae8-cbed868f4d28", + }, + }, + }, "alerting": Object { "status": "error", }, @@ -2666,6 +2880,13 @@ describe('Task Runner', () => { "kind": "alert", }, "kibana": Object { + "alert": Object { + "rule": Object { + "execution": Object { + "uuid": "5f6aa57d-3e22-484e-bae8-cbed868f4d28", + }, + }, + }, "saved_objects": Array [ Object { "id": "1", @@ -2704,6 +2925,13 @@ describe('Task Runner', () => { "reason": "decrypt", }, "kibana": Object { + "alert": Object { + "rule": Object { + "execution": Object { + "uuid": "5f6aa57d-3e22-484e-bae8-cbed868f4d28", + }, + }, + }, "alerting": Object { "status": "error", }, @@ -2795,6 +3023,13 @@ describe('Task Runner', () => { "kind": "alert", }, "kibana": Object { + "alert": Object { + "rule": Object { + "execution": Object { + "uuid": "5f6aa57d-3e22-484e-bae8-cbed868f4d28", + }, + }, + }, "saved_objects": Array [ Object { "id": "1", @@ -2833,6 +3068,13 @@ describe('Task Runner', () => { "reason": "license", }, "kibana": Object { + "alert": Object { + "rule": Object { + "execution": Object { + "uuid": "5f6aa57d-3e22-484e-bae8-cbed868f4d28", + }, + }, + }, "alerting": Object { "status": "error", }, @@ -2924,6 +3166,13 @@ describe('Task Runner', () => { "kind": "alert", }, "kibana": Object { + "alert": Object { + "rule": Object { + "execution": Object { + "uuid": "5f6aa57d-3e22-484e-bae8-cbed868f4d28", + }, + }, + }, "saved_objects": Array [ Object { "id": "1", @@ -2962,6 +3211,13 @@ describe('Task Runner', () => { "reason": "unknown", }, "kibana": Object { + "alert": Object { + "rule": Object { + "execution": Object { + "uuid": "5f6aa57d-3e22-484e-bae8-cbed868f4d28", + }, + }, + }, "alerting": Object { "status": "error", }, @@ -3052,6 +3308,13 @@ describe('Task Runner', () => { "kind": "alert", }, "kibana": Object { + "alert": Object { + "rule": Object { + "execution": Object { + "uuid": "5f6aa57d-3e22-484e-bae8-cbed868f4d28", + }, + }, + }, "saved_objects": Array [ Object { "id": "1", @@ -3090,6 +3353,13 @@ describe('Task Runner', () => { "reason": "read", }, "kibana": Object { + "alert": Object { + "rule": Object { + "execution": Object { + "uuid": "5f6aa57d-3e22-484e-bae8-cbed868f4d28", + }, + }, + }, "alerting": Object { "status": "error", }, @@ -3358,6 +3628,13 @@ describe('Task Runner', () => { "kind": "alert", }, "kibana": Object { + "alert": Object { + "rule": Object { + "execution": Object { + "uuid": "5f6aa57d-3e22-484e-bae8-cbed868f4d28", + }, + }, + }, "saved_objects": Array [ Object { "id": "1", @@ -3393,6 +3670,13 @@ describe('Task Runner', () => { "start": "1970-01-01T00:00:00.000Z", }, "kibana": Object { + "alert": Object { + "rule": Object { + "execution": Object { + "uuid": "5f6aa57d-3e22-484e-bae8-cbed868f4d28", + }, + }, + }, "alerting": Object { "action_group_id": "default", "instance_id": "1", @@ -3429,6 +3713,13 @@ describe('Task Runner', () => { "start": "1970-01-01T00:00:00.000Z", }, "kibana": Object { + "alert": Object { + "rule": Object { + "execution": Object { + "uuid": "5f6aa57d-3e22-484e-bae8-cbed868f4d28", + }, + }, + }, "alerting": Object { "action_group_id": "default", "instance_id": "2", @@ -3465,6 +3756,13 @@ describe('Task Runner', () => { "start": "1970-01-01T00:00:00.000Z", }, "kibana": Object { + "alert": Object { + "rule": Object { + "execution": Object { + "uuid": "5f6aa57d-3e22-484e-bae8-cbed868f4d28", + }, + }, + }, "alerting": Object { "action_group_id": "default", "instance_id": "1", @@ -3501,6 +3799,13 @@ describe('Task Runner', () => { "start": "1970-01-01T00:00:00.000Z", }, "kibana": Object { + "alert": Object { + "rule": Object { + "execution": Object { + "uuid": "5f6aa57d-3e22-484e-bae8-cbed868f4d28", + }, + }, + }, "alerting": Object { "action_group_id": "default", "instance_id": "2", @@ -3536,6 +3841,13 @@ describe('Task Runner', () => { "outcome": "success", }, "kibana": Object { + "alert": Object { + "rule": Object { + "execution": Object { + "uuid": "5f6aa57d-3e22-484e-bae8-cbed868f4d28", + }, + }, + }, "alerting": Object { "status": "active", }, @@ -3643,6 +3955,13 @@ describe('Task Runner', () => { "kind": "alert", }, "kibana": Object { + "alert": Object { + "rule": Object { + "execution": Object { + "uuid": "5f6aa57d-3e22-484e-bae8-cbed868f4d28", + }, + }, + }, "saved_objects": Array [ Object { "id": "1", @@ -3678,6 +3997,13 @@ describe('Task Runner', () => { "start": "1969-12-31T00:00:00.000Z", }, "kibana": Object { + "alert": Object { + "rule": Object { + "execution": Object { + "uuid": "5f6aa57d-3e22-484e-bae8-cbed868f4d28", + }, + }, + }, "alerting": Object { "action_group_id": "default", "instance_id": "1", @@ -3714,6 +4040,13 @@ describe('Task Runner', () => { "start": "1969-12-31T06:00:00.000Z", }, "kibana": Object { + "alert": Object { + "rule": Object { + "execution": Object { + "uuid": "5f6aa57d-3e22-484e-bae8-cbed868f4d28", + }, + }, + }, "alerting": Object { "action_group_id": "default", "instance_id": "2", @@ -3749,6 +4082,13 @@ describe('Task Runner', () => { "outcome": "success", }, "kibana": Object { + "alert": Object { + "rule": Object { + "execution": Object { + "uuid": "5f6aa57d-3e22-484e-bae8-cbed868f4d28", + }, + }, + }, "alerting": Object { "status": "active", }, @@ -3848,6 +4188,13 @@ describe('Task Runner', () => { "kind": "alert", }, "kibana": Object { + "alert": Object { + "rule": Object { + "execution": Object { + "uuid": "5f6aa57d-3e22-484e-bae8-cbed868f4d28", + }, + }, + }, "saved_objects": Array [ Object { "id": "1", @@ -3881,6 +4228,13 @@ describe('Task Runner', () => { "kind": "alert", }, "kibana": Object { + "alert": Object { + "rule": Object { + "execution": Object { + "uuid": "5f6aa57d-3e22-484e-bae8-cbed868f4d28", + }, + }, + }, "alerting": Object { "action_group_id": "default", "instance_id": "1", @@ -3915,6 +4269,13 @@ describe('Task Runner', () => { "kind": "alert", }, "kibana": Object { + "alert": Object { + "rule": Object { + "execution": Object { + "uuid": "5f6aa57d-3e22-484e-bae8-cbed868f4d28", + }, + }, + }, "alerting": Object { "action_group_id": "default", "instance_id": "2", @@ -3950,6 +4311,13 @@ describe('Task Runner', () => { "outcome": "success", }, "kibana": Object { + "alert": Object { + "rule": Object { + "execution": Object { + "uuid": "5f6aa57d-3e22-484e-bae8-cbed868f4d28", + }, + }, + }, "alerting": Object { "status": "active", }, @@ -4044,6 +4412,13 @@ describe('Task Runner', () => { "kind": "alert", }, "kibana": Object { + "alert": Object { + "rule": Object { + "execution": Object { + "uuid": "5f6aa57d-3e22-484e-bae8-cbed868f4d28", + }, + }, + }, "saved_objects": Array [ Object { "id": "1", @@ -4080,6 +4455,13 @@ describe('Task Runner', () => { "start": "1969-12-31T00:00:00.000Z", }, "kibana": Object { + "alert": Object { + "rule": Object { + "execution": Object { + "uuid": "5f6aa57d-3e22-484e-bae8-cbed868f4d28", + }, + }, + }, "alerting": Object { "instance_id": "1", }, @@ -4116,6 +4498,13 @@ describe('Task Runner', () => { "start": "1969-12-31T06:00:00.000Z", }, "kibana": Object { + "alert": Object { + "rule": Object { + "execution": Object { + "uuid": "5f6aa57d-3e22-484e-bae8-cbed868f4d28", + }, + }, + }, "alerting": Object { "instance_id": "2", }, @@ -4150,6 +4539,13 @@ describe('Task Runner', () => { "outcome": "success", }, "kibana": Object { + "alert": Object { + "rule": Object { + "execution": Object { + "uuid": "5f6aa57d-3e22-484e-bae8-cbed868f4d28", + }, + }, + }, "alerting": Object { "status": "ok", }, @@ -4246,6 +4642,13 @@ describe('Task Runner', () => { "kind": "alert", }, "kibana": Object { + "alert": Object { + "rule": Object { + "execution": Object { + "uuid": "5f6aa57d-3e22-484e-bae8-cbed868f4d28", + }, + }, + }, "saved_objects": Array [ Object { "id": "1", @@ -4279,6 +4682,13 @@ describe('Task Runner', () => { "kind": "alert", }, "kibana": Object { + "alert": Object { + "rule": Object { + "execution": Object { + "uuid": "5f6aa57d-3e22-484e-bae8-cbed868f4d28", + }, + }, + }, "alerting": Object { "instance_id": "1", }, @@ -4312,6 +4722,13 @@ describe('Task Runner', () => { "kind": "alert", }, "kibana": Object { + "alert": Object { + "rule": Object { + "execution": Object { + "uuid": "5f6aa57d-3e22-484e-bae8-cbed868f4d28", + }, + }, + }, "alerting": Object { "instance_id": "2", }, @@ -4346,6 +4763,13 @@ describe('Task Runner', () => { "outcome": "success", }, "kibana": Object { + "alert": Object { + "rule": Object { + "execution": Object { + "uuid": "5f6aa57d-3e22-484e-bae8-cbed868f4d28", + }, + }, + }, "alerting": Object { "status": "ok", }, @@ -4506,6 +4930,13 @@ describe('Task Runner', () => { "kind": "alert", }, "kibana": Object { + "alert": Object { + "rule": Object { + "execution": Object { + "uuid": "5f6aa57d-3e22-484e-bae8-cbed868f4d28", + }, + }, + }, "saved_objects": Array [ Object { "id": "1", @@ -4596,6 +5027,13 @@ describe('Task Runner', () => { category: ['alerts'], }, kibana: { + alert: { + rule: { + execution: { + uuid: '5f6aa57d-3e22-484e-bae8-cbed868f4d28', + }, + }, + }, saved_objects: [ { rel: 'primary', type: 'alert', id: '1', namespace: undefined, type_id: 'test' }, ], @@ -4618,6 +5056,13 @@ describe('Task Runner', () => { outcome: 'failure', }, kibana: { + alert: { + rule: { + execution: { + uuid: '5f6aa57d-3e22-484e-bae8-cbed868f4d28', + }, + }, + }, saved_objects: [ { rel: 'primary', type: 'alert', id: '1', namespace: undefined, type_id: 'test' }, ], diff --git a/x-pack/plugins/alerting/server/task_runner/task_runner.ts b/x-pack/plugins/alerting/server/task_runner/task_runner.ts index b4fa5a1927fee5..9640dd9038ce76 100644 --- a/x-pack/plugins/alerting/server/task_runner/task_runner.ts +++ b/x-pack/plugins/alerting/server/task_runner/task_runner.ts @@ -8,6 +8,7 @@ import apm from 'elastic-apm-node'; import type { PublicMethodsOf } from '@kbn/utility-types'; import { Dictionary, pickBy, mapValues, without, cloneDeep } from 'lodash'; import type { Request } from '@hapi/hapi'; +import uuid from 'uuid'; import { addSpaceIdToPath } from '../../../spaces/server'; import { Logger, KibanaRequest } from '../../../../../src/core/server'; import { TaskRunnerContext } from './task_runner_factory'; @@ -106,6 +107,7 @@ export class TaskRunner< ActionGroupIds, RecoveryActionGroupId >; + private readonly executionId: string; private readonly ruleTypeRegistry: RuleTypeRegistry; private searchAbortController: AbortController; private cancelled: boolean; @@ -131,6 +133,7 @@ export class TaskRunner< this.ruleTypeRegistry = context.ruleTypeRegistry; this.searchAbortController = new AbortController(); this.cancelled = false; + this.executionId = uuid.v4(); } async getDecryptedAttributes( @@ -209,6 +212,7 @@ export class TaskRunner< ruleId, ruleName, tags, + executionId: this.executionId, logger: this.logger, actionsPlugin: this.context.actionsPlugin, apiKey, @@ -324,6 +328,7 @@ export class TaskRunner< updatedRuleTypeState = await this.context.executionContext.withContext(ctx, () => this.ruleType.executor({ alertId: ruleId, + executionId: this.executionId, services: { ...services, alertInstanceFactory: createAlertInstanceFactory< @@ -411,6 +416,7 @@ export class TaskRunner< if (this.shouldLogAndScheduleActionsForAlerts()) { generateNewAndRecoveredAlertEvents({ eventLogger, + executionId: this.executionId, originalAlerts, currentAlerts: alertsWithScheduledActions, recoveredAlerts, @@ -612,6 +618,7 @@ export class TaskRunner< ruleType: this.ruleType as UntypedNormalizedRuleType, action: EVENT_LOG_ACTIONS.execute, namespace, + executionId: this.executionId, task: { scheduled: this.taskInstance.runAt.toISOString(), scheduleDelay: Millis2Nanos * scheduleDelay, @@ -785,6 +792,13 @@ export class TaskRunner< this.ruleType.ruleTaskTimeout }`, kibana: { + alert: { + rule: { + execution: { + uuid: this.executionId, + }, + }, + }, saved_objects: [ { rel: SAVED_OBJECT_REL_PRIMARY, @@ -883,6 +897,7 @@ interface GenerateNewAndRecoveredAlertEventsParams< InstanceContext extends AlertInstanceContext > { eventLogger: IEventLogger; + executionId: string; originalAlerts: Dictionary>; currentAlerts: Dictionary>; recoveredAlerts: Dictionary>; @@ -911,6 +926,7 @@ function generateNewAndRecoveredAlertEvents< >(params: GenerateNewAndRecoveredAlertEventsParams) { const { eventLogger, + executionId, ruleId, namespace, currentAlerts, @@ -990,6 +1006,13 @@ function generateNewAndRecoveredAlertEvents< ...(state?.duration !== undefined ? { duration: state.duration as number } : {}), }, kibana: { + alert: { + rule: { + execution: { + uuid: executionId, + }, + }, + }, alerting: { instance_id: alertId, ...(group ? { action_group_id: group } : {}), diff --git a/x-pack/plugins/alerting/server/task_runner/task_runner_cancel.test.ts b/x-pack/plugins/alerting/server/task_runner/task_runner_cancel.test.ts index 3e3c3351a8e675..e24be639c7fcc2 100644 --- a/x-pack/plugins/alerting/server/task_runner/task_runner_cancel.test.ts +++ b/x-pack/plugins/alerting/server/task_runner/task_runner_cancel.test.ts @@ -32,6 +32,10 @@ import { Alert, RecoveredActionGroup } from '../../common'; import { UntypedNormalizedRuleType } from '../rule_type_registry'; import { ruleTypeRegistryMock } from '../rule_type_registry.mock'; +jest.mock('uuid', () => ({ + v4: () => '5f6aa57d-3e22-484e-bae8-cbed868f4d28', +})); + const ruleType: jest.Mocked = { id: 'test', name: 'My test rule', @@ -208,6 +212,13 @@ describe('Task Runner Cancel', () => { kind: 'alert', }, kibana: { + alert: { + rule: { + execution: { + uuid: '5f6aa57d-3e22-484e-bae8-cbed868f4d28', + }, + }, + }, saved_objects: [ { id: '1', @@ -236,6 +247,13 @@ describe('Task Runner Cancel', () => { kind: 'alert', }, kibana: { + alert: { + rule: { + execution: { + uuid: '5f6aa57d-3e22-484e-bae8-cbed868f4d28', + }, + }, + }, saved_objects: [ { id: '1', @@ -261,6 +279,13 @@ describe('Task Runner Cancel', () => { outcome: 'success', }, kibana: { + alert: { + rule: { + execution: { + uuid: '5f6aa57d-3e22-484e-bae8-cbed868f4d28', + }, + }, + }, alerting: { status: 'ok', }, @@ -437,6 +462,13 @@ describe('Task Runner Cancel', () => { kind: 'alert', }, kibana: { + alert: { + rule: { + execution: { + uuid: '5f6aa57d-3e22-484e-bae8-cbed868f4d28', + }, + }, + }, task: { schedule_delay: 0, scheduled: '1970-01-01T00:00:00.000Z', @@ -465,6 +497,13 @@ describe('Task Runner Cancel', () => { kind: 'alert', }, kibana: { + alert: { + rule: { + execution: { + uuid: '5f6aa57d-3e22-484e-bae8-cbed868f4d28', + }, + }, + }, saved_objects: [ { id: '1', @@ -491,6 +530,13 @@ describe('Task Runner Cancel', () => { outcome: 'success', }, kibana: { + alert: { + rule: { + execution: { + uuid: '5f6aa57d-3e22-484e-bae8-cbed868f4d28', + }, + }, + }, alerting: { status: 'active', }, @@ -553,6 +599,13 @@ describe('Task Runner Cancel', () => { kind: 'alert', }, kibana: { + alert: { + rule: { + execution: { + uuid: '5f6aa57d-3e22-484e-bae8-cbed868f4d28', + }, + }, + }, task: { schedule_delay: 0, scheduled: '1970-01-01T00:00:00.000Z', @@ -582,6 +635,13 @@ describe('Task Runner Cancel', () => { kind: 'alert', }, kibana: { + alert: { + rule: { + execution: { + uuid: '5f6aa57d-3e22-484e-bae8-cbed868f4d28', + }, + }, + }, saved_objects: [ { id: '1', @@ -609,6 +669,13 @@ describe('Task Runner Cancel', () => { start: '1970-01-01T00:00:00.000Z', }, kibana: { + alert: { + rule: { + execution: { + uuid: '5f6aa57d-3e22-484e-bae8-cbed868f4d28', + }, + }, + }, alerting: { action_group_id: 'default', instance_id: '1', @@ -642,6 +709,13 @@ describe('Task Runner Cancel', () => { start: '1970-01-01T00:00:00.000Z', }, kibana: { + alert: { + rule: { + execution: { + uuid: '5f6aa57d-3e22-484e-bae8-cbed868f4d28', + }, + }, + }, alerting: { action_group_id: 'default', instance_id: '1', @@ -666,6 +740,13 @@ describe('Task Runner Cancel', () => { kind: 'alert', }, kibana: { + alert: { + rule: { + execution: { + uuid: '5f6aa57d-3e22-484e-bae8-cbed868f4d28', + }, + }, + }, alerting: { instance_id: '1', action_group_id: 'default', @@ -697,6 +778,13 @@ describe('Task Runner Cancel', () => { expect(eventLogger.logEvent).toHaveBeenNthCalledWith(6, { event: { action: 'execute', category: ['alerts'], kind: 'alert', outcome: 'success' }, kibana: { + alert: { + rule: { + execution: { + uuid: '5f6aa57d-3e22-484e-bae8-cbed868f4d28', + }, + }, + }, alerting: { status: 'active', }, diff --git a/x-pack/plugins/alerting/server/types.ts b/x-pack/plugins/alerting/server/types.ts index 866c8665ddb658..93ee520c7126a7 100644 --- a/x-pack/plugins/alerting/server/types.ts +++ b/x-pack/plugins/alerting/server/types.ts @@ -90,6 +90,7 @@ export interface AlertExecutorOptions< ActionGroupIds extends string = never > { alertId: string; + executionId: string; startedAt: Date; previousStartedAt: Date | null; services: AlertServices; diff --git a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.test.ts b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.test.ts index 4bbbb355d573e1..a8289d5766cc5d 100644 --- a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.test.ts +++ b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.test.ts @@ -51,6 +51,7 @@ const initialRuleState: TestRuleState = { const mockOptions = { alertId: '', + executionId: '', startedAt: new Date(), previousStartedAt: null, state: { diff --git a/x-pack/plugins/rule_registry/common/assets/field_maps/technical_rule_field_map.ts b/x-pack/plugins/rule_registry/common/assets/field_maps/technical_rule_field_map.ts index d0feac5f8aa32f..c81329baad5727 100644 --- a/x-pack/plugins/rule_registry/common/assets/field_maps/technical_rule_field_map.ts +++ b/x-pack/plugins/rule_registry/common/assets/field_maps/technical_rule_field_map.ts @@ -107,6 +107,11 @@ export const technicalRuleFieldMap = { array: false, required: false, }, + [Fields.ALERT_RULE_EXECUTION_UUID]: { + type: 'keyword', + array: false, + required: false, + }, [Fields.ALERT_RULE_FROM]: { type: 'keyword', array: false, diff --git a/x-pack/plugins/rule_registry/server/utils/create_lifecycle_rule_type.test.ts b/x-pack/plugins/rule_registry/server/utils/create_lifecycle_rule_type.test.ts index d822d9316ad192..05a71677c7535e 100644 --- a/x-pack/plugins/rule_registry/server/utils/create_lifecycle_rule_type.test.ts +++ b/x-pack/plugins/rule_registry/server/utils/create_lifecycle_rule_type.test.ts @@ -119,6 +119,7 @@ function createRule(shouldWriteAlerts: boolean = true) { tags: ['tags'], updatedBy: 'updatedBy', namespace: 'namespace', + executionId: 'b33f65d7-6e8b-4aae-8d20-c93613dec9f9', })) ?? {}) as Record; previousStartedAt = startedAt; @@ -224,6 +225,7 @@ describe('createLifecycleRuleTypeFactory', () => { "kibana.alert.instance.id": "opbeans-java", "kibana.alert.rule.category": "ruleTypeName", "kibana.alert.rule.consumer": "consumer", + "kibana.alert.rule.execution.uuid": "b33f65d7-6e8b-4aae-8d20-c93613dec9f9", "kibana.alert.rule.name": "name", "kibana.alert.rule.producer": "producer", "kibana.alert.rule.rule_type_id": "ruleTypeId", @@ -251,6 +253,7 @@ describe('createLifecycleRuleTypeFactory', () => { "kibana.alert.instance.id": "opbeans-node", "kibana.alert.rule.category": "ruleTypeName", "kibana.alert.rule.consumer": "consumer", + "kibana.alert.rule.execution.uuid": "b33f65d7-6e8b-4aae-8d20-c93613dec9f9", "kibana.alert.rule.name": "name", "kibana.alert.rule.producer": "producer", "kibana.alert.rule.rule_type_id": "ruleTypeId", diff --git a/x-pack/plugins/rule_registry/server/utils/get_common_alert_fields.ts b/x-pack/plugins/rule_registry/server/utils/get_common_alert_fields.ts index 8b4daf30763f6a..db8c56f84b2c4c 100644 --- a/x-pack/plugins/rule_registry/server/utils/get_common_alert_fields.ts +++ b/x-pack/plugins/rule_registry/server/utils/get_common_alert_fields.ts @@ -11,6 +11,7 @@ import { ALERT_UUID, ALERT_RULE_CATEGORY, ALERT_RULE_CONSUMER, + ALERT_RULE_EXECUTION_UUID, ALERT_RULE_NAME, ALERT_RULE_PRODUCER, ALERT_RULE_TYPE_ID, @@ -26,6 +27,7 @@ import { ParsedTechnicalFields } from '../../common/parse_technical_fields'; const commonAlertFieldNames = [ ALERT_RULE_CATEGORY, ALERT_RULE_CONSUMER, + ALERT_RULE_EXECUTION_UUID, ALERT_RULE_NAME, ALERT_RULE_PRODUCER, ALERT_RULE_TYPE_ID, @@ -47,6 +49,7 @@ export const getCommonAlertFields = ( return { [ALERT_RULE_CATEGORY]: options.rule.ruleTypeName, [ALERT_RULE_CONSUMER]: options.rule.consumer, + [ALERT_RULE_EXECUTION_UUID]: options.executionId, [ALERT_RULE_NAME]: options.rule.name, [ALERT_RULE_PRODUCER]: options.rule.producer, [ALERT_RULE_TYPE_ID]: options.rule.ruleTypeId, diff --git a/x-pack/plugins/rule_registry/server/utils/rule_executor_test_utils.ts b/x-pack/plugins/rule_registry/server/utils/rule_executor_test_utils.ts index 10cce043fe3fda..08b1b0a8ecbf2a 100644 --- a/x-pack/plugins/rule_registry/server/utils/rule_executor_test_utils.ts +++ b/x-pack/plugins/rule_registry/server/utils/rule_executor_test_utils.ts @@ -79,4 +79,5 @@ export const createDefaultAlertExecutorOptions = < updatedBy: null, previousStartedAt: null, namespace: undefined, + executionId: 'b33f65d7-6e8b-4aae-8d20-c93613deb33f', }); diff --git a/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_details.spec.ts b/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_details.spec.ts index 7b9dd63c732516..964819164b315f 100644 --- a/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_details.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_details.spec.ts @@ -57,7 +57,7 @@ describe('Alert details with unmapped fields', () => { // This test needs to be updated to not look for the field in a specific row, as it prevents us from adding/removing fields it.skip('Displays the unmapped field on the table', () => { const expectedUnmmappedField = { - row: 82, + row: 83, field: 'unmapped', text: 'This is the unmapped field', }; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_rules_notification_alert_type.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_rules_notification_alert_type.test.ts index f064380cc4a13a..1d97b7a39779a4 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_rules_notification_alert_type.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_rules_notification_alert_type.test.ts @@ -39,6 +39,7 @@ describe('legacyRules_notification_alert_type', () => { payload = { alertId: '1111', + executionId: 'b33f65d7-b33f-4aae-8d20-c93613dec9f9', services: alertServices, params: { ruleAlertId: '2222' }, state: {}, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/index/__snapshots__/get_signals_template.test.ts.snap b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/index/__snapshots__/get_signals_template.test.ts.snap index e03e438650df91..b826ed83d34edb 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/index/__snapshots__/get_signals_template.test.ts.snap +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/index/__snapshots__/get_signals_template.test.ts.snap @@ -4164,6 +4164,13 @@ Object { "enabled": Object { "type": "keyword", }, + "execution": Object { + "properties": Object { + "uuid": Object { + "type": "keyword", + }, + }, + }, "false_positives": Object { "type": "keyword", }, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/index/signals_mapping.json b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/index/signals_mapping.json index 4f754ecd2d33a7..6df246d06760d7 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/index/signals_mapping.json +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/index/signals_mapping.json @@ -286,6 +286,13 @@ "enabled": { "type": "keyword" }, + "execution": { + "properties": { + "uuid": { + "type": "keyword" + } + } + }, "filters": { "type": "object" }, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/preview_rules_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/preview_rules_route.ts index 204c67bf6cf5ac..263aa9e54737de 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/preview_rules_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/preview_rules_route.ts @@ -170,6 +170,7 @@ export const previewRulesRoute = async ( statePreview = (await executor({ alertId: previewId, createdBy: rule.createdBy, + executionId: uuid.v4(), name: rule.name, params, previousStartedAt, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/__mocks__/rule_execution_log_client.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/__mocks__/rule_execution_log_client.ts index 22a41f356c226e..7cf82722c47ffd 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/__mocks__/rule_execution_log_client.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/__mocks__/rule_execution_log_client.ts @@ -23,6 +23,7 @@ const ruleExecutionLogClientMock = { const ruleExecutionLoggerMock = { create: (context: Partial = {}): jest.Mocked => ({ context: { + executionId: context.executionId ?? 'some execution id', ruleId: context.ruleId ?? 'some rule id', ruleName: context.ruleName ?? 'Some rule', ruleType: context.ruleType ?? 'some rule type', diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/rule_execution_events/events_writer.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/rule_execution_events/events_writer.ts index dad30e9cb5d88c..2869f1c2c82e86 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/rule_execution_events/events_writer.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/rule_execution_events/events_writer.ts @@ -24,6 +24,7 @@ export interface IRuleExecutionEventsWriter { } export interface BaseArgs { + executionId: string; ruleId: string; ruleName: string; ruleType: string; @@ -49,7 +50,7 @@ export const createRuleExecutionEventsWriter = ( let sequence = 0; return { - logStatusChange({ ruleId, ruleName, ruleType, spaceId, newStatus, message }) { + logStatusChange({ executionId, ruleId, ruleName, ruleType, spaceId, newStatus, message }) { eventLogger.logEvent({ '@timestamp': nowISO(), message, @@ -69,6 +70,7 @@ export const createRuleExecutionEventsWriter = ( execution: { status: newStatus, status_order: ruleExecutionStatusOrderByStatus[newStatus], + uuid: executionId, }, }, }, @@ -85,7 +87,7 @@ export const createRuleExecutionEventsWriter = ( }); }, - logExecutionMetrics({ ruleId, ruleName, ruleType, spaceId, metrics }) { + logExecutionMetrics({ executionId, ruleId, ruleName, ruleType, spaceId, metrics }) { eventLogger.logEvent({ '@timestamp': nowISO(), rule: { @@ -103,6 +105,7 @@ export const createRuleExecutionEventsWriter = ( rule: { execution: { metrics, + uuid: executionId, }, }, }, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/rule_execution_logger/logger.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/rule_execution_logger/logger.ts index f67aae472ef604..a3e14f9569e252 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/rule_execution_logger/logger.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/rule_execution_logger/logger.ts @@ -28,7 +28,7 @@ export const createRuleExecutionLogger = ( logger: Logger, context: RuleExecutionContext ): IRuleExecutionLogger => { - const { ruleId, ruleName, ruleType, spaceId } = context; + const { executionId, ruleId, ruleName, ruleType, spaceId } = context; const ruleExecutionLogger: IRuleExecutionLogger = { get context() { @@ -44,7 +44,7 @@ export const createRuleExecutionLogger = ( ]); } catch (e) { const logMessage = 'Error logging rule execution status change'; - const logAttributes = `status: "${args.newStatus}", rule id: "${ruleId}", rule name: "${ruleName}"`; + const logAttributes = `status: "${args.newStatus}", rule id: "${ruleId}", rule name: "${ruleName}", execution uuid: "${executionId}"`; const logReason = e instanceof Error ? e.stack ?? e.message : String(e); const logMeta: ExtMeta = { rule: { @@ -53,6 +53,7 @@ export const createRuleExecutionLogger = ( type: ruleType, execution: { status: args.newStatus, + uuid: executionId, }, }, kibana: { @@ -65,6 +66,7 @@ export const createRuleExecutionLogger = ( }, }; + // TODO: Add executionId to new status SO? const writeStatusChangeToSavedObjects = async ( args: NormalizedStatusChangeArgs ): Promise => { @@ -86,6 +88,7 @@ export const createRuleExecutionLogger = ( if (metrics) { eventsWriter.logExecutionMetrics({ + executionId, ruleId, ruleName, ruleType, @@ -95,6 +98,7 @@ export const createRuleExecutionLogger = ( } eventsWriter.logStatusChange({ + executionId, ruleId, ruleName, ruleType, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/rule_execution_logger/logger_interface.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/rule_execution_logger/logger_interface.ts index e31c10bd9747f4..874d60cf4a401a 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/rule_execution_logger/logger_interface.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_execution_log/rule_execution_logger/logger_interface.ts @@ -29,6 +29,7 @@ export interface IRuleExecutionLogger { } export interface RuleExecutionContext { + executionId: string; ruleId: string; ruleName: string; ruleType: string; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/create_security_rule_type_wrapper.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/create_security_rule_type_wrapper.ts index a643f428e58e7c..ba30b0335fb394 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/create_security_rule_type_wrapper.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/create_security_rule_type_wrapper.ts @@ -60,6 +60,7 @@ export const createSecurityRuleTypeWrapper: CreateSecurityRuleTypeWrapper = return withSecuritySpan('scurityRuleTypeExecutor', async () => { const { alertId, + executionId, params, previousStartedAt, startedAt, @@ -81,6 +82,7 @@ export const createSecurityRuleTypeWrapper: CreateSecurityRuleTypeWrapper = eventLogService, logger, { + executionId, ruleId: alertId, ruleName: rule.name, ruleType: rule.ruleTypeId, @@ -104,6 +106,7 @@ export const createSecurityRuleTypeWrapper: CreateSecurityRuleTypeWrapper = const buildRuleMessage = buildRuleMessageFactory({ id: alertId, + executionId, ruleId, name, index: spaceId, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/build_rule_message_factory.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/build_rule_message_factory.ts index 6ebc902db6992d..bac112bb3cab12 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/build_rule_message_factory.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/build_rule_message_factory.ts @@ -7,6 +7,7 @@ export type BuildRuleMessage = (...messages: string[]) => string; export interface BuildRuleMessageFactoryParams { + executionId: string; name: string; id: string; ruleId: string | null | undefined; @@ -15,12 +16,13 @@ export interface BuildRuleMessageFactoryParams { // TODO: change `index` param to `spaceId` export const buildRuleMessageFactory = - ({ id, ruleId, index, name }: BuildRuleMessageFactoryParams): BuildRuleMessage => + ({ executionId, id, ruleId, index, name }: BuildRuleMessageFactoryParams): BuildRuleMessage => (...messages) => [ ...messages, `name: "${name}"`, `id: "${id}"`, `rule id: "${ruleId ?? '(unknown rule id)'}"`, + `execution id: "${executionId}"`, `space ID: "${index}"`, ].join(' '); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/utils/build_alert.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/utils/build_alert.ts index 88b4ae01b3a64c..07f2dfa31015c4 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/utils/build_alert.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/factories/utils/build_alert.ts @@ -93,6 +93,8 @@ export const buildAncestors = (doc: SimpleHit): Ancestor[] => { * Builds the `kibana.alert.*` fields that are common across all alerts. * @param docs The parent alerts/events of the new alert to be built. * @param rule The rule that is generating the new alert. + * @param spaceId The space ID in which the rule was executed. + * @param reason Human readable string summarizing alert. */ export const buildAlert = ( docs: SimpleHit[], diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.test.ts index c620d51a833826..cae1019ae3f80c 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.test.ts @@ -663,7 +663,6 @@ describe('utils', () => { }, }, }; - const ruleExecutionLogger = ruleExecutionLogMock.logger.create(); mockLogger.warn.mockClear(); diff --git a/x-pack/plugins/stack_alerts/server/alert_types/es_query/alert_type.test.ts b/x-pack/plugins/stack_alerts/server/alert_types/es_query/alert_type.test.ts index 6b424adaa54aba..c0d05c44201fb9 100644 --- a/x-pack/plugins/stack_alerts/server/alert_types/es_query/alert_type.test.ts +++ b/x-pack/plugins/stack_alerts/server/alert_types/es_query/alert_type.test.ts @@ -140,6 +140,7 @@ describe('alertType', () => { const result = await alertType.executor({ alertId: uuid.v4(), + executionId: uuid.v4(), startedAt: new Date(), previousStartedAt: new Date(), services: alertServices as unknown as AlertServices< @@ -218,6 +219,7 @@ describe('alertType', () => { const result = await alertType.executor({ alertId: uuid.v4(), + executionId: uuid.v4(), startedAt: new Date(), previousStartedAt: new Date(), services: alertServices as unknown as AlertServices< @@ -369,6 +371,7 @@ describe('alertType', () => { const result = await alertType.executor({ alertId: uuid.v4(), + executionId: uuid.v4(), startedAt: new Date(), previousStartedAt: new Date(), services: alertServices as unknown as AlertServices< @@ -446,6 +449,7 @@ describe('alertType', () => { const executorOptions = { alertId: uuid.v4(), + executionId: uuid.v4(), startedAt: new Date(), previousStartedAt: new Date(), services: alertServices as unknown as AlertServices< @@ -559,6 +563,7 @@ describe('alertType', () => { const result = await alertType.executor({ alertId: uuid.v4(), + executionId: uuid.v4(), startedAt: new Date(), previousStartedAt: new Date(), services: alertServices as unknown as AlertServices< @@ -642,6 +647,7 @@ describe('alertType', () => { const result = await alertType.executor({ alertId: uuid.v4(), + executionId: uuid.v4(), startedAt: new Date(), previousStartedAt: new Date(), services: alertServices as unknown as AlertServices< diff --git a/x-pack/plugins/stack_alerts/server/alert_types/index_threshold/alert_type.test.ts b/x-pack/plugins/stack_alerts/server/alert_types/index_threshold/alert_type.test.ts index 7ab382ec77172e..f6b1c4a3a3b0a8 100644 --- a/x-pack/plugins/stack_alerts/server/alert_types/index_threshold/alert_type.test.ts +++ b/x-pack/plugins/stack_alerts/server/alert_types/index_threshold/alert_type.test.ts @@ -169,6 +169,7 @@ describe('alertType', () => { await alertType.executor({ alertId: uuid.v4(), + executionId: uuid.v4(), startedAt: new Date(), previousStartedAt: new Date(), services: alertServices as unknown as AlertServices<{}, ActionContext, typeof ActionGroupId>, @@ -230,6 +231,7 @@ describe('alertType', () => { await alertType.executor({ alertId: uuid.v4(), + executionId: uuid.v4(), startedAt: new Date(), previousStartedAt: new Date(), services: customAlertServices as unknown as AlertServices< @@ -295,6 +297,7 @@ describe('alertType', () => { await alertType.executor({ alertId: uuid.v4(), + executionId: uuid.v4(), startedAt: new Date(), previousStartedAt: new Date(), services: customAlertServices as unknown as AlertServices< diff --git a/x-pack/test/alerting_api_integration/common/lib/get_event_log.ts b/x-pack/test/alerting_api_integration/common/lib/get_event_log.ts index a4cc9d5139148c..3ee79291703381 100644 --- a/x-pack/test/alerting_api_integration/common/lib/get_event_log.ts +++ b/x-pack/test/alerting_api_integration/common/lib/get_event_log.ts @@ -16,7 +16,7 @@ interface EqualCondition { equal: number; } -function isEqualConsition( +function isEqualCondition( condition: GreaterThanEqualCondition | EqualCondition ): condition is EqualCondition { return Number.isInteger((condition as EqualCondition).equal); @@ -67,7 +67,7 @@ export async function getEventLog(params: GetEventLogParams): Promise= condition.gte) ) @@ -76,7 +76,7 @@ export async function getEventLog(params: GetEventLogParams): Promise event?.event?.action !== 'execute' ); + // Verify unique executionId generated per `action:execute` grouping + const eventExecutionIdSet = new Set(); + const totalUniqueExecutionIds = new Set(); + let totalExecutionEventCount = 0; + events.forEach((event) => { + totalUniqueExecutionIds.add(event?.kibana?.alert?.rule?.execution?.uuid); + if (event?.event?.action === 'execute') { + totalExecutionEventCount += 1; + eventExecutionIdSet.add(event?.kibana?.alert?.rule?.execution?.uuid); + expect(eventExecutionIdSet.size).to.equal(1); + eventExecutionIdSet.clear(); + } else { + eventExecutionIdSet.add(event?.kibana?.alert?.rule?.execution?.uuid); + } + }); + + // Ensure every execution actually had a unique id from the others + expect(totalUniqueExecutionIds.size).to.equal(totalExecutionEventCount); + const currentAlertSpan: { alertId?: string; start?: string; diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/create_ml.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/create_ml.ts index cb1c41852465f6..343db03c2ae27e 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/create_ml.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/create_ml.ts @@ -8,6 +8,7 @@ import expect from '@kbn/expect'; import { ALERT_REASON, + ALERT_RULE_EXECUTION_UUID, ALERT_RULE_NAMESPACE, ALERT_RULE_PARAMETERS, ALERT_RULE_UPDATED_AT, @@ -120,6 +121,7 @@ export default ({ getService }: FtrProviderContext) => { expect(signal._source).eql({ '@timestamp': signal._source['@timestamp'], + [ALERT_RULE_EXECUTION_UUID]: signal._source[ALERT_RULE_EXECUTION_UUID], [ALERT_UUID]: signal._source[ALERT_UUID], [VERSION]: signal._source[VERSION], actual: [1], diff --git a/x-pack/test/rule_registry/spaces_only/tests/trial/create_rule.ts b/x-pack/test/rule_registry/spaces_only/tests/trial/create_rule.ts index ac36bad1f595ba..be3146f34c30ef 100644 --- a/x-pack/test/rule_registry/spaces_only/tests/trial/create_rule.ts +++ b/x-pack/test/rule_registry/spaces_only/tests/trial/create_rule.ts @@ -9,6 +9,7 @@ import expect from '@kbn/expect'; import { ALERT_DURATION, ALERT_END, + ALERT_RULE_EXECUTION_UUID, ALERT_RULE_UUID, ALERT_START, ALERT_STATUS, @@ -187,7 +188,14 @@ export default function registryRulesApiTest({ getService }: FtrProviderContext) const alertEvent = afterViolatingDataResponse.hits.hits[0].fields as Record; - const exclude = ['@timestamp', ALERT_START, ALERT_UUID, ALERT_RULE_UUID, VERSION]; + const exclude = [ + '@timestamp', + ALERT_START, + ALERT_UUID, + ALERT_RULE_EXECUTION_UUID, + ALERT_RULE_UUID, + VERSION, + ]; const toCompare = omit(alertEvent, exclude);

      8w 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�i3L{~q@S(w8Srn4xQ45XM{JBl(&>OSf_5T!HE> zLSaD5H91$5k=5T6!&%2DBmksshS)0@wvz_Tt?ROD-8J>Zq9KLr*^whTDsGPJkRnYR zJ2CPW;Xko$;BKIr!I?eN8)mef^ErU+k1F5W+BsPE@``^SdjtM*Z^9m!K5G;KJRW(^ z6HjUJY4q#jX`(_$i#MEaTs~Tzaa80%1C03?n2r_9Aa2Z&ouYQ&0*&x%No+yWnCZhb z=G!ZI|L3x=F#c(N{pGgT@y-1rE|{?;f8F~ca7e&H3f~*f+U<&HwCJ;ci1Q-x@`-WE zP%SqPAX;_~33>LrV8}PR#R<*d@>k;vjI$}yZZ<(jlsn&togFdTA*n3rAvIi|D`nn6 z`~r1@GxajI^ZhOVD5cHpdKm{3q>%n-KDnDJR(k5E))&GSPQt9@s*%#!ISs9i<3;e~ zs@fF^IA#q2ayUaTc>|-^3d-8GK01l)_Bo(f0G1f^AnO@&E(@VXbbBl2TFxA_LU=NjWyU0dSr z^yzBXl~B32WVbmD%!9*|c2e4up;@EmyK0?3a{jwLTQc8QL=Y)_!g0&Z|RZ$d^Zvapvkr95P` zBMW_BkTV*-88xnN!$hLXixS@A`{!C2p08ZiB3||L6-5&^7dEd_lYrSg zNOf^k;}ZP-LyZ=1!#SV5KrgJ;%u&K!rD@F-nk#bmBn?F!Dszxc8sM40;^X=hg!n#0 zzRX80X(1WSnV@KWiF<3XDav9|cB^0;!WzOF{G5SoWSP(W@MC^y{R8b=2b(A)dc6z#6PjhppIusSnGWDP*=18aZJIHXAW zUbaTHs|({(9&^zp5U{%)#UAxB(m=rkWJ6anra{oD5JgtaIcOJS8RYsgF5#`0oCLu(pw|7|PH;@2SLz5<2YI2TOkY8@#*@e1( zxGphH@W;lIAn>q2n^_Fv?<3;10#N~ZY8HmgT5iJ@S0Scs4ZEDQPs9JB-3ZE>^5`H# zJwF)Ra1#Nfs62i=hS2t89``F9z9y4{<9b+>T}}2by^B3^*(0{>eJ5*zDoIWDPY$^F z^uXBm@!P=R05O8KPM2GT=P+6=rbK>9&$pIJcS!p`wx+ag__aN68*fcrj~PAgg{e8B z9NEO{3VggTY_P@ZD8<>oCTm@z#77}lb;E_3ZB?Tg27%^X_T9N7I93!^xt!|}R;ER- z3KBn|PM^DTcM{gI={!c7FZa=~ec=t`KuI2BFFoh=p7QliqERX3ud>Lg<1D)`^F6(< zXaoXDxh3G!Rjy~S{2UF}de?qI6jXs6x0w%R`duvDicX7Q%fsyv-k(5Qw!pmC$bSQE zLy%2btm%aTatAl#1VO(-xH6m@9%s4`%$3h`egV!vV)d+ z1ZFnjfRzYS3il5r#Na|GWbYV|*G!jJp677lIuA#{`w9gel3q|n$t1aMK6lk$5p2K{ z09lLib>^qM;{I5=FQvmZWY%-_{p-!S&izpz+S8?_JK9D?Yue4bMU>}ytF!(I>4imi zOD)rz#UD}{#ae?-0FDmud+hAxXa)RSta%D456lp~AzIeYu%h6pq5uj9SR5)8L($z= z(*xaYx6F`(5QERm)gaj8m%zdFr1aDV%?d{<3l^QHP18$eFV#@EN`%WHJrHsj6?`1T z3T~?M^w)W07;fx*)0V2eF)gm1Ypf;}{#pW*DcfN}Pe6-j^X_p69J;Le1%|TIoqoPJ zl5tL|zZgbpreQmQvz;43j-8udxI+O$Oq{k-&#F*dwU1Ym-`eSGuZdAK;@%1wl==v& zmzr;DK4>eaJV73OsTncdw((?irwlsO@Hcs0A=cJ^CF}fkNjgu8#sxX>Ah$B@q%%Oj zOG}aN4^%Q?GjhJK_CU%sMedaP`ZP8&g%v1j?lP^SM9U$d5x!~!TlX^sLRX+aW$xFy ze1P>&NP9>SdHcU1-n4yGOj#bS9$Rp;0myg}>;%84NP-YGF>6v8K~)%Pje@s|V$_xt z3K-#-uj|k@Cy~2sp&TP?p#H*}t#+J`tK0Wmv8VU{gzPr%6Z)^T+uhsuYD z%{)4S!GD){o1YuOTMMiHbrin;S9Ca{qkxk3He}?Guo*pc^%LI8we(8VgjwVEY80L_N^amj-m`LE%8>Tp>Z;f*rL2X#=4MM<2E^QA%>8Oo zogyej^AMVA4ej=s;EuH+x+6b>JbJ)Gzapeu~1JZxQ?{b6jyVd|2gNuGc>Ys8R za{ih#(iN?v!iVfUH3qvEsQeReKa$T7q5puUTJUvot{Vle+^WbRd;Wi<-GF~^x3)Ll zi{89HRypy1Lu+wWV8V{1u@4TY4gRQ9fb2SwH z>Y`E0JH|)U7_f%y1^%S)4)zV-%BLDU7L3yhx~BvJq>@Xu}gD zM+Mhrlv!wYl|?00M32|vmM(R$l;c{BPwcZIp;d2b? z(j2hyL{VTzWGH@y9FhZ<-lkQ6%bgIA{SY-g>b{YNY0^ic`m5OuJ~inL^ZQKA5mHe$ zu2`>#qz>Ra;^QtpZb*6^UfQTdaZ-m=zbC@`xNS*wLv-||{(kymM6S6j%eVCs1y97Yf-wYUz0Vo z7rB&;|4cx<{RZKYE|>5S77EW2PSoz-+5m&UMFtG6^xyNJ@8DpqH|0S7Td>=|$+|^7 z-nc4l{W!Tk@g!5-Lhd@Swvw&g^ zepjWyDONN@&lyXOY^M?-d?KVy9l$2@f=p;G+Mai;F4b#@w=wl!3BbRW#`kcamUVdV zTp^e=2qLxhefgBiQwE4heBn%x69Lt!eC#| z@!DXY^m}(9D46mJRHz)CyI$CLhMrgm7=uN^h_)_*T@+C}2j&0@Iu{;-Y`lzHnz^u6 zR1#DngfSKZR^2Cj;$Y*ZPau5?VSLf9sY&H>YG3FXNOmOIG+8$=o$?Aq_;vp1D4j%; z3P2qt(J`o_j4!~jwNpMUa~;uNAWr>Wha80}U+q~TCvR1R**44RPku#Xg!?v3tCDMQ=&9g6*6nMe3h2 zOkI|YDO!jdl}8M2VvR<@O>E7M?EQ(4{q-m3_MQ{q|B8Oo=lT`H>__${v3^TP*hq<3 z7<>T6gbMLxhrmghxQw%;@=G#lyaUadyW2LO_X_XbXC^Lpg%sVRM3D zxmxapte=oS?cEWCp_s9PQ%MzWbhg$`2R&1D`_5l*=1U2a0fo7X3Stz7d^>>YSCOQ@ z>l>~6`?(oGJaRMp?}MLXmm{+WHA^FiTlKh%DOq6@Z!pkU*#AG~M?#p&PTMu*il~k4kiS zIw~K{{-m>+)qUS5(A8r0;Ye-$AxM(P*Y>LG{?ymx?s!gVA4~M)xT4E>>vHjA-E6Hu zOB$22BDCp$$-(_UF}MScV;2BxXwO+2KW)${8@;K##rmUO+Ihoarhkdz?ZMejsSw|h zM0*Pkh6S5SiC723<7<7coGJURdWlmtzu$^%xP+=LQd##>5{eh5CHb9x&S+-njZ!;N z)YtjVZ(!tD$CAw6KN6fSWzUT@Ww43HTjT0iA9k*?R?Z2i%Fe*JUb6v3>lM)ACO1wQ zz6Z`(a$Rdv=5u_$rMV?k8J^VBieHSdIerV^90V%f%mhi*RxV3*iRw1qYk#0Lncrhx z?nIr7SZgK>sckB!8W0jQ`EZ?tGiyhx!zb6q$DRIYG2L0bG>&}vItESAKGZR{iMn)c z^qjQNohG5<GwAk*^9M;S&jyx^s+S@gd%RuAPHw=Qf9YAO#7wvWO=DN@$$aY4=M9_ zY2e*)PlJ}=_nw)=2}Bd>@3jsaua5Rl_>V6^JCk7lH#3I1#w&MVN-@C8%lP{Ea}1?W z_Elz+MAk8p{LFT^gXsr_M_S)6QKJKHpT{IcS>Qi#_$7J~e8n;I!SeJ#{LS`w-0`p- z>(3jvsUXRo|FQ)aoT)FhNPCdqO z(^8jKpSv?;$%a(NUu2Cf>31zQFzSTyB5u^* z9p-s}!x$T5!DZs4guGCb{9B3E7&?KNV81>4{ zJ8DIiYeJrk^sI=u2CgX~zaiVE0bI8EytcLCEYM+(<_nsZF6v; zYVp(P+y}h?%bbnENuNY8T-Y1p4UTmV?j15KQ4XsX-Kad=5%nqL+3RH2UZZTaBNs1C zZ~KT1{;xigLct6fj{ywVHd{tE=Jxi^rlVUQXz!C1HhAk+_R!9Wdl);dFY|7Oj z+~cMp!Ym9s43d;{20q)38r!-%tI63FJ0C=+!Asa$yT|tRcRzDd$#@(zyJ?SrabFZL zeb?euML4_hoHrJ%ntA8AQ2_+_wTr6U_`wB^d1V&;+#>{i5Ireoh=NQ5u&f)|N&izz!oCD?#pJiBL^7(5rp9LlmeD+2iMD8v} zISWK06bJK;*OyLs7nmWcJ%JP?Evx0^%(lF$@IObLWLS~}3_Mwly)aPH>~@>zdCtU5 zhqNC?{)D=40><-_v(SrffTKu#`a4RXpKYfTp4kKV;sWyq^M0R(Yp4ldQF*yniJv2% z%;<68EYiGnnLCG-bK_)bXs)_t)ZWUO*Jg9wK1t*46 z6Hd6=n|F+9G}B8+izU%PNNYrQNdnjR(+&-S7NR%;DRuLwn{juke`WIVARL&`TZKCp zw!@^y$7bTMw|kE&fg)_{0^y%lO+MHi>MKVy82H&3`GpDc`@Z50RyeXmqrQiFW8`t; z$Vaw!06bgR2-3Pi2+2y#q(|dI@$gqo^Z?l6ckM4q-#I~)Y9@bsw zuqgBH#BvhXCg0dP|5Zx($Dg>!g12K$L`=A>xb&)i!gKVvj_JRrjj1*&V~smrH*s0L zh1+i|b^GzNYS*X%qGhbiCC;0x)l?#k+4KZ3$V?008&uQ|{Lxz38vQN<2-+*3+c%k4kwZCwJ@Fe^84$h;KdW0NnBeB zR+J2ez3v(mEI4e7&SRrqh~7|mVOewgSNN}K8&|>nZ=)XY2li7fEu-vXI6fR1!09Lc=&?TeIsP1k2#r8Q3Nh~A5yFb_x#4+02;)9z@{%z$Is)qE zg_GyOIxUTZkErXDpMpQU+5kR`dznI_iiSWdSvlbrhoTX)nvfFKhD=&*AX~N`3YCcm zjtG(U2d3NGO#ZUTr?AaGPSv}T|Wl39m;#&cv>5 zA6ZC4xBv{s1FIS7xs9h@TgEZ`KO{Q>Q<1Ibd#ZSwp(5be9^WoR48$nE5c>;FuT zgibJBn&9rwB>RFqbqS6U_Oapb7;)ZvV7l~N1UOmFq0R!c_=S2RMI9c8>h)h+EjOYA z8?ZfBu>N=<8(ypiegxGa5G)8)EKu#_!n5GX-5@>2Ihskk8Sy+sEaLt-g+*d#ARbKV z-xRBJ9+ckKkw6_qxv)Qrt14^Vq3fg<}k%de9uoJxASi6q+!;Ii)b~!Rt4po$3$(2Tv*-P)7I&es|?pG+h5-s53?D8M}CVN z(~{M}(K8pz2`XJ9A>9(cbU|*uAYQ?2cD`QIBZ9W8a*aoYw_#tojV4`{6ceUCe*Bz) zSbywe|FYrqlj480P54!-+c)x0{3XVdxMLc8SdDY4a=-Im{cKMW%ncbgdg2`Bncy+y z`)XIc;Yg@$D!_OML@V2EdJLVvx2PA=8eu8=eCBc!agY#@2D(%Q7t~-4IR@TKzlRedW%|>NdIKw`kWZo&zvNe2v0ea zMq+;vhM9mGYuQoc%)ic?{pKhiAjgd6p(WPt-43EqmJuHm{ls2~fF%Q8JqD5Y+P8&{ zphORyNxfxM=A&HPLqKl$V4*%la?}9+Mfh?aSjdpfD`>TQM6#a zb40#cVpC#Bwxh|*bv7(FcH9BpULjNY?f_W6%cH!k3rww8W_Vr0x0Q#E%Hd~zK_AHe;M z?!RXeKo{&Hqd7GCg%y)vm}{CEp8)#D@0}2<0*~Dk{6JXQW0#)Od!9n2Zem#`M~O1v zm3BQ7)PUC93!_(_eTCXb&N`GI1HUs32+<`UTJv}Asq`Kz!_X8FV)Ss@{gAm>hd(U# z{`QerS|ZJ~kx3XgK0zum!Z7PH+ltTpE4)~S`4BYJ(=C? zQ&w#j4P&P!mPx4#ZB|NRodt4~IVR{l3jvIhTdl!q3bK%%5lGPT%u3%c)Jj2qT+LF% z^O+w{80Ce0&rJMYRBKPI>?lm(y8+%#^SpMJm5E&BFjYictFy%m#bDQurxDWt`#UxD zo+5e)#LYNqm>J$;1%#sqpJkr%)!B&hSwtU@_K(;fM-gyUAfS}9n?bZ{aj?=>urHwh zN}rvwu3XhqckRQl8CA2pnOU32u*p4oFre_dK|L&uSKRf+>AvO&X>Ni}`@c}*W|zma zvl&+k)oprNA0A#G1VCjq)fktmqT7G{z1E=`h zxKw&3eOajJKWMr-SKYIxHDq&`5ut6SQIUmf8WsiGs-r7|)` z-p)#xm|)suJzkdO4l6-j(4z0Au~J|Im;ZXidpPhMe;pm0F3LMn%DKI{!1xK`L!O+V zW?V4A;o*4@voyLbFFerl3IU$a zFFbRRuP!O9KQR)H!tRj2&d4i9Rq)sZ1KAbGmn5 zc|gty=jyN+?fh6iy}GjK;MP0QdX;ew_f`sn5-+sW&MJ9!gra zb*hDYY;E>B27_$V)&zL2$91Y5=k0y#P#ug2j|BnWD-xUL`o<4Bg}gNx>6fI=80WzV zxI>3Cx*EAx6-?6Tu`slH+PuvFBGa=$GQHvtnJ(*yt}&Dig6UrW4NN~Ku7_+v@tU)` zo{6&d@aW=y4V7LJ3u7J>+8A1I^Q8XR^uwE7BBBTF$Z_ zC^jDay4*b1m-i%D%nIGSoW2R+@-G=qh{ey7=*RUR@Gco>p-k>gq;H`{FZ_os z-w$0L5-teCvM*&#;Cd&QbYM!pN56i1Tk{g=j9K_pF87~wIc5GQGU$Kk@}PR+#kRy4 zmj=xtsXKB*{TF+3czcg`Wnki7YNJIHbEeDfqSvZPs-HC!F2MPaUftC+w>>PwU2Hjr z&G|NPG7O;z1{19_`t+3~IwhbNGe08dY-dzMxvLkF@gPh!(ZV()|D~Syq0B<}h-COP z#pw^dyK@_l{R$$*W%rUkbE9=xyaoG`lHpM&@AvOD4crgXh*F_R=8b+&!{0yrn&IUc zuC#@nT;Aq`P6V744Qov-xNO{W?;h7#=J_?}=ey04+0tY54btV{ZD-ljJ)2RtaVZmd ze=1}n4a0FwNtq4ABg=}2Nu$;#jBX&%Y*zmRlLs;?X%hb@Og_XX|G$FCM-QbRW^Ms- zu#xDFoc0AE{FIb|p=U9Oo0+t|;pEnnf|)lUE$)Qxm)yLmgmjp!p(0l1t^+z(PV_xr za#nx=*pwfs<+6dFS!-imZ$1XjlNvbE~e|Ok$Bb``PYb&iR90v(7E8`=QHYiNas}e!ETnra@$JPOA_@xTHhu&+*rZ2j#d! z7cGqNk`66v#2X7o)B~bxY_EwUfBY-{8l@6Am^`Y?2K2GrA%BYc)}7PJn%L)wJL2ITibydVmJl zJs2O(-b=}X|8^oP%=&~e7OV05llLs_0I{aVZ>dwez7igK0v{!Y8N#p8@V{j&W6&q zV4&p7NIR2s6}3TjfUcnLPCxW%fez{m3}KdPk_OR|)F@K$+bL3E7Qt_$!?VXtgR&*w z3$`LTx~>7U!Yl-M=e1N`yD}^-9g=w+_$?aWTPOEJ7QYey3qD^wKCSp(U2b`PvZ|Sf zSDO56Ga95=7Lr|8mHnq#_Y37voG7}JF%zya=73D{KIj?SrdQrlCr9uUkY1P{^SLJ9 z{vt0Mh;L@Z3IcbgHJNx1A7#Z%D{n85@hgH6NR4W)3sJ**F6bq@jnrB3OIixb;3dW4 z6OLg}xEMMrv15>8dYU_AF+i?5%^k&U;pvjZ_Wg2$uqpU`in4P2UHrmR1I6I*T{?YN>S{W@I0a?%wwEFF7OjAg9` zmGn$EjhwVDH+A)It(OQ{LFbK45GMC)Y=+%rRzC z%7I!wz(DM!=~sshjVyKzNX8zUoD6Z`&LuS?WQH8Lkz~^ay4u_gPj$Ijymgh{wYBmk zFGWDvO(ndI4`46)NG%iG^4`Gj-8+xYMFxrVA=?NFB#U&}O=@EcGB{e7vAM7q#!6d` zej3{CQyB7w`47iWqmYXWFaipf)-Kh31GIzj)hrlDK6SPA#Vg<&@=E8ktpE|I~Bpko9a-4l70OML6tdn`Q(+q3;q|&D|N7n@y`E zXO6L>5%DcFQnge@RoLk`kLc`J)6LgXafrx^)jaKsX-yZ5XeMpe>}qF z8B^ty#``0Wv}x;bA^DPw{nspHHn{6=;XIv0Pbr2vR&OJNtqk=(NFFB0=l!qE&UOki zySf)j&txureV3Q_5Sq=yHRR(9dg$zHP_+ZdNtcCLr($mxu`|X@^Jt#vdcm+1B3}%} zB_dol@&!CgLywXFN<)8`n|eR`x#m7C>_5ODlvmMWtzXW|4)s6s2^G`(@;P?0RRT7JLVBHgvK`q~J4~_YQF+Z5<&LQS~s{obOec zN-zofkH)U->Rv6>5}MFnKncPagopxaPJKW7I(kf+p6_CT?DV72zu4*JMXNvTbPVS+ zJI&toQNu0&DMIu!odHHExNEb*rK5@lk9}{^09Ay5i;~WQr%%63fn7>Pc8*Xo* z#4&f|+22}2u+z(LNf-1CSpcR`?=@(bA2=lri?J&pRNJn<&YQ~W!x-JP3YDN|6ExmBp3H0IS4J2ECDXyoxGftj0eQHxX zSRu&2`ob!J`0Wqi(`;K5^BIXzT8W6JOx!gQawyijOhpmRU}bA&l}{%J+$r$|S*f_p znTBKPqL;W#iXJc_g3+jTQfuG-lF0`5FaDCr?Ud=;XLi>U6CI;B`7fxU13|WwoPHdN zxsDVfP$fT5rO4&YFlJISeZUvN(7fRI>Q`n?^ni@r4z92=6zX#i80x*J$1oYG^=kH2 zC=E6OWudFH>AE>*toc~9AWgE zd%EizHr3Y@aig>j#l`ksqLyEOY%Q##ZJ=yCbI%(;ew=*1E(9Jfi+*3j{R1Zhf9d3G zT&??;|3N1I2bi4u=7iW+7dMliZnX01_nTid^Ie%nh zAh$B$0VFU|Wu?17+L-*AjiZiqD3InHlT&p0z4TQxszF!i)Sa+nZwDS#VH7hv#Zk=J zm8w7KBLLC=$F7MR=^)8giUaxAuG!`#z`r8sWi90D)&#P~C_(doSYupK3#iX^N)2Txk|_bvLfkYXIeCFK{#QahETTWXu3HQ_vI7!+Xr_>O^^#v zY^Qf@qGR_B#_FJNC7wV}SWqWJT@W*Vg^M3N2Pnp*yeGd&b6F=vne=zjJdW+)%@r=|#X#UQ>yl}ntcjfLB_=^e4V9J4*uxr3!ggs{HD*FW- zKQp=yFfLCbV>lRIakVf@5fSz&z@P8+Nny!M>jlUO%fdB-obX>vSmxCJ6#q>{mfi{( zDRhND-}B=7)7xLHD$e8nI`wM@uBqjqs+Wg0YBXG1L)_d!45du3SQvMa2S$={L1DGJ z;o=!TSAtatmW_a0Sog9ydcWf*ZBDM3@wx`Beaq|VHzMX}^ zsLaa2#>o8m%AN})N&VT7+oQ?9*Qc?iDd!N=PWKRbJf5OoRT)=6VJBxeLrE06BM zgftTkXL*^`cQKRsVyUypYEgIl=+A299Tr zCM(QF&?%59o*&F7#)a+;Nl|0ay!GLCzlH)TiJv#f;IM03`Pi8c#$p>THfnugEmp7=_P(+i-X2xTAGNb5>>|y;rEmFh7jF&_);{mHFgV3 zuE-|y(SA>t{h_+jraNs!bhQ${Fq*!aXJ)lAtA&BQvt8+0WqIQ~Hi(UyY_NzHl`-2I z(v&tN$LIa#k-|Q9>xTTlP~{VCAXA^%Ham-C=4*hdOxO!|xy7v|5=5EHsbe9*e|kTn&-YI-BO(Dt0Wy}(orD}38{l^cR;lHjjv5_ z-p)sQ#k{LYSy~w@*-N$!*wI)kkF$j49^_J4S%0=C<1tU~dYaB-7w=T>dw;gs#^P_V z{moa!j$yG3Z}oell=34*Gc@!GL9KNZ#V5|OUVQV5=)(m1MR~Zxsj0C;ObwWL6jz2R zwKq`0M4GCbJ$S)^Vmupl!vJKDgZAabz|;4`rnT{_aV!Ud*X3-n7umSftPGP|+ybjV z#5AmLI7hI6N3g?CR^HA11OgWyWemm$VOlTSI!r27*_u=YcclnBUGpnS;(X#11^WMn zSKds0a(j&V1uUHM{F}V;f8xsX-=DsYzMay+Ssi`hUo~P)g>dW!{{wTXm{(l-+fRdx z{|#Ly(37xwbX+|=e0(`DfG1ota!9^W_K`&|?pHE*0J^apQc^eAI!)B8m18gnVeA}G zgI#9!K^rc3K#GAC37so|m7+YNM+D!k+za*ZEHy{}+~MsTm17uVZ+G(&+)BLCb)nR5 z2`^@q1NiqyBwZJ}iDH^wO8wim@ z*>0vMwoyL5K6u@ZWR`MG&2FaT{~cdv$(_h=>ZLU+5>kjd51mWhBZTsW`JDxouiF^N zQ}ZFmwI~K}0pyWI1nvQ1ngsYfb9QO#kHM3ruvGN$VBEw4JGjoXeJAvIJezaQy|Tau zWm{I^r|h6Sm4tqoRuYy#nl)i>g(3bHdFIj}BYY4}c}i;=W%9e2f3Vr1#->d{27lC| z?Aco%RP;1=7`N-OT(nM-mFuSpLFfSWd2@3esPbZUfH;4KXXD}gn+l%G=>lUPC%Jm8 z&*j)3@pPlPpmj~)G(*fTs+r~g%+G=i1@A)0L;ex+nGmKH>d+v6W`qOi!qWU^rIX7T zV!ogZ|K5G2ia`)G0{M?3Gju@@SN_*dZI@%6&!)FU>J=YN_Dq)V#XfUITl%daz=kFD5`Z z17%qUeb!;F`n!ta(_l+VCHzE8K+DAPRzYs&f_0HRX_HqW(l_3b_&ssopUd-bcm!!wA%#CZL>rJqr!jTz{l zg_nd=&%(=y?41+2%js;dyRFr=A3`yRJx-%isgPDtCr6*ZwVPF=ROlvWwDAb$j*fJ* zCBi!WL4B3d&ih~Ldxq))({zt6H-R%`*{*bJE0G9nF*CDy2L65-%tVR@n#bCO?k_pI zu}$+4l~Y5Gq$Fbhz`lXbXfTq9C5LZZNg|e2yLkqP+ZL1B+)6kvD=owj#!p)eW_{a? zb-r1I(;0dlU?RJlW z&QXR=6^&B7$&Ts~=Kbu6B}qh>er}uXJ)ah%*OqnC<60Feu`2OU#vTV=)v7>)OR1Zy z9sB)wv9Ek%Cf@ElVzQhylr2H~cS;?pTW>;bUZ#8;I>$LYi9M0a&6!^R7PNvL6#ZJ^ z*u7BRtfmpgJp$NCsxo?f)mEjO;wxVg8^zsO<(cFlYFgxb{f^G9!q+m3`y*3E=W1=S z@;8UB`^%p8m+R1dx!I1hO^xexd)K~?*j&qvk<&{-?<#$IgUaY~6L~NgDyh}Jl#zK3 zxv#&=jdj7e7KtgA4PS3~Qn-7iq{wpIxjLu3T~hCNITr@h`xb_02w>W+^JL%2-z5>? zMIGCwqlFltpjtlA!g6FWez~E&IKzB0y<7H191(Ask4S^lJ`}o8;jzlK!1on(-O7-$fMOlnze z7k~ojB?!}zVI~>;vI?}W9menK+_8kqK6#EY`8%mkF(^RHng`=C_|uxfEn>h-62K^> zY=~_k+$=y@-JK~4)ej)$IToBJzAAzkK@TSmi5tKWPE5lrits1*w|;s7qXe!vWmpM( zJgi#B(5{IXyyS4OI&g$Bs1RcrlZ28tFphvzFa`elM&t?RmV^Gb{+lNlvHD&RVB~yC z{2nlmxIF=zD5QOt@{vsSNo>*l5-DD2t4Q=p^?H^)^KN(xW@f@-+2Q|MNI+N+@CN$uq zpGiQo!jX>E6$dTGG!wd#5a(|$_^WC3fg3)Z7b^H4_y?Sjlpgzuhm56<2)Dz2_!u%vKzcXx;2 z?k<4@C%7cId*SX@g*$}c79dD)cXtgC+#zVDc%Jv`?zQHdp6U5hKUfQ@sJi!_Tj%Vv z_rdD>5b;aOKRnR4u61+jYDD;J) zGodCEkoOT|g_Mkh%Xef);N8dJKK*A)X5Z9y<+ zZ(kVbg`9^TF=4I~7?BVB3&2KSd#FJ+eq>%of)wfQp-VqXJ+9 zzzQt!f}4XcCk*s9kL8RS&%d&TGXo*#f5o3Dfw*@YgqZ()K9^crfcNlIgsWvXom-iI*GS=lp=+N21h6Z?B;6qcVZ#wswZx zkNOc=o_oMMF{N?#98aAQiMh$EEUyoXPl!B)0LUIgb$ph*JPNfJ+@7i*=IFOP(RJpm zoL}>Z#MQ712S~q>p5 zF0kGCzxv&3S$xeSbY*;gcx@NhMluJlnu{wkUX@YgBuKm+ctel_uN!(a@A~tmG59$O zIZ@mfZzxY{Oz(A0G+oY}MHHY zI3MWA_jI9uJCXKE#`9b^8&t_DkYfy7NSa(I|5Q2|H(?U5UKSg#(EaC%h%LH)7md@F zKJS-uFQe%>TXooO<2iFhgl#3kUiLIoIz~6qC<0E&mvDyT!86262l(q6#R2aDqEoS= z!vR~1IR1eAd;Wnf`K&c7zNdejxD0Pj+)d-Wf!)V}v>mrT15m_1R5T7XaBlwCWxwEO zw=F77P2gOe&1=4ui@xi7-TC6XH|cU=&ilTTvVeS(`py)B$N_wBNu-C(-$}QA>@`wP zzuI`{`<-cXSQLg(-B15W0>OQqlrVs?%DmBlZ`#QX(DZV3J9jL(T=Ot<{@A!&w>+bv zV5Imt4i6g39Y%3$GgYqa9SyBMq(VXGhOY@ONdaj;Cz;_F{5mH3&BvLc_g>7#|KmTB zNWq2A%wBre3fB|%T;ma2#o%W4A2BX%4yujowhfQDD3A@+{wmvtzCb3$$^gv?o7t?I zZ-k55TF8aoMS@{hCG1k=NF{M1O#|0sM?lRfTjzjv$crAf1jw3qB#|2cN3L7Ny`)~R%ep$77u}1^fDjVGPV;u@35xb>}k_EJOd}g0@a^_ z4GHh&fPFU>3OP|j3Au!W%n5jsdD+<2GsRe9&Y^S8;ANch6-$U2w?~I5X-BS zHvX&j71@7TalQV_ihH*NhT92ef-PNsIlcnjH7;nOzWr(C-H%j7jdNPqPoGCGoza>dnu=}AKhldPIAfKx%11|q6N?|R$M_r<>j44uk zAXRt373z^GGihcnjHGxXHO%WxDHXSTNuR(-b$H>mpe)pUoin@KK#oj39ckW^M5iJ~ zh+U#RYvh=@OxbI&7+E*-2H()#bUDoi7frR&lM9Kubicp3< ztK%f@A7Ii6?8W_%Ag^L#js#iAr~!)$m#uAIU?GB{)cb8_IAqPFFpAXk~$Nck8M zMf~F1ZwNW8*n8?mgfftb|9iz>k2+LQyMnjq_ zuX40T_Ab@i6p>Gij4UxMq z0!oAcMTDwEOF;OeOc>UrcplDfBQ#B@f;XKUqBC*7ZIvOgzVjTX_XIgO+#(-Y00=D$ z;Lhtd+fa76uvvK#WJ{v|R8?5nQ>h&d_8S*>Wy1HRQ@O6SgqaP6!6P4ff3(>fIAmXa z{o6d0GhLml>B6YL{b9aC3l{`iY-@$<alX3p z)<7JV4=>fudaX6T%HBvwVlBBlE96{#5UMFN-w|x1p+F;RDZeIRN%4vb7Nh#EGCMqH znO7tC51vchhphe^vq9vQk^T(9Fd@G>|D_MXx7SSgg;;z`%7G*O!Ac6t&t4vBR#mIM zh7&*zZHIwkTikXnPJm!Ek{0IvNmZoF)hBNHkyT$saOZ}Q1E!VIYazqN=(0JqUPXwZ zt)z^1dhT(wKbjyoV>=md*)HcR?cKqgdnC9=q$@q9KRq#Ex$52OyprR^79GFqq*3L~ z{8Q?SXs+~kU9o{=IYV#^Nc-?OXBYlMDH(7QOPZ88*jz)_+|Wkl4^KCKTI`ynFoyAiD%%ZXRIIsLvr4!cYF;;Z zq@d0XaRLK1U9OEFe-n{3H0QJHTds{Vi73KPxM;}Us3SOGr= zxc>sg?|vL%5pxXD9TJ-}<0THv*v;It< zmXlRM1{hI3+T^d_4Ua8mh%XMJs|paD7`+0 zO3hq0rsUz5IW;kTjhBRq#2A*Dl-&Mc1IdRJ0-BjzY^2%}6asWfQ#z3uVL##YPpDf~`#&NL+JpP&G`8x8UZq68G&Pbz(yC%XrMmB>Xr_AJSSYSfh8~Im8_&#n$V=ppy7Nfd#_UCTm9}qO zrwvF=Pmm@_^nrM*LW`^A&*gQVE1n$>7ys4pQh4J4Sy36~6=@sxjv&R?ajrO3v9pXG#!NWkgc|pwre9es z4`xI>5>2j#t!Fp!%ZDVddaVLKeS~%qMn0+2CEb(RNA?{R_>`YDlo8jERlob())u!h zaOqrocB~|RySsAu!OzRT5%>e>lINFJDSH*iPYRK$=XwB3N(P7asmR1s2+p&Y1P%4h z^Bl-(#4De5E6B(on`Wz-$TNWFb&L89%K_>4gyPR3I+%(qiFomFn=mQYtmnR4y`TTK zB`amwzYKE@9L8YXPdpzw=}AGe(~ZGxx;KBcXV8(AOPt0)jECCe3MZ*1QC*Lz(Ne}g z2yjb47?uV8bqv$Y95er;t9a$M>ArMflurhS5o3%wnTBG;SA*6&(a|CNOX>|A>>98OKq;NPEVGIRm*VnT2-6E$h`4@I+RgZkEMMHzlf&O{YSM7$X*x2ILM0F4L zhd=WoZUb=yr%y54_9h$3X>*RHZv-UJ|3#zyJXw&x8o|LZ?nRyae}5I91mqzzawdw5%OL3h7u=faPiPRb+F`QtD08XnZWLe)F;dNPF!0eRG#cpx)dNkJ*^8H*~QEQl~X-jEjHZ7EM&+M{lIgOVP3n>qJ zODU5T+dXYC9nZFvxU_MX%ZUOI7Ikb)9M<&xQvcxUp}5VU4gL**+`0rOJSo%zxxSNz zhpJvXQ<&C~zg-TI$)=Ra$~^va9#o+tK~*v}Xc~)3gsYxIw_Q zvlHLBt!snc4HFND7mP4ZcsWP|dVO(!x;fa!-_ivPf50qy7WopX2_3d4Z;GgeO=Sxq z$cGbCXV7r@&@ZAy`Lhc+pD5{+6vJTAVbERUdyl?6y?|yfyn*)o(C93bI;;`2o@pqb z&AM4dluGDYQy5cyGrxJ+wG^#FKD>ELIr=Q~PG8b!v4m8=d&Yd~6NygXlUGt9^zqF; z?nDF2M2Ouz9VOvC;=V{UpCg6GQCgM3kcT6q8KgGN! z^y>)BDGA4OB#XE59bwH6y#c{`(810LCJvuH#aBDlDKs1X5n#3SOIwmmw7r%0O6ixe zQ0Zm(T}}D(K@Sg~z(BAsNQt9P0Q&b{hj04%P4Wx{^l#ZEh)kExXZdU18sE2Ru~Ubi zP#vl1x@b4aF4&)hi>#|}k_CNWI|#M6x zc@iA?X~ns_X8TlG;>zM$$|alCAFEfe>mvn=6GO8}V!{w3l7Pk7Imw}<11_D&v{VTM zNUi!Aj(MS^D-X$(2trHAfkh(f5gn^uFxQpzr_lp0ow!0RF zT&UTgjY%zVW;NL<)f07K%qaS80WjOVcJvJ6&JFjav(jC^%LMKhB_PB;lFVb5c5ydfXy78;1`#qZhqRzdx{rzetA zMo~}U%Bw?fT!~YL(NaPKIC{Gf*Z{hB%NmV*Xj=sq)qXOo?Rze2tfh#f`v-HRet=+( zn*YHZiMG)C8}EMHeoE*zXzoBD+S{{CC4u0a4#qBWt@c;R^yh1%u~!!;ny4d7J9PUl z;s3~J&2`|AP5?RJ7`i~SP|-j$LrA~&2xCjZ^ZevQ=vd+A9!DayD{L^ejNj+w+5^U0QzI`y`z0NdgH)8S7Q>ybtH zzP`ZT>|M?P7yZ>$kpP~TKoc91N*Zw2JfyL3*UUfH3t3biQGxdg;ZDdlzHQcZf7wq0j7S`a-jWi` zmZV0k&`tB8w4|h4xif^(j%Yun$C}8xNxl-F(W)4IV5s$Ept5;_#^fX4LJO_p%X_Un z&o-(FBSXdfn9CUC*yPB#gGD2V|1%B)f;m!!4M-4!hP}5|zGG{W?*SbHtzUvRqP`I;s{XxZ}Rrb)GAo$|g#J5Sh}B zw~GYPw+$%P5r8zIb5sNIpRJuB>^fqLm|>x{e9wt9(`l|#`K_BG3>vSaK`qpS_6@;` zm5?X2ziX)w)VV{tnDcX#hHtNh6v>rIr4#bd^YVZ%pI?EmmyoJ>7s-5H- z{>-*r;XVpA`@NHdUvwg5YU{`Xwx#4&W00?0n zBW|DTNgEm#ke@z$^cFL_@8T*cml-Mft(+b;GE}H3kJV%@fQ&TR07=VBG(&Qr`&TA9 zJRs50!klt1)H<-DbZo!5Kxnm-K3>ey-)g5ipwSTqEhLHlHq3+U^G;5_zmh($wEC1o zfdHUo7ovTDxn#T{pV-!kA^k_H)j*kfQ_l;%VpCBO=V*}v^zvM`1n#k zGF6{&miP%n+kZ&M1~0W4dL>t0Qzlh1Qq>gDPuPjHl4P(y*7cL#dFm0^3kVHPpD?gH&%0T0@6i`l+9Ti6%HMp-Z5v!Uw z)qHUzleh7Q@H_cz$LETTmBS>KF3!li=Y zpNMe`_Y_3{4=3t;CKrG(!SS4crI0;-ypu?{T3>{?;O)MCm6Z+a`Eg&B|)pq&$Y)!YK^U zC6_zQp8?PFE_W#gvn05;G~Q2Qkt#I=#{9;Big;g*UZQd2lf18C)(%DeM2t>{+p;1> zA0j`j<^T{;>Uw+H0aKf&`(xD?&x@I#j?fWl`vtDzJ7+uP6NF)#;Htavw0U4<5zTsyRGEwsdFrOQ>Gpdti#io8Uh~t zoPI!5BHhqFf_3UMSe)<-#Pf^c&xIn6}bOg90klPt8(dT&NKo6gW1 zgVNEU<`^UBSU~LCX%=gAsy%t`uzPy_#RZx3BXO*0xzt4ZKxk;b_ckFCn33+qbRr|j z&Z}iPiB+bqaE`M{Wcu}sa2DaAdDY{b{f#l`2^AQe4hPRxlxT4z7m29)3KeO4cE#xQ zfwhOcUxEc%1eeF;!y+6Wy8tU-PRmS#yj%46-pxwm`Q)@!|o}3ny6# zHDi<2pAbHPb(3>%4sHa$)+t#auq0l0LVDrk-}8G9BJx0v&TgvtJ{T?=?_5K(?`>zl z0fYYtBi(F4pB0tpt;>txu3DAtwO=O^NLYO8^Zx}L5vJeAK{&@U0e>M}czJj_INcwg zOgp+{HvwmD&;W%OF9h-7$~9(hVlbY$2@=z2-6Oz-mMtri+>VEc#;PK zTGnnz%W0A5;m4$m@W_OFMijv3u=j_PD>!n~ma(*-AXwz)@oQsUH4o#EQdB%%s zo?mboD|wN%O3)27!LroOSW;V9lhcm8K!MC%(sWtJdV??DE7FWhJD)K`wdomjss9=91Sm6iXYhZ0Fp7z zR%K&CN?oR0uGTQ6Z=Xx&fSrVxcJ&Ht^Gn4YUsz!wO$^9T6W$$Q$WOld#D5x*)kH{W z_qzldK4rfJj0!)kxJVRxDe%RO80U5WK|FJo&$b_HV$VpFkxhnFg*iu9N)}Nq@D277_arKi}X!my7Fm<31M_oVNyB zM@#0mgZ~#-;Ut791jq%$8N>W&QaqldDXS=J^XKP4u9A`;BwTVCn#L~Q+N!c!*{M2P zwC|0jR=4VELbwD-259Ng75@PirPQnWE}IzKpp7o*-#X$j?c3m@Paxp;GvkjKY612z zgSd$#4tn*2slrRCCtRkh?MipSlv0m+>YDZZBKfPN($eC}cOoduW7;6$WdIX`qoH^( z_yZQG`2|2`@!R!_RL#1wX}Zj@X=*INRQmpxE);AE&A(f8-$Mv4*x3LBEfHL|i#eM$ z;@?a=e6FAfwT!p_-;>|5LBNEKq5``PI1Y}l+E()~~3y38VcLAGnJVf)D zrT=3@b&c=$IKJ%V6K?r-x&F?iZbo;E@JK62zZJ-8Mf7_XGb@iZoh5plqjXR@Rkq88 zGZ;cT+OklWRP%4N#!|Q4`C!f&K$|#Y=mwnG=X|=_9B(4Kfq(0PzYVr{C9G$KY90Qc z462(Al80d;G>!kf!<013xb4kIl|)A`x<^KoKV*@%?wIo1*`kHscZq9_-#lZfu+EVK z@(Y-E8Nv;rLAm#w;nk07Mh!V z(#z=C$b&)Hwsc_iOe0o{OBX+1 zU&o@m*Lc&i#W@yZFCP+1BtK$v#`uo8;Mds?OnBxdREP)ZDaEY&Yg$dq{ArI}r*ajl zoE@XaQ6O$mc(a?n_S}p0;H_BxYd39)V8tLIsW^RV-pxU~K}hUZ9e1>(to)@5vQ!o{ zk{KJ-CEz{)atolbNe;-hAnhw;h(NKW$R?*@`xW8i2L9_eh1@AE)jup0Iv$7{^Q$kj zm?+ym%5GRH;>6y%=29#BIEgeDgdL!<4lV7h_F=^LsfF2$HJ}qAJ2Z-*H-{ zZ$&(lQgR+3RxU#XO#yVjtItAqzxJ`S%wp>b0;_g7saBAzClm00fPGZg?NMX!2! zTo+p^*L2dCzd}^n=>plpiAG`+*$(X2RUy}V3j+ZMKa6Z0v&nuzBUlg%bcF%*z-tOY ze{P6_ScxR*f*6Lt0rx3N$|)2{w$XoY4N9rGk^f-@0UMahuMV|iS#D{6y>-QQI9P!5 z`wQn%!?DTdp<99}L~BF4WXZ=fTG{7K(X2m3#hL~h^SfG=e$LpSrz^AyE^n`I;&G9? zjM#L^09@dF{W-@6ie?1Rbp@uN%gmrI8Z1-(R#SeH`!Ku^VlCghHh(vJaT{VAI+Jy4 z#Q%A`qC%;rP)xUC;q#Y;hh8Rw?6POz1cgY?uzAJnI`AB4-LW}*XsmTTjf7&-?S=jr zU+z7szAL{U?dM(IGQGTrvc70zZIvAO+s>&teM>`be0iB2`D^FvD5_kVf@4`7)zO3=p*pFR~2KHD3sD z%WcGOoXoK@Dt9jB2ho5MU}M$6_Xp4yF+8-cCVu*v!4TX7#(EH|%ZXl>mJpQH9)Z)O zxa?fFANMO~>ZeT{FFe(AUqM@6&$P6y%l>O79`Wmo`<5+HXSUVPTcYT)pPR|6mG09u zA5w_MMN$q4EI4B_fVmgH!V~&|_;hzE3bm(oNqzy}nRE2YdT3S;*w;JJ&+wX@=YKql zZIFRyq2%$;nP|SP-x)Bgw3Q!?1vJ=pmaUAlyl}@yFc3($P0C}Z*6evDOt*1kzQpfp zX&X__7j$;eixy8;0Xf>j>PK{T-&u4B(mKzq9>U?3)jJVFz}(R-x_3$L9ytzeLRV2s z>duY2?~^JoJ(Jag^j*wyJPc%$HrewsJ@vEwXEMJI=_%YoI%*}zjWqLICOFhs6h=SUokgTj?UrD z1ngbv4=YrpyhpSuuYl#R6xmnR@*wzXr|viC#~05rM7jUK-y zzRx-3#sYrHEgs9B$-?K#bja0T_=5?jq{#n33f$mYMAsG7o#A*!nKq17pGm#H7fdvJ zw`1NV%@vqWILhAO$R|%OM^d@Z8I7cS`Z(~tV%;ZjJ(ogcA^Jsg=>3RdB^zD5 z6upfoz*22umSsdG(AMKeEI}?iPO(bvjDCav&o$rbd7p$IYnyrk*RE^S2pUs*pQO`b zae%3bFL4fPd*8kBG6^`z4=GX(@ zF&wlyReEd4Wwsks>K!&$q*Z)}%@p9DvH&ifq!>^d4!wSsx5BbuSr{Akc#oe?$%#t> zQ4qn}m#(R!NN2GYiR0j?M3TlZ!3l6}W1;K~|4!t|5XAc+uQH`blx8ZDCbTPor!<5j ztclyNFbB>d@EQvFAd*+bY+>2Lt&=svTEwl6+HXP(>MhR`*k9}Q?SM?GUs|2 zkYT*ZeeO^#HZ6<*e?l>R6=Yu(ku3+z@1cY?P0LU9K*3j&k12)kd|7VmY8r2Iaod4mk$k&<-p1>5#=!?cvE^(PMb48 zGQ9AME)2bl!d}$hps$~Ya4t2DH2F9nX7}{UWuzpWadeyZlyxBW!{aYUnz4R;4+eBKa;5x4)aVDY}rh&7ic&ZFNCW& zhXb)?*VTwU`7uh2eq9G98rL>?)8wr2bg;!-Dnp^$9Sx=1P5faxS0k(^mdhElE6mLiF5v#}7t zsBe`b4Ex$Df@y*$89=&wa_q zbJsGoNYJ@|*BC$tm9hbk%r=x9wro~T1=$j>D1TYOBoirN#c9=Q|7a`oUf_1ImBF*o zQF;(oWYo&_N4JlqmKFW#=3=qdQMUqXN%cxNHB^iT(+YYT zDiUg~F=}UFU1QwbzKJxs0+iEDFhduESOyJ|h;rZ`ys&@4XT~D5`j+{@g>$SA?o}IE}*;A`-A(o0n5G4$4GOX!%kp&XmjcR6Te?#x#{W zJ6%+*x+`kZZ}?%&psu2)d(X{mFnVwJjnU!rt20{q-~wTE@czT-gawb7D=hs_NatTh z=ces{GCFZ@j1G{SKKg$`I)CWeK@Eej^$YN=Gl7v;tYnLLPe(9&%PhgVNmUC`N+v)x z(TGThLuk3N4}g1}~tj+#U%BkZEC8bc;GfpJ;&fX@r2eotFxI5 z1ykyr!{l7yFJ^UIle~=?39ZEf`91SD$-GGEFOZ!A^7lb}nxsC{tdXHiT~Y5FEw9!8 zgXt9dD6r)JH<-@ce_=YjH8=|WCv&U!O?y6VA4VthkT$+vf`LpT@(nC^C9FUFk?9$< zMbbf`hsW!?@J41FOD^b_E_yf9*s^Ftf2hXhr$hJKLDT{MdI zV}6kUqjWYI@QjLpiubfLJ6*~avt<2(NRn4I#pq;>dmJVm3o`BJXnsZ+y%WS3ifY7s zHwslmWU*XsPLv(m@A8nBA&E5{BQ-vNL+DmV*ci&HM!dB{IOioQ?x;#%URxS6>!3Yf zql9J!sb^<4ZCrSOD!UL6yG<2ZYajkv%xc%T)$slVURMjV>oEWlZ4+OGiBq`vh)39l zzhf}PLBJX;+p@pPFNgPVTqI3aE>vd}kSVXb8CzO>Zb<>IohV&WZgPxQt!$T)dtN^q zmU-hMj?5B_1l2OV!*^$S`kS#hq=a&=GM@rEK3Ch7e6oEjXS=V{@C}8T@tSBG`}D3` zi!cM@b_2smP3hMK`3P>lZ@$l4=o%4shv$>z4_O%E$EH1(X}c!sAa#$ZSY##}|32;3 zNFrX%MJ9n_Ew!}FS+RXlHduh9ASxoCS|C81S;X@C;kEhZ3pf0mpe&(1y4Q2TrDVBW zXNuqS`fq8z+|?A5;ty`lMFMmET5mFph(jQGA>AnzFK8o>_U}G8oSx!dMG|)$I&N@L z=vMz~KFzNo7At>6u-eemXYk|(?Qf-F_9xMtOPIZyvf!bocs>cUTa6Cw`(>@TMf64D zruB6>$K5{yy7%rSd5_MgH_T$~Vk_e7;;rgpN(hR2Gc)EE*Kc~V7@()h z32AlZy?S%}BE`pm%K3Qo1)YFJ+=Q{8_e)=@mhHqxePbzJyIB~=ooUEX#1QBY^fnH< zBIaK`>C*UCA7e~aW(jCca$ZIYLU9d=``Eo|+L}HKw=#1F#|B9Jfz}{5Z`uAaJ=gI^ zsL8_lO#a?0(eUQ)N5Ya}k?@4HR0$yenixFxEWaY7-Fq<#X(Q^-p+P~lxf5%5SwT;flm_lZb%TbrLJ^8$}YD7T5vJ3{2>QUL^ zJE=&G!7#;nUD&U2#dhgFw~%hK@Km*icVFqc5`C_RiEG(kLFQ+#-oGfzw70aQT@UxG zcO4$A*)QO6Xt&w?gz5-$ZTzh67t6}ld2 zEAZ7O=~Is;7}`KnzqgG{GK8lo_WLO^)X$?ow~nb2{NuSxR-Fxh$ZV3Ot~K20>Qz^K zRY+)K<;C0Ct=*Gx-2;k!ghE_AT3)PrMg(eND)zsJ$*CNNHGK} z>4FKWx)`D+)bX~{E10M;RT3tLxrel`A*&jix<6eO<0>5gggwI{lf3>HtMk90I_VHp zrx*C%AK9fr+P`u&}%2-P$_eC!2|FEF0W6;Da^$mI6&m z>A{lCDvB;zvj0`TPFj-TX)@y&kl@S|4pHcq+(aChxrT;q_~#E8R=@je-1%BQ_geWb z$V6!rmmfQp*|B_Wj#fChTV`hH1 zLlTVL^TSh+BLBjXyu>s|MA)D%g?{R%m>7bJN)MU$M!j2GU;T6r>v-dH0RO)Mb_%rL zq-9AP>7hmK=A2e%?_u9c(xf4xqK=Ma3&sXEr|JlhUniw~V{Sm(=a2~pS?mfvQHxqe z__qmqbjSq#$C{<>Asm;Ozo5iy>pA#Epbw6c-d>51F!@q_yk-;QX z;71WCMpv{EPM|g8$S*==Ihh@Qh@p&pY1hm^O6TjCSQ!p4Ghjpxrah?s_gT>8*=6_a z9*#st5pmiQ?PaLZf>*S&Oce4ut_I)ItUV(Q90JRMjy2&WWlWa`H#NEj!23h)cHvp4 z#CxPt$KSyjMk*N0XrMr|wIXnuI7hR!A4lh!u|HHa6HvA6eL17afqp$E5o1piZUon2 z^Z4kQJ~26@9G$elm19;Ls^_Day)=0wJxNN|@UGDOJk|+Lya4 zr@$0Q&%m+pPqgebfZ<}~AaBAxIE!8&9(&51e#dS-YLSq}u z3aC4uOfxnsZX3Oo>w#Hcv=oB|QNG6Swj%V46oq8`LZZgDyktR>3#}&?0BZNBeinZL z9jZL61cC{jz^MU(fERTNpI=Pu``q=KGfScgVqoVlXrd|vUs>>jr}H_ zvU3ol!!}{1-_P(@qNOBUfj>s1cWPRWc{xS9b^50d3)sk4No)M!8PP0xdh&>*0WWl3 ze$WDDFA0r<_Z1)1jQJ;6B&&l$V}Ty-308|A@xkF|Rsq{BJ?Myc8=Dg!26e;p>7Y#+A(3V%M@qYz z`OS)x)9=$SXO4lK{7>C~vS1T*Wnil9t&1R>6Dy9;!mkNS*Av7LoAj;?6IhxlEV(Sv zv(FQ0{?H=tHdhk?947$MUF^X*mN@@<*X19^tHN;cOl%KF6)v%SvK1}ADx_R@LVz_e z+=e5bYFZIeu)OR|0fc|0P4k@}Iw6f_?k9rK7PTK3lipJ%tLMmaRILcMM-ybLrfmVBc z0`%gSzl56Io$?lt zdyCtEy;sD9btq{R!n5Rz_Ay(KaQ4nb*|-~UzYCp3^1}Gd8v3Ii`Vf^Ty&uSj4HLM* zyz z{C{L`&_)^)Cedq#eV(og^x#qfc`0lo8kuW1X7qy*de(P>Z;085M!BSs&}gLP7JMEK zKTF}#E~*U?-jVB$f(nn)rJyFRf+@#^psIjseEK8&XD)%vzzN9Jx1gcpU_37WaYoEo z7+4LH6I8_XNj@caJGzKRXJtoK(dwEtH>ELZhE!EoNee;#ErX0t?GwR~l!Hyvk^vDO zt-)j*2&{QW=bcyYv`Ir{Kuf@f)`?F(&Z;?>D;r;OA)}X2_t(*I(Pq)dtJ3^dFJ$|M zIeTlg&E;!v2mPW5)eCtM-L)M>yPxENj^oPD3?k5|AvSqzv6^C2^$YhuM#)b}$ecVl zS-$6S40_8x?PFNy2KA^+cLr*4B{9;ifYt)Ag997vX4s~E9f{`t0&-O0y`-&K)aAD) z6xrwv3>+n_w`jE>%g8wv-u-udi;M!pS8mB%^m{+b1cnK%vF!p=?4ED8KfAO8J5pj- zkOH8?0pV}JNVxrTE5;`bp!iR6aS8Xl3Pqjw$@d5-;bx{;%8EK*>_P&jw0k#_Q77YW zWf({W`GA>T4{p>PKX|H)PXa$$Sg7X>GUWgAQ*t4#79lZKnReC~P55?k^vwB%2`U*7 zk?a${rI86|C@cUDmGKPhF-Z-l=`$<-2688nM6n%=Bifp~>?(Q2rPoZy|_ZbE=g9=brm!+SNM)73?- zz=kWAoia-vTD#1YeW78^CuYGVNCmmLA=V08|L^lyEw|+YM;?Y6Kj>kh`@!Xl`A^sN z>PG$vbQeh&O}d^Dg`FNJ);>n$dW95p`AGkUZXG_1e#CK5V!)`I;DtvWM3EE71-Z_K z)G>Mq3-}+un*fde0bqXQ>$o~b;eA&<6in049k9zvn4=hzXu65k`kxsC#TeE_iY3Vvgh zF&mcp7A+NvY}0W-#B=ng|7nY$sh8k_0n!X_LEr`&Kjb}uyzZOaTQDeLUTJShLCB8) zS{4X{*5%&V<~?O+SN~EL2ykjW6nwAv=Kl)&A>qA~1*UF`Ztspqf&JtPLR)~0R?xc6 z7$1*rUyrtTU+)s;XWs?lU7){>ej8M-#O203`7@R7z6qmy*76akrXzhltVQycoYcYZ z*^Q`UY)IRS@GMHtJoT5C#l;Y`0ou-pA95%7)jr=^dHJf7Lw%4qP!J#OpBEfin4raJ z2>jRZ1+Ql)-;2eS`t1-l9*7K4d{G3^kY-Gh6dFjFR%;UeZEC*04zN79^KO8~{YV^E z{yw6Laf~{t1(E6^^58c=G3mH7`e-5lzgyjElG>$`ua6J0#(wi2A-=hvH!-p|*+7f0SffrEizlxEGfSZ%CKvS|U( zMmnc^8?IFgzOeRzg0?VQjOO9|3^MQQ!@Y`ko80r!pb+oeu};dLo*v-Hc;hK{2qZYe ze)_4MUYPBn^Fba>SF_EMz@sZ66jnK+Oe-F(#c*eixlFzR^ zF$TVR_EKQR32`nJf()Jkv;>gvmXd_)rk>-+`!$4~5^bb1WV{f(0VKZ!AlHY`0`S78 zjvda%F$*xJfKw@cDB zW!;iLVq7LIq#ry-8TCl1Cb+BCly{BR2e@xq-xVyLm2fH--f}7ppg_D^@3!Eg621a2 zuvfcLyg=zt=4-v+GrlKh(CZ6;99VkG9)~UEHBo%gq1+}898s*J_2p8tmWtjrla9Xa3sBKtXeRg+qyM_7x55EBaU+9;QlO%&W zKgk3BQpd6VFZj#G|rYqPP`9 z*-uEiwZxXjY0m@Y1h~^vDrl*QHBu|KE#{j!cj4tgLpY3`1p}X@T!)oq>^t>{_jqZ1-&O{S1%8b8F7qFsBWcMNeQjCP7Srrno77(fRund!P0Lp2Wi6b znNdPYJ9f-;$}~bw<)B)|L|8dM4?X69Y)zpjX84KrB)|$%l|G!eb_JD8Gs8Qnr=XXfFT00qxa61*8E-*W6qAdu#jp$HQ>8%@ z88b;RDS}=rg@Gaa%bx|_dGXa|rLv;qJg)=j@dWupHN!8#U26u~_$jMoIFW>C%GP4T zQw(X}lXXJeIEcxzpOa>vZM-K0L=J$YL`dx(wZsWSm{tS}g zck3?B>Gs4~tWDfE0t+Xy-do3HxV&Vu-2fKk;ofaY#Qu^6c#{!$1_Z(PgI8_2AG9+b z!{yZ;tJgSi5>%8?At+w?zTvN%2I)Kp3@?{8KK=UYu^C;!H?n5IK1#@YStH1H+vlhw zt_Sp!x7re^Yb3y2ZDVcab)7%6(Q==EW*wjXI*r6bvy?{fG13tD9}q497p*GRdb%II zaISl_8`VG6Pm(GwZVK+WKd)mbl6<;8efG}X_iKAAZZ;_nEV>_!i8F8YO9Hwg6^bMm zF8o9xjacHHu$GI5cb=8?XWOxq7-b#VrtiY*B$_LnW$6!-!=RXq*SyRB-w-a5X*Tw@ z<{Ut;#N0NNyX#C(3g~GFXZEJ=ek^WEfEa0UZ1W2KP2aZVj63aFws4BOo+hDk#kTx5 zT~2vO!|39!(UHBw?l}%0feF7;DXOgJd8J?V^AcU^3T9lF^2J?rL0aRFm%&3LZ~;FG z`~5HxnuNF$Pp8z2IFCMf1nRn7O7qkNc}oCobsOJx#ks@98iD&bvvwwp%YJeLmOLM` zSM0ebZa=hn7U>V3pKTji+}?!;UNjP&vU_R4QqaaKskjDw2)n<@c#O~3E>5e|%wti& z4f(Ps&ACQzSGrB2uHWD_;jpFg;TJe|d)xLd9G^xdk1KjKg}AL#Ej9`(Dfj1)e7zHJ zjeoAE7caae$Nao>82qzwZ1u>YI}D5MD?t# zhLjz~gG?-larTr-AF6TtJO9a7M5->`cW+M{#2-GtRZTJ%4LBd|?z6o}v$V&1C0`I5 zSzpN)qO@1?#r$vb6iD9&usxe#_j*$ zFX1~p$sNq9tDtod>FIi`BZ+q(%!6QuZ-=(#!+lO+LIv=4VuGzqV(w_xz|Qp?4uzOb zP2&6DQ6^1t^kC} zG_?t^FtZ+<2ng97Xfl@%EKuf61;rm6b!@>J7GEV_L$l5Lu{@O}3dWmti@(RlnM%8W z@XY0fFMCWc5*x=0;i$Kw$BM9ZW#Yv$WT=+6D;+81jsKZO-<-Z6#i!Ic3e$sRFfroE zLSmhoNDn;4wpPDCvD*2<96&RP!iCTMu>A%ex2|g`K?`m%@~v}S_6VFXBBWRc#Z9pA+aIFtKKUOgHIzRSvAIlLjXYxFa zUQmv+i&|~-e4d>m@h4&J#u)LsGx_?gj~ENGH-nRxs!lfhRBR5s1V`M?``l;)n%U29 z-l@>hf(U+a#`}US_eW}V0EwiYM)L6$D?+4a^3sB2wFV&oK`{5@v5qj3$q%9(LE~2e zTI7Fi#RDh%f-G--xBe~?s=VIjLZl#HAgyseuSq&fhGKyS6ENp#=>iC`HJtC1NG?SZ z$}0vGW6LOzt9BGaRou?RKfvtXCD3l>e=oMt+mC?XLhvO>Tn`Y!jS?bnRNK26=V`*) z8h-4}C`Jt~As3Hu6=xsJs%ZeZ?5=wQ)9Rwtt1_}GEQhtQ2lev{!qGu;k?1rgXOma{ zvh1SWMTKEZ#)q^eh(P@>0@zsTpH;iDhoB%*fpWFx=!MFwDpDokoCAg^iqpqhc{(9o zcOhGFD@xm2nIqW7&P^QN+!Dcsc!ZtD0SdTL3gkH7`-|`HBoP!nn^@wVts{+qn~VA> zcX-OON#e??(vu~`2`VHW?OFfPMH{#XN!Y5A+f>;-hbGuBM>Zi-@xy*Sht ze3A=6nms+2^n8(cz*k+(HW4MQiSMheCch{E@88*K(Ay3H;3%PMhP`y2qHURg8XZm% zKYxViBz;@~Wj}juHJ_+F&h~=2E5jsLi~wcDdM}YgYM>@L?>}Ie_!)$CK3FB`1MJCI z92J{>TEhY( zD0m8O0wn{}=mRQ|>SF3t5{Rq!$VGTlLie%Kf)az~@0W5vBmmOIgegC^D0|hJ2T)65 zsC*V2hmn|NqKn@bP1r{@@$v(LX9O_ouUmhbx8$4ulK9o>RdEq(xzr9&1IljMDo`Wf z1)x6^2nggyTYTYn3&zoB-BC8hqob)V997FawWoFS z#~4YtS-!&&HzYgFV%Ww9=4t9>Kgx!)A;?{r7QD)8-lJeB@1^mR=U+bPZq+&Ik0{k( z{Wjn#j&7gGD%izStNlcqx6_+%%8nA*ODDm_?47I=fR%ffSijh{{6|%jo;ko}@;3$} z?o&JQvbn%ZHzlA9{oO(;^ahhqIL9ot zO1E`vfKy0v2|kNTn%WWf8@OIwSQkFNsgS}kUFq)Q`HT~*A|8*6#LO0ue)U-UUAM-I z8oog~5L9Q@kMebfuHWto6>y4&10@1WcmCG!wdp5ftO zJROA57YQ4?gMDAao9767euG}d@%EZUz98NRs1%dH`O(hG&-VKt62|uX9}?!hDui_i$2-(LJqS2)JJg2vUboHfL3m5bu_TN+ zD9jkDY>Ma3t2)IWNQq&HVP6}M!$|DHUlt&70A&y-W!n0Opy&J_8wbi z@~Vzg3*S(s4d05%GNX?my;GB?t=TiGHOF7fWTJ}|idne4oHt2Ci~{oWo=ARtD*nE{ zV<1R6<2xpdq|4~!mBfNZ2aORNf~tP7L8>~`bCt9f3+O*Z_k_A74E-rxpLv zV>1Kx*i^9&HW*y;|BJ>3@T##vdDYki{!?R9$arUmPx)VHY+znBHva#W#s>JGJT~e7 z;<5P`jZNBrPh+F3Et=uM^qVLx%iJ>;id6k!E#BBTI+os% zUFDKuRV297RY;2736VU6XV+}U<;vQr$gGw1FfBwvh5OWnBWcMIw_!|8J&Dp37tnvD zK*0g(6+d_f%Q1PO=7KiDmwn2~-TIM64L2^;kD!n6SMR!TiZCq0N~SjJGP**zAX^kp z%%jEWM*QDIOxu4XVu1f0B!);U{{jCG5kvJAmB5G49hs8tjWEm5?WnwUm0^wGyiRDw zu?S^V%h$S?sPaDvKYVqAzUA(A5Jh%w#)0KU-A{deVeHd3 z6X0abQ2?Qa@ki9~(DObCsYpL60hdn(~ zcQsue#%6~j-LLh{_AX_T)|LF9grBOM$z1}Hf`~W+0(;_^L2&XO2(HCLGOCp@P(~R< z+Pq&j0I7BCNzJ{0s<=veWd2EN=u;a|m^C)`7PV*@wOgXa4}xVA`w|vZGB0F<>2b&GCaOO7giHU%hR~QXNhmEB{92*ByTDdN92f8aPxq=Jp#xT|+S&*b zHyvhAj$$eQScij-8}j)nl^9dI!v;0&05*O-k+{zlS{BIH)oqtGdgh;c5=lw#^9t5lxUPFH9_r-u%X2IB^U?GShnlTNQ zSW_eoR7p0ViYcnYv2Owe%ddUH*pOXx!F9a#G-qD7+aD&MtcCq--2$XV9Ia6Upg|28`yjT0Yuv zqcv>_t=B+04LC_VX|&{lOMbnDAG8w%B1Bs<%OZz>p#rTFCU2f}%uMR|cH4&X_b;VK z+~Xh_dQrFA;&AC1Y834iHw4=@1&7`A|2SwA?d&wZo&TEp)V>VyPb>x`FXR5NSd8F* zjm6lojqXov?WKf0k&3VZi%cU45hPQZKG<0$689L0x^UvUL3yR;zJx@yxR+gFMp63f ztv;CDDYAyAO%d+zT!KS>EYo90)6;j0D?PryAKl^hiyHc^@<7Q+znAcZzzyGHl4y!#Eb1i>XgQ#L%x^tv)Q%3kF!Zji8<()Mz_Dy!^xobL3HVARDq zw&$4y$iojhx<0$xxMKxRjq`!~eYxf*7(u2g5|FTr186jj^h%~|R1)j~Jv32N>b73P z1}ey4pypMl5;XVw>0s^V=y|HClExwMTn{zKpaVXJ`|?re~3A9WtyEnVnMZqrSUz20OKyRy9J|BJ@PKyRw5;J4?? zf%(%HR0H*lM;a9b+vR}tkP9~qgE#qjjwhe%!LdG%`XH@*c45rl=_p;&I+BoyGB}Wz zY~e`5p)U+NG-ZumL#7BGP+;=~3YoRfLb-ct z7uV|-(SvyzH`D9KmFkiSp*I+{4Rq%h&lg%TAygg*Zzsg=`xNt3(-fx{%YQ4vUiAN{ zt$|oMt#J3;IcY)TIFJA;BTHlXfCWf1&{~j2Yq^Xa{nD>nTY}+QtH*qxS>8Vq4>_Yn zdP>4^j$nyXjc#fXM8lg3Ig|!xe)qd)olU=J1hBKOv+eQPbgVr$-d=r;%6+zh3gbIe zP^IQb$tpKlwqtEU6Q>>k&T4?yY0{_p@)m#k$WnD{%8zqCBm<>I*cwpgG33{+>cO%H z!o!U}@iD0O_vy^fbs_mT4sQxSvugj9z=KS-C8t6%tXw<;s{BzF2Am9 zxJ)U=t5aK);R>#gkVRERIO!==UJ;24`b@iHerc|59E8Mda2$-^3{#`Du?@8HRkr~X zrLx_42I=aS2;RAvaZr~LP$__v7D-cD`>?$*;d`KWSNV!>9*4zr3D}GU%iP1c%N!(_S5)Tkv}>IRksPK#YC(!U+=hw|k@S067__w!{9oHxRLo5ysr# z=7HCJv#Xw4>u_-YnVI=NBQpo5@kwqcHhWUmICaBgV;}DeP`s}36$W+~aF96kLygfV zFqH_R^9qav9mWNq!*xl7w$r{5LBqyk{B`HCFE%<=Pe3itGB<1c*Ek=Qd2A1FIHW)< z{>dTt(C2OY`+j!hp&4|}p?&~#Y6H=hl^*hMaO?J6#U5xUEzL$p&wk@*Z)nZB`~O2& z1AH~s{Hw6$M0X>1YUQ$dX~hqg1&XD9hhrRSFpvlw=j&cF{;jHusr=pS=2XLfOswjI+NhneEB;(KPf z^r$v{?YMitnVG(}E5XE4@*?l*s=#sBZDY_0gfgs;;#WE`OQ+eWbRzH~@8TX8c#MO* z2_U(E;AM?Tiq_@R#QRl4+D<5bC@HnhSQ?=|94YgvhJnn)@m(!JT1%`VzKojWV$|4T zaBPoB{0dc{LV#M*f%C6r{iml&@Q1Bu1s`0B|0x6m{F{P-yK3n8>V39nipDWcz62s) z8iLcFzt?kLEc7je0t>+gZZ3Ctt1Z?Z|6)3pa2*(EFpI<=5|@=k(H&A1TB*HGnS<_y z^XkFAq07nPTv@!#{Enc@j~r;*hv=KxHgH>Z;_J$UX_GB!qke zx6sl4>?rI98YP5e`0sgU?3;4Y&`5wcx$f^vAc$l$_yWbiXgS6cU|o51E+1P~S80Yw zHu_ag(w83$sqtypwwuBm%cC``IGPXM^ydN7?IZf!wwtk)VD!q~h z`OX25A-SbMQF8!7ATWi75c7zGUmf1h>;k4d5Q6A-4Ajgn&5U^c!Y(WKhjT z!}HO>)U)i-FAp>Wn0B$(mqhpBEXgkm$faD?E2~>hcZ<{HVrd+;Y-9T>_|f5c$#S4! z3Ie!O3z+n>hirAXo46^!M~II^qA9tK&2~DIr%bQcCsHP3C-oTGTsZC@UQQZ!Gkp@J7Kbq zQ}|OvA#J!KDo}*$u-hPN)Bru(CA$YNu3nNhNcrL#%#wHUiE4O{n4srvy1^tt7(%>y zreF<0=LZLRls~Pv5aHmVRN%lwELLwF)h-k;IAs$a>GQA=K`=RNt+ef)-V6CZ1vBbE zUH7Fd;m6j3IIx`Z^TFPv_FjAi9qd5nP39EI)MAKX9j zIqQo0IF|hi`PyTw4`=Ma9W5hIl*m5^IVc~Tqhq^it+WsQk2D>uM<4t3Q=!_`g~v-2 zk(j_5g;O81+)bJjTxOyWjZLP;h#tDQwD1wV>`f?~OQx~KzWGRwIeBKf?2RaiDY#6R zK$>6-F4HBUCzTT$ay&?K?fSu>gVS`*Xk%7D?zo&u61&0_>+U*8ko6*%Y}uO+)@uXx zGDXby(c!b^F;6V`<5ImVc$m)JT*5)U?A^VY54(x-L1ot z>B2bjjD;RuXkg9~&$b#LYS@GQ?8SE=5tI{tTpKtDch>$x26fU!KS7{An9pZ7!?M3jDgeG`f%A;tP| zS{Kz_!Wv!?BYs%|{+_T0-sVX|%>v6O^TanbH{HPbC*rY_j3ITSLv~lwtTc ziPgN6W_&yb>;~+6n#XRphZiu|=IEH%+uk-*LbiSth6}TBnL|Nk9I#ui%_Aj5k zy?mXUZhe3)i2qYWW?}lU`k`;G@cRDn4qrsWatU6iWd*XWxyDjaOEs9ILaBKwhvuzd z&N94YUH`6s&u${!07WXhTDIE$Vu2~!%O_kci%dB9*UK&thKacDxpf{qd-S2)-=OG# zEU!#gpN@7-V;-^>f;_7b$;L&ni9Fiuz!Vvs8y8fw3?MUlz2c^HTN|e>*0++3zwx^_ zm`07ts8^AWbBJZLMN_N5-~`5iKSTC7tip3QFanyy;Nb36V3Qi%23VvsB~~P_6E@~SY(s!Q+aRS=I{{xeSAf+)He&nV_u}6lOtt3xLpRQM!dqJavr6AT)6( zUvs<*a79*!`9pmedp)%9_8vq4pOk@jT;;kOkM@fzaZrYPgsyrqbqzQ&Ybe@)HJL-o z?DF0{wnJ4ED$r{?%zXDxK!B-UB?u>($&uHctj*^g?~2auC%C<_%9y7~*S48eUV&j4 z)L||Mee>%U7;r*PDJ@W_E&YAaQnCIWnoo}d)I{c1jE$>ZW~omw;yt^iC(0#?rjl$ic@%6OXJ`*2S4HCxsxvytV# z(Tbxm-JD~Y$?Vy)w{Kew=tUWCuxw0u_h|Exzh04gclhF$bW=5$nX%PrWch>4&?#wJ zN`7cNY5I`nrZ$)UWH#%g)R?JpZ%Txw#1iV38%IT_KXy)1=x$1OPdrpo+A8uz%-0*J z;3tjZq&A+)m~rBh!4mm#D#5H%?WgjHP(`Q3b;ibEb!j{0R!ow23>PssZeeI zdO_+cy(65YXZwQiJj=W!BdevHl?427fiT+C=ooP2rx+8Y@mT&S3ElY9NvKm|gYv7H{puXk1r1C-RR>ca-*X{O+ zw5Otu0NQf5m+v+Nr^_3WM8wrZB-JlzJ)JR=U+88(a}SX!sKLo6-Czb;-UHji;@B%T zrOnJ{spid?lTByd&zf&tvI`+Zrwk3s0<}86>LbOdBiVMjn3y)`pAnaK9U64`cct!* z>JRu4*qzuB+gCoW-nTVA%hu;tTkn)NYFjLEwEX~Yei|g( zS$9o;@n$!!(SFuu-U_*13I+DyZWS!C)wAkZ_pN8D09SfK0bwz)J}K3b3o&W1{R~eg zFjY%q9edi9x4%!{(Z1vxbR#ePw1g_|DAgmZ4uN1p930E(mLEjwB)eW9ipGuCz}PP0 z)I)l@PQ!0U_Xllc1f4*hF+jG*54r(7Od(mJ*G-#u4cZ~vBOzF`&w-FZ|?0Q5AC+aTIG0&ro^ICPxZ^dR&k{6Ui*;6nkdkbe#Z{}_B|L9H%?UV3*Fga>{V zA08`2HAT0adHWlJc8+Bh=>{HM=NesuwmfAE#jkQJs)H77>xC*n@Lf!-xM^`oj9Rrx zt1pMleU$@pHWJw`7y-EyRd(RNV3H8Bz5ZIlnS=L`qBRvwW64fnB*))V!s;hPS@m%Q zlLUc{mU*Mo`VU3m=f7M9e*UFSS<}A4?0OLT_tvO`NZm+Zh;(6COP#o09|DA)^3Fb! z$NQARgN&ea$g@BODUBW^#1Q!fA{$))1;KJ45$=+k=`Ks@H}2Qlck5m28Wi&i<|Vk4wi@%>;~XR#pvz~Lc8JA3*y z(X|eY@b7URAz8V?%z1q5W|P)SEy`FfhMe&@jHus`c2Qw;PL_2m&Sa=TmI( z4EgNqsn!zu0N>1pwcvw@e8As8f<*`4!t(boQ9P5)OcsGOHvgIp2FJ;% zd&c+Jmrcw)W^B~gH2uB&vvnHFWzqFg2J;o|hUjJLuPC;;SU})Gwcro--*#EZzZq8D ztIOoE><~9kd0{{8)-rSIYF0BZielmO9&l2L$w%Y)XdYGz;IVhtPD40swZR(&v7$ke z-CW!JI0N>2+4e#7znKqLNJx=|=}!oAQ=1g> z5=J0~^K>{MocRmN*f&MjvyOoLB2d?joVQBHS6w84!M7>vLBB6pTQFxuU4O2!yd+Th zI*e`mUn5QfV;x4Q{Q^8t)=gV?4ch#HZM%y=hgx9*&LG^Y4tCu?SKQ_CGR%4kOncr* z-e03E!@Q3LqFR0(=A;#To@iWu+^a*U)b>0T(4S#_5y+xj6^Kig6JnEB)}uu8>CLWYY-vR8@Bl@JnLFvY}fb{`Gei! z`AS{g=uRe*9s^ICn$P72jV;<1-P$(JMU+e_ErG0}PXn;dFfK486^ZL#)a=(5Qjbp5 zQG#0@8&zMb3V;jqmgEMA$;}+y-)S$Q(Tlo<4RZR0AaX>kt^LlRH?@nSkmqH7Laifw zZ@8#a#Jx?KDu(aey3)9kOQTqz&Qf&Kh>iW~_ly7W+vl#C_xJrS*ijSZ*z z$?5YbRzS}8I_h%5%BP>lWQ{+qWaNaO78+bST33Wlx%kV&1net;SUyYXtQ?xOo^hL% zNzWwNWBdv2^9V_Onxuwq zqBSVyi6CB~53T6H4BJrBdw2fqw#<#Wehl*$rKUcI9ps=eo_>dSkj@kHFLc19my4UV zmxPL;JWh*-G5$|fiN^;cN9QWe!tFL~9oAM=nOAM_#_x_8W_ekRQaIPh&PdXZl~=vV zs&y4k59TfFfr7BncPB?$wkPG(_*?^=bETbtB}6HL*Ssv*1d-6b4@Ta`f@@2NCu4_Op5=@0 z1gwz>TG!fuc6#n!N_-kFp$~9L6%S!xZBDe_m!XoFD*&?%%;j2Aa&0ta@#QfZVonJL zH%)ng9^MXxqFa`Z8UG8o`Y39J94B>}_I$ogrJtKy_uzTN-q=iA+2eR$Uqw^!l|T`FYRP*Jn*o0j?FzVVN@| z!>>GPl{}`(3`j*c)=aI#Os!}X3cKeTEjUA2NbNlT^lRrurH@%?Y#0kZ zcW;1`X@?LK@@x^|0>%{M1^wBa?2}3vbY|4OG?8g}4DQPj^?9dG@-^`d%H0#7%L-Dv z$fd2~7A*snijf-K)N%~=ZD1RviBKMv-5V1D`Y2^=891o*3StMdpGu7YMHEV{2u@Qp zQEVyCx8o5AN}3glgV5OrD71}kAp9SV*gmnBHme@ik}rvRg{=wILk)i8l^ z;n=l^>vv8$*HB7eisGOSdqK8UCUS^S(TRKYM2U4 zwQ@aqbQ@L`Il@{J@K~6XR=5O0`Kr@mTIN&m($KV{!=Qjri#QqMq+Fl!Aqc4zY{Tc5FEzfVL3J+*xw{*;)>%j+}ekX{~ z=G?}ZdWmEj^jFPzw?#A)dsr2|^!9$qza)~~O(@v{dw}VeeDIgNH~!hlgEF!3-^8(; z4MG)@N%`@aXW^94XQ9_vg862r+(JvKpdg$Sr|R8?>B(+pL$exqx8>uX-hQOCN+Z7> zCImMcsj;)pT%{Bf90f%bnVYA9;-!5(W14M9I9B#iJy1 zhICSl$0`uA9oEtbC^96Lh6p=PV=$Qv%uA9K6g~GYB_KVV*n)FidWBz&BL!xmnavQh z#nlGO;?opkFR`yp_-VWN26UZ^wSJ}>=qkGguxC?Lg$rPbQwEYvz;`=C=Ah5eXA?70 zjz~K^WLl+;qcd=P0|Fc;79M+5#h?}IL=nwA);RgHoI;z5R(K9`PFWm?AmePb$p8KE?Njb5tV1RG^U6)gP*S$`y z_rp3%L!ysFi#XE&nL{m5_erL0{Co~1PfU5E6boE64thlj4EAAa z$ipmUT4*=FR;z3-JAwh6W9WByab*;KoKQ;HNug{hZLW~o^Qg>Y^uzeH_ye;}v(!df zu@}%&r*u>F=9~BwymI++0dE^VhNtm~MR@3r`WPCF)B=k?%o@#vSOn&y(u(XrGmu+c zUN62~npn;2`jA!Lex|9Q*19W~l~R(%CWrI;jt~=v%AgLqD-7{W69vcH`?Az#a|k>t zjAx=#zXrgkS!^KETok?V&qGTZ&bYmK6*6`BXsVWCp_%6yc| zBDgAo=`muyw^L!MS;^)7Qo4bO%yi2OBDQuUM)2riGUlmw(pk5^vR1 zaHe!EpdZaSpf+#a|Gr63CZ!qvxu7_O7c+T?h=B;;qqvSm!A9#T{M4&ie}J4#6OGAs&5Jd?fnRCIz$a7;R__LzCb z+yY4W0o6`Ye3tpArVOWsvrEjL02Y_Af~cBf*$&et&Kwga@_hl6Q70Kqzp)#u0MA6x z*raPc?|ZE6(vdWLc;{yg1NHuNXFRYR?wxvkF#h4n7LsmgcPf%Y+FnIiL=DZy)(qb9 zaEC;(5$skQH|O*lX-a^}xhWGDAZZ}Pm;*TemjA#Al7n4I6PkgBY}Z3?Ojdf=Yy}-W z3}Vzq$I9kn5v!BSRG79mmr`n>B2@zGRH-h!XOV_AhD9{pOuGA2CPZ=8CdLQ zA0UJmFkwzaayxo)9A}lwLfFCC$J&8St^pwmX?l1j09(#pOSr^*@D*4a6V1u;d9tZ6 zcl7Z91XH`*=;lRlcdtD*?{oZBl@gd9m~~Z$6CS~vy>JH1P_sk+B^hVCuJ1cWP-U~#IcgZ>8xm)6;K(A74^^6=>wyAA4RtYB*laYg;w6fl#hg zmL7rl4GHgDw6pAxQEtwIadq^D3k{3IESe3_1mM>?vih8H%0QyjvjA(l|)=c0*lg9lHho9+*jUG3vc2H9GZd}+@ms_W<&{|az@kzC{ za`3+UxFlx9q~@(MK8t!hdhkfva%*3&0ZmP+DnnFuWB$GY)$bKTrqQ3 zSpE4lV`XRe6}J50VOqA7(bt_d1J2y&*2n(A;9)`G9_KeT*jYWT=?W}5uVAdiW5RXj z<@hwDMrDqMhQ`>@SMqcz8MNyA@Mz1t`mRMeW>(n9!|LmDHk@l*L^^Sge(EGOG19w^ z;ytaEl7;eD+gzi))LwP{2x#p5HAXk(n{|%cOnE`?>TfuzISKFR z>Cj8{~c4y97@te|gfZn+~lkH3z-K@FBq*mv7 zIYq^9A$>EOl$v5SP+Y1nK_TI<9~7G9xwH&FabJus#h#=z)ZYB%=#^y*KUj2A{l zgtL_8h#o|a@Z?`y zxS%ea6H>wmQLlrUXkC5`7p9iuwx}9$Rd@U({j}N?YR^B+3W|S-*oM0%}k|5kV1M5)b9v zZ=VisTue{c+2c6a{Dx9}hFsS?ab)T{0q}C`c3L?y<+eHT29BJh0*3V7&~IGC=5J`) zxc_NEdWISMY=NzwW8gi$pqOfZV`^xPfVhj3iXJHhY;~d#a(S7+WO6rB>LjF8h>#B6 z-`kLWtIBC@Nti&>U{T00K$z!{;mS(P&HcgQ;OOopv4bW;tq}}#%Mn#+8H}@XG6Rwm ztxN@X;@tTU3#qR3@%)s@Ecvh99_|=p8B&t%-k2)*Ze**zb<#2so?b{!do9#^?;9TA z$naj^cO$E+UBB`W>JJAqs!J z&qDrsJ_VqOu+z%S#<5?Qv+uTBKH|Ri9vv}H1q#gbuM(HNp_if(tZ}N4V)ROhCj$OH z=C{$EXP4`Op7EzP5msuCI5O0`lM1Lvu}QT>jLmq)2r)AXQ7#Q9KmNc7%*}X|6Q4*; zpmU?J;`1tR74HpdBy~b`P9b_2GSMz^Si)Ln3E|P6w>K?_h!@#P{culH3AH}+vWaNE z`811rk{>a6q(u&uVaDB(XcdZR0shN@`%Cg?rEpGv{P6O9v(8DjUX8wY#;5! z>hwzWPM6IKE*qYO;XU7cQqP6QnSak0paGktlW8N0RDW%vD=IR#Z9oC`8FFk-TE{0U zaQ89I9r>$Mhj)}Z2<^VhosA9rr(Ewgus0`0585eH1hcyls5Hs3om$AD$rc<2H3t+U zbDWSSHR2FKfS?#y=stsH-wX4*W0i^%eUYs-4vM9Kp4CZyGFT|$ad%kbw7ofCPdLFf z*nAfefZWAG4Zuf6e|^Nz4-c0c$L3LP>hqv{CR6;Ko|Qzzh;P5vMGVEIm)|6*(>X+I z*<`uc5rB&a&QyK&j7osyJ6O{+&g5;(!5NGQpI6qF_on$L$r3JubKF6&_6CIM7NAFD zQN=vIpYWmUS<+hy!qjgbh&c3BHS@=wb|xfk^8PmkDAPWnr%(>nx_T$aYZ6S79ZQ$Q zSab{q@+t;49j+BzY5EWhf>wjw-Pxc>G*W+~$HKJJ^1bba0ofPw#bEiq!^043Mu8R? zIn;ri(fCwxrsfu3M?XtTm-ah)Nv$E9$R0$qbUCa@wt6%uEdE_sk~8buE0C0&9;=STj^&2ntpX}ynaViaPPI5~+86D+CuUWnE z+JvxfS|`2Xjv$G>1g+Er7?6j97Gt*-CV5wH?lSY^R39+#;f;!25uRQXL5PAwzidZ;mTYc!kHnArH!$_3wxCh9y{ z&0y4OqY-gz6u0DVfDXogFG1vjm2~bzk}p2Sm6<4Rz?EkdqTRBL&qyX;c-2Q5PaM5S zhf}a$fC~EcK6kbrrCruJbvVi1op0{%!=!WkL>Di1$>)zh)wfQYqpr zCci*O15)uBnK#zOHXTib9rHNyIMzyS%$;ipNwc0iO)KC20d8}Rg|bugqVHl1;MI!s zw2EgF=_J6wt=|1IxHJ&G!Gi>fL!i7PNb=V3vIgh^ zL8hivF(Y96%{tbCfmOXsC*G5XD9C~YIO71F!Z-*u)Gp%xbBA3dHsVClU>)zT6Ys)3 z$Ykih2sXIiV6Nls^Qy8984yt?5DrDVUuPO~Z1RY0;)RBA^iQ%=Kn^7)82iLT0fb(Eqty9SJb)&}hTuqrF{ z>>)t!adDoA$i10}V3DHXb`98QDCC`8fyy#cY$}1WZWlGqXSNa5r$o%U)pqVv0x^?^ z8;a!CENdc)*0JVDUBw*V?t2Y>EgIvIA(Po~km13%foEm2n>%he?>phpVK>tlBMnK| z-{8>2DxmTTr;ZdE=rkiU(i$=4fXW%G%c4fnr;NJmF{wGmHA!f9n<=oknmKQdfIHMT zVejQxRPL8L@p(FnxyJMeYNOv*3qUlU`x}VZo-!(Yn|{7APSOLE-Yp&}$~oc$Wf)fr zP)?@6S#|E4bBZo)Le@2hUz*)ZS-rt)exQjG4^)a5!}D5EXaW~j;h=*!*6ebW3iiM$ zEcZD0JY);SDlm)dH9NM^P;HhC{N$WLT-%c6@+{z3UIt2nDTv?2u73Nn}`uO9sH_Kz244fo8CTv%66xcnzYEEv=+I5>4Y zU3TT{H}OYo5^#`{ArrJjvDBSl-dkjJKJHkd_iV^*s-qH`6r(|KJO_*e=ijVsHR+S6 z7gWkY;D@s=Okr$}?e)B|8hnGE{BE3P@q0bNH{+|xKT}}2r-FH3mx}!E6V!u}3=_EJVpF6z4 zqZ{8jiQ-Lxir{GXJvb>L1Hy-!&Zf@wl$$CC1NLqB$?*6eE(+aUZ%_87FVWlpF0d5o zezDisBas&;Bh@PCBazr6s^y7MeKQzY^fdsA#qFcMg>?`2gy`0fx^T!)$Vm$w9LQT? zZEz!d+j|pDtmrN~*56Vvx1UA>$;oXm>Gu)UM8{J$=Y*aHIdqaQd1iV|qoP_csq7c< zdW=fH+PTD!NVNED;NC80E+d_Zeotut`|Fgb>KEiO@4JnXv#$J2M3iTyK>v%hyNrtC z+xtY{I0OjpPH+fLa1HJ*!Ce#F35~lu1b5d2cZVjp26uP&+vI=Fd7im5bMLG*i&wC^ zimu+(RlD~7?C(!f3X-1QxhkSZeQ_-LDE;dTmNwB^^)M!7lhU&Z9318cm>SKM>aq|C z8pi7C-7TNwOesh*Af&m~Lm{=(&WJ#iToS}6V06p5s`C0bLNk{Xtod?Tm$^^ffzgIJ zIC}2u7scPs$_B?}R|c0Kv{H@meydqLAG7t8GSm@kN+faHG4#`fUL;TvMWRwBP$47v z(ih_z-l4PFrhbH7`R$6p49g7u3Ys$4d(}HX@9yO^5H2r4BnwDG;sVKPu76k22j443 z^l>rvAlwT$RbEkvvo(|L#x|kmytgx5phwgPQ~|2I2Fl9nif1TSy`MyGbvw(3e=?S1 zlG;%+(5`qWS>c4HER}4|q&xc0?%7@DsYh&4wKM+Qwple!ubTDjaQB$AM$Sw+!Rrl3 z#KlPJ6=hsDh(`Fp{tQHMV(ih)6m6f~aL{N5^a1+%q5OnvIy`v=`;=}GzommqD0`dX zS#ehwVLDE=$abn@hb5*NYw`tttkySRC@M88z;uw$j%e9eSHx!HQz4}5FqnbsQkpkuVPS&!Yjfk_I*(0 zZqnQJdIj!Xl0ZZrW>YoLS5B8vxwg-?G^M~u3wfsy^l#8aJF(-Fk)E!qMzr)E{p`cs z><@iz?P`I++#v|mJ$-E?%LqSSo%jxosg4)8FA|(VGeQ>A7*Xhqz@*5DPyE~QJ!p!c z;O}sxzxu;FsWDsTJR5d4Way*{0R`R!F7ePKpj~al=TPH_9Nr9CW*)a)qAO%r009a- zY$xN`!m`8e<@RlGI0u0FY<_HoKrkSU-RcQvmuG31x`o_Ukrh!v>r2&nz_Y3OJrKh-12N3 zX!HI-(a=&DE6Fa7O(6?6hC^WONwJV+u1`3%`jHL*5>Sl*_woBLF{AM7 zopWm9@=-KD=}}}tlYAXJG6cL;xqJZ{E;yX-_J7NJbao7fNQ&fX_hl^{smUDH%-r)3 zs+LY*`Bi3Xc5L4i!9Y3>BDdH7(7IGm^Pfkh51v1$pZ3CRZM^hgUb-by^9+Uj%GFJN~70r37p zp3j7b$t&`ZBnEKcXCWMdXayY5F0ek6XRgzLGGHHPB9Ljq<~wb2yyT)+X<-z46!|wB z^5TUVTe==fYhy&4t|I6=)A}_T8cZ$D$?z()lhKAxuJnm8YO{iX{<~ln6z$d9xv{}* ztJ7p%1xR|}uqmAk27dn_On@(Vtq|l!N>LjL!Ijbdx3jCS074ZJn?~bd;;EChxY~jI zui?@Q;knSM=KPzff@O-xNfb-NNkt@9p)T<*XfBFK8WgykwZ!3nmWd zMxp3c@YNkdt7LsnDf8}70VPt{s`e2PuDa8}fDsUmIy7^Na_JPIdR#*VP#h59E zj!W5lc5b|Um)67JS)!4S=J}6lKGi$|J}#_q=W?#vCZEpv_R$%$l$9yKS{wOLiqFv8W;-3!M@bp8e3OG z>FR+^vtiVAd2WIP&nk8_}OLXD)eiJgV0Yz89#JoB^ z8$o;2P@g6*V@6-?ql?12B`(cJ$PqP>CJ2MdhC0}t$#hcYxsFJ@5y~ywT%;XoW*F*> zn$^&%IF0vveiVE@mEf*d_92tm9Ir+7Q{%D?z)4M=z}LEg*8nH^(?=TVFvXzX5V!X| z`QihY1YMHEtAxz+B9H}|-45cwQpb1v+7U?D-iJnzUoQb&Z@0ecmP?Wj9u3#At$~G4 zq?)GAsN*A(ICPSa!#{*@$pR1)I{U#p>bA&yt9gm&Ta8&_608LqKpCrSfJtie&QM1k z%io`QOZ}P<+%=ZfyB#JyIx^W_dzzcU@$C=-VJm3Y?}^r0IWrHy1D(5>)x+raP;FX^ zR^fxf#j69wN{VJ_T@4*ogFuYTJnU^dv9;_uvCBb-2^@ux0WV2rU6X?OiZKM|(O^ zMV;U=l>7^1?VZ*oQ2P+RY<_NgUU_s24RLZV@Tdk!@3Txo9on}rZfOc|D4myc+A=zlO&FTx|tqTx{r6= zIwyS)sDZ?ELb~8?v7$zcly@Z|-_kdiKOiC9nd|x=i7lm;HjRq-emUdN$i+W7PNAEDY+43h%y992`;nMK3RQ_ilW3~6WeDz8Oni9^ za`v)j*>smlsZPxAuG4%5!DkOyZA&I3z8cA39TFA75xqxwdp?1dWS_<02hk1L zeUVX}E9^9~c*XYmz2)ZsNivE?N1d`%c$`8&7)(6&(qKH%$9I0n^#J%HdQR@l;|IC9kMbd#%V+p;6;tV^-@lzI(|dURkzB0`Z)a~ad)R#L zdJ>F+N$U6s)bZ9gw$rbVOr~_~Lo52m*}vt+$O)S}0eyr_W`7){&ekuyoHc&P@R-CW1f9O(?TA2YWHHaBMr3UT>&bk7-gz_I zy$2l58DWc`h1|Q1>2TsFNX`qVS~4G%Rnpqsr+0xX*X7L_N&DY^*Zst;SzvMy6l=cn zCTL6F>A2>eX${paid!+88@T;F`>fwr3AiG znDLme_W1BjZ-PK0FXZ;&q%-|IU@#ElBKObgqcu^XZhG2?cgxp~BA#QmOIG=yBAlMa zF>7?7YSp$$^mz+w+)VEf?Ez!Vi6TkXB*~=z5>nlE8r7t2VR*m^H|vON5CL6V@HNhH zt!2|W0gtmut-VLpxg@hJ`m?8IOD)Dn-ovhb@^$v-u!*Xrfs=hZ!~F<_^y~Ihiw=4D z7S{(#8&`bufk@A(-xp}e$(cYS3gLY=TIFyc$L>>e+vvU~mVMTiTT{Y??d+pEWjo4st zjn6`08&>vHEOW5Y(z#}ca?s6>w#TF`m4}pl%M{(0C7wrY+po*SrpzKj>I1vr9bN%5oAa*mfN0JD!_Z z=pOSF6+3D9C&d$`m$`47q|Y(=U5WQGa~xaUG7<1ED0;UxwFuxXuiHWs$=pXzZ`Jb_ zMGAYwMsv*BHd}DI9@k&X6Mr0BdAT?Nz6{TCN37lD57+8@{Kzou@G$6z&>%XRYjFxr zgcEaIWTIRvRD`N;Z))#oe{y^td)P^9P#^K_e(P$-tX%l$pZ0jkRhf^wAT}a4f(CV~ z7_b4!_YVGjkdq!b`P(f+tirROjqN;A^#(z+-Y8GM({gq18-j0@Q-#y)j9p> z4t@preVs#I_^o;9cOh=5eEoZTII7jRz{D0(mchR}auwcwDAk77{UwjjiOj6Fo>n?U ziS&ng2EX*+Yl`f5Up*uYuh-NnX52zfPXJ5ToZe99Rg8RxYer>HWSlF(XAz^u{$Uqg z|9XR8LiB@DBfjc*R7h?huZ6Avh=52~A+y{DRM?@=`Zsq?YQw(PwnbfO3#>e?VtUni zt!r=EsUZ3h*h{J~;d0y+1rZ9~qBOUG0v1p3?-r6a><0D-;iSRafy|PP^|~(1;2wM) zL^wzr8XkmT7}I3Ya%9j2=oW_}b)V3O_kR*we52do00IDQ#EJ;6Xw4r+UQMvno&ZRi z=!C%Vwp*H{(%%8i*!4GEtt!0~OzwX*wKg=g*YBVEC)PQW`ud#Pk+5%y!O)x$y(9h7 z>ND#LEz;NJc5m8hl`|xi?grMz!W(}-^v=U)(U8Y)tq%S;qCty)#Xb`};w@GyDb>=y z+DNFeVGU+t4gB&qMK96?ZsHIqa2o;N7(FWV$wxO~=*GW|bmn(v3vMJo+J72p?vb{h z*nx%a2Mp8$tG-*cfsnppV%x^2PbiUH`=%a5Oxn-WH2fdWfek#6kce~MT1+%~W=FQ|G#AOcd~bT**o8~~`H`#SH0z{5GP|D6X=hE+Ke#|WgHr>$0by@BtS-+nTP z=%r>@^Jmd1Gi|FDUSz&AD6c>R-FI%)s*ZY+ zsE>GC`qvx(3aa_C$bu1W`iJE%pIzU*+PKqr3IaSp5ds5>8F(%C(BenWcr_D&$bUj+@Ouxw_FllbMuH`}T-w{Ql7f#_v6l{}#z`6n z=eOSF5iViaIsxOh73|jvK$DeqrR-nL?eG_@g3K*aBfUZV^#Kp;*Bn5dm36Lc%Jr-$ zgj(vG!S@0GR82DsX1-rASzvr?3g)tUaT{0;MCk>e|LhG{5HA2bKEV!Ep3Pg&8H}JEfm0~ z#mJgM?T+G8B=TFOVx4x8M|dy$_@9>@LfiXMa>tWm^|*+w2GU;e^LA33D^uheuM}q8 zpDq^gzchL^K4c_5dnxt~dkQSsf~%ijZ#l>$J9v@&WVfx_2j)x$j@z(3jdx7#FD)Zg zQK1t)3ogI!Nn}GJUP0}-4+*iXf04NV@s!-~`ZBhd^~$w}gnt}2iY?)1qM)D`9i8^L zZn}7^tKztvzbdw0!FfohQY!Brq&CX#3Q&kA8ul-0b>V0$(k}Y_a(?%ftKqxYk6*v4 zl0<^i<|;>*-UH{*vFCl-?7qCuzpXQYcS0gtdqQ$>_{`=} zLY(z!67FX;)(B8Rxt}#EWwcI^#w}BPKBYX&!!RM7Yr)oBYg^#$+_+cPE z-s`*f@X2n)!1PAuPuPL|mQl;zJNfT>zb0M%%m7^o(bcTO+k>1LE58=YTQby}ndN~k zQ4yep^Svflg4oQt>+|oI>_mG4onOZ=tsW}mJ%ZVr)1G6q88(ybekE{);z5ph!KI|4 zPd&N0t9!P}rm}vQ{&76|dvYyjf$&Pds2&F<%~lW&5daf^ozX7jRS@uGd*ybbk@Nk0 z881GYA}I=s!X(J!^iDWs-up8wWQrD0F!@ zQOcYt_18>yS7T6y3Q6f@)RAt|+9kZ0--9!S%W>RiIVFd34q34SC#W|t6Gp*ME}@`l zH4g8^&71^H>J-`V-U05e9LDR9?ckqkYUPQKpARtk1U<+Tiuu%`zq9(KO2>=eiQ4Cn z_Kal4mI8Ina;OK&MK5|&NLA6?3Mq)u$g~UrV_?Ymo{vS;HjP3-nb0YBo|r)8!?zS+ zgS6ESMxf=G6+gFJuBhZ3dUc)4yp&r%gmrfY`{+OhH1#~e?|4LF!&^!D5tf<8uE?b! z=3$h~kb}-vt_x8JbwT-#mNJh zd2RgP#PmO4n&Q8MX@@s3EiycDC&ODrEX`iR3l_leYGe!mUfRfbLbU8qs+~@x3^vJ} zh@^dg>JZC-y+CGja`d3$Z4gmRo!%fqP1dKa{5~>szoV)We5D?w5{VU3Y6*s%wSX#K z2VhvlCWM1kSLA5Sb`*Ieq&~DGx~`eK@JLCj1C^tAT0k~rD%>`$wwP5cFfb?Ggc~4aPuRbc9bPed{BJBG-TD^GI z-K2;Bc?!|=4`bkrU@3RjIrYh-^uY80YoPLG_+PC!A^j%Oso1nLqi6L$%>|mM@j_GD!q-M!?Wo;F^0Zuc z%Z2ESC~(wMaHLt35`Q&lO4o+1H}hHDHzs6T1f`5AXFH`tRAB2dWyhn1ap)%0`d}LC zwp$pcp8An0AxE3xDRoYGtkVQ|dISGOrQf9VrULK9v}8TqpPDA26$-QuYvxrg8wgFJ zY?L)0%0n5;3x6sTT2k3Uf;2xIr%kYS1ZSYD8{Os_;@yX#hiZliuj#{8f*VIfvZx?{ zFZ3OhTz_77;;5o;PFVJ+-(*N*h=nX^Wbw&Q1f>i%(@Kf74T;nhptD|-YX+4FhS3*U zd?msXUUT*Hh!~n01N1Hm^-vd<>$nXHbTofaaJ_5EtRcj(Mo zeg#d?p((hgOMF(&Zi3&41##oeuIi9QJ4F#Sm}8kDLukgP+;!`!7PK-2-^C{`IAqxA zBz}`B_8~v*OvY#rKpoMmTju_X6ojJZ!3IQm5(6n>6+hWtK$7=|u_UptPwMzVgA`8* z1shop-GmiQA)-|Uil;^K)xov1#jWbYLuokF37uJv zrO=P+QDU8|XERTU4!P#QY6d&z22pwLmsXq?;?RvzY@_Pho51hwY${tS?Qt^?3IOgq z6qHF_8ONqwgDW{MMZgEhP6WOitg=RS5@CMpvUsi4oD;Q_w_nCvZaErFT+` z8pvOGKLpm8tzUze)HuXyEPQM`!|@DY4Kv_r#X`)L3xoDVkrD_nzaJ_)iX(>nhK{)a z!gPa77e#i9@!Gx=)HzU?f6N;jX9E@!E=7bCsx{U`m{pGM;g7jeS@fp`6mBSkw0g@* zbMUCA(RH9hw3vDW+(u4JcMF@G7Mi|cQ(O2Ea^SH+8Jb}dI-DP2sRjCD(2>wfb|YP% zoclAf{LCX1ROdc4B+n1EC=d9E@R?5{(q$wiDD3w!%>q*BR!ya|vakD=ss->5!$&Go zjENMxa1?mdI=v7Cvec@vZ|TZ<@;Nt1_XdRrf3zkOtW2@hzwnA93`@rjE_n5CAja((P}89CJn2VWT*d=e>Z#-Vi|UWDW5BeB=fnLv$nEV zIiEI9PsrV6MD3olj;E!v!PFi|e9aZAb{j+_idCkO1OtO!ffZUy=f{n}7%f^ccX>SP z6o((r!*@Je^77Tv=l6P&SqnGr@`1$M%mF!WFi%j#enoS;R2}?Y1uR?0#^$O%SfBc2F4U_YGg{ifGi*^YxR#r;hVja!*j zdUm@JO4yI&R}uV%9w^GEG~6%V{}lmt(q_XMn-0RSEBc2D))u>`&7aE*(z>qi`g$ip z;_0L2Pu}cAC$$TE_`v$eBIBhykI4NP-NtW$$p6Kpjnf?va;0(wn|G=XR%@$<0%(H- z?>Y|XqE^1hM7rG8`U*(@cxCecG#M-(J{6hMC6IaM2SRjbAGt#P&P?2GxBpS`!Zu3F z?!sdXNs@(O+{CNSb3sZ{A#*6(Geik%%Z>+0qXl8S)lN!Qz4cRMPVvDHPyrfnK{Q4WaXgMnAh zsaSeIDlm11f1}QDUH?$$PmA|I47;ZWjL$M&7jwcibv6RSmj6-C9Y{Su>iwejZKXF53-YW2rp@aV@SG)BL?Y%NlmSN541^_oVnYalZAwpC24gOThMz%06jvrdi<&Z-g0#saBHK0shho?NLf_FfOz?S2LR>`j9vSU#RhpKJ7 z4AXg-@S&#u7jvTVBrc7X&c&ki-ZU z>_8_s)$~zOayO>yRu@29*ek~p7V1-0a;XM*#^$I6p-qU7J-`6OH^pDk+;Yb$@ala<}?Hzp;42pl@p!wdZ0m+{&Z4!^Je7-TzKH0R6lG;a@#!z5*Tjviu=UpE9tk#P=(lGGO$2DXo@|IR z9_AJQ1f`N-9&Hlw7HB3f&gh{Yjh9Mdd&@U6Vjlz*Z*okY7y z2L3Hv_>_xEUVY=HYh}*XnjqN682stHQvpQH5D&15NCO56K^h;wMQtO(5JVZM(jCBZ z-PB4VB)cLZ4;Xp6eR$h}E0>Ea@TLXmT^NrJ=#4v`O0nzWJOxVmO)uR{$|JOQ9LNxGi6Ei0;Y2+#fFcd1Zi5m=5m zs8WsCC;pQESSHE)8xcF4hlx0JYbTI0=9wjamb5;H}7LQ4LS{0STuPbcr=&Y1fHKS zx4^}`18~9BxEt!;hjd-2f^&z}B^_qXe2|jnK{rrf4(&c* zAXRn#QwFZ3!k_m{ED7zcKDWy(1Pkt-K|3364`0=L@#%V7uq{Y`Iy)poi|P8;{AmY$ z+YHIFaQw-Oj}fG4LV**a8MR2uzqEubS4$_0S&jWa`pL=6|(*b0zUp&HJh+(A)nee88O!dEXG+(*aNoBr10cbAk#3}0&-MR(l z+|aplM1#NK(-43ea6)WcMq)UKP1Y@;sMCcgtLPy^rZ#iLHEk`<{;DC5w8a53b%D5gPcSNOxV836De7QK4aC&KWmvHdw0BF zxaeb42qrJM7mjWAE_b(fO+E zBF7=ZQpYRKev$g}W@C8PLMul6gj0-Az^rqW@m>YSdb{4HT z;Q6B9eo~IfwgQm)FjQL+r2uR)coDVHx_nLNow~lu&NQ3ZTc|wzxH|IjhFhDidU*y-zbDAgYC%w}3etq%CJ7kH(Cj^S;PtWd0P z){(X4j!kogzu9V24+!;t&7gs+#YZoYLkG-(^9k@QCVFp3MzX7UlM#hG_Q^DOu98faAu#55oc`!M&fXX~G zON8Cnp;KH)HF@(TM0C@|{KL*%Vvmt$K zi}B0%1L91eAawIZ-J)J2ZBPg$`$oT+Z<;PYTtx%BHkawgYVgJ0y}R(uTYG!owF;`4ik5SPknuigN{ zp!C?ZXyd&m>vA-z?$ajvB@rO09bV&`4rx3BeV)wy0Zba&8P-?>7yi}&7ydS4po;-f z!KtQafwu6O7!86FF<8|5Kr`Rwrio1@%~?!B6D7@4YWN-&8mG~nD%n15Y*T*n7M88# z{|8P7y}@aDQ5nZ73`hx2DD`}ZG;O5WEeHf*<2X`EuJ~>H^(pR6?U9CW z6Y>8;o57{I|3jNwUJoz(3_coiKA#G)lG12`*`wbi-x~QL1St&`9ZjF~Ts(tt=s9}G z(RX-hnu}k7vhT%)DwZH=q&weGU%%nj+S8Tv(o6G$V+|CcdTK7ktz^d0nvYRFDK?0} z1?wEX4+i@toiJJ36&$eIotoCZkC4G#7i|m_^kMU11Fz-tuWQM8-j=8d9Mx_`v{ToW zeJZyJ%9ledZIXXi{ymY{#+!m(g(0u$T}8)tGtETPSp{O3_w66guQT!r4rh)}+>0i( z_?Kv*k+{<^yVvwI=IbC$YEv|TO!0vwO5k@GCI1Cd-efz!hHZw_B4eo#`7ujm? zC`W6kdHD--^hhAQvkyH;PwNiS4aRMoSC3NR)?APz0M{#L&POBBQdg5!XiZvEx%E1C znh~5qpfXU#y$f40vA!b#tiVN(qYNH7KsgzW@cOm#_7O} z4_r~}zgU{IVEi_rThfa>7Eeb=;DNcytJgTaP8=)R9YOR)ek<>c?Hx-^7FV%^k72vv zd>_%lk`3nx$teCU*gKa>tbc;tBF|-+Nc7Z*v8gRvH8A5m3-nol3|FOe5VtUkrSp~E zvmwM~OS_{4y6xgP_u!1j3jn~+xU4O}vGx^q{N20LTL}Q(c>I+kG(Rnd_CHZUG!mw; z#AtDKxN0J}G!j%aC>_n*epGA#9Wb>5%Hks6g!~ww5&i z*-0U9kZoCy;_#~qEcv_-(j5E}txH6Xrp|#1R1Bv28kWc)pn%)gMjlU)>%(&eVbCY2 z*<`Nqqa|xUn~AXjLS2Yx68!x<7%vY5{98Kn@VrT9YBR0B(pkAl_J1Rt@BO}^aB5pG z@J3A4hQuyDE`_5_AD`DOStFfO~6BxSQS3RQhw^tmVK5?pC2P= z1s4==SDOF+`gjT&TkY^#Xx@hkR1-IB9yg?Z=Lk>1m^UWfjW``ytdl<>_#UJ(+VVeZ z=jmcUSHe6|7p?_*w*i*^am7ANT%y*?_g|JFeBS!CK!eDh9gJt^2jj1YE*JpW9+9=0 zvWfvl1xck%fxybT(SK%`az1tXSwXE)mab>tatKloSp!lOA zOA^p<6n9MJ!a(zLeE;~usNKLN#T^%m8BR3>2mosBsjY}y`Ms`N)#BVN1^|g~{}RSi z+0j%mWl+$;CDo)HPWdB3S!Y$K13*SSGL4KBe6pW*dJbwz3n$~LrOkjEtIm5U^nsh*d1`3 z-anLF7oNC$gO%_Uko!J}dlsYn0(u83K#e>=EXw;2$KyH8#otb_i z6MG8c`d=E#T5ZHkmS8iRec2nDqiR11kk3Y3aU!sLyUh|ho~N#`!@3^JxLgo$6$Z@P z4I}{h3zxenO{1k2u@h@?#1L4=Jc1J1CLo@{<;#OpYjILQW|awT;8|$+uPIv+s`}va z<6>_%fYRro@f8+era@#NKIH>9$*&%l zxxi(ScZ}r#jjN(-jjt;dp>2yFe3!yHO)1K<-b|CPHB)d7u{(fU{-uW@LJ51dnDIPr z*(96sdy2NMNEm5c4r5Icuit5eV}#h}q(jUuVVn@fd!P?*_c$mcAf-N9)#{FwSZ zIT~}a?MPo1@nTEkE9HWApaT@R8Vq0uJd|R<_!|Kd==i*t(xoHvLN#nq39Vu`iT9Xs zN9Vrn!zkGewTBPB$28}zN_41uzc!mL7qR(N4qJV&J9dFP+L$ba5qm3Y&b=l8Oqt$u z^9C0+-vk#m*Otu2l+hfO{9DvKwyXQ!Ma{w8G5DJXi3as(d5tf;t5tw5x-x$spjlG8 zqVOM$73gkwGM#MbPXd{%sN$Dbtg!If@Bsyql)NLXqzs`6ka++@75L5CQe46SvWC*# z|12Zu;Cxhyh_0`1sgUtu7W^;Y{C~)sf&Zg#reCB6FLAPTP9yjTuUs|idMlsWx3-Qr z=^A{rUaiL#E={U6lG{ne3<4nvx}j(sVJ{#LUO<2+_e|VvPQL54dp^uO{RvK6&76Ij z<>{uoapta1U~}*FyK)9Ecl4hdN8h#y_+b=-kn+^my^p1+TmZe)xP$oMC#$D4k|tlX;1xG}*IxkNmOK!ot^Mg=8nU#xQ|>gB!{T zcZZZLwK?%Ft$63X@eTSDY8Djq4v}x@?vKUaEgcijeSqe2)p=7>b;zd3<+m~&DB`|p_RTO8T)kg z#g~CdI1y3-mE}1%o=!%EFcvTF^|!VeIqSPbaNskz^GsIzVtI9GkfqPRigM#SC{0?c z4C27*HC9WsrVHrXfTni?YFc#p1Z-RWIV6aM5r<?Re)mUfK!yFP#jjwQ{AFPJ$=QaIECOXz9tBzG(uUY) z)he61>tfZAkiMR8^s4V`JggU{f!6RP&ZVZ?>vhHkdsCy!d&mBpT%+=ZytW*R=H`*Y zpMlkfJI({uqqaE8bv~&b{2pOb)Eci-uX?nFSslbR%-gI;hfFJ5ZuK%;y3JRWcDy?T z^7Zml>*_$o+1(pPj{LW5J}lm`nbhqf&)-)AkN)>S9SX^P<`Y(k$cgU@pY)QCc%cy1 zov^3}9Glo;)-Kq#T|VK=(PEhK)r1@nBJIa}^LYp#NSNz}YRr*~vj=MZ7PvszOWtq2 zPVp{#GbyZ4Bg{DXme`ZdRGSj_IdjVTT}{+}KwQe2a=1o?zGK?#{X-wbYYiuf*8Qu> z-S+7O(xhUP_Cqaa-j7quY37y)X`AG?D&;b#4HJk~CneP()+^_gDpIy}hntT(mOOb) z=B$rmc%w!qS=6#?0mFu>C-IUK6|2&M!c_#z?nUHW&g|j~H_mQVdy!>IgPvb;S-LT; zf$EebmCxWfhbSEF?xAwy}3WCpL!0w3}?bSE8XSvN@o6qeKd;Tw$O9?13n}FYp{RaYHmHo?Zcr5-u(t4HvV7Vit_RXqp4kw=|7CF;K@y2#f}TL z&Ssr)ejkqDj5xMPMG4eHesBIl1;dukHh4#MafbNyDH!f^3dk=B7RRQquzS8-Y6YfUiLq+N{D+4I->$ATSfKg<0 zRM&!}A$PDnhIyAQ;xFm=E}KCe0SkIu%bSk_ZiwMl91W5tYUw0G2hw8WES0YgP`0KjLDs@P)*Nr?vhPyuf9BV;qAeShEgE<1!Ci)5+jA`@DXSV`KvV|BFz zAk88d;EypEW=-mYP3dDr=v!q@A0ppXRR>7(wi&--3tE6tJg&W`@d;B%pzxarP^a~w zGn|}Vg@Bkoz4r&agS1eD+|z$i2Rut<-AZE#4JiWp{vJvsOk{{Swi^l%vUr1rNeUpR zWjf0_x%5Ci@x5WB1gKnq0<)J@_v{vDAUEIT2PuTn5YwXbKuya6NZ7NA!YKxdBZz12 zWr?mWd{#o75j5`7=|D7}6P!}u&aaCt*w0G2(R-)F#~d1ko&WghtB7% zBh}aRiB*HPL(sV3rUC`J{lkrrv}0o5P?mI{)8VPl)Bf#~@C)=k8^e9wt@_JT?MthA z=~L(gH5n;HyV(WxhY-w?-$i980XN7E8{OCd&(K28u#!AKymj{{Y;+n}6G2t_iv;4821X@_vRZgbMWpP+^w}W`-vjRQ{$E=N% zdNr%J4LPrNEOvt5kbX4Gecb_DiuQ|BIO>Jci;n7TZuiz$G2q^@+U-7mLu|Lr+EX@d zx=pI1BS{Yp=!lxY+Hn@2V!hgp-L~Ene%TmN%SvUK8&ikXis?*s>54X|{>eeh^h?C; zO^4GfiHZBFHVC=TZb)G4o4(lB<3pK-8K*XIXwye45`6zD&{e;;Bkk{<*)4D8ao_$b zLsq@2gx3aLX{;Uw%LkDO1;H=)^IwYohOw@)Z1w{aKdY_FwdfuGO=4}Dz>`%WksU!l zMEe+4y9vWAMMbi$@;Nq!Cs&h8{;{&wBZbOAX%s7C{bs_6+uQSzG}nvQ)8TcVNVu-T z;Kege+HmUt?N}ghVaL)WQo}ntLa)x2h|lQ-PUb!kD4(`DB=zSDI1i_QE7I-wVjPJy z1=uf1>wY(}J@~=Ze~PeQ9->Hh)#6tEgPzRMDAdx87p0c%18sOO&NX-=)w42jYZRWPD0ub-@kCmHzQZ?&H7p1fUwv3Q~LO-taen&i(eEM19vQWQC zMU`TaeTgHntvBOX)t@n;_+p}_~Ff4zspnTrKQP;XJMm}aqOUEdpaK#Adg!i z=)Tx~f2IXQy!*Kt^UF{nKUX_wx@5?1P*foRJ#io`TS1&z#c~opizaH?J!OGS`4@=c zYD@FjOOx8GTDZTSZS?Z zE~CvYhX6~e#6*V#EaYw3LU`(sUZFyv zLJZbGAw_~z?4k(t^mD6<*qCTsIhy9Rf3ijDX$u5genrSGA_sc}higQKdJLCJZ zLV=3T-H@tE(wh_#gciA>e9Vr!NPaYVrXCvzM)=$wWL6e$)G(j=Z!oL(AOc$U|A-Co zi#Z3m6O?HhHx8rH$v546(!bc{v28WyN#;pmccqIa>+7NZE0t9og)xTPSnkV|QEe0r z8H4Ydg25;P&{5>N+nS(}r5M0&}={JfSe*i`OL^hP80TyvCwIOV? z(4VmZ>5?H_67{@BqVabomDTwR+=$!=a}pABM5`smOqhLz(A6r za%8d^lftLRO%{vQTzFjS12LJl3A!TC{9`c&Ij?!HJSK}=M(!Im4CBU%bqL_1;_l{2 z9UZcjcbZGL#CE09>O_v)x}F=mx|g$WIyE0 ziX@?n8tH!D5Hk&dPd5p~964(raC>Pm72jxmq~_Zm@;v+5;mx;_lIe*#>e2v(cQ1 zKQZH|mB8}YO`IkBEsj+<1Ev7&EsnJn&Yo@h#{kNofa1|q*0~R?{;nCxo4Q4zgJdQ< zG9SV|IPc2RvWcXX%Jyxe8KP_CgSB(0XfJ6je6b^66?MqL6VPdf$8w21tZV_n3k*TU z&dgvldCZXv>5_|~ewGt`Nt()|k!PhV+Afsoon~CJy=N6hv>lEzhhJqVqUN0)S0^*t zK~mcQ9S>B7r)Wk*r&BrH;R9kK)h$oisNqSi)yBEBh>G^31CF##F9yLrr44)|_=Af?(spG=dq3CZJNlU!-J8fP}u9W!ZVGZeC%)JH#7 zPn%EZZnb)R2~t69CCYu!&~ zBn9&KlgAhv!Li}sEQrH$qfo1lzoWRmDh^R)Hbfo*s>)>de--FdS&37Cv(qFVgmRK` zgCN;o506x54;^O}$SDp_{!+@%=V+)W%rRr1k-mFOKJGW-n@lindBAji;9 zY3_c9u*j}Emn!NTe;C3L?O6F^&L4~X#NWRg3c$R?7XEC2`@;mF{su49c_^j9`bNL% zMAsN-3CAaN`Y{7cUG>A1WUGWVagch-Tk2P5>a5V0owZ}UPoEZO2W%nyz9R}V!0pDu z)1wOiLmbNgEe=1}Yyl?zK@RoVu4;ZkjtDB1O#M-HSg#i1=>Mb*ZU5GW z8HPeU|Evw!bvK6z05nDa;D*+JbHf|B34d-*Orrc`oPg3|HL`j6vHz$I4?xyI;k|AB`BuRT_-w<(wYok5^F-_L)`Rr@BMCo~1W)+=lXoy8^X2Xw>w?5> zpEukoEs?fXp94n?Hqrym_Pq zB>BlM5;}2e8rTS)$}uD)O-S&62F8EMY4x~g+E{HD+7RL^I8=1G4k0?gsjng-b`CuwLer2hgTv=X!E*IjwlZ%T?0xB zAARpSu%YRqrw@(=07U1(8%OXQc%7OQS-KrL405usgosOVUwgQuZTJ)B%t{Aa;+mBM zB~_^nRSRP;2{0|5@J9J2c;19UJ&ag)@%5zAju-cfE%Jwt!UdW?emNNtE%urt+9Nb| zPL{d=n@#!#qXX}Ca=B^>+ox_m?l_5SX^K2vHr6N99NGQRVXY~)SNp9sXN|$Fsx7E5 zTH6iV_8Ky-^I*8#jJf9E=*#MdDlN*N;hlAE$0Ie{g$<5^7i&Zbj*!oWStzxOdG$R0 zI*v7!XX6hB{Gi=}zf}gge*C%Z6Yk>oM3Hl4&;!5a7Mkf@T-(L11ZGcl`<)xC1qk@# zWGrt6jnSL2f9U9B1??yOX2E{r{$Z3!lG@F>h#xZ<*`Xw9G@1f8D;N$mO0V2wCn}VD z!WLr=nkzaEH%3^*hGn+2brHq!GDN?Rt@%e(_5V;+1w~bVE7j~&eGxYJNn{V!3c5yq zOU=U6KN!ZzPTkvb_3TT>C>WBJas>vYweF}OoP=qrN!r|3zdtCHeXU{3%k)uJN=_C| zof$TJrL<%_Qt}B4jLrsRub{!4yzOO~5Nu54c!(i?!_g`j0v^U`8Ex)6;(D@0;-|Bb z3u?DfKPGf6V^PC~K}(wqh&#D1rdd&jQ;eU<)`*%dU^B)Jf9L6`COQ~k!`anl-i2_! z`zD&9KR1(Bb5O{D$=6lHVAWbLg9@n!uIDqN`89#Vcmi=n_rfB5)J+m1~4T zID_Uz7|fS=1o1=nzodKFdf6_W&*-~1Ui_ZVABOKO03`o4It1!(qSBrXNzpxU-h}tB zLH4RhXTdxF)lh5}esrt%cdmQ!Yv%w%VIV{434{{Qh5F=-q)i7ON*T43cg0Ukcz(o_ z!iSZbmokO}l&3Y-xfva$QXr=vK-t4kLd3|>hBOfaTnM)G!zRi;{*_{F>#*DUoXFdSFgCpG3jw9BQ_`Ad?Cv7J6i(fSjzm4k>1M-IkTG-&!ifLdBFYi)1G>y_*Z&{uGI@1pdn!alx#mZVAxd`UJ|p7NC@ZdQq_w&4Bdo()3~f!$z0ys)*$D|(F!KNUj3+(_|(JYjGj-Wax`5D|D2{nSH;3W5yui1FkGI0h)|Iw=4nF%wc1 zQKNjde6hd;>awzZ{P!+vG}PZ+R^~2HmlcbJn)Qc!(q82h7(RfpF5?^)1`_5bzOS2m zxtmy!h*)srd>t|*4eejmh!!tl4o+u{PA#Z^AcE6W(&w3gxp3zwC|J^=jSg(vXAmR6 zp<&s>vbw7)K^gX!<{fa+Oed9a&|N2H69D6fq|pa9(UlmpgbAj6|3dZ$pi;RiyvloK zGIc$rVqj!us-oht6ISKGDo)Ox;VRU>`ijz7JPKuvliC5pg1<8z5=)z~ zi9S@2!(<4hMd2Q3O6|_z$MkUvQ;B##!T%5NBH%ye zSv}J${a#(%u5aQ41fWoEH2zz@_%G;1(b{vTmbq2+geEYHf}1?h*_oOeUG6C>szl$g z!wdL3&8m%WkhmF<6Z*Ag34U##63W2{te+Y(IH)$_{`mZ4rfPbDWepmxqMBCBy3L7p z8=eB1y63OzCYfSf5F@ktZf~3eRWkYfCfL+?rH|~AaJLQ@OH$TnRO|cr`OP)cn!w4x zNl^MQc9Q#T%^-*IVaMtP%3Ran6CQ+vfjkX+MfnkxoDo1gKEt2u^u?T8*f^tI5~O4E zc~$ULGMzL$7q$6>bmNy%;vKue)5KzgK?d`<5z1oH2}%M;e>cvan=VP$j{blJ&WX~nlV!jLfs;2t`aXyR!ZiUdf0 z0T~kh2KBJ!AW&cFo(kESwPD&H3|r$8Gzjg^1v(uKqT+B4?Pw;dDsn#*Fo<-Vhh>{a zYKv1i+T*+j%4Uq8{}jW7iK%f#@> z>vCr7diUn(c$($^V+{WbVtCbm%*d(+jG1ON^SNzs`AT)9Z)HC?A#eW@4Al3%ZSv=E z^dmyHN$=v!87_$W5V#5&Ef?Is?7Cl?XNWv_yCP;hyMvga4kd=4J$L`?pkq6-iY2Hg zn!2K=<3RM*s&6FX2bBswHHL3NtLXHZFL`&V(#=jO1#&upUBl*2_7uA-L93M8&i!Y% z3tq^yD7mE^-sFK;c21gT@}YC+tcBDC4JRAx0%}of2!0U53ZMP~+MuSGy?U@ReEIP3 z#hBl%$M*=J9Ygi}S!U&Dy?Xk_4GDE9SWsvvrReeG-8zX?alw?U=?I4K^mGnK6_ZT* zo`lE;yOyisCa*_t|27wBcbMohKWxR%;SBN9`gHt)6q!uy-b&+&sb$vv$=Uq0S!LNh zc#%gRx+Oh*s>P-np-6X$N1;$#Olt2RM|p_#z}UM17MLho4pX^Rn1&?rcwTr~oHcah>V;F-o9%MJtgPVQI3|bA9s6 z1@GLqHG$2|wig#DN=O7M4-&CLPSn=OComP-{ckD=rQc|55U7R`N$Y0{Rm6iTsLa`| zQ_tp^0;S=36^I_Lk$eIDU6(W?>jRHa{g2}dv{77YG(6e`cwqP`|#R78yp@rP|GBa{A*?Q3LKU4nDsHbp8fQl8L7PFe@;t zoz@H(t4#p0zR*P;m)6BBSFetb@Kr-SJ_a)r?IHgd+ry{p+TTf)A1&~wQmtQic?QN6 z8UlX1I=44XwxCXD{3Lu{KUJz~0JwN2A`(REkXMFMG9!(M#}<*w+s>;Z);V$?jpHP- ziMwIU8)Z(xZcKarm52o$YS!=kq#~%(hBHsFnCLQTsVvIU5UAH$rmB2k-SQ`5w`%?TWP1>P3sqn z*$gauHZ3SC8xsp2CUoFIOeXMe-(%)IlLDjC_&4tOIIQD{c|>f(Xf@4UKTf?FJ57$J zpLT7Qi`->}Ebm*v2%A7Zg-Vf)X`Jz`ETo7O9L`r>(>inEW^|PysvxP@uk{jQJqO&p zgwD>jMBE)RiL&t&Bc%ayG})t9jyv3YHL;?xzuk@J_v2`@uwqGkS`bIzqe&b#Xu&G! zyG{5+E}$Kh*iY4q^H59GEv&N+iUiHC_`D+i*vSq;5l1jUr9;}Op_~mtEKf*3_(XDr zW;LlgBw+}a%Zq z*E>SZQ}othI2rIcT_oP^&fhcbx=n@08`CT3*k||{30WB8Gk@O_d#!KTWA96JlGut<S@W13e?!brxP;&Y)DHV}Jk<7J=ldz+5UXhGV3oOkXf9$!l-VIasgx9y z>6-gx6Yr*-?!M6_U7=osoHd4%+_`Bi-847JsZxlvVG>C`w`D%P^&uQjLJT|Ctnp!3 zfYt*RjN5SwIk2fH#0mCjiv=~mFiTFoPu#e!qH>5iMqc%tFQ~d=`g*H0!(ki(9$-wz z<)P~cCSD>=W}M(I*o@)|2^Q>c2qkct!=t&p{70Dc7ab{3+^D<2cA)MWCL8qC*+H!N z` z?7i%VwUq(uR)+?k-D5S)dI9ySpB-jnW&JD5EE!{rK;n=ti>)nG&i1!kDsJt z``{nMSbdkY;gDdE-v6|a56hPU#XXNQ4G$?GgV+d)qNVi=IoROJD%Vv@0#iTyf=x^n+b8U3dwkz(SksO0myz>^sl52wQ!k)g=3IH z$N88(#0e*XWS_J;-t{K&PrvlfkH=w6mi(Ch%>JF`Y;KN;Mc?OO5cz@o_F zK)Z=eT1SuUap%7FI%u4Pq!`36*a=azC9q5LF%`rY-{rG^QuzeF6vzj%U6@R+Z?&O2 zZ2(?ZHyx_MhEoqt90&1AWqih}FPe`hJy5QO+S+k-VG{g_WBXQEsnK0Ne$zn2<50Za zvqd-Z6{k^wcKVFWYq{D>7{Bu9;RU+&9MH=dA83Z~3%Lbp#cZ6=Ui=>D?4U~KD~3kq zUteV(i4xhAM_)ur2MgjcdhE?Qr3A>Ra6| zEK8S0Vx2K>a0?q@P{r#C^A6R}RKOejd>+F%))#LZJseDcow)6p_K%W#nk5%KNg$sc2K%Bi>g+ z5%?F$RypWy{5-~N#%zb$_D=gH_g;6`*FG$r5E);lAov09PsM;%&jr1zd@(2ytks3v zx-6a4`tq3emfVQpYlkmPQGzOX`(Z`{lph)0-khm@5<~irm>~L9pT<>mSU7ulX+d>V zeY5I=3HSk-Y?+RxG%n+6h6!kGe_ZNxEu_B;xhp{r-Vt0kG znrHmoM;UU!>s=2L1tAB#?C3F|u2Z}y1oe(r)Uz`LrK!`SU>2P_ zd;YO5L}+(AOEV=vtC#71w!FyBXo^^6C&bkj8$*jggsq>*2wAAI==OI8bgymvxHR;# z&5dga(ccQ3gn(^jB}GgL!-_PjK_5-V(UAKEMZDnjSm5r=pU!d(-^y-yt<%N!X(1VP$sXQ6uAW%c+PlVd&|$k3B?p0e4Ph99NnGgIO~BRF=kDishuq9AI#} zcuO#r@Bn-Bhc~{?d%pg+e^{@72RCv0BDzdYw4ISqRLbEBBa$Tf5C_x7L0RrElsF(LJG@MB4d1a^?ZOuN>Q(84<4h0_ z-}@iYe9Wk9nLFV8GjBzk=ify&QR#oRR!$?7)j`vMI$DeC_D67gEI46^-1$EDV{O%@ zLVW(YuGa=(^{>(U4*86lfu+jg z_mt_9Sr#hG32kw(E!w+=h^@1hVoWn_3;%2`nv>tVZr1+>3&@RerM~l0Er>*@BeXE} zO>D@J8ux(L{XK?!0e2Y1te-g3FtJ=QKEBM85M$oy}@ij^{JaiIAmzC$TN|?a;#Dmpg*xF|T3_pl$@DZ@AZGyldRrIIBE{J^l!30(Ro!8z}$Vzc_bi)(knt9lWwk zX>m~gl{00|{&lf_Sb#$%x@S!0Ii62&;bb5=U^_qV!1Ov96!uR@$Ev`&WFn4+ff~}D z%zAa|jZ-GhB&>X5VUXUvTZ7NosMO#;uzhvEL_O%yx8|<8!z@nGhaBBq~PZj~q0rq#}O*VV#J{ zssTF-7IdctK3aTR$56bi#%=_;fA9eM7~Z(-RsTtgDkTSC54G;6Zyh_ErBQElee!|IA69C4RuQ zW1Z!Bn|h6b2j%QwTM+etWv+ghGuiX^_(>1yN^K6B6BU0%6&BRR)3rPON7#RIRI(*>moiZy}G#JkEkMAX;XqfQbAU+ zA$tki?8|TXn-LX$J;1gXvM>lDWt5@Hm@-( z-_EAENJ={j?wmDnVFvL0185!mdyU82l5+l1Ng|x1C>6>ZZQ|Q8I7@a#+ilFSpfyw> zUjR(~1v|13pCxoM%`nthlPV5m9()umB~A%z;Nh)M1#I3{=T~)~Fr1aMiaulx zTHrxTO$^PsPALtE^xH_kK7^+xia=Q8>9{LR8bs{WnyhnZ?wrpx5Y{z`N66Dv0o&4< z$%{RWc5FNFYy*5T%SrSkA2(YjPg?gsLbPu(xlsnI1w5b$p7V}bvzbo2$ z*08HUq#B!YQP-%*-*AC z<`S_>;mcvU2-y6Rzr`u{j@rIa4L~&I1Mq(OHM+3lB1;aI2@Z=7|$7hNTjp(q_Zq zP%b)qAu+`{3|B0m`Od_%xPB*=d>F2r51fx?6uvr-dT)}YW1bZf#FttX@olGb3Q}MM zMX6^f3#R2%zW9hic-Zd#%p@05{Z^Dh>&m;2ZWGEoy|XZ;AsyiF*Ri9x(8{6a6L$dA zp^L=Uk;XMMlHnvBH6{T-{Hnz94wnD&%d;{Pj>1qhFlncpc`&TJQV_;g_|aEDI+zVi;GSsmXxc;iVXeG8WD;0!&i%4 zwct;>{c8Q2d^8BY?kE%Ag*ZG3~%t zjxVg_#IT%L4Se7L2hDiyz6!Up(YwG&V}rvX?PVJ*2CVqsq3B^jer~o1GhkoYH}}gX z1}PaCjMVU;U3y6qL2^kvcWdeQUAK>pZ~1=4H_S)lwKAl`DJ;RJc)Wg%$_0399ll1! zGEP;zQgfvVM>;FluU83vV?)uf9Dcg^OPSs<4^yUcb!N~2hy9|-95Oz?I*T8lexKlC zGDuR`gCZ1ZOTlu#e)#?IY|<>|Ibu1qqUSN2XN2!mXBFEpT9Y%>D)+=eFGc}!3tNV^vJWVV!Mw-cp zA@DekJtx$pabJ=e$J@w??EA6A; z;Ymy|(UR*)A>vPMT}uYL)6hw&V5F5m=pNN&JOTY8Qk~r4k|uz^F}Sd2J&eKtWQ1+|m$w@ck_c?FL+s zeY0nsH>(p!bUtc7oJ&>L%vdtmxmsEWiJ+Q#J zUTAYVkB*SWwGtfcw(W9YogRFYNryEw5R1m{LYG3x_6#gQ(pgC&kL@yNqS=oo1#kdD z$&)j1zvz612-QRsmv`Pp($OahB{;m0R|vgLL2E}gSQlAid0Df{79 zyoB?pGp+tx4P&08T^GX?OIImz24!ULDCfsNAL3?#k;waLd#fTf!-=zaL;CHsB z91N&G$JB*L%vp1vOk`JDTH4JtS=!NZsgDSm3M%wQNG0)(L>GQntNo=xFanOq*RP<< z$Bp^%{5khnIHq~;~Z2C+v%hr?ofmfh}!HA^>%8NVbhU>a(o zp-`*%K>0NZ?W4aRUOn7GqFr9~qt@@u`9t$ytO1f25g#m>j_aQ-UMd7(O@S${^0c?a?QNwI=~1JB zwAylYM~Io{6Ry*D=INTe>BpdJz_PmP-nld(W!+Qx+v3BDdI%4SR(9O_`hoH8Bd_*@ zM@fF(?(p#^KX3m=K>MFlGQO-z>Fa*NrZgFX8UFcsEAyMAc;T`bI@${ZhcI8?1l)*> zFSqUJMsHh(umU{SG&fEpz7CDLxwyaM$3{fNlN(uKwso9If!$UH_108iRJM4r7xXlTzG)l13-athG1;!vLgukni!m#5MlcTc&K`+V?fu1GU) z|9pZgwGoldPur8=X%_~^kmb9IM_`(!Xde(AHVk0BC9CA`i}kf%tWfA+7G`?ol19Af zFOWz>g>2eTG)t_C8rEg5#i~*Z^1HIcmlfX2&YlB)CFpJQB0~i9 zQ*eq5?JWpmz|)%-#j4;+kKk_?==UYeSF~I-t&?#~)Sr^W##UhT5CU-+n3AO)CI+!% z^i`Z1lS$=@mmM4VQAw`V#{!xPZXs_{wM^&XHh zOzA_-Ud!KS>ih5zUGNaT$%$69h#}O{E;4T05;xA9EC@8#Q!_N2vIc_g^|={0HMFey z9*k@PjB1v^E2Xb6eg~)J8Yp3~HCu;;%E#1AnDFiYIrB~voOEb4#YyW8sv7sq?59L) z(zIa)sB=OIWi)q}nWuP2&RM*!ltGz7#)HT6MVRr>h|G{IzXd#_3pRqkTcMI1Fro^< z_|nG|kQIsm)xRbVV7cx428nP3&74B8T&|=yof$dp%E3p#Msfz~PJ60W$M+X3YS%Zx zi5PnAKIHTW-xK8Y1omGSvxd?|NoMP2-2iYU)GCQoehj+FRaze)g{}Ak3RCegw^+AW z4|&f#9-iMOo?hoRokBis)k5U_a*HI^_*&rV3C2MAIZ?7upUrT{te9}!l07EN$Blgj z0up{#WznYu3PTz^jVO{d(OK}LY7jgcj`?)M#Ah&*PPvd%Kv$r|p;cB4Lz`fp6=hAys!Vp7;&s$1n+B=VfFgi zw2*Q1FfsM!4+f>4^`$k*SR+7wznyvo#D&x>$gq1NeL{i^)6)?adsycln9~eR>!4>R z^c>VSkEu$ZaAsqiVP|9HZ(Z+O9uS|e-_8U!RwAGv_A{<`K({{JZrkray9>8k?!g~H zC#!sW)>afTk5M~uT2%ABShUmn0IwrSqUJ0<9XBK%I`EOcCut{?Xt=%yftO4f2EL6T z)9EslX!SU`7Zx86G>MzXJ1eN0s}T|!;(4tSGG^UWQ-KI+D*}lih7gbl+EWy=2meZc zcPf;QAp?qvO#<}a(BDZAAI!6l=b~sw#?<4{2mz}$xG;zWk@%jYhggiglb~o~#&o&c zGB&*AN?@6x3vx{-DN^ptPDL;3&Bp?)-aiJU_;UES}ZF}Fz))#Bxr++~OuOXkH z4MqWQ{#t{c1L4QlbjD;PtU}#r&jpm9?Wt&WM%mHVd{DF)%*D%3>=u29*|Ow z;qWskQ|jQHyq8g&ZD&=<3btYH<^Z-q+#!JS*8*X;oW3+fG93fdfe9M!7V;mRR)z8J zCm%AX{@&JXyM>$qt*1vQa{78Ru}XmD>B3c4-rW83$dpds(&~Pfv8<@=$Ov$`FR*^V zZYu2MYkn^em3{MCB>x%@|_<~{$Xk9aCc+CbtJ-H*W8)@nifWlJG zl4(maO}#jv@=g88&tmg3-E~WgDgxp_u~dep%)UopLkdUSo?K)>LIs#^wV;@pGbm;z zkJaE(A28+xc%fFULB>)CfDMV-1}Ajg({hR7g#1{}SS3ZD@7n)q*$>&ZYypayk-kOm zh7k@47KgOWV@gtv7ikeR!|nTRp~3USz21r_T8-O4+MD*8OuPJW>bybYWUkSh>VfSw ziMLJBh*zL`re8__DgQkPD0^k}fZfurXz31a-OQSc0ndu_;bxK_K!t&ZWD(*4h1sfm zHWc6^A-Hx+P%sG^QP3_pEE4}%zt4Y#K>&H6>%8`aB@Md$r1RvXOz1^f`I~Pk;usdu z{_?uD|JP)s{51S~O&|&k$(bHe1M{RclMt#91v}6Gvyzq?Mf|P~Ah_g^@C` zdw4J0K3gx^;aGeCnE6(Pd&uSVw8(3?_o5m5AywMxW7&SEr0Wr=XhwqoXt?>SXofk` z#mTO>`Ls~k0&vpj7!R71n~*D*w6l@2q@wDQ9J|Mjd8-G__;M$QQ73~Y5j24N$xH~f zm9rXq;8Vb~K(=0Xhcc?OE_p$eNfs0h7>xshv|K;H;oR8tonk_#qUO+7B)Qu$&}eTC zgVW5B0`v)KTr1tSkx~uAQ?$0_$+Mb%m>rJ^o$|eC2AVze=kYwlTXShWZ*M`7PPQ0J znkR+!S|AX@gri@0=S{PYQlvr50-53*E~~5ZEkFi#hc)$N3|wDv{U+(5>0Y!4+M3I8 z3xKTq+Wy+s-r_aD%o2h(J3gi6`!e20iRC(9bLvi%W^ zPTTwidD3kucU`zSF>9F{3Kzi(Y@~IN?P_()+V}Ykmwz1^Th%AvJU`8>apQ96cM~pw zBc2~|;80E~j7I|D3ASP-iyR!6g+>%aI zeTvLDgK>ms*R{IZS?i5~&Qu;?i?noE!f!4xWdl(o9yl~aYu{0}!j&EnHEIQcC93$9 z4!>>+Z!TYnCP~BP|XZh)p&$$S8x3Qm^%Bu=XzV)*7N|#3pS9PZU)fz;Dhl; za-QtCdTAuOxw&Usd+L&if4qZqR=;# zx+%4zHL;DniwI&T3e!qi+N>fCH&d;7P!mqoXLAp>Y@X<+duQ{3g~I*gYC8G zwP@B4_vzJ6q{vVt<`v0^f(IDd_ae!&6e&h!eEnWs%{`ttEe?mlkO-niI=5E4g7PZO zN_t@#xY~EnY;0FYzQ4=59*O6Xyy$r2#GpZ&pj{vVqD=Z-KlyDOa*%(~2WDkspQU1H zv6t&;)-LSmyA&MADV5@rIk+^75=ZESOhT-H<8vyeh>>qRTT&olp8?92!7R#6RtI0iz!o-tr|TYRV2#p8#HY*Zd2d1$fFV?HV5VYK7r14kS3g3dhU875MBl6hm=z9 zj;0nGz?QM9)*#9QBu(Pr3)1XU%c*mkj46J=Qe2oaLXx~iF(U7vTrRNGg-CQkH4i`y zSX+L`etok=g&ciMzaX%Ue>5g3E>NMbzxYU*Wxj9{KMN<DrcA%v#V$&+IrrZjrMqQc)*2u4;(R#YOX<{$aV zFjj8RuiVSp%j&WwKT!L#;{0iUeD~s2rv?V^pnM^1Z|_wpxKO+GAbA1QLpw@I9rtRF zv)~1=?3M;i;2gSPr&PjEnBj;QDOUwCVmY~o8l7eE@Eis})-Y_Nkm6^2Ja|hJ8LrWK z?)ZZGffQeb_UkhoLa9%$)FN!4IGt9Q8to?`S#?^rcMF0NhJm2ZM3y2}Y@Xo=&It;l zfd=}+Ca@i_a}#ryzrt%a!6HC2WemF#rHq3D2zfw&1MJq6fBh5jj`{!}0mVKepsGBIqk?H0<mryr&Pb7rQs@)Y+r`j|O06#knu z#EJ#^X#wJ0_YD5C?g{)`_dw^17^=5_FyiTPf@lUjTIPiWiZ4SVggi39-)=#i6qoue z$p{YOb7)*8;)?!Mk2Y%tD7MrfhLZ&2`@~Dqq~9O zl4)lK;`L)yjv<*ky@wE%hzhFMQC9_D>Asn2h#Hv9098j=HVAvlKXeBQ+rWzs3njL7 zZk7OQysq|*0d~-$Ft@TN!ok9H*m{3WQnQFvMBN%WYYu41Db47=MY7Hk9T%+qSv!D} zn*?(PT}DFcAHrsjRP>x=_xvG31#4YfB>H+SqzDa^Iw`wm&o+xb+c^v8(S+;9Df=MD zy{o-=2W*m{?5#(EYLrMJA5ufhr-(Jp2PBN4sEP_SLe=gNSNi?**|5H2xxBPPRSd+Q zMR`B_&J$PSH1c5!zT4iyyzXCj6-$J(T9_KAs}{4{ql?jIOeaZUp=`_{u&X~1R-K)Z zLdb72QTtNHPhKK_XDVP_rbRm6==#2L-!kHeib0enV?w`d!hq1=Ovzj{E;s15 zNQj(&z#Cy9d$4ZT$bYw5kZDgg_KbWBXQ@Frr2vUNzWE`X76V!7;APz;k}Xwzj!)Xx zsWU{}3(OdFoecJaON0+KUJI}R5XoDI45ZVBWAsdG`eETh_f3dq)?-PBxRaA0M0gKI zTg4HK$l~_bLFh*d@m}I%Z~G5>Fkn#6op7FbyNAoZw~Z^vBw&45PuI{(1o3G+KNbn% z!|V|2rA(O*iT##O&+bRBAP*zh!&;|N$4zhO2y5-XnlldMu;o$h_pwG$1CR@=b1jE% zMtw!tEH#ZG)4|jEA}l(19Ee2hjov!D`N0`M+pA%wfQuuxw!`(0Vc@}OMffT5|pY%~i(24h<-eo|@ zQiq;U2Fw)%J;45atF-Os&(AvRD}jT$Qmw~_sv^>Qy`@R9lILa43c3-QQM*Lc8P~MSD(EEI%v*W5vIY- z$`ypH0SxSyWpj(e?d2ySSVo3k13}n33{4Ba zd<0f~B~34R1|1@@>8eF}ki#2hzpdjeTs|pfjVZnxl^aH+mA~QJf{w~B2mHeL*@tMI zkq&0IHUQ*4S%2Z}L4La^LdgJJL#P1O?`i}R{Hm@FtKo-i3$){?(x{414y~^Ug&YIO z85UppM|S|Pcct7PB|QP#Ut3A2=jr9K}X_*0}oRVI8cVR;*A+ zk)$G1iY}(T-1n!CHRGn|YVs&#n5y9;mqPF$`yr}TGAti$>;^e0QE3fQ+MW1KOh_^u zaDwZgUBJFOFT8Vkqe~zBfL@Sv9gKB(#1PVr&JYcFx;cb(5Iw}9ir^*%3{FzgyBz$K zrUi2pObS|!3_`^Pr-yboPuV*%_zjBZqG&q}nzbp}7O{exgY?EdHGUqxwiiFsVk$h)@FccLJ<1>If zmz{=NMhbW)SS+#5olsJE6{kVo(FwCv(hW7aL)@_Vc~kd!vxa!)qK0fh%%{0Sd7O~| zF+Zaj1S=yvvUJQLWX*8kxr1~zxcx4f^b2#Xct|HONMn3Q`<0z`CN5E1tQcyx9QUlJ zol40n&Gj-YWchNXCgt^T*`L{Yk(rpphQ(Xq4?gAzf-x>GE_a|qX4|Ssfy%OMm3s;JA84HaYm5W2}aJqX`rqosHxdbeW=5@qF4VY+aYb1m()l2PalF3<@rC%dUjQrQE%ADXx&(M z44Pllx6W^*z_5U6foW9_e6r$c-C}x*%NJxOxe{TptGet#3}aO2raqj6mcU`$8$%ug zbRuD0`c?%Gvb=t|H^0%U)j4nbZjT)C(TA^XdkTohM$AqGEqNWH*1IUMV(&*Ew;LEX zAkLt1rGdUO5B60@%k=u!&$%tPt{cu(f7Upa&s2M-mcpB548)P0R9Q;^u0qJivJ$!jQ*EUXJ_T#nGW;Te`Y!o zT>IxdZZax(9OR!@z`;w)m0HMRU+Wo0zVX^8vqeP6wq3N^mEoO=Q_n+2oS%6~>EKpoE+2VV* zx8q_8@zi?C3at5$m^MJ(FY~?;(^sBnCCVS)ov24GqiAPSGybjPI`J9 z<=;uqj93-aJL#GFi}VoxgYq09 z`nBr5-w=mxnTmFghNqPxhsM@fOn8Rb2sSOP#;F@;%zJY!Hb-3pdl7j@)5;q#I~z2= zFTvE=ZEZjLk$(wp^+lV1Gl0#z2Crk;@z!zCck+j$kOu9Md|8z8DOYvMr8E_5QxtS2 zpHrn+hCLrRzrz^r)shO@LIOPjJtQ)jG}aaYHAWifrA2t3RL;0Fu*}(%$R&u&Z97aYNc)`k0&hw z8kQNG)_o5+kFbxqP3_6R4`O4FQ`n}iPcaXx9;Yy#Ufm0t3>PwF@=*&->8ZR3&~cP1 z2S0s3OJ%~dPAO-&>>sm>jqfoyfaVSpAsNzUv&(H)(*v0#4mf;)!Aeg6g8qcug3vR8 zc0TE8O9oEVZXq)atg!xu&QJxT<#@u-s42vG%wC1(w%ZyxYCa0%BGTw+D}}ZoKV_m& z4Pnb;G!E%PKhtG3YK$0cU1v+zk`x(gp2a;?qS5#V%eBc@3#Zj07sZE z2wBsz+4!9DZkNe)_uh7d=(69X?RncE{WKwjrx5Ge&%XXTmR0o_78LkQjx{Ej4*S0F zP$5P4QPPC;L1HE^sIo&rLOEV1XfKLQ%vCCND9}oL2RsUz4r%M%F$K}^I-O|bQHmT% z7D}N!+d2;*A(Z_-Ki!e_)jS4_MTq^WW6cQ6O&d@m`_W#%CR<8M!r_HMWMbu>CwLH~ zzp9v!OQar#uRoECRD8A-RgN%uL!mq<@%8bvXciNF81spf7ZfVej1lT;?!0 z|Er`27esmh|5v8xE)ny8lb%KP|AFWM{68Q){}a&z_2~(odHmu3oP1x<1=$X#?F`7-Gk^H{JH~92q00nPWv!E4~ z+Hi2{R_UZhG`8%Jh$~&ZdN)?K6B8lO6pOB(Ts{gwBN(|i+Cg-J=fb#PN02y-p!MU$ zJ2muUz=Bj5UZw@@mUWXe)|ybyJ>lIKN#`zRk%qO$1)>uJvZhZP;fmQpvx1M`>yx2k z19Q7h2$UnK2?$ z8G}|J<~UQex)WTFq>%E=nhTB^EF3eirfx50s^g(2KoUf+#l<&4H=E_-)9VxFI<5fbTd3>;k~fuR=r@(9JGD0om9;2uhVa?DQto(&!rJJhBZ zH4g}q*q^D}oteR3zN1S3qdoY+nHVC{hw#P+XsO(EE!!m(n7Q7PSc;9`-1MY9sPp># z8-QwO+G2Wbv>a9+QH<>IJwJ6n4Gkj9!4d9JiCUBv)T0t-Uv5_a{Yn2tVc$|A>whu! z&Ow$n-?nHOUAC*cj4snB(+?lar zt(7@*%{g<-G06PgzK{>EMdGC~fCD+Y^};DB-pPy%UA^dG=a!20pbSECg}gZVwM-EZ z9gDzF4m2dIzh5lijn;=k)Dc@%p{aztLt+pRlQSdLnlvt>uG4!(tCr~E!SlBpGa{`I zNa{7ptvp`iw-4N)q_FG?>9rS1>Z!%xDW^a1(Enr#m7~T}rf!FqGLRGj=L9Uu3?)V2 zpL!OKODBm4=Cz=hRQ`DlK*dWpCcQFlbVpsMQ(2h1b!icCfVbzgU=EyQg06Sh1w8;g z2olc~bT~eJaR3Km#Pn2f5=W_d>$gn$YxA*jVCo|&UFy~@v&x^|Nfl;3N zX;Z%4gk8Tc^~Yous970prTzaWs^|X%_0U@E;&9Z<%Si{31lIu=kC`oy13l4ToYreV zn+;vywCJ+K(L2V@2>t)A;YrOqI==(=_3 z%+y)D42U83k`iGOiE@Z|xlN@NM3nTx6DE*_3CqjL53q$~jYNZsAj$d*iFTmSkiVHW zBBT8eP>-QX(DR63{2w*x3LRYTpU9$=v;xGZrhuuyXZFz~Y+|doLW4V;8!V5`kafT5 z2A5-);L!|g!5+@8dx6Eg3@T+6WG1&SqSp*0L2tt4Z&z7sYxB&cCgOGDM`fCm@_9}Z zjBey6H`cV|Zp9j|U;(Odf>QRog=y%aKL?-R+*ywcg>n$}+BDQIlW<4zbuAij17{pl zg8<#!P(22Y%b0YZYM3&=8#j{=-8N@qq(YqhW6K6E%|!-9%qeR~mo~jvpy1(xamD$Q zU*_z<4KXdNjEMPJ$w!_u&nFx_SmD(L`u2^2ot?mVHHPEFl`7&)Q z*v$EO8oRK$Inbj_13TM$EKQsKLHsiTm|fOM28BZk{PZ1SFodhf^mocwV!$ySgVGxu zt;z2$TB>}j@{#~2h$aEm(C6WnK?6zZ9aHXB^Sl>L3a6IU(QO4CPrgyd$XXm|m6IX5 z(HZ>r;>6$XuSfL7c?#o?m+00_-n~)7h!_Yh$X2BeY=8|N8xoP39XM9+t=eiMy+XvyPFHD&A%Vr9o#)6 zYw)fQkbHe>ok##opAU6QVigM>@t0}dZ+*03g~1FkQvrM3cf4cVi0ydi0Oqo!l|_mW zSQ)*jI=7ERVOYXu^dUORn$+!0uICm$cJ=~BB~Fi2wJk6<#u=LJw4gNT1gz^T>vh(KZgn1Q*~L*{ zQIkO}&!Bcl#+d*~Obc6gbYubNOPQ*;1#W8R78us|6ZWA~8TPUF`+H%B4Kg2FT_l%g z+~-{H<@;ASt0~g9EDQm=xyL){bg%2w&n+-YY>xj8kHhpY9;fYJJPy%cJdOmD$Inf3 zGQlLVnhkRoLcaat1RqPmGZ0Z-l7~_-MxImWw!x_3 zZ^&OnTf_`O4KN$2Q(F|?1IU_%ocXeNl9MQ{$AS!)A z18f+t5%D;f1WM_VbX0vJ`4-NLIivr&&_~)WPg}n{k8$UtbTefCK!MhQkvJ{qSflMZ(NPm}u6NrLKn^dXitV9!VojR4Xn&55S_vb`Z6J~4lI z_89aXpw6OtImUn98b=vJ%b}x+raF?!5sK$UHNgqWi5P_>Rv|B=Ej!KEfL~p(nE6je z@-xCZ9?9XKI)l>nqYi`@lF&?G(A77=Lf)=zO@Mw|oMqV;Od7tC^UDt!>-4-3!61_U z5mu@(^9LpwNXhy#eeJK6A|pn305LM3T#h&(Vw(h=MvO{5AFBy1Px#%Nt5IEY7iT_? z+6WL6^5jQ7-xX<~n3VM=@e(f$JR!>dhLd%O;{O1qItOhEQRZ0piZrMT#CKx%8NlB2BmGEY!?lOjCyl`gX2>Wc7U3iRZ z2@g`Wh&=}3EFc#s%1xoDtctfXt|MwSO!U-L(`2A}PfsK)YXmmQ&qIiP{Kr$|cHW5r zXGdXK(pE@SEc{V9E5b(g(CkGIl=}7azdn zXd&!iKUFyHFGng4L3!Dd#tiMypg z$jO5ApLMW;3QZZmh-lIhL&i?kyoROQqSw z8QUg_{m_8?SZuZo`-L&F<}`*97ubAbVdCLisVPS#0vF1Ij^ zO{OyO(G?|YBe)_EncZi1(3i#s;wioqYDeojnpvW%@BTS)0Ow(R>}^9Efx3u2%S0bU*^SUsT%HLhUU48ay*m?gRyCd(XBf8@8ltH&JO^bpc?UVE#B>Qz zJ6d`@G&#>p(aQilwI6q@RVm{r2vbQaSP_MnsgrC<)!w-rbMz($%bQ>q6`oBXrbLy* znUIo8X6?+4nu`oE_ak8B&qdV<4W&lH`h@g~l#9r;7?2G`K;%WjDwd#xoLzz>qm@Do zjX&C{S+RNsemMFfX0%w*yNG)(Ey&f+6J~V5o63$#Vfp|fP}9n;1spYq*)e1Bq9l$> z7&0RbaBNTLBJ0v`;mhJ`cXjRNQ-V@4o)e{ADS5s;Ilkm9>`B>ApRsCYd)hF(T_p_g z*kjT9EC`rvjW~rV4U4PKhT$0(vFrbX=>Pr~(Xa9^qF)Vc6a~T943t2L`pes&cqV3r za)71hp;%H~{w3UKxkW;JcVhDHh>?9qB`*bs$A1p)d{KJ%C}TkBC~Qn?qmJ}(Lk zUH^#&%@I?OAX&8ct(a$j+aK_65YU|^lKJ>I2tfO7lx0dR{w4eZie|jF4%*z;tuD)) zx&KbdoEcWGK9NLak&i+(4zF24USBrm0LC75Wk;|!IWzIss<-xy9Cmo(lzinc>~(mU z#2%^4F5W?$0B`h^OJyM7-{9_8TeYYNqy1%Q*r@%3VtmMwjv`5T=r?0wOB=}v)TNHZJnjj1KR7v=O#1KlAFBxhDV zke|hZ{(?^J$I=OJ6x?U*dyxk36rAJCh?t%xP6Gl|L_dUJ>>;~-UyBwVjU3Sla-x9F z(48$}as3851jy6C;|yfwMMtZds8u>dw~XO9sv~-?Wq&(H8Xg`q`m?@3k_x7MWx3Y%1ETJQXz%Dc@e{% z8f;D$O+-YW{GPXOdxov*WOwI0 z&^7v*!bgEt_?MA%q<~`;(2!zPbzy_xgF^S&g}(fQkBdxlDdgtGFaVD2^}00uf&>?F zd93Gnk!g#ML(kUk%&msIadL3Q-}VGS`fr?I{Wne!`|mhmQfH*hq}_<%Y?IA4BXBHm zFgDe$3$f|qlg~C0{GjIhkDyXJX$n-DNA-IJ3-YlsKzwI~TddX6Mh_$RdnCIR){&Z= z*}7-pOeIOxpE}FJ&;MVg0-)7mHxzu9-(y*FTnfqjO-K;M4Nnav_qEov&Jka9xj)v_ zeK$BcKZHAx*wA~AzcRM7X;w`}dJl;J#u4438$?`o>$mq=eWq??buYzUx1_1v#83NH zfc%$?d^Ki>U)?>a!kF{D$6k+au^0Osr*h%jnA zggrp+%KVbv*sMk!cACJfVqYOwA+b zo(6;&RU=UD@0!Q>mMRcZXPZ>Of72?8^^tE}!%5><3M_v`Q9orMfY^ z#4^7sZSpy{rGRyBVvu8i(*^=TliN|8K&B2J3?|fMj#%duc3?uP}2beYIX<^6( zb$qw;OEBS#>yDC_E6>tXHMYU<0m0d#BbwnqXx*7VHfGA7Y zO%8wZd)Y0{HzPKk=X7-iXsT?j6ptlXkN8eyq!;Id)XTCNkhSb(l*wc-3_&EM(GpIF7yR0=go&RB#KE64}-uhhCIzptyVoNimJlpKM) z`X@B$fDzkGyrGda=lHkbUl7k>nci7MN1&EWptLrv&wzrh62ZY?&xP8q#g*CrbV)Ts}#8bq92@(kY>Qc!@^^ z$NV7Yz+N##z83dfR&>*gLQDUDrl0_p*P^0K<%T}jJnFI2q zsgx@AQr+37$7s*)u;_+1O=hJ?V?jEiw%(hHf2Y5C&Akc->K5_}(6h~qZN{Ev7F@kN z*&mmuURZ)t0@f~wUW5R^1NfFb<39p^Vj)q9w zm4)yfg}8Hx7q!o06T8@BsA7El4JD#7jwQl`p+f&E|Aq2)xax_LEc?WC0FqSDjw-T~}1UNlzYt24O%O1VQD^R*{g9cM=L5BGfC7RVX%%oQoub zIvJOGq4V8@Ap=kf!M|rPl2mQVKCY)1$S?$j2X7zJW2;9W!$#=JrSSL+06@B>gqOg;=A1udTUxyW3Po~nT(}V)kIhb-&|fM)aZ-X zDuPL+vDv}d32#vE*xVn|?}R8Gg+a~KL-vfvo!=y>;FqR@9hq|psrhL949^PEOdrc# z?oJKNOmeIIQfmak`j`n}Vf_+E(Dgmn z#nAPNKEC6?ZP+)bIm&}ZO$CM;jGmeZ_oKo-U6FN*lP;xA}6SqusPw9`fqHM`HSy9%|MDk}^w40zd6ZJ2Ri`?zvKQ8Wey|3M`ux zbV^@zU2cT(MW8CHCv`Wjv!h1D)q^E&i9u%(j)fHu3Sg#|Ic$g9ko5xDJpD{f7TfRs zW%CTr@U%f#OiUs~j1#;OW4Qm9=Y#GJYh zeU-O~D_4GyaT?(P8bk~EekMgJ#E)-TDzF^TDP*de`IDjjO7!pjf+jzi)=I6d&aVz! zZtagBg3kO?ckICF5L;)CH_v5muZ%P2K@40|3GBhS0MhSEQ)Z6dSE&t`(@WK@+Z8pV zjNwF@2atNnxM-I?1aT;m?M|vLl)dtMObVe6TNoj@sh4XYOuz~Blir(p-&?pm8sa{2 z0cA=ap!S)8>KH+hIT)Z$hGWtTF$&8a%ANnZGlsF(!+44O&CSC(&M3f{g5fXiCcY8c z5HMA{{&elxy!fy}06z3{??(^5a2b}TDL(W1f^E!5*p_p+5l3_q(J?-nhdm9MV^oy` z7uEOUlY6X|wl2^iWmPgo8Bsk3cx7^^Xs*#=f&znXk$8>wKJe8E zMjmN7q$XC!l{(7RvVI1}%UEj5hF<%0^P3-?pgaeL``sxouk!xs&wXDB93CoYYrMtblnT6ohOUNKMuzuFlPvu{ydId;=Wp6{{?2T%kte6GK*ohhfOKx zge4yGG&7gwyG~jrF_$%xRT5s*25*EBLi_V~i{yHJZSSgUM0KuN#`ps-1f-=?V(Lp4 zH*2~h&xsp1)#wqRLQW@RAyXhzLl&BQI-pkzv`5qvs&`zDOUDFZdhnONx_y{J;f~rG z3GGTnb^@mcaAUiA`+DrUSoj|~nCaoBYjd%Do zP}*&s?Tj`~D8Y*q7K z3(FPwqd0fZJHlA>`C)&FQsfu0DAQ!J`XhXN6kK&T07~T7%u;Ao&-Ed3x}B;E0X7tT zB2e%e-fGt8=IHYLba7_^l3{%IALZ~sNRs%5iQ=E%Pnc7*sdP8yY-tKaIq8*}tz8+_ zP{!6+$#+4^t0=gJ_w%)zt|Fh$X=mZCh)*O}!AXtKMk?30E^Hzat3r!jS>xa#$lmdZ zC}jZPbiW8e1k2LHS2HoW1<(xxSxa|J0((!U%%9a}`qsN7J9Jr`P+ycpbs$Az zI>#zcC6a{B{v>Sb+l1n-0j;5)Yb{mu>rSdIbU)Q7(;44$EQvvKnnchH?30Pr1dY#p z%9u{6^FcE2)V$ny8Bi*j@zU}>41@j7NKONvrrk=!OCI%n{q>JFteeN56`;Jg_Ayul z=s*Z~mS9~j79czI;bhT~y**%UW|l^nwnQb$(9}~6wKh4}u;>sQQ_g_-3=4a>tXzXC zScoCXL9P`eX}~#FMTl8lP;v*Xc7V^iWu--r+pdGp&USIF8*>TYS(H&qg^&x{JXnGM zM-4B`in-;AIckaaK5S8eEU5m0dXUDh4xYo&%ol28dw?a-GO|`Jg4^z+-!BeV9nm-r zaAos^0?#pU+yCI*`l*n4?uiIErM#j0Qwnas5N~ok!m-Gw`0jQy=%?9WKl~xs(B<2* zCct061noO>9&A}N(-6t|%AoUz4>=;%wu)eS4AqIukZCY6B~MoyuW`#vJlhx)c#*A_ z6-#zA0l0#^Xo2*L^7%H``FWkm(yM=NehKm|&=6{*K5NSmYNwFO`Pz!c_ggDFr3FJ~ z0#txVCvjL|gw!<*kz^^uJ!?Oi7>2D&Rk6Roy&S_|e?_{vkw+d39>FMdt zDNF9Fp69Tb0VNv=XW7(O>F|OPV$81w5)!|m0cx`k+KGv2d07n|UhZFLVb={&e$xaa zonM?B9v-88Em#sl&}YU`#Te~U3_~cxSTsQ@m!ZEOX-&ClMGwY~A&L`$ zlnTQFAIZgBu|~B@-puF=9%@I2#AfwprA}d5=THe^e5*x0aXLd$kB#1geqG}@v z#$l=Vr$w6Y=9R5~uXRD~t1#em-|Tn&f|fY8vkQ8$lrVcfLtx<@D&;tmsDG=%r+JE# zdX8*cwr9PM!YS*n+7EBv4p@_daEtCb>^+N&Qz%ealTam3r;Tqv8-k=8Y6SH=0k@Of z`+1<aji&;y7vtaUT-2r^kd#t4 z9FGTSWpmE6}+dDF5uo5nqQ7yt^GcZ*q}NO7D!ny zrEsCfwc6v?t4?Z@sbG$UVVSysR6qH3la*)tPQI9NX+TgT>7oH7g;qJrMA@G1Mw#T& z4ekM)ObeJEE62p)`szA0w+HHH(#>>QTlsP4JkR}ce@dyY1DSFU5I}ST_%X57jH>4_ zc>R?-$G&wU<9onc9q9=7)4z-)wMMvSN*(;~Kx56)BXbJtE&qDH9Xt?0nVKPuY3SLQ z!JWd!jDaq{eN%#7zJZWo`A;T^yrN*X5d-n~i5y5Th`~*(8kE6QfbF7dNAl05c8H)B zOa~;G??9>ZeE=s|FEvUp&p>?|q(M+0RyqVj&MPveUr)C_@axR5>~eG<|MXp|!xW7m zehg-g{%0u{EUVVm>0!_;TjpqaqCB$P1;?x1ONP#QF_Y#mHnw`pQx-+AH>UEcIm$Z) z8{T+b>u7s+I|6G}X1IezEI-BvgYiQtcPYCry{1laDL{AHsL+NIqZpoou0v^?gD-xv^O?dCI>M;Zg<*aYx?MHa|oj&nSnh##~@J*=ROjBN$kWXoef(L zBUyh4Uh$d3IU+fgm-Z@KMH256oWxBf#g7#{{At^mYjAd@2Yja$X`l#t7z0w?ed1f% z2^?5nG(bnXsdZ%h^(8M2qxP?tK(mL!-GX@eF7JH_GA0RwMK7S6-wMTL1TI!#kzn+P zEK-O#D88L#b-|W~B$u0)o0cBZ1FQ;Kmq|e=wW|h{Uc^^qBQSLsUiT**Er`)sU)rC` znxe+{s>RF6Yg&flUxdt#TzBTsiK+moYetjO)I&LNet5MC=(bIZ+snhvM}kyFd2kJY z=FY|FSJ$rk-@i}-2B?kdl+|((=gUnPg~j#2>RLt&gY%cqygiA(d3;fS5Ql*pp=2ac zJoennGDgpE`5vNV2ik4;wbuG`m!5xQYa%lRk^Lhtj>LZc`m!t2R+PpA zBPP0|)&+w)rNf`~9c3RmYLodJO%b35Kl?u54lVQt#Nn^#7T2u|z{e&HJ-eIMt9~`= zD1u)L-xTh65vL%-Qdcz2IL6492=G_&t88n(FGZ82F6U1;33tEh9T2mhryoJ@%RH;@ znl@kQz+0&+qQ5n)A=FC!$TUSK8}J6QvR~YWN+86T0Z9sYIyo7ZrNN5ahXGDv<#1nl zwNP=!-xmkqZEpSkF2`@nj#XIrE??Q{Wb=)_shhYU5BJYvQT=!w%@p{9A_SMz9Wqpp z*ZaoP5d~_%>|cvrW*n*k6%?GKsE>}!7Q#SO5iu!<%~;`y2m>DUHw_SEb6%<4_;fO1 zdj|ni-(V6cOIo1{%^U?(=gU$oDh)vF3GrHu)^9L}$ka&kw9aG3riAHT{?x0@#U`J$7up49y*>uw|d&R!i@o$cg4ktXU2u7T-C^FTB<=^_&(p7|=ho>!Dr#M;#eh^dY6(FvhFNZ>J) zeQEvSNfWp*y$ci<$20mXE^dxPpP)(A!)i%HI0_o|8&qo$JgX;VVsLI`_F(Vk{sk1W zNm;dPxP{U}%;F}CA}rzJ>y)iIil{K$i3h#3sL?y61+gR4AA9O=L}V`C>sS>g@CRq5 zu1NTxAxsJU324p%1Q5_m-Y!Si^e~kWV8RZ5Q}wQ;90HzBu2yklbxWVM@$+5q=TYJy5+OgN$PZG(8kA42M$A9Wid zhu8$|Xe)rj$ z)Bu1*`djDVcBdU4oz!6j+D_&McEMiyI(Gl#{!h93`WD*(p0w)*>K4ers%s@*Hh0dy z%H&~4sl?ybZ-xG&OkRGC3n-2S!3$o9JJRz{; z!l)1J#xi(IVf5-*|IJ-hM&EcjWCtL;Z(--H2z4bnwwuRp@_pcblHZ@}F*}bYOTU{G{PI}qY9g-bI_N;Pmp4QrH^=2&yVWNOFu<5`zp7W-e6%@V8X4$I^o7kl zUp>$`=R7ujj%|S2GTCZIo(CN1qGwi8Q9Mms=)s$y+-e{$Njabve#pMD%EwNf=WQ(d z?*oqHCfY>ueIy$c_d;kgktIDX<0=|r7!t#%*z(G z9S7c)-%6M1?)bFl+SYr%1=ga4%u07(hMH2bM>dIwojPi9vCjF0Oce><*ylyA=24*6 zTVi>lA~-2q+r)!t6#$Dr+AQOgUAN)2#FY77myl+-XXo*~Zy}iqe&?!i^p}BWTed|X zSFJ(#5&_#; zuz2v4y08Td29Q4Dir(VI+OBB~-r|T*=${1X#=VCx+>WR)KqBj;F+?~h7~ojKUiAP- z@SuZW1}FfGRLdCyFb&h=w@XAb5(L`oD1>czJNNgFzF9MX6<+^(l`a%4endL ziB2S+*X?$>b$-RSuD(=%($@uFx?-v5^cbK5PIXL&afGQUUt_DTrfeU&xz8qA#tW?l0}2;$$C2hrP_ z>Xp!$8?f&j*mt$2dLi`fZ{InXTOOv@!1n!lwS#V3O^K|v_&6)Wl5fOD}<_S zZlcYg_fhW#BgEjP0Xhs;&kKW6<^4`R#9G9SR%KVzWz}^8Qke+PL9)!!y4_D>WC?!| zZadgoM5_mGCCp+8zv-Wr)qh(5-G{^bpS}l{#Q-eDvbk!`D6DR{XbWpddSjAefR58L zogdaOl&XK4I!@U1e_J+fme;>M5CrmCo{+tW2!o8`Ep6OK*S=G1^TH#vN;rc7p zvh8Xn&3nS2&D6H-&h1LMDe|CEN7=3owOIA%dB$bzV4-z?s^;Y`d1oAZw5@gWCgwnw z*9NqAi&eKGedU~(H60*{9z;E+e*hj23P!5)qSoLk3?ETI0|rl^63*+Oz2k(-CgTvd z=5URr=vD8LVt&lu=E6*c1Ri%lF6N(ICUXL?(FR z(2*hGOp=3zn$0c9EuGA6?QdVFCipYCPZw9qV3pk7$G!*&84bZyj8!+dIgG@5qIoze-dI<7cdRF}+QT2h6an zed4Opyw7sk3?1SQ9wwYed@S<-`02X8QKjce@%`tJ-1kTmf{h2FH-xI z6nA?VxkGL+l4~1gkh>wA7M=$9xLyT?oLXSvEJ|#GUj-qaG6zvKDF0`GAH|(~E+E@Q zh|+mgG{hz0(a%L_-f3ijmS2OydzDPjSe?QH3BAd=w6^H{aO7JHO%wkQnpfNh>Vscg zHrx&5Rn%MMlSSO-?cc2Eje|8{x zh!rh3U6@*6>+kLav9y+cu-vr(yFI4!n(S$i-DCh#+rnzdS&u&?29KQLy<+v7Xm;(h8o1!NWGRt~>S{T8rfj;=FS6Fy^>Vv(^C*l}anP>>Xzi?aJ4rR` zb92S|8hfG1aBslhssGgN z()_X9`4lbUrZVi|47V`VENPtz-hu*;!U?1@O_W1c-BUZOf%__yEiH`^!QsY0sh6CjXC^m>|&YT08-4PVGLr)c+3sMeb~l}ONDO@k?r31>Br9Ao0!J zcl1IndTDw0ubX+@Hfi2}CF^s{vg;OL3Q~}FRmwEFKm2$uJ7&FzbS~D;Al8N$HFmJF z-NKHClB;%l*5ZqT#PU_Y$qb%#qcgWi#cTRZjyTtB9km#ck`My=318AZ{&?&Bh1tk3 z0~Z+l9um?U6-VXH0`prnLBmkN{^Z|r(Gw~!pCAptlkEcvpq0A5%wcV1G2+02AFIm> z6<0jQ5Clnx4uWQbj92E4`IZNG`$+^Hj{UYDRE9P;6-pl($4QjG2tLe`u<)HF1*Jz} z3m+oUJGcNi@6!Bf%VNTXOn`*8jhO<9cicK&I52Y(R8TJNv*@H`k{Awux~6)|pzW9n zHq9LoUh^F5gG{!7Pe#33*!n5;{V40lsfRXNM?5T)4&srgNQB6~9tWySY7x7ObUew8E^!SzbpqpW-@T-9u5%30T#+YaZgC@W`fk;+Np5MlV6N$(Oyl75H3!p}W=^QQpgNF-=08+`zl;N=5GQ=QpLGBY z^mHeZzL3fR36vw6m<8o_#j^%$glZ|4ofvAqhFwU1Z&%TFr!djod6Ot0rR@&U&Zlg0 zjxr1GJy6XIWAFIndpx~hk6iD zc$z0&Kxyh=hF$i>5_I|aRWOYNjAgzbpH!G)1Sxx+ehzvHW(i_zGKh0;%2n1|0t&?O z?=p!)tIM?*KE?{o$~*H;)3Z$bc0Y`}j~*1-Dbg)4*&;kix#un*OWXXMH)@!!SW=>} z9jPyiDOW;sI4{ka$jK`sB=0|tV-7&gFio`EXC4#|@(JJ+9}lmcy30`uW~2ynVkwTW zE(q{GXKBhI9dHNZI0ECC3k*Ag;$W@5QQn15C)c5fLUNyFvZ>3C-D-% z{Ea`=!F-D1E$B{$bQxGH4oZI6A6xm$`t^LNj3X~{feaIoo`Tzfg0RQ8#VS3Xfs|95 z>vSxrpT{ekPK8<+=PN88u*LM9b!EncsaB^P;hEK&T&@h{3E||Uh7r3OcMQ4;_~{R zJj5s-zTI)+ESC-8wUgnBOT04o1=5eLltUdCp91fYBZy(vDFL;RN9n z%{k7I?NIM|AC55;>~|l0r4=!>UKUj?(mvKeuv_hyiz}1Jqe<*mJCo@J+escT=YEoSPR%h@ zdZnJ_ZF}NcDYJ~kgET$ol4uELs?@~{<(Kc48WJ7D04#q2ACm4Pd)>9LZv2CHXE>vY zUO02b3=KeWuj_Ge*D`N{g5U6Vl{&Hw)chx^B{`ag?+x`@VVhrOl>4#C7aCC6Vkn*; zoj1ouj0?Fx?Be(Y=YBfc&lzRt?u5IrI5mnbxpy)PGEbATV5DkJ@+v5xOoSDD=R&?E zU_^<12H4Ma*3fS@Xx;BZ$P6nKFrpzJ-qmzR9k3(yp^vA=9*`QedOj`-rP9?Nz~dj5 zZ*dk_#*?eGW^hQy!lnq1L^-dVjfk%DMnl96qzV?orqR&hCo1L5NSL9;Nr(>fmZk}e zqZksC-tMg+D2+;$&*$ixc@o=DOJ$T-H?ZA801##uhGE-}JMCm}k#~{+;o43^m&Du* zEVq*l5F+8_rT}t<6S+^n0}_Q3nd#DB=%@!d#U8StE-OA``Rq8c^W)Pi+h!p%5I&Pw zKB~yw$G4?CFVY=3xxWV!=hJ3BEZFJpYK9@Y&+N+BPdj?ftJR~Ct^`{s7Ic(z_CMNf z0hZZgL0ca5+|^HYq%02|XIm1rI3yK$8>n`#SQEpXSV?32cPl^t0A73qXR9=sJCPrC zs&p#4_*e|VaSAf;JfmS^!RYco02xZv_c>5VHs|?E?kN+qp+kpx8mFwljK^n@Y^@#k zoX_)#7wgXG;@_O$mZ@pA*Rbd|w80yIznsozbR*SMnLmPu5JsrQ@hDAudhICXqv1vM z<2cU_Ex~jeS5cv#6IM{dI( zc9_TeTaX;DUIc~*f9s*%0${9@oFwPZ=k{ks_3n0dqq-H}`us3p_VANFkaZUjDhoH= z*xAB|Hxn>&>druOOmsrO{C~^w7E0v?kbWMf1(Sb$92ZCmg2auk;a{KMtEqa@GI{D< zU27@RWA{Ary01zt+VaA41AJv)$$3~}{nmTOZ3+&nVpi!@ib|J~_}$0r+FrfQ^AEwz zUY9eV!`0RE*_k*>Ekn9>HUsBW_2u3$m489h2hgIhwPJC%h=|moqNWBcXDt7!C-$la z-8R(Lb-8!hc_8o84{fxNT%1_lU|1_XzSC`;9qpgh1@t~$Wj7IPELlG-j4X_JmwCHX zqv!Yy-7DBL&#_!$c1-D@jzt1h;nyQQ=cIK1W>gbhOn)hEm;zg_woqoC*Q9KA9o`^04!n_Jh44S zMXxs}^WuL>eh7Sh;*MjpkXD{GQ=0@DY$0m-D=EPwhe`*ooDQGng9W^8b3J;v<~!i5 z+@<=o!&^8(sCF*;O1{Y3jduX)=KfxP!a48m^6SDo_f`4g*`i4z9lzG4)-1x2J$3P* zQ?pwHD8ZS20Mj$0*ez-s;oJCVO}2_h-EQ=CyvhXk6@&>W24TFB%qw-j@F!?-;R*ofQ<Eo(G{KAIr^V_(674};~Z~el}s>yY`k+~Mh?v`)frhc zMYAupti-EKJ8pl2l2=5HIG^228guDaq>Ln#SP9tDF{KMeu7<}|+L54zS8`A}UK=4_ zAEXT_J08a(OA{)9v~Y+;O0Ywy{jBD&mng;rH)cFartHA#Nv$#mqB!uiaes54O0`LC z#nzmHq<$a`=PD`%jLk16kdxtXJj&D-L6|ct#={rukyT?WuX&avV=J6ws{%g^pUR-p z2-+b@%7sZHrS$tuhsTPF01--`F9MRD^u>1HV`W{X#b#g(hxxj7>TpzAXSn+3Jxx78PNct?3~s(ht=K1*Wx(0gkHe5BaVMLao{6GEB+efQJ0P}-F@%i5!I*+V7=7*0o_!y@ z-Ad%&H)aLtQO2aokz{CXF0vE`)|P}Y6-igc=A|!?8>0j zT@-LSxF*Ln^V-Df&qZRbRD4u$8o=w&YTufS0Q(XEq(_nx$u>oKnD`u+gB~QdShJq} zLV_z#NGi+49*q!d#+fiPm0SX1(j2xi#eX%WWtpZcTVi$mEbQyA%VF z5)aWHYBXkb%(tYi5yKYh&x)Z%m3@Y)W#X!~6?1;xl=Gir|6d5MR7BOIjM~zz^kIr$`dFRw*2haiBaq;JV!u)jwt2W8`)rldx($$17XR|x zSsj%%olOv|D`6@uq6`ypeBFJUo!xeyQ;PZ(vw|*+F)m3bgWZzu^CxYZQAb#xaNio{ z4DOj5H0a^O-o5uZLtFcV1rgu@t8dDi=ELvVatK{RzZK{c)TyQhm3@qxljff;2%W^# zO+$);5}r7TWE!|9gJfFt@|JdF%JRnJfOD%}U5=~_p{p#!@}{=KRAkxdq>UNK-VCqJ zhP@4++Cgajm7h@0rppDOyUUi0 zZ4JtqhQUj3GIgaFPVeywm-rMxNVc?;f<8X!-L5t#xiI%gx|~l_3E~mImzGcZU+%;O zR^12{%=o(S6Sy^tJ6E&bxwxnZC4}&u)@LTa3sB~hm*|eHS%09$rlp3aA4`13iP@}! zg56jE{D?2Ivv!7X%xayd32;(zGZM&;{M=Ubrg=#l=Lhvg6^PZaJ6#a zJ7bLhYZh;4n}r>Puew}RL-dJos%$J3*s(mwS-MB5sC@2crcd)aPJf4B0>ko$JhHT| zH+!{NRkbI!XM?kpmeKh&ROF+lsH)t=^;H5oC8L3_Ovf)K9DD}gCTc$o)FkU^3^a@L zhxi4}RUsz)Ov4hBimpFg&dLaWSHLeC-e5*j-f$U^Z{QmT@gXB%erx>#5Sx|lNXU@NgcFB198ry6q zM{IhQ<2H~?q^-kn71aFCv~#1+d1aP|D<@##3>@(Pg*)4j2$sEiA-KMNsX>Sq9*p(p z4pw5k8RIf*DqSOrNAEnu7_=v#{W8r>b+xG>{Tokv$0&Qy*I1xzAGn*me|NPeZ0Brj z`TmT}RRDy+g_H)6kPIEq^j`NqjxY24|1Fhm-Y2Jfg)a){)?PZG;R3kK!i`ki(mkQW zjsJLIQwLf+%&(twN5Uv@CP(KIIg2BtNhcvTHN!CQclly49W`R%kJr-7jPNBYd3~2burRw}WmTuM)yr0oWW50#$mRga1=xH3=2=gePUMZs zkCNcGXA;iRLAr6{z;zm;xj&!&ht`{V<;&P}j1JYiDX~$<>LpDOnQvmyt2$zcM&C|M zrF(7DR!dB!52P0amo>v!p$Ae;{XvXQF2CEqr4xzUd~*ljI>F==YvjniyYI|VH zOPbY|8DwLHj$!Df7R7yn%dvd90+tGMg)ru5a@!2aB7)&R3z->LzBarTIxej(wm=P$ zb?696^a14q7zCj5S$GoyYh*Y|zl4$gl+rOWD}Da3ha|V{YX~AX28%fNdS@O+&d1ce z&_GE?NJ)VF*6`D`wp*3=4UX>wS==8)M6RjW!T-pP0NSNKHqw!Dp8pHQj{m1B@K~Fh zTSII6wr0t_G*w;LVDLZox8jkwlLzDZWMOOIp3opUUszrG$2}~fIJsq-oUr<=IeoKI zTT9`ZhIoX7UV;76iBSc4QlqtOAEb)5ywi_iGO=cxE!^uB?L6E~vDw5rSjhpZxFxIC z#pMo+!u0`XNZ@BDNH)tN$C~A3-S(Am54hHnuZnSmb1^PVLdDdzzH-`b*C>MWI7XL1CkR$ zvI0~$bV?UUTjgDGfuFicN9sP8V39FV($lVcs9E7&H?0=$^rkxo%x~JymZ*1|)+YEB0+L&m{ZqaIXgPHz)#zW7d{!-O0rN?cRtKzMF@%AaQ*a*e zYO}$i_efXO&kn1rIHr^sG6AiXbE(~CZ{TNBSH+aC{P`+yTCotU%7MOz{;~qwVMF$Q z>JKIUOA?pZbxtj;ou0NspW>*H?E{sGKx>e_>;B1$yONm*wUsU=-i+^OcbYh{`>?VL z{1U=7zbae;G+X=_p~lQKu2~ZhZA|80B14@Rwz56bJZ-_rj7f*8%mI&s zcfam^ZBD>VvZ)XE;rMAWwa*Cl>z@e{a#?no@JBUQSWSpV6fqK7H|T@2%}IT&xw-)O zn@`_g?=5!Copv_9`M}yQ6%!pISVSWy3p0!zY4s~)C1Za+IOmeMU}trv@xhmc^5>j5Qt-I2 zaL~=ys$D;H#x0fSK;+610A8;uV*?W3LeWw#rTpk?zS~EuN%A;%&WzlhZP6+~7a5_K zKoyQ3EbLv~ryWmVD?qC@$D7lt+S8+Glrh4lR6g2%HWNl43Mw|Fzqpc=2tY??d5<6Y z4qTLR`YHrELS#uu~- zg*1qHJ3ZUjQ1na_%z*6Dxn9H$)K_&sIiY66c=RDbFEe^@K!Pgx)Yu2{v+hx-Isej| zkTz3m-yUH%$rqpuy0C1{9&OAlOst$oWxrLyr%y}DsO?}uWZQ&IRqzkuIWOs*w9g*5 zf0kw#FPg*dJA9%LZd-}IZ3g*c}Q8fWMiuzHNnQ) zV97pK^uTM8Up@vFED3zHthWa8{q%|Y{j#ya#U7EKkPQ&PQUIC@OswW35&xrelb1I+ zYvG!8A?d0xjlqXfUap&9@Jw6FP}D-4`96zI9qT>P1w^(`lmo(wcw z@->s-nDci2H73hdmq`QO@JXz02l0QSw-hdzvnN)ZiNE6NtMTu)l|k;-^D;;PG{!L< zQI38#(AdCKniAx2jM#ZSiK%GGI@%QO zm0A(5D+8F>NC)}=RMA5*Fid;xwgok86^4;IQh1qx@thHrmB;p&GX6jwSjSVLD3OC{H<*O^pK3of{?jQmj%0=15&$* zqGTXb91t{75M}z?vCzD5H=j&C`?gDlO8VgHo_#ZDD5l8s0wbjxaW)^?AkrJp(cPzU z?lAog1C=P_jqc>85HXb5`qmtcR5`ds)N3U0GlHd(v!z?tA#-raJQJdELchEUP;}Uq zrAP)*xl{%qiZ04Bn=hn%3+KyGQqY&d2p1&EWxwR+%c?W){p9Z0g88j8kx$4xsq8v_Sznv#sr#nqme_y!JCx{Cz%P6^os5;%pyG&s?xH~MU5Y1widoMs|{AQ2urUW zQdu|ZL+Z8hb`519oXh`8v|k&pMACe)Rp70!-)7l}6%X58MDuclE4&i!3b=UQr#Acv*69O0>eL_V>BK-<&*5qPHV1#1=36mh^%3sW1@Z)Ax&U8H ziaBfMx9{_dp;ExkQj`IGj2#LRN4yX%$rT_y_NYfak?eLByhu= zLM%M!z^D(hLnS{Q(Zt6}G9mxz;@`He&p*Dk-8tcxLG+y1Ed9hBE}82_0(_jsFI1r| z$^KHcmFe;kkAa}u3@4vNyKpsVTnhg)@8AK`A-jA+{`V*qk=hm*I3<0s+QmWog_Y7# ziN=_PPt>Kb21z4cuKEd@7<^t|pUxybxXR|nequ=C)Y4SJo4EtFc+a;G#>iX!=n;i* zo`0COx`Qr8?R)Z^X{bUtyZ~z-Yhpv}=N2UG5lZ*I^c&~c8x5G!oc_@zIL-kg$~f35 z7Cnl3C4cK#5xxXSJUhsSNLa1_2G19D^Zmh{NkNI$qDx)fSMvRzdHDImj+tcAEdajO z95F0phNAs;ChVx&+`O@D5Qq=xjRom^>-2y z!CBxc1<0gFh>doSo)>h!RkflVl~gpY<*lm91?Y`vYzJPO=QAgHW2jE6iwgy-)IRsJ zIxcWkt}Wm^R+STn0lAVv?-mDOm6O2d8%?Dzjc=cYjx{he`SNU$Mo zh$uI}m3(DYQO#1`Z|=x~C?i>WnAN z{O2KKJ70NLg}#6we|m>bg0vRN>mE9X@wCHlaSk`az4lnaPUz>#qRc(7N~gRB{rh5e zk7pnq6=-tbU$h5Ecx)MZ6!7gUe+j7=3F;I7nb(s3<5EpAU;#~OM`U#5)tuTdhjCdx zpb-_>Eja_lZLWxukcc`AYC{oVU3G`Jly7<@SLal`G6`-h=zhAG0f&eA$J;t!`Y!?lUzB zb1w0EQ1GV2Fz1OcJJu}ayoHr7xoy>$7@fd%Krzmdj)+sX>^oj&X*@!Y-1u2mb}^$^?+EX>Y409$Lw5e2Xo3- zb87vr_ls~rl=wW?Fs~XLklnHOEjD7_HcOjFskK9r<$2ufiGR*kkBV`}!p(~r5@+fP^K1Le$4T6E9c$f@EO6dORmc`6~OXfUd(u;hEG0A7arh@4Jy14lma}L z38ioe))AQb(*bS;ujC1=lfBu`Y>Gr_zqH;?IDT=Udj%err|7)fyuFkGg5M%&RNwQw zUzLU4(?7k=?9=;<2J0)mBO%j8VEqIHr!uCb9A=5+w^-gzN?NFVKFGp+aobd63FFWU zeH$KAInjACXTopR$N|JXI2t(|=4!kumwT89VBX(=6tO$FB6JgD1%SoqsUP`u#s)|1 zAS=*fH@A6SFopD&WG{NN1@e=*;!`2jxBVTPj}@K~w^G~)0RxskUj z;M$!QbRJ~mB4mA?Ss1GrdH{W6|L>*01o!FRl&-OB?`-Q{tuiJy#HSE1bAwPi!lgq$IYg#9|&AZThu zz_95ryyU4jxfy-w1oh)yG*ccdU4A*xWCgo|n@nQ(w1ExJoLucr@s1+i(W@VsfY*v0 z)&V|_IbLZduU#Yr2c|(s;gZ`cO&Z4|4)q_T#ZCvzdBFsgqy<99SN7v#aE4t#$lt=K zWq%|1EZV@3@pX~H=ivLeE)Qo5)ujVX&@N({@PG|Azvy7}x$$!YvR8>^3sj)H&|$MQ6FgA{Ortjg;Croc|D#$K#9Cp(q;Ch<1BRGL}` zrh0u)TOy?;IKpr&m2EYVRf5liQB$cok6E%e7$7`1_F`F-nyZ^_B{IkM2wjwlIRREu zz=K$ns=%IOl{(?#-#RR&${OB8I*p|2*mH0&+uDJps_eCsZZBODHLoHNp#*?!DFCcp zhg87p&d};!M|sV&6CP_@Qy!(hy~B9xvieqV>$eoh_xRXm#ajAS6!RJ$q;gXwH?vH! z*W0;*{&s>sNDUf?Xfc~6%C;WC^aK4P%oejNn;h$o7`9nPpf*qOe=gMPY;y$iH%_Bq4gS1b3;j#$C>$>P0Ow4cY_}$wVV8NZqiNI3;loq zbx(x7a96&x#2z7*Sy$SL$}(iTnqu0CCiCq!l|mNFp<#^Gt#wb`oW&XI$eO>Ns`SLMccNjhLDExSBndPG9`l_f zY%9(?bG74cZ@wd1{YJZOePQ9YWBN+zSa-FL^R7@P#l|*%6&2no8*ph&fnSL_^8Qb_ z_(fPf#_4>T;Svk{wpQf*(Ejk+dX9JD2{^X7F!9tP@^0^;DYD+cU}YYI0D7slzodNl1fxc80~q@)`XsVK z{&I*|vFC#EA5n==#2xWkpd(#g^VSKY9%yO^QJGe*11!pyvP12YfRC4y$Ow?*lUV`Kz9MnA#GOJm z`GGHXH)OYNRFyq9{ha2q;ypqw;xXm#X+R`8DioRM)AzP6=t%{NhDwWkdfaielWVCr|l#R-^ZhV zfKtc2aOSmG<~3pA4d6_I)MJu2f-~yP_@;p-_~uY-!$Jkm8)NIs2}s`v>7+g}q-@1a zUT&Sm9yro)Y&yPevc3kV6W*yrG?)}+=uuqdQh&%9F&3MmHcu#JOM%OxxR`aPs4WyH z85fZkb`Se4Mf)+2{Nlu%y+*R82W;}veS*}D+?Q4A%A{YI8UR1tYrGdqNQIVM;95PZ zzZ|b6zZDWVjTM4k<@mWOJ|8eJhU{8GOLMq7>?YVTi80QKz(=y%HNh0>Pn1f%PcP^e z=WAJ@LgpS$gQQZI0q=n!xXtE+?a$wx`Q=X3$vo~r)8;>cihzGg#h>~sTc5INFs;fm z`8CA?S#ZzBCkgEb)o^;!lQGmk_w zAl?6B3J8Zc#O*qSZ%TwZR1D22sG>=)e00Nx;DtUmynP5r=uc0jHD@U-l!BxC!3`-V zGGlWUmoku^$F&FbJ$gVT_M6I&%8Y^e_&hv$uzejca}Tu3Rj|SV z)lBL14>NhkCg|qb!}4@Lo0PDixvy5?%~KN!MSsukN|=72#!Q`k*!DW^iC`n*OH;}H z;Rut0Im9gj_$umI@WK2$bkdVE88}KWv+7Vfv~b}$s9&L^x0|X z3+aY9KdcDsaEEe5)nTltxKd3;gmbUOazpR__KGfldBxzYpxVOH64hTma`Ea01D=4D zSrwL;(M0F;Ksj|gVqQ4RVo}W9D$El2&t(NQN}HBcS%Hau;!ARORr{`0&t)oANY2uy zvR!c?vUtz)7g;=zEhhU1SzPPomFQ9slQkFC6eYiU@%<2Cv2KYeoPkMM;fZOHESj*R zbKfh8X{aTOqqtejYmRdXxRFc|czjX#dV4L+;yZoIZ6ym&K{7UsvHzO(>_#7YAU zZI8-la`_$S@s8n%s~6$qwz24A*{KpInE}W{h0W1FCx<>cRPEo7Y2N~HH^%rqe@&}G z)4iv)`2s?#jUw|&!?Cmvku+L7_7}SoH3uF2=@8xWu7vZcrmHXtC^~TQS@R3VJXn!YS^DBK)6+%R&0EhI<%!MbrY5IWHVvYYsfLi)5c`RQ&Q2IQiK zx$Y9OOFNvEktwZV9z(?i^|tKA0(@6qauUNPuYkA%BX(tsVRq;x*7n~zxEWeHn9ecc ziW-W&(nn$)a8M++3E^Ym?ARQZ~pujtb9ao>#YCB>1)@Nt-az5x|j zQ--eM)t4yNpjS=$WEhnV;O$x1H-)bfLzD$|j^y(iC9<+j6}X!YndM?D`sh-d339FZ zHUKHv_!bzc;W7;SnFSV0Hp|f8Z$x2@qJcKVm&yN{@?rcs6-dNRzzS~o^&MeM!{?ew zw%hAb<10o1C~(Q(bO@n6(Pdcil)+kpW2uy18rFN0Y`~o`CJ7wR)cLtKBMGMIg)f@w zJG|Y)%#BTu;lu%+q7t|o5Dwo5Ao@Th!UEb`k}1C}kLUF8ge{gMky6gGY%y}t4~l|9 zlNO`7{g90nn)6vMMel?+gc4aPO_!@TD|$oB#lT`O!xBC;uB_+8=_&BKje@|+pwu3N zQn8aQFx;Pqvva~)Md-T=PSInsCWZ7DxyPGr$pppmnJko_f!M)64`Hw<06h8>TEa}` zo3U4tY_}dh>jd&j#!AnHYfV#~pD_(;JM-7e?qM2RufiU|MJ-;!KIM(StJiJ(tP#-S9mk%1EM$ZGY=#I;7T6VJM9Ns!2FLNB3te`zaEh`qNPGw zix)^R8juU)n=X5;6hwLz(6UNCr8AXwUlg8oL79+rkXGY5#%9?&jdzy3Cwa?>i~f4= zeplD+@8-3xp7&}hj(rDxPkk8cKGY1H0&8zaZ;qeP@e7v*8q;59^{asGJ5gfQ&8{tr z0Ie18CaZ;IYids^pa8Vg+c-0#oWNO%9}PSr8-YHcsd!Ld@6vVjBB;L6QMuFhX5#)x zn^C6op5yFIz_y0}w9;BA@X&P(2BTy`<6ePMhn`yf>27st03q$KzHE%6Y7a#;U9miv#X+;W0KK;MO$9mfje5y?l^6@c~7sSaE4 z^-T4}7Q4XYkwBY3*(BnnbQ%nx$Jm;oJ_ilT_kr@EhDeSwqGa99mci zV4n$^>jVH)?$5hQwQ9A2axE`5?RHX}>Al6t1e06qv@lLp0q`Tg2l2*bPCPDHKXtmO z?e>Rr4oIloo_Ap;K&!ZkM)RJQqM_1$q)8Oqk+>gGvCix=5G!j&V1M)z*SqdZ5cyEK zw^^9_t(=-}CD^OR@xwyjP6u#EZq;qRLy&M4=Fk&x=*4{~EVcvOJv%z;@Y?8iwAHzV zzJ_`x6_p~JuAy1CVE>|x8?PXaCrs$e1#PO1MG~so!Os@nu(%T zgKfG22)!kwV(1hMB(c#BcQxDjGf)ae#D<$Nz0!T}&%T=HE$<6eIHO2mz=)h*x(+?Aj>LA7ohs`N;SgxaW(N3UB|WoiO5qwPhp6+ zCD>TF1(D>>$594RdM~P-W%Z6_P8l{e;JZ~X6n!$;y%MskwrL_2vVuhMMEj&B^rQ8wKY=zAq*!qc zfXo#K#)?prI0o6JE^Qcz;81qhgf-GN214_CDAW~|Uq6_*uQdjTmY!MOPW+6o_BWqs zE2FQ$$;aen#`ABd>Zj+oSw-;vzaAEam@qMAJNb*1npGs20*Hl~SU)B!oN1+|RO2e5 z$tn$^_H!Q)bmP%6k|jfnz!lU;UaI*2>Ss_TOf?Z_N}x5h za(=-$hw(_scT zK1iW$|9wXy>?!qIE9h7!7gvyYT$mB0!f?|Lb|qZ%TNkJZCjqPa~F1wf&g5fv{+5M1kl8fzpl9Al68x zv=bbQ!~w7^wzUqTaD+qbGBEhVrSRyRJl7uGuMS?@*LJu}@@+bq07 zLw7H;*4fH{|C>?#?-RwbVXQtB_9i`1j)H59Gbxw#;8}QFV>~Fl8`ieLQ9@9IgRq-S zGIJEVWXk>3(gojQcAkYQ@*e(*N>Q-_U@SOTK^QS%#LxXO72_IDRYX0THVS9Bwtfjz zDU9-Jy5z_n1HG1|nJHRZ&<4oQ1AIu&6ta86r|zK9I0!b80#6@d)sGticE=~NU_B+Dq&KzB2;s$sH2sF{ z{&HlZ%En|7qqAHWeGM3f=!bSfwJg?pPgbNGWvM_>xpvr8@0=UXTKvUNKk$cS_3lT8 zP6p>pcN$y(&u&kl(!b|`p4gDWfDj2+!OvgsdJ@kY3$t134*vY)Gm;brPQ;l+yz})m z3ufYI#TNYx&REt7~m1UfcJoqfnOEqX7;c$zI^S|y3p_B{8xijWPfVD8~)hE z3Gv#}H4Q4~GTQV}vqkja2X`XRSM>CpkFrKLP36q$d*By7Pwi1~ZkDJ3`$##W+NE`^ z2&=89;q!Ct&EygP$_~0gieQUGTrX8C*|vLUA#s|^3C+12xGzzoqQnE<>UdT<9d?jI zpm&UrEUm5O>yMR<3;DoAQm~W}qr?u2fc4*@1y@FiBhV>~z04rkD1Q`lu^WE5nd}Pp zqm_?mh*`J=6OZWQDR?wWb(pbUnswo})9GCmt{Bi$43ZhuP)55xKQXa9x3hEVS3?UB z78g>=oKI~-;M@nWipBW6$>OB=YZ86Q_>3vpn2!lM;BqL}rvioU568}q%ji5IwxbUp zZ=dO(Uq0(qZJpQSUHW7)zDqb{F@9*Wwa|f7*T9tQeg}F94BjLD=SW63zNQhq;mB0F zHUhtiLux4apR+}~sJW;SKJ)vgX0)HxVW~40;or5$^fg}zjpMx9h)AaC3MGa5x23#g zrb5HGZdk-7U&A{D{#;o5CyQOG+<3FH(fzgXynzeEmVo>!4O9oDRvPiHS_^t+v%<;s zBghRSsgqIlQh?EpJswus zh`72NC;5xGwRvY=>Fo6F{aMZKOgWDpu{=!3*9=w+xxkbspO;CdgLu$naq2;H5@o?fcsI@%6qLpyX z5;SUt>xf<5rfW=2lD+KlGeGw9h$&)c^2R!OI~e273Q+%>MJ-kqSS5IK#pl+c0X{6G zFg=OxKh3sDe#`-mmVkhr0Fi&Ila$>j1}}QY4n?`Wv^>Zd^3z1k7Can->(6<|WpiEL zyt29>fc%ottx6Eto8e0(@2I# zutr~Wg60JUS=&Zfj-#DTQXmE)q(vCzEvLIfivp+fqCeO}V}Hcx2#jl##euZjYlVsg z9{?FgqyZ04!V{An&qB&GMa?zt7*k;ywZy?`42HSIIGE0G%6k^>{|&T)Y>} z03<=eR^ST(kNP`RrozGhp+Sm5ve<8S{dkU%Bj~4|XsN40D`X(8q11L;Hv4(+d$aOj z2=_irdG}U&s;mYcQ?t_-4}dJ* z^^V|FGsfA~RBb&Duz4C93o;ypy8?`CireShEMGM2oKuCEd25mC)76;6Qx0{dy3}yO z6H|>f_=3i(^bN=gOU&}I5V{ox_z%?-aAx?`;KvQ1X@d~EaGtAnFH~$IT>9i~8;<{D zg;ZfgP#(SJmm6z8LVOg}_Ytv71)d`;Ftup0WXkn=auo`eh5zLTTRgcIb24^vH=HUF z(;bk3C^C>A02UsBSq*KH{P+N%m9i*Ads%q8<1hUHpw;KdMnpj!sU$-Ch>dF1xis z4hhMFeqbI-R1JSe#!Q6#9O{_L9k5uEY8%XlxBv;c6f~}#nn=Qv0$>Xuh0^8x)rwGJ zJVWa_iWIErL?zk@nr#qfEE~tnx!kBoehdNk#x?!pLuv{SR%hf#&0{I`kYou}WT>Ml z``D(xHKF<@)4w#~?)`+vESIgWUPA?c7sBiZ5YbU4mPRF!t0+~mp66``oEhB?n}Ji$ z?mM8_mHeD0%?W-LQN)L?85-#3*7|Tb`}+0MN^3}=5O#LBSkW|}kEZRl#p~PmQP`4f zI@c@ue1zzJ@QB-8vTOE@@qT(5h-N1CNN7EhLklKykv)JC_ZfyK{A2+Ur`#k$kSijV z88PTq?YZ;(?JXLmq9Y_5P&Gm$i_2ppY6#=kXIfW|_`hPGXEgsI_GtnolNd!+06sW9 zS7-@xgcJ$HUk{NL{e6{g3S|%?UDn-0Cc44?toy)hjL&T=U3!LhzEMN?Ht+o-_PHdl z7t1)ErlZ-f7yZ4-N=+Vghd`}w4{u`wi5 zK6+AFFm0gV5=NG;XEg0mP5WQjCtWP9RK*-hf<0LvW@MtTLG+`&?k5#r5gDPX$_N8H zLhX=JC+FkcSzZt(^ao)=g#_Mz!-R_B4DhSQc<7(s3fDZ^95HUU7f59xj(tuHq_zc4(6DmMVY2$B&x zGcC6Lr3wGvm~fv*(y({rP!) zZcCr*I!Hor9TynvmXWcR;FpLU7oWJU%Tiv&|i*DJ2+mp~BCW-QoUZ?oqy-u0FLfM0# zz!P~$OaQHVvtyA=Vv)>$Mg@z`Z;oR5I$%^>AwXQDI%*Ug-2r9f7~hW|R=xCi zBPw)-Rdo`Bh7_l0B%XIYek*A)UyAp&9U3gcyK7nt2jIh|-k5dwq7PhAfaH^yJ3s5m z{{q-OFoPUZ75^WBKmLjgLB?~YmYNPnNT8k~sBj9%Y&|~q?0hHEU1$InD?*9^?kK)S ze{TG|aA&t-0h%Bi#mSIVD@QTI%bDQHmsW%(_D8<2BkZ>L1;pYCqId-8RPY}ud0%py(=N=)WF|gWggWdnV@+RP)>CJW2m|&+~#P|2R ziAruoJh;vCS1its#(1HJ`^CGXx{S2-rNi{ocBasSUm}+(C$|Ex(2AvokljnCb24sFEMYG=+{FSSTf!8j^4XrKGj$D~N$8LTNy zSt;wHv;a(ThhXyy6b)sh7RU{&f?Ny0wZV{!vm;@n(O*}%^=AonB{W_spVH&LE?aZd z;XMcAq)a}`Fc8Rml`_u#4Nk1fYyuaiUY=JBYDI)pzhJ#wc|}uH4WKWk%Z@vGJZ_SzN*NHCNo0bD*~C~` zS}h&2E_;7`q9U)vyfHd{5DM&XFAO!HFq8uHSn(LXBI>Nb4fVgy+>?Z_RjhTsuBJL8 zaL>RCFj?03{ea%aG(~pj{2WWK=$PI4F%*lpmP@Dn4J?}*aS#;)+Yfk%oaU%gV2g%q zon%|X8v&;HZG61B9Ai|ZC26+lqfjY*BQ|>6xqn&u14>BF8jW6s00OPRPmZg011=}P z9?Gi9K@hscs5UXqfvL-|JW(VlcVQywQn{+l9M{->*@7cNHFf~E0#73!d)fuyO2axF||xVtZkWgmBbKp6OW zisZ8tE3b^!qxm#QzG_2eTM>+SNT_)LG=x9CGrrOhKRBl8o_-4TXW)npZz3x`?vQ&u z(bCq6E|UwF{$O?;Zlw`eZjHeCKp@w<{H2U6Pi^6Z;>w*$O9Wn zsDW&er9?&~>QfzVrVMlmgQW8(nY^M(SgU}(GI~hp+7x*~rZ46WWMWv81z{;&0A*TE z@y2pAqYs!D@eX8nZEzpp2wU5@1>mm6X%T|Guq#LkA-mhn)2?fFnp!^UVxqH22^oW@ zLVerI=zxQ%N0^2vrgzDM#zl;-!!8TcV&pUFY$u9$%^n&&+FqVQGC2&lBAoJzpB znvz=AFq^~7kC3K>;trOeS;vhpejB;oX`<**kr~27ZT8LVdtVi;foRWn=^m4_qfI#R z3tBnqU4H9#Lz9SK8wz2eNd=Kldf?9&Y@MWj7s2CY{T5CCx~PsYNF6VkmO&_v=ZAKZX`#F_+H|&YE-zGY)X9_oC!kgPd2Rv(7CS{4Y-gTs z6bl@YoxCyC!4h~+BM(sqE!k)+dGL5%s!Sn4*VL*lEx>1atMz`K-O!-kH<+&JFY=}X_9K(ZYwik@udx8#eE z^H@98ZTi{a^ZaDk!KR^pyf(YU6|ipI^>|;prT=zcy=ILN9CCZ&Pq9UTVPyXuq}y@ZY{Xto2phzH(r0_;jwI z6WX`}@BXOQ*4!T*_P@XFp9fWXnpGUA;`AAGd3*3!A$%3@HCmfIo_F4^pT&8fsV0nC zc{ew6!bPI!NT0tQsaiigz^MwkKU$J}=d-;$s^!3nn)-FsfcYlAN6*<&pud6iGG&Ie z|6IiLys?h2m-z(rao!M_Y`53hYn{fQdVDnj8ZEY3-Y#?u!)~<$5bixI->sdlteaL2 z1aJ@|gU>6c&mw|{-8gx-ZtR)sMPLu1`}1_{PTSw##JjGlIjo%iR*nXAqji$1*vWSt z2~+~beH`n@S7iIBHE;!Z3cI3{OwaE;SbrtZFnDM$%XV$K(UvX_yf3AZk4*xt_`4n_{#8(v*pZ~9am63zDt7aS)xtX92B{Ef@DYBz8Zc`6=k z=$ZMuY_(s9;!X41EjnGIlxJ;&1o*M&-?v$FjQut^uvUwV;tfLa?Z38Uo1+#jNY^sL zTn`AlI!;^b;##e|43se6(0h%_4>E`Y9gmws-PqCjQNoVY@ z=hAY~0#Qo@o+Y0dVPffZY`2qVucY;dzh7>_Bx~O9RL%iB>z(ACj4}!_rQdmh@&1m5 zU5xQAU;7({+FZS7tXFAQ(6^vrWd+;4@hi~l?D6a0`-OAl(Gj{>0U#-Gb3SX%vMDap z^{KCNLmh=4nJmwYa_K+g4fyuCV2>QR_>8V9Z)C`SvtkdLpy=%}y%4hu)BV=QURb+O zO>OUjr!BTaNT)ch-PL%A{P~~?Wato7DCFHHF~?h45gMxjWO0s}jovr!r;4A=$vU!D z%TVNsfbZzs^KCCkUhmEG24?DQpXA${Y138>n;#rn=Bf}i|CPa^q*r~ndFr@;r`DyQ z=tKARYyncdV3`Lsxy&A?a$e0HTJMj-)ieG3B%yw z?^FxkSq6$*U6HRLA&8ylzQupOg!@YrKz2yhDv&?-k^(Xctl5 z%HL3A`_QwV_Pt5`PS+ok|NBQGf+rP5QEOJ{W9-{ZB3;pV{(N^|51M{|Jpm~sS;b<({AZNd}6cgc;)QSP3XD>c)W45qAc{(K8;(hsaMAY$nHSvgP0UMeQKPwuUx$h@#1l-16E)9z~XYWl(mn?FOg2A7vZK*9Fz9( zicS^hGSCR*YA*9einTP(QxRmrl*b#z8D!>~fn;IS%0bLaHpvy;d;TO`*qvX$^l){& z-)mnuuqHU2(5CPLE-z7F&r^Ab-OZ1*izU~}(N;L;njRY;Y6Z`itY^DiUWgcE;l%^4 zzwm)y)FbmMrW6GwP=wj?4E>Y0?^QyHd+BYHE-x=r_y5in@EQ1Dr>xI{Ftf=w1Q)p- z?|^=$cKngryan;`jwY~NxnqlJ-FE*U_s?8>+JatO*soPA-D)+8mXL2M<$ImE14BzI zL&IdqPQIM{*VzPHz{jJ6uHM3uw*IagXa=OAZQV68#t z(iQE?=I|L<$T+yt!lF-j0)(!FqSovj|OXAlf$W)WSgc?3VtE_am!TXOQ})J ztXZrjo;Z)2ivdGZkW&h`Lc7qfw){~X>FW8E20;}nNY|d=#HnE5+>{hFX@TC!pFs`}d(5;QM9-o-yw`dVtHH8){m7CYc*W9>t~~{FBUTmBYyrY+2kCtF?U`^`NUkf-@@(`h2vm71 z)Hqj7BD-M&RJ8|g&CLMQpcp_u=Fa^m3V5h24$-Lywvbi*uVm1Ey(|P=`44?#36?jC zS^1Th0EnPS)c8rDkju&tq_@H{jJ?HLVHYxzmwhxT8fF^HFhGKx(4?QfnhnBVm}ENw zu^4 zP*l4R{!I8&vN1NfACh%K`&Y8WYa$jS@Q36d)%vKpaBFC-KPK4eKLWle6^`+?Dqt@Y zTG@E0y*``h0nXq3oLR2_!yDY}xlrF%=r@GysDH6HB#EN@Tiuy%&IyjjI=Ne`fla0n zAyPgV7RDso0IRTt1w;m$7U&SKLj+t4{O(Nd4by61ldx;yuH(D+m^j_d|eK=-DG`vOWK=f88PqUp?fBz>vGg^i~1M$4iKp+O&P>X*w zv|zr0lzn{ne0~?_>uR}@-a)k#;$r~LhV27R)?(Q<82>EY{kz-zpUtKthsf&K6fzmm z2MFD?cBmu1XI~4m986*FQesC07@`%pxp(nsTF6_vDYzFX+|Ki>tH-bSspuNWfFS-p z`-bs4_R{qpt`TiuyLhnUROeUq*Ao*zNW8IHHt>!jc-z~4`lxAAj$9N2x(dLc6JLQJSuqVZ zMPNT=F^gAd>2PAqnm}=S9Bbr=;FPpWwvPo?8i&hsWY)Wcs67PEV$v(ub&;nc*%(*Ya4b-7&s=7S8n?RW(y%_YK zkMf5DOGUWHNtMjgwC?g#A(&y|NoPH6No0FVDxsDw;vFh8@rKexBufPxHHj&HiC}T> z?oCE?PL_P13HM3{_v zof*x-#-8%^*aAk`x?GqcJl1J%6cvvg26BG_Pa~UWwxXA{LVNSwN`jwcX=Rpd@I0ruqhEB<0BKo<%< zKYXo5D;A=T1Xqw0je3!!ViBDzhY zK16nmXDv^EEqqyFB(cbUSO<*X5;|LEP^X&wW<+_00xhq(EAAlM?>v+U(u-Q)Lir$D zxccTn(#!NfDfop79Jq_Q<3quVEJFSB7Q$~nRuJXZ0!^?E;W=N$gx*&v0J@wNHxj}? zskB+$`G>2Q`CyWdy(ww%Q(U|+SLY#3U*0%Tc!JrOqF~E8eAA8wA~PB2PiF4N1G&R= z%!Hz7STces3fe#WN=F%{2=E1?(lxN5*v))VGLUR9!odc=27r&dlAIpIsoXkJn={-F zRAAq9b<#4qN6p7+%EYeb!FVE*fr_R^Vq8esPN8&?&I@8SBom=?g@(waibu7D__!5xOaXxyS0kAl=-@ z^ZELR#R2I0H5oyI_WD)4zq-SmfC!72Of*Eabd;9x^l%+9aWRHjEYuBFGo`qyD*6$f z)Lc_tfs07x@zHJF0tSxB9d{ zke}u@V?sD@$9ZRdCxK-(Djd3$Wb!@?veq}4Q)1xB^=-~vJHqM0_EY9?1ov9EGRX+F z<-#7d#Vi_wVX~)cvK*J-wP?bhaiVVJcRc&D%u-sa{nQ(T%%-h^60vxE#@pjTsE^jA zQ(r33QYtUz76*kTviGOoKSceN8O3@%J_g_jQZp>?TvQOTGZRY>Gv2h%Hc(bvOGTT` zga@9Q-Yf22(me%+8}utbgCN!^ZDR7Cq z{bLN_@%e1U5typi!(=d8#J^=`^+W|n$P~s=&g;4Mid5W={?ISC}K0eqsETUmWZMi*TfJN)>IGP*JZ0g}?r=1u5Gn@v^N2*A_B5M9!!#Nr-dP} z4a|EzxzH7YXWB`60EXbCPUb-%^|#LHIb*@UdLSKW)m+f&Fu&XX+fY?=0i)O{u}Fu^ z&rbn63_TJsGhz%f=JlwM>NQnWm**0U?}_Ap^q1CDTT5Z9L$(0MD`yu9%9x(C@J$s` znVEVi-twYZGmG-|(UqIhAmf_Y3d=hC?%|n#)wzCLlVyk8jkjWXR!O&aM@4|7k?KK$ z|82(F@C0@~5|MGdnp_IWJqDU-er z)6$@VA8VX4$g8f1aS_oYXtAT(ezaV$f_CqgbyNCYQ$Y}uxVTp4yj}Z&^Zq0Y>aWfr z(VYumYhHgv7^R%(yjx>0F zYJ47D>WTGsGOBtjY#6uN{yaC6F*|9dA%69BV@-Qo|J^e}ht0+5ph^I-y~szG<{LjBeD(vf*LY#Ql}(EH0!RpqVN{$8z+o+#q`2G(B~ zLT(Zz4zar@V>krK_0et9#-HY_-~Z=40Qf%#0!xMKLgc__EOE-IsR&~9F%a36CL4O~ ztz`9wOJ;W?>$gQBb#ukxs48<4#u}uKk<~uemDAG9?`N$i6*twTr*v1 z9MF;1>05rBFW&@M<)Wr+qIdLWV#&j!>VFLt#`>6_g{>r6opxC^H8ufP`X&OvZSzV= zygf1N5vTlLuWj3Ywry1PG4!}f0sDunZ(|ETBAQmmrS#P-ai`ip8V#**d2F;VuROj; zwy$CQ{JC?T`Nqmm5*+SR=3J4@*igG&)z)m+`6#`0Z0V9c;O)(ad)kF&;l)AzCYbKi zXnYr{CbCm!Y;u8eqYa$U^E$YxECGB1zotwe6>AULdv*wIA}*24WD16tl=fnwWalYdMh zG@{K_d0a244Ht;}Jnf8m*W%5OIze|Q;8mTjP7&JI9k+`B+A(of_hb1HO^tTKRDJDP zpv(W6&^4NeKc$?JoTX+AEk4z^LW8`{l>@XzHFg9w0Z$udM2vk#%6KUj9!W@KC1RU2 zSrHz)!XOK>MI{2m8eZ63AsN4Uv4jk?mUKTcg)(;O*(hEOiwbl)-WQ7ih*3$Q1&dNJ zciza|aojTg-Q$2cKcBXMRJbL=#?3`qG7n>V2Q4PfG@yTM)ackFrX!Ln{t|14L_x!8 z6+VxVVe!GKy>0GgamzKQdKyXOOZ42Zcv__7r~#>iIolP=91A$Zq@hYUF)emvCdjUrh=GVmH&K#-Uv~&*F0- zzs?%qoE->0t1e&kCXPNMh(D!RTlM+GC{AE1Z^^rYoS+1b$RH}AVpI8 zM-R+u#*L_9ofAALPLPnV>$>y8@r1Z$BgT!|XRn8?x{t8$6EAxsKq&M3WBa^5T=<2R zwe>W8LyqVfg7Vh{rhFGGkZO1-BlpM7hVj?L?kP5hoL$8C1cmHbEcG^@>?uW&5#EJ_ zsDtvSBJA;c@M(GP-ZHRv831JkbP0h|qh25i2NLIpjDeZ=HVB-7~9x}K- zFe8m@4eF8F@jTYrLD$l?pnC##gUSVdqeSj;__lQFqVc>3+&ZP>l^B3j3(zyP`D-G6 zQ=Xuw^bm2kKRn-ijrD$gtfk*@Ej&+i@d}?aBo!V8$&gRJb9$Q_Trhgo3`s+#f^s z<7dClD){uxV1Q*Qyyada#I00aNN7pvT{)qDIr-FAiJ9so!Rs6qv>Zyduh zX{5o>FlwLx$TdpK!SgUWt4tul0w$#X>>i}+paj6Wve`0XVU;@p8Xa#NY91}NCrKm5bW-l8`WOH00v zsnDp#n4m}%B1IMvM3>OXgRH>rd?Ja$S3|0j#9N5gpaWtO4>jjk8(?~V`MNLk{`v-@ zpf;&R|0fYHGl>h+LlE7J+=)eS>0sR98}`_eW=pG=j+BRm1AibLSo99Ex+;@SeFZ#F z>G3s4h4lK6m}CKmve4_xtefY%^ZCWr+WhGn@)u@7}PFfoh4Y?C78NK3G(I|)zS@QHb1oHB1-`2?Jz6?5;dkctZ zJX9iR-B9}a>0A0;-jibu0wYbi3_=}{f*=yS4uVVU8iYj@>}y4)9FpnwF&&a=%hOAW z`h@udw>|dtN0%b2Jn6-JV||g{Vy-Av+-;_Xu(iW({_GJQu_h?bn~C|mDd{H^9km%S z-ch?7s;#;(Jev3w`7mGcHBq2vRko%Lz0ukE8C=V&Z~%IwK$zq6rQp~K1kf#YcV_OU zv9tz$>#T#&?pbsaWFR5bu(PAZYtjAv?q=_13Wc(;I>dou0IP2TK8jKvr`p%^W!dc{$iF2%K1bWtkmF4s6pdz*4 zwYPBMFtOT;$)DV=_aKj!s*^Hx$04Py;%^AL?cAX0TrD6wc?;EOrWk%tDmNSWUZ1$ zmhob9Bgq_bh~rV9CZ-<)fO%)(z9O7xacRj` zI!6YvB%X-sv!uW{B@C*8JU#4TNzGA7e&rHWKp-8&1aa7r$*^QXG8?3d16OEHBLR`s zat<@H%Sz!8a9Os?@x&R_V8FzuRLdVUHy@R@4*)(3Pakd4A2Uo9HFh)MGQX@#9gYVs zSjUSN?wI>{`WH1Ejjs#k_X*@KmITHoA~SfZ=uihI^E2@B;%(n~`?Y6(k8ilV`j7nJ z&Q|DfdCvG>Qmd zqhO|!CN#8d;%+!Y>%~Dy+u)!Vz`UU`9LGdnkgT=^_OF{HX1+$F{Y+-*uPgCKL^#0p zF;MK10iL0PO;SK;e+9S9t*(It>6;UPh{aL?J7$Ud>9S$&!T$d3v;#VZidJm|mU&RH z(BCK#)jxtQm#Rynz)NUvzz(ow@$#`3;nhll#=C|9omN^#-@)2Ag@76onFJY12sP?o z5$HNRy`Lu36!*2$k_1cnqvMl+PaMi1oy z;M`ks>(q#PbVK(dA{4N>6W|k!rlOb5??m^eGst0QricIaNv@3V{in?{9IBc%tmEoG?UD>AJCrp}m3j8{4csXvQ2gc?Kfg+`qQ< zU1v^p5H!>N^d%(L8^de5F~dBMr(cMhQG(__cC;@^a*$m+4YIxRsu?d~m_x7ml#wM8b#wzqun(`oeHJ*{bDoQFP zrFlEuDHfARpS|0>sEZgHuLp!mLg^rto6CvFwZkvAn#o~Sxx1|KynMbhy_Yun4V~yW z8mEMvxMfzKOq?jo(9D}CigrQvi@9_ygw4cW#(BoL;aJRSuWFS^Qx(<u|F|JPii*VRrb&|iEQA|+2i@0su_5W z8dhk>A-0QVT1h02?8<7m60mev{Puh1XZI7F-ydT-NsI*EOliRCb` z#)WLYGLM3LxR1AYQ$2evZjNN2%v`?XGgtv>cB=Q$_ApZJ^S~fw#bhfTUCv5{w1qTz z(zKFXTHd5~TD-naf$xj?LMDtSV}iO~CpvhyO^Z~Ffc4IN#=+gmc6-;^o1R0-lX~=- z9c%5+i!WDO+rWjhXZ;+O5aT`md1cbE(I!mqNMX`3B~mouaOY^0k-#rFR)VDIKHdpz zoct{kgYk2%puwPhx!ZbJ!I#9!+J;7Ep2uZi!HKK~Qt($kracnKTxx|mG^5yc3;WYk zv>Zv(xwsY&-At4y4iJ5btn30y??V^teT2sQS=?bCPF zk3RF?&bAd|Mot*_4$P?sG>hDVz(}RSNp-4SaL6g3GDCm$#P&zM98I(03(8HPT?6|< zX7_1sY%?w$uyzS_wpe((6Z-bSDJLxUQVud3*3=uQXWfKk8yHR6pk@OD{S2d~A2y6A*FxUhw=8E)wxl3TZGsVp3f2_r>8BSKk}#P%y&4bNu|M6v zMBL-ul}UlBPEY4u)?R!sFRwJ;0R+;HgvW<9GRjBp#8BFbIdd?)`4Z?9{6A34J82S* z)5WM%JGBT6&YrV^G`-jOIK?8+LkdLtXFOL{57-2}x!v0C!TXg`yhIxKUL}8#q4u^@ zgNC|))q44>nXOzm_TVsf9WD>{%^`3x5N_lZ{BQ_dTUnrM`gc%{jT z>(4VDc6lKnA)cgK*&%nKp$WUVpBa4r* z>Q2H8+ikUG@PyMgfaMoxeP*#q&Po8JPFqV0;f^2Ggh@fsEEY6DSy2%-zVKSwzSt1P zL<4z#0v5p_OP1kKFI#f83V*w~poEH&{(UB}FS-wiQ1OlE57{|%$ajr_QksOg4nw~fH3cZr|yZG zUH`o^ec!SN;u3-LjjW0vNY*Sm%<)_6aOB|aV#7^pj7Fq~!BUE|Q&#!FCS$4dBmhZ3 z)DL}+ud`R=17@#RY@>OiK`I@n#S80`SiqBrzM0rV>QGXQ)N)74m7{o7$l$~24+^Oq z+n0SC&ufJOb2i6uFWQx6fXyS7=Sc-9<{(yps*OU^q&H2_2)PoT@jH3?CiZ?G*nySG zM@K9D#|_TbZt0@U?=J0X`6 zctTpVXMClkWK;F5DX;9`cyWGR5sS8B`Dc^mI7v(iKR_csW<;pLoeR@3i_SS5MC7}U+-loWCGK-lBduIZ&T}aOc3@DoEz#nb zXtltCt$@#2qtA;K2PE>i0>gLFxht@3Sjo~|$XFv9>Jj0Btb={cD&_6P8~?FysXaPo z&?bJ*G`JccCP$JYRiI2FCb5p|s<;WpSXeUk5g{dfGMSHgP+JyiH9$j+o0f;Oov3H? zUT%BJ2wsDI5)0Bq=GcfY5y<4aq)fD^)dRym(^BuXTLX(ye>5mqy+kxpI~YNhJm~dl zM172Pz`PZK_hX09i}oAt`p6}cNF+B_c_jeq+;|CF=78xLcyG)^&xb)NobsHGgWMSZN(Bp?4r2rF%^KZN zCG7oAc6U+EKx^oG&r*9>Gh+gSC(V4Q2DLFY%!4Ug( zMw=;`0i$*i953XA_Z#dUNZRK;OkDlJ6sxsGWJ+4n2k7DLTIx+EQ`ZSuZzB>cuuUhC z3>r33TRv<}C#vHnb$^oh^h;F^%ZtCr+(Y{PHl;7D1-6dF?PH1J8+~8;Slp^*Z150# zG8;!W`;s}jYw>yqSYnck_lkg~-Cv{99Y&-{6-30s2j5ORxBfU7VW&=U>sz=>mTBM~ zlf_SqgI_S?<{yw~@wvgq^}zorVEZof$Y^>zJD?D^&U1UQi}+D4QY&>bhTr6!VT_!DpCSv%9Y$N6t#+QAfkd!(b z84h==+oTREajTYrqhg5gbWOa<{ad#QrH;}0ZUzP^?8NVFj?UF9ktEB9hUC)8b#EiA zw3D7u&~ih@>My?TfuejjOduGI(+&g%n5(qtK%sgJ)g*{P>^iR(PNWZbXh<{ohst>7 zBmylI1`U2VpVx+^KK}6F8^Jp`22I33MkPO5G5VMxEWS5}VHtV2Ntj{T^`T^TzU23h z6E190lH(|eiX+)wQj)~-c7hBKOOT{1&@qa)%RVz(N4uLtW$12yVb71noh4ier{!P| zSnIl`)pg>`77yJ+N%Mk3CWKmY{S%(fAJ2b!7BM7lMm=oQqw{%?7}c+3bWq3a9J(Sr zb9 zK$XgmP)WvP(=G?7z0M2(Os;*ue;DRM)ksGntWmBuKAk{U1PB^hBrr{lr?1!+`W76> z9)Z6BWYr_LqX-7PvUEm*i&8|iBBjNBv{1bXMPyizffGbBVyXk9LRgYXw|GEgD46gl zPXpu+hNsIwVBqy_Xi!^FgG;(GMWoiyxjGQ#NJgQQOqG#%acA6t1Zx7PM-8KZK&$9a z=!7HzeOuV{uTwVp`d=kDCB??>2*~-JP^MIbb$A3D9MO&Jl>|{gSH36pdbu(rXwnjN zN9RgQLC<^F_7d+7cYTP9`_VlrKp5p&`_`!JZr4uUi^!>t1)S=P_UaBcS8no@!%<8Q{e0s`yS>oo6E3su81h}h#Z zLms2wOQ`4R;0$TPbO@(^5SdrFIIfW{ zW~?HEeOs{dpodZtD4kG=40%D$2pL!7!aP-?ZBZy1Kz?gHDa6xl_%-$0a%-MYH_tgn&n2-_ZO^8*qc7apNp1 zh~EOosBc`hYCo-OsrgZftZfg^o4c)L_~E4!q2fTY4y99HosaER?O{7$>qoHj;;0?fzd-_xAJ}&B)naF0O;Y_^ed%f2i(%p>E(O)h#yRcL+7! z=d|tv)AcI1(iea54D{=?vklFX$=Z4L(FVR2p21wEP6Y(D#hnmuGRLfPl;icGS9!jk z%_vW}KbT-n^d`Sl+IU#6{E%g-Pmp+Bl3)ILk?x!?5uqr)r>~mh_Jk+Zr)^Hca!np(>sS^t1oUjV5L*hyLg?YAPUa# z8$pR%<=J_G&0tw{*7S}C|32-=dGe%>)0#jo_%>sow0LUwCSs&*W>!COTborj=1{4M zppTF_U=^$*5o+pI#}#%uvZUevLc0;-xtaNZoZ6N%@DL`WEd2h1v6)AG_DJlp>y+^= zjM1xQ>3eoBdKy-~8ONPwFWeUEt7$*0XDu@_SBjDmmgrs^0w0~d1#DUMhSG3o?6CMohNGvBO0ASYlr+sOQzgyIDb{6%f#WTf@OI+rZ*T-pjM)(|tmJjfL?2(B z)1>zOP+j=JMbS9JUOvAO-Oy-|bl%U23-vn2e-5lRc+ksW)mXbX?8uD9Kz`O1gKw)X zv#iNN|5jG(UJ7Ywfa?M`n8qUiKv^%(Jg$5L_>IP{RfU*UUAN3OQY|;l0wTXCm08DN zH_5#7d&u+q}YbQVr1{D|>^%6D@UlR5_Z@K^=f%l=c6 zhtq1us_snB;TQ#jfZdEmsg-K21LbOirIXcfd(?~7sLPCAbd80| z)Le*9j=&q-4k*}V%D1qa_z;pCKofTqPEX?RW||}LLqwPk+zA-%F@Jm5KH+8tV=v0G zQ{kKT52Cm2dt3E%(WVzN{fDq>KRNeWQ6g=Tp7bx-nt3Bxan6^nHP78uM_Sb>B^CAf zWkFA>fIw?&TYRgI$J*PvaX&N+)bJ+LO{V9YzBIp4Qv^X1lZh?SZe#RD!+*JQVC)B2 zP8ZW34l?k)f7Go1N5v_4|BN4&S3JX?U{&qE&>^4xAchx;y&;LeLqPkFe)K8%r(m`h zf(oAOE>&NC(Br|N{XZ=GmHZdSKm1Rw5kDa3bXJg%M6&O+^%5``p2QgA{1u6f`o7i6 zIMonLhOMCB{!3=~P=Fc(OQ2;40!;<#ATNX=s56TQ4+YO|qws`7#L(xj`4Y>70mzQMv-k-aAnveA1oVt1m8v!=2>fLn z`$-Jv1bz_6KNQ`&NEDlgKVAhGJVfDf2%hH72xE<6{(}r7v)lN>iR}h4eqnNu<&nW6 zvRVakj*x;kfU$Iz<)Quj{_gziv7zyMcr!^&+eaeR-|fVsaLa81j5`EKta(VGEB36r z_`Gzw&=@s=b8MPZ`!zG7aWYrZg+9O0e!{&ZGRawq#=7l?pVlzYG9Ii!XAr*sgE{|1&Y71#knU5;daA^Hh&0r`29n;|2(p|Uih=@Qm{v#zwzP!F>6{ThFboM+{ZKy z{;TGlaw9%*QSQ8t$!XZwlXPt zqF&x!;qi*v`1%K@?8rLJs_jb+2TGwu<#SGetcZz#S>>3ni;$-PnD zn#4wf?y_YZCJsH#NUW5PxsA~fq(&0lSEG^r%IWaHWg0fV520$Cr_S^mE&nEC4!ge!w2(CT5IuRgFpE6 z#ajo!<&9im>iazqWt-^)0XH+lCJ6;)qwT=1ow+=?$mrwUTd-#MOF60WG!uE43DaN= z1A03|A;r!;s)VIVANrb2BNPSNp2m7})*NuYnLEw|d%cNVn+Hcb4>F7IZ`N!fm(0S> z;)pq={PF_DnoH3vfxttj>CZwlxzoJdW!SzkA6w3o`kS(rwgu~3hH-|J%jitNGH@`N z$2(&Y?0)X4;`*Y6X=&_mw|-smSB5%XJ$-A1CAb?!mM;o?Iw+rmWj}m#{mP`fvH{Rb z`F|e#-FU94apYemkhBh8O|Kut?tbIdo4IB2Dac~Q-MUU)f+^IG*9l3X34X-`u$&d4 zvlZs$%15w=&Y~5~jwb`F>-Ax*w?-b&SvXVIcdnmj&-bTiGgnM44RWp~2k~eEDL>9*qiRp zngH{yXmvGpdVvdF#v}HeS#bY^{}?V)==9fYy@7#91}n?oFMnQ_G)QbD-lHh`-FrlS zr^Z6=_L5{_wqRA)xh!JWWgP`%Qtir)QnLKkBi;c@rmFPHM`amIwfF%lPDW%iFyXWP z#1XQB#t)QBe2eRA&BO*-a`Yaux6|=oG{3#Q=zUP#&BfpT9~`$@6bVLUBoT=JJf6@R zd@VbK)C_gD9?>i~C9zadEiIM`Behdu{a4CM1bYe>FgA$-dk|`1$#ARyl}X^2z-;1Z zPudU-gU!z>g=L2v*NKrA3PQGg7IpmT@=mWR2}Mi8k{jF6KYQ1y(VM<9VC7 zCAcq>FQ8g;!BO6OZzbW42^ES!G8pbpUs;v*C8NoDZxGoJ`dNIpvo}NeA_b0ppxy`- z%$px70T%Z&f)LP8SW1XOQ=2JB< zv8wew`*NmgBxQ4^f1Qkg{}2^7?x-@tP+(?9o2P(&6fkOt=S2;EV*-+$@k}kMQp_wu zWE_^|zke8OCV~a#pe~$6t>ABWA`a%p4?RT~0`2TaF@?yBZr@e@qaP9eK&AjxUNZ2n z-N*tyZvZgm7?gJcw_o)s@}hsc#chY{;~^WSJ5DQ}bXJx@nZhU3-N;>GO7RJG2m1d5 zb^rR`P`9^)&As`Rx5O_5GDI}ElX6IxR`77kfJ{;{S8CIcy^w9WcqDFkTTkQ%s=FSv z9zZOZ+6C)rMi{s}If6ap63~66029mHjV(PU0T~cS(d~%HivoHCHgz(?80jDeMo4ZQ z7Q@RTEPo~${lGvx<)w-#&$T$)LDZ8qPj}H9GeoI&V;pQOuW9w|Yh3M4$zCX9%j>E3 zCW0%Dcy<`h0b}168NE$Rk?b(LXcQ|!FrUdS3SmAHR|2|G~C@6_g;xccjJotSutTZB*A# zw>e3Lp{tHj5`hNF{NCl&{pvd#E0yJ*x>fjlG-M7FHwh-6qCL}_MZ26-kfre>t`liQ}6ha{V8I78P1LJ~&4vSEY7>qWW`0UWhtY{z^@l>F<)m3qlqiapvq__p6e>Gp?Bs%zPvU=0Y%qbs)ZYu3>+N_$YOG47J%ZBlmV+g$=olc9hZav za)|h7)!{t`pUT{M3&H<3t$cGdEO+Qi`y##?9&GN*^7&$CQp9R+!sNWQ!Ds2Xv38dI zmyGNRZO&J!eMq#HCuZgpVP=93H8QTc(y}7Fh>=a9Y_Il1fvt5n8>w(j7z2l+*)Jg@ z5qwP)Gpu9-5o_LAmgKU9#b(Vxb0=UxLmf&6B}e$257oB%lYeE)-dHmhP~cx;Wf_9z zOVky~r>5fnQuEGB(}e5^dplFsYA4m3$-C#zwl#?=W)t_l-d%p-5@06*P>k0!p8b<2 z3?I2+{PlOX3x{o73R2mZ=Sj$+LdT0e$8}zMqTpEyJ)ic&jJe0Wc;Y`vc5W-c)51qG z3!%~JShXTHJO+;m4Bh~w(L8;x0@S5L~Pn^R5zpa1rJ6a6C3^@$yQAl zXk_OVZ??l}{<|UYDb#9}t%zq!LxIr%)T{zGH~ zKagy9r_KatBcM&{(x7hM8n))-qP@B>oV?Pm^e?0iqg$?jPPhIKYi|`5SJSR*qYc5` zgS%Uh-~@MfcMBdICT_vqT|#gT?vh3W1PJaBB)IGDyx(5mTKoU^9%CJ>qdw{$bJnb? zr)t)9U;S5K;1u-c8S)Nheg6CW`dW-ba5cgz*zBU8w>bZI0BxEb&;qtY;NM zek_PagF&{{)J5OtonwFiL3ZG;vCkNvZM;U(Dv4jdzOn=;mFaLi0DZ5;@mqHj&1=6` z40yg*e&2j0h9%kjU`>56{M{g5A(H|u@4Yg9gAofl{=dB26k7f%(7WSAwhgs=pUF{R zMp$6`I6q;@^t6T~qD#wGH9ny>qdp3XAdJu4)c51G<#xB$HxSA<&aq+!O?;lw>7XJKr=fkrE z(9PUADm?k~Jllbfk*fnStn(u|z2F`oA)_4Jx7V~H822-rM&^DSovZcG!-`BKIY(fk z+kV+sV^A{p(a2r>3=Gc5NcqP8!_DW0>ORp$;dZqf&LjzG^~OA(%rZx}jw=0FXVqEAj#T-ztI!kDi|@a?m zH?EFV_ASKsJiJH;j{Qa`%2$&Q9-H~Km6TM3wgg{KgJ2_DLP_&GAh9)xe03fhs1A*s zIrP-eUAs0wVi!^&R8vb+!zzS8io6}AC924{_c(zm+{DyITBQ2Cp~CtZoP_aW!Z2YF z8jT&PV>vB&HF-Thz~3&YUrGc+RZxqH%$A3iAtLd6A%yGJP=@a0`>e_WsFgGAuTZ(8W(O7qE%>?+W_ zm@M+x2r6!lbi{0hw6}io4EMA7!Afc|9%a@9I^PX1P+j#t?%ok!@b8!3lMwrzJpJnF zJTk}wt8eI_^=Y1|PTmp;%cYr_36EcbXYjYdA4B3% z;TqZdV(fq|IpwR#;*o1 zYiDt!x61X#wXHHPbbT3HY0;>Pa#HLmwz77LPgpF?P(Hf)W2yk=^sf#bpD5Zigs!J* zGJ{V(6yyHu1?l%(qHLB$>5a3+8zWOMr`wm00M!q9)1bM6^o(q;MNA>4()6EeR5ol{ zHFK>sc31tYHfTOkInX`~*j*0c-)1im)?W;AUts>HXl}Dd;9oR%QimVoUz)r0LxV5g zidzE%D8vn0N>%I6dmOdOjdeY_O_R=+<3V#&d%Q!G`?p@t~v5 z)3clBKhG!I3+C)PXx(!E!D3TZ^_obsXP8tppvCCjb*JGXqVO=OrWZT8N}|xN%ysse znAFX1{94_--B|XxO+o4Q2Zij`X`=)GL4#v(uwm@azmGielyw&JZM z52=7c0fC5lzo3NNo85kE*EmHd%D?S1;Xmes3;BCkh5~w9b&Nv$MWHf;qbrn+z#*%n z;lX==(1M-(FENHuRbP4&PkQ4E>kUU()k@%xN1!YtYRVi*qOX_&1c>?*t!iFZ%~set zxOOE`=_+)x6*yFz&=;#=q{>(l#tk{37}{z|6wF_Znm?5#j&*9JBE_e9sypZ4}~ z;dIgP^wC#Tm*2ikMVrxGZ_nU2v}R7`j|nKtVy-b%OJ-~9-NOqPhJ#Y@Jw^+nVA2Nz z%^~OM7FLj`)DFUy1vcDtLqZ>e;VapjTNAD0t6k<1B{`^ zk(ks6j-#Zvdzk^TxM{&&g~UJ^`|{b4#XFy|5ZxMKkv&Z=qHZOFVZk&;Cb-mY{2dI` zSG87!N;?gHR^&cn0}$)q=aFvcaQ=82zm`2Y7Y>)6+5{EPN#ZYeS4BB8x^t6ExuNPg zy}ov2ot8b8@z~KJ?%4CgL~=WRYb8MN#|00xkyV@fJD{uD?pVCl_Y`3zAdyRy!?Gyj zro-s+(WUY+nb)TP64@Bd#W6?WW#cOnv^`6rIq6Ko+3~kxNAZ4TtL9o)np5I_Yc{TdS2N&c|idZ<0iU zp-%xI8k1kc-N)RkA<@^u*B#Q?jGAg`S$85Sh2dVO(}*H58#0z+A=-+v0aqMCr|);W z@pVG!T830*-}Zc)(s-S+c6vo7XF~Wc{!)H#q)q>-p7o`8;WpOPrsVM`{g2q)pkU3| z8!hiXdm^Yx*Kz3547u%2;^wpKA|@GLcKJF$_1WMzM-nR^3W?Txv?EfWb!q+L{q5=r z9$!@ntAKiwS0D5y*e0gI`K`pP=IcM;M>3%?bXN7a%ZQ*{aeKlt5#^FP3Aqj04OE%-4~Qmzcg)MW73*6691<+vTt@{S^TTYOHw4|&cA4bT-DNCfut#o zuW+!Y$YO4hMLvYCSi6>=4r$Vp5$%qk`^zAm+|>BKZ(!tQG4<}e4n+WYodo>}SYNlLU4KgFC}H&Ea^ zipAeR$am(u7PfWtmT&FaBAD}lk-;II`Nf%pg_eqy3s(0_@b9t`>n8jtsqL!x-k8#T0Z)`N+rma#5#+p0*6dyYeg1YOO-nNWwlOu(i zTD2#}JWJ&2<*?k!a9R*pCDVS69bjST54YLH_e*uU`I-*PsrK13PQFi; z04qxWQ^sLOe}c@@0YD&XHDAC&3&IHCXn(nkgdowTCNCAj_lnMdGAN#wQS00w&llq&+~@y2t%dXj-! z!pGl+xw&Jgd}+~RSQSo^#_|MT6tFa~z~-j}n!?GtCx`h4bt@!PDZakWx>V^*c#<7I z_c$nF3g5Xnk`@cgo$58}z|FCB5mO^Si*0bWGQU3wbIJ61ZFV{Ha0=-W5J5=a#WPogSc9b1Cm)qnHJ z2>UnHU5h5<4OzSDXKU%u&I9;=22FlXZ1a4K({y3sV#+n&?uHVVQLr$=;#*@ zs`->5jyc)nxf=4l;kh-9`)_V z?D36l6yZR<3tWN}9??Jh`JPS@6A|A!p2prL=c|wc=|TBCJxS%KUD642?g=`(T|j72 z|JgBt%HK{v-*_cgVqa)9iEbak}?^!L|ijL{;?kl~gEGD!<6{)Uc9h(@)q>&|ytz zsN#{z8{x&7u9LC<#Rv&nfa^O+xK-p&PcP_lm;KA>E6a4!mMh2n6f?e$v=AzN{Hid9 zjw@+pS-SD!rkZq;5rib~{U``74wB$l>vq1kMTDt$U`&%_qD&2+On5+Yzi~Y{ep$F) zn9PruxESRWjaD0GOTYZex zZl}BR;-Og$Oj?VUF}dH**82C~n>x#BHq&>;^xH3wC=VH3K{90u)Nc3=J+`N$BvE86 z@JT@h7AI72rIx(_%~u3bl~E0qi{{`Sm*AuXevHL2jFd?2`9m-RPN~HKUIBg3KQMWO z|FiScjYFg7b6&2hvyN#rmOjCdjudkm&+%w7={c9eF+ZfQTC|87DT~xcp<8^~tTHR8 z)A*UHTr}-j?=AFZst`|UDDao+L`8{vT86)0>m!tPG5|^q;<`{;aqLd_&1WSQftrl| z9A%s`A+z%%+OpHS5z>pFVQT(=B_Ml&j}4NK>M zxs#C9WQJ%UI*d4$p78wLjN=UKmmbK``xiP7saHmDS|feyztYZsLbZu2n3g6yKWl!l z=9C8wgjCc2u!AF2D~ZM?YewW=#~r;^EKXrGu8wEF^`Gjm>OLVQp&CXSRHHQGe`;_G zXlwKJ2xtOO%@`Dfi*wvq0vJ`EkG#W$GfzX1y}n=2AdFFAuUy~ z34F)Zd?3s2K-!f4@=Jd4nsea|3BQ^zX$;(Xh7x9&QFqi9}mXYJHb#3RHicZ@nkEIBdA8?W& zz52gTcK5R@80HxFEUzp=%t6XQrn^`Bn%^GkQ2@acE_Fp>RB#!jw2iNTgt6K6O=*>I z6@4+YqqxWu+d|_{ql_8J;s&unkplyefDzeugPzieEm!l}%hpTKf0yk32kfqN6C<+z zI``+w4@z4$l}cT2EE9m1Pbh3?g<(xew$RO$qMJwT)+$2_W7{VGdfhrlv8QSX8}yz# zwsZEPG(A)`sXSL9oL(hj9*Su<1h@P3X4%E}=y7#_7|o=VU5CRv80+A}nZoC}FADa<>9`lXY$vNik5Q?PU zqG)M@LOdHF8>%a!02h?K`>c6bPM1QGgb{>AnKnKABA%E*{U+|u)=iPPX zHy0ot4&6KSz&erWryh%wA3HJH7|jr@YLeGX*5XfRyS9p$y{g!1cD64@U^Z5^FI(TA zOiI%mq+02WmeksuNGizorl5vX-k5hAIR*$lU;lC6FIYwx#=$#086+^5@a`)-k>%1{ zgxR`8{xtP&z&i{0iB2;@kcDP0jxF6pN!^>lux6J{$`rwoLeY1BOu+ZI3X`}6%q{|a zm*_*c%gP%WBxVEHj*GKc4AnGO(UL~hmCFtL-g3&X7A2XX`ZvS)%)BGcJz4rUjC&2b zc4K*LnqS?uG?2<3gGFt)@YQu!Ex>LuMR6Q;e+!@vu;+hw`9igR=UhMg3eP-7VIT9=7=0eiR z2|Gm%^JI>XG1H*+udLvlRST8$`82KcNZQE3FY?_KN0?9_vlL}Dgeh=%`h&)-P#Fg-CvKfQ z;zfX@knI=DR+KRNNq&NlrnO@Xf&yp&pa)jY#->`CxI-HRAQssX4`^>dd*7B>+QX_UrByE zccJeCy=Gzc8MAZNFwJJV%!S2M;tq2b^$MyEpM-@DlDXe7OS4diSXiuLR%mur zr7nc1JE8Wf37dG|byboI2P`kO3SvRw;Vf}M-gM}u%zT&RP47CIf3U2r%oIeF(gijb z=-(vC}Q-$iBrKPyNsi&A#AQ z+h-6?4CnSNL@;0=c9l&Z-iEX5JfnM*o1%Fk2W|K(6ybLkWFz8U@iM2okNo-~^lKUB z-+=f3!FL1yUBH`t<|W|#GSczI$1RRKduUgT99iC&n(7bJACP!FMphvlBzE3L5mR1a ziGryACNxY2_fy7@XvReoTybC>VJP^^R~>#tDsV#{EW`mg?ZSrAf5I03dIhYl`HL() zMm2cTuq>Kkfura8u%y0liB+U&^o5!vbB)ECaNEP_>!$eFS>DyUNzoCxP z<^BcNDA;wzbh>$wEa?HOI}Zdh?|w*o_PnrZtrrvab2^369nHL4{*B1=Yaz9+Bxiz3 zOV$|QWrQ<@NUt*`%=yFkG^IBbOQYBf7mY@&USxzjRHJ!s8YG2bGRAgu&V#24*r8W*YG>R6ZP;bR(r~zvI=A;Hk4S6*4 z6P%~WDd?coxL(lOTwg~-+ErX|J~=xz0z0JZfT05oXg;t?`3dbeVYl_;1^s{l(xq!= zAG-$Pk6i6fy}CNueBIXUuXy5bI0@ZazGuvaC49Ec#2f85U`T?6JAsKSU{%pR_#z*$ zp0@nb*LOp_j__%>0PqcJ-}5!3I5Z!x*e|cHLoapZEy??;EuC%R7M-E_x@r1sy@rIm|~&TJ4rX>gw{o$_hBjQMF7ZPd798Lme#Z}5-@b0I81XP zI1bFLVJXs(aG4nLUDN_n`6xK&@7o(^`Rtj5H^@1^oBT~eg5)*p9aS;(Rd*gDg|EJs z^BEO-Yp7KaP%U|tKGdr@X5KP5J|CU*aRkqcvCtHyRc}xxynVTOd@(t?ix7G8=_7S3 z#g{VzdrRFw2M-QNyU^0q3>)!r4`cmrrurAsebuQeRJ@@zfI4-${3G%&|8w*yvrTuW{IU9M1YuwoF!14I zq@}y}59#uM578$7!o1Bil_lD9_GzOY3%>ijIwr{*+Mgjk*LuL~*AKCHOSx^g>H=Pl ziF~(3ExkYeF9{$L@BXRozoN&7L*oLb2Oou{STMHVy3G1{j!!#max~-+QW_^Vvnjc(%{`Eh^!lK`(ZY}iEi`oFmI(f%QPbG zFZ_I4uVswS5A#Me>WJbb6TXgOBDLrjZn;d91z2S@4mFwSPU-K+Eo*l4BG!xDQI zrN8X$YPXFWPNnf%DA&6d+SZo&Kg8Wk|A@PfR5?FM2}w1fIM_aV&Yr%bJCwdqQVN$J z(>{92O?c4XtX{qHp*8dS#V3Klf$Xee`fe zY#i8Ee&e)Bw%oH91_?8DseWyWRDP8JIO{d|u~wC6gOlgoe;lqiQ(V1|B!>1{PQUXus@pI%RTUpm3JU?kQkcC2Q@KB=EbX@-w7!KD4DL|B&^wCFr%N zEwM~hI)n$qh2hARpJlvwBUZR2lF?BN9s)??a!pED0ru2cLmFn~2U%}UXrq>7V`RfP zQv_0}huKzPu9Rpq9XTP)NhVfa%I8WkFe&Uw1oFrZ+Nk{fPKsOzvQ6_0UE#P%4)V0{ z^V!GFoZ~z3LFGO917eLZn4ikV387Plok505P}d)VH*WpY1lcU+muC9EWS&z?Z8okF@*rHkr^29pEH8 z@SgVlHKD(cLLD}#TPrh#U+Jb+qvPi~s*o~yHdfdw1JQY>8Su;`M_ZgC(dX9tpj*lc zGhIeOZVTSIJn9OvzDUiTm(}SuqeF+2eSlB#Eh*=W9F|1PQ+Pw$4A%;NOk$r=PdHOd zcHp+ZdF(+5br4jOUN=4#49(BG~YDc~7=+A8<6)(Fw0qa#5upxG%GD6-n`<-~xtj zSA01Ab5+ZrtdRQEhAUAySq6*{xhv}#;Etu6(mvGKv`CRS zsxl-}F1xB4<^P(uE3+*NQ|}dM+tOY>mHvAa8A~{mEI8`hUE{6ztQX*l=d89r@n;w5 zM1lx%3&Yx;>#Czi9ItvpxIRg%yV>J&ffTW?QfFmL)y%u zm^<&+no;eUl86cS6SsfRX0E|!-3fa)Ur|)z@#Lk?mSXy!s3{nsRU!x z^MNiKpgEAmOMhn}J>!NlRq3d{&^z%+Te%a}_A1bUsj9xfQ>}kJA`_97+IQCf^e23J02^Y@Z9aN>lfRS-ZeG=E+vB)$Y#;%vgob z1>G){jpmAi;ZUTeb+*9H-*%?z7JK>I&dk6($B)acu{0l6;9(@5QTu+Dsuorx@JW{m zV(y5(H|kHwi3aC)M+TU5^4-sFgIh|<7x!vVl20x10X3G!KX;a2^NR_0Kg+wz4k^op zZiXAT-Vw(A*=ledUKH{V!7fYNDxXTx^V4d;5%Hc07+hYk98#9z+Xg`?gxO(;a2+zE zoB34UU%g#5G~w4&ezGt)@3rRWSV`{QSF3)=@o0<4S9aGRp2Mg`I-fmz+-{@@Sb9W1 z$KJ9o1qP?88 z9?l!^I7U@3$9Ws+um@H0t1*TeNwb$LE(m1z;=MVtm)~$$5HU#X?W}AJRTYlPzClmJ zxHjI{^APi!O0nX_jnmZKV4mB%A@ENYTaPhF2jt@KH8L*(g&3;cp*dw1zQKC|6_K%3;7dNPmWWW}gY9(5OVrEG z;heIQ_x0tz2lQdNK{A^S99YSqPIwpwQPc`iAvhAa#zx|$gdSTPc*q}*@am?TRS0@Vo z&5Fj-$Lfh|6EWBj{WbkS+x_t~-Vp>*&$|!YqZ{7(kgfPH z+xTW}$R6;IYJ6(rqyL_i?9Z*Xj)5P6-ZRMDMLrO_xViC%B4GtVm?))O>=W!}ubNsq z$Asf?YoF##KXE}kbNggHxvzd4Q?CW%<&RZ3|B0Z7n-B_DRx6$Q{44r)RIJoPyE*uf zIlcG9YYJ*LY3yrUi0q?G4aNm#dKUcmuai14Rzvc0xCvDQcJxvuCcf6>x;oQ-V*4I# zVzn|gB%+x`JQbTMfs_lyMW@&mR7l61pm5q1%l)Q2Z_SPAqnePvBC`_~4eFAp)^}NY z%y6Z)Hm>4YH^z(@92S^G1m#{2OlDkbkR2;9IH^fx2HhZ0D36w41-M?J_)el)*jOq%ZguM1 zp$Pg*yM|v?Xoza)Epkz96RNO1O`T7my;M;EJcq>1S35fSt+RiRf2RkoT3P8(4&iHU z69_}Fz!ZK;%gp550LydD_^8WZe>3LzsVGeFJoJSqC19Ko&kvrp9uo!%?xV0Qp zFxEPTrx~3}hz1ctK~glyeX^RAjMyFFMe9g#BrYgm@}#lmE~-^2`w86eL3yi#s^b6e z9H%5UhR(kZnUcXQTbcprlx6c3Vzyr7iU3eIT` z2Q_K_OPF;`X=6fC%e=IK5()h{m{EV@R+ggO&ls@t?m(jyJLTrPqUmb%3bcSXh)K*hfkEJ>H<71{JGsSdcLX<57yHPfh z-Hb~kku<{*Lji?p^)o@Cix|WYq9=0S)#2qZ;+|!oruH|yqrFt{y)KS>)iH0!zDga} z1x{)Zoux?7qow<;_HjkFk@n7ZiW!uyBPt8#eU{E^tP}7~EH8xYb`A(zkSt~Lx=kx* z?K~)5hC{{a>A$S1lp&sf{Nr~2@{hy+7yo$QfBMHk|Mri2QpW$09vsUNLaq2vL6i~PqF z;vP4GxW~2sy2nkjCbTHmXO-h7jt&w9FMT*i{odwi7u!FKA`1phNSI9V-$*FzA64Gi zZnq~Iz9^~mLzM7^*&GR3zuc6(n{w!&8a;r(Oyxh6#zPir@)H?@7+>(uv!#(ona^wv za`x65x<${dSYrrPVBHomW_cwl^xn7yb)J{yUS@8VmV|dIRxYv);(q!iUtsxm8tXjk zS*v`(0Yy6AxV0o=amXeZoA%>O&n(xkk%UCB1{VC%ky6H&DPixDnZnY(djmvWEXPPd z;4jK9P$opp^-hNq_M6pkYEa=R(^B|JLt?=wk=ibyIEP{wd*i2+WO67o$dpxJW<_pp z)dU;qWx!e8f+gDMQ9!6^eJGbz!DPxP)|GS&RYZCABI4^b|C8rO^~e04o?y8-;YXPY zgiqh{8bt#W*gp_7*yCHqK!=q7vZ?}nULNU`;cm&B9l(dfO#E^sY5FX-2Qx$`lEo;a z*%UL93lq8QQDyTCbH!lyd${{jI}l$qch>=4a6VroJ^C(>YhXe0rGXY)nBRm;w-p=j z)_B(*iEYdMA`IqjGt&3~YcyRRK=O z`jFaIbKmBr;WDPrZ4=3jQi@9>w^&7e(xL`AD~Ja9pv)4b)^#&VGX{ z?T(el$x`*wp<##a*wnW-c@^gwgq<>%)`_LeJl57HHket`5-LIO5^Zzi+RJ*((b}{8!buOaGIs#&w-VgXTlgBj zlk_-wux>IvQtGC0#NTz@GLwmOPP~)&$q2`3bY<<{{JgggtA(>MlpYME2Lz*h3+AAK%UfhR*fAvyP zAyOSw4IHC51lxiprYAx(5`37mC#|o7x!<1DXdMu=#Fm+_+ySQV*!#tuC1^~qLv>Lj zL~g=q$*<2SB`gx~BCn+vo@yU}g9Qr|+z_%S<4?E|PBn9K#ctYS#w8Q4=`bYcAIdEc zMtcp6<1+j9N(D)*d?G=}kR9TUd8!kcQ56p_`g`6#a=w>OKim(ndw14JW}$Ys^B4-u zbPCSz^!97;0KjF4jHMWVe(wO})7pikTr1uob<=}f;m@lFj;WPPvraO%%&m$ylDb!+BRMgOl~1Nq>KJcd~zW_<%AUMZWk^ zz%{QkB6|zr{>G!#s$JnBIVp4K`@Eevfg+Vua9pBDOiyz-VGq`Q6genR+{FW`kR>%fN^9*7Jtdc9Jy^*tbHP zWOnDv#*U?TUA+tSy61V$5ie|fTi?qFy2thA%=_~(C2F|eA6@gh+a}lR0W(LQj@lRR z=SltLZ2M+)lZKfLg%Q?Mg)-O{*UWK2LuA*>L@@Ki=ZR1YSYli1hNtgg!{kLN>(ohO zCUEJ?Df?oqdDBJpytOc&?t?yO>M8YUg4BJzWOUx4sBV} zHit7AbQt)^h$t*^+gL;y5c=eyQwNK~a|aFHt|z!nG&6VLN0H42@V15fzoMKSGvkqs ze&tc~2`z0JCsOQftI~;O(jv z=jSzkH_kvpz868my+Z;AHGt&g*FN-Ur{I(Cp6E0YnpbxRF-o$RmC^X1K;aMnUqreHy{Jkv|XbBu`qPt{NKD3SPs& zZJrfZSYWC^z-Y}E@llB_$&T*_@{iBbSHZQl?|YWJV4H5UVY^b&bWpF7T(R;6imeN; zlK6e#y78$N7!CG`yM9=3BlslVK>4^t8F@?(ZSLK#-Cu7G3H^|_ou+b2O%1{wjU~<8 z66e~Z^2HF6Q#A=H*#TdqW~7i%mPoZ>B_|>1g6*DXfhPy6-^a-#S(VkU4d1}^mRx0# z1Um@U;Z0_jY4OgGd`!xU7mivIG&tu&LveZTzO{?%r|84|K#S4?N8fM@>WxBO19Gk; zRP=qGB#J~ypJfKx%PJdNC0g~S{@DzaMwlnd{17mrYT7Vw1Ytk({W$a})Tlv7L+;*z zUMcY!@bS}957elrx`D{ZZqAVzm0AD646y{) z!GM@T`Ut=!@7W13!=o87*ngEs8V1#a;W-H8fs;K{6cEZDNytYn52wWgm(ztmYv?9* zFm~60|N94IF=0VWL+E&tuFVESArv&rWCRWkG7asS5h%2jChR74n@~;!$A3m{op^b# zuJ6A1f>5+XhbY*8T~!I0v7d#sO`4!wRt2yZwVc6&i0!o>YKfJ4Q9+12L>s8VKy~$| z$Z}6UYe2rI5_F&3*fd?D2Ldt@Rbtae4&4V#w0Z;0YtxxbTL*W+kwj*ib^HQ{QVaTl z9EwCR2VOje-6wL|%1)klgUo_iAS*ngV#&ZvQOvDjS!;yG&GS8kMsf21>N76lfXvnyIO=3Z zxII%0+yvBD-ByJIyPdb`LmQ|DAOjwf4b=2{^46ER-3hr|?!YmUkG)jf`s?udVNDaI zb!666HV-=E9UZ+BQMa%^F2j$tu8<|%IWHo>Pnk#dvRl}~z+bz1i zPpR>BjFH`2h;?5@0aSW1iL{MX6NxW8hR|(6QN7`>dcPT14L8^~*!TI4U!?83qJw8g zU)rre&b7oo(yi-(y-Z-gb zRSdf)Y6bs(+%<6rj+v=xU0#$+PJ{!bW0lf4xVG@t?0X0TBQfe(_~=)hdJ)g~$LfVk z{DKCU(0pDp99-Ub@)|A>FksHY`FN00%+bFl%J5cPLurz?Y7?l-?I9FTi(QpU3~g35bh3G z+^*R(SfuNn-SH*n+$a?aG&k7FIQ)d)JiYpSJ?)6fSJt#sIW@{Lj8napREsnbg)WT# z-I-=xm|rm%8xsSI_rdfDJuE2U?vV#76Aa}fS|)$$NW47#ptZe)BU;vEP%4oyP0N{@ zQ)vMamB*BAxu!9pyt=f8cc zo=}1!QO}Yq(Tnaj%ls0<{5}dtRUlka#w$P_(ig{Fb@3QcdrP%lrqc^Fz~k-*sV9b=3*?paFBSI1L`*jVBFSdz#%jZZk*oL_W32za&(TnhH0 z_jY3vT3WfiNW%c#>r|NL8`7kz;m;DC=`^AQ?@^Rnphp!zULl+!9=xQ>KzGmc;^RH6 z3dm2Xh5m!B-|U#A0-06r;yyRzvgtoi&5@MV$5aJoY`ATK&3bS6U^&;q9&-4S%yk%q z>7rq1wu$|eu$9!2;r(En5lIw9t&5@8ek|f{^$?9jm;z_w;sspJ+`C6MoLmMj?pj}L zG|nwrWLD`V(*!1_Lvh1E&fJPdFAbn{&pXQFtc1X9TX@l7p@g?gf~z2BZ0mY?Je->P;;#z*9+oaMAa3k{ zdW@-su1Bg*Hmy84hJ$87Xh?RLPu&DI$6~t{T^mT={*!C*vt|L+guo=D^JLfbm+tK! zlcTogdbd|Zf<2p=)TEu~zTiTcr9HJ7+_KP&$ICCi?Xi}8wHuZ&=`5`KjFh^**OJVk zq`bpWnYS}}8Fb%-0;`y8(a8zZW%e9CI#svb{$c!bvn0y7p)xatNg{U{`1u$eDnhLW ztyD$R_AYx*#jF#G@{t6M2B&pNh(AOctmFtSDA#Lx(VkA%;Qac{&HW`r`@syAuZlY! zE0b_YMu|D?-5{wzg zq6%kJT0p`@ItQ3`AnoPuM(x#?u) zqNP{seezi_KJ;8NVhATRD0!oT02(j(zJeGD$>g)|uL~dXcKu}U5Ke%<-{;()^efUu zcOT*R64=C81g{Sk>yYA1Rh`^izJK~n)FL6QB!Ao0iegta3tz%m7K&QSL^M8vuNZ?4 z-5XlCK^g1Er7;imvZW5hA|L*D+ZBF&ns;OW?Gar>Z=K&HBl}zs=pehKFQAydZcP=a-V9&A&wof0V3Kw z)0lxMcga_7aDW-R*TWM@yYK{1u~MYCdA?2f2j7&D3 z{PO%w(s zF}{YVeZ`^xlS4kFcbZz9J>_*IySB z3TNLvL)htja~8u=Y0cdBhk^W;92k-3%#Fckw;~u(&eL494ovBy?KXUDXimXS!2Zi7 zkQW8;c;0`^k1*Q*;(bL210wdR2<%JYXQc}fbD#MHGPgtT;RYd#4=uo=@Vx9H8sa)m zspx-C&escM4`kmbuj+XTCeB@UZfu+bA;P{xfD9Mx{-mA?=zcA^h&qCb2F4J|Qe7_5 zU%uIbuN2I1AXw1fMM|HCW5{E)S2aS!Gyu!418w`@EfYf2v5U&PH((kjBS_w-+8aAs zmSwnF#%WOJw+ z>0u4mM8US=B#NMTf}V|kZdI#dGzG)h;Hz&T(!Op98OaDi4yw5sc0>v-bs&d%C!iTk z+BHC+AiCk#fXerGl^ADh_7u1)*^F4b&Kt4E|JKS16Fm_ly8b3-7q%%2p^t&dMA6%ft|4Ou zI=d7OcFmZ0)?5eo`;8}p5Ka4xaE{R};x75l4R%7WbgjJ`*8j!YTSnCtbP3uQcXtWF z-6goYYp|ffU4sTL?iMcY!QI{6-Q6_=hv4wtyl;2UbWit8&-&&MYjJL!bKz92y{c+I z`zf*kviMzjeMGKOX@I2(7u8`0DK>U5M6x2RN1vJSQr54Du7<_Ai|j4`u^gvp&m{Fu z(iq1WjIN!XLz-H#xvD?~pFdd)ugj+QxTr>1J>7aB#40vm-da<$uj0Vx1H`9Ap4BUD zIO~Jj6tkQu5nJC{?Mm9l<`fb%Ra}U%9(bj0Gt=@gjn++%BX&%;vpdq_Cdlqxl4|0M z?_1|~hH&+>0|3TpOJ(rlTtjtqm-*Lv!ap&v3P;=XsCp0vJA{@lT?ilbZ~S;dm0_DLcy@PjRGU z&#G}rlR!qReh%tm*72TT(_fmq)<4q(qp0LB#eGrHQ(T}MUFN>0O0|(S>*2P%JIn?5xCo?)34fSzQMT9Iw|ioK4*H=`CiA z*B*LM?~_N&1~7~#iV~B`*>A(o!^|HLf7^KX^*%iZR#jwY`16Ti__E|wp6GZ>=u?6d zN>P&#t}7yVNVS}}Bx1?yei%8YuWyG6n=|~!5nJs5eSm%+#HNVWyk|Md%ganhi5r24 zmQ|0`!0_@{ym;UzCK(hz^u3@uc?k4)Ure)JEjirsdD??MjvJM((t7$b+j)8X0eNEP zb&NxTkK;Y2#@{JmQi+YP;7cu219`f=<#K8{AK6m5bH+{iFmaRX^+$@L%cnY1E{kRG&juf%(VO8>mE}h(b zPfxSnwlRhkgvTWUpMOR7U|Mkx@we0DBMtUh=DbVq54I92JsSPQij~WwHQLG1VM$!E zSgkF2U)%;tca$DX^?=VQn6-X(dcf_~fIf+ib@B~+6)1Qh{2WA|~oCxwhd#?za7w#MA#1-Tbr z{o8_*#odn=cSr9|#KtS>wl~j&fzO?G^^7G9F+7RD3!hg>;*V2@gCdj(8>4O(E^ARO ztOr(-+Lq>c!UxHH$$7r6tHBSBbYlI`n#mG^5U=bT^M<<)U1eVHYQFDNtayauY@iv? z%X&pw)z&zcC>eqk=Z(g1639`wD*TpnSzy0r+gir6nmQqHWrY6wABzR6B}I3eq=JF4 zvZ+qs8S$>eqQCUl2j{f+MGJv6AKu-ya?eMNvO$hCZ|YLEN%qJVV3wm49R`Oo`Cy}g z;2WZyCZCHTh_$|*fA;Kj+hB%BE6?Qjo>cao@Zj-<2DP zmJZE`(PCLboU&sniw(xENb=mxayl17ii+ESBCX;+p3y)VG-rUAT4 zTYOjUyAJ-k-_0}KzJ&fTtRx{qlgjepTrD1@F`Rp&aTiE|GF(3xMk_!*TWD4OM(1=WZ*BI6SkAJn z$(k~rw|IUBT@RJ;X3vK)0kh3-hujF1b9V#il2Q?Ib^B9zqj=}Zpt4vdAl~D=3c6~^@e;DrD);BFu2#PpMw@f% z)`doiq+5MdL_TzY3ztOdDvbVk$Jd$;WY&Ak*xqpF4u;~Z$kmRxI@0J^^#1Bm^W8D@ zJ9PdYFZ<{;XN+Bj@v-ki8U*FGXnwO#=Q6P;zD;#nA1%32!)e0arggvcd+QybO;Gru z49N9NfgOka#m0uN20nE@0)`fxxHV8Ue)=7{_PavuIefY|?z5YS8VnkW0!8 z{lxTZxo#(51ePY>g0Ba0W$ScA(()5a|NcM|jbcDh!j~Ny>nE>^=AKlZ$BX2Fx}&W9TTlmD_k-XHElp%elVCQ1$?s_oiSbske=I36Df zP{Yj;(Oic3t;hFUp(Q&Bj-R8Io2^Ge+`Ax-hFXu6>$`)*l*gflc!<=Wd_Lf$eDD-) zciOO+{VknD(0)u@WbYI_+|^c)gWL8L)&A7l!Gx|CT6t{m$;Lw4)3&jf{s9FnN^TX; zXtXFs(e?vzY--O8=Y1P{RX0ZXMYPN>COG(3SNOE=;>;-ix#d|?4|bprA{dzTi3dG7 zQAUOA1sI~L#UuP|SjB^%(_n!)#AAvC*Zay*2x{qP%&@{HBxo{}I>y~oBc99*zG4PN zBd@a8;>y^%uD^9qy;6EsIDympZ@;n@LY(O#$#6O$zcYXQ9=|^+Brl%LN#TR}Y53Wt z|D7NhB9gtk2tJQB@Eyb!|3O$)hEsj?hp;DQZ+!1Xm=vnph5wg>{eZU0w z8J5Wpekr49F89LeFtXkj8Sl>)s6%rJF-M{Hp>Re+k4!P=dqpu?8dv-e9ADZBzr~Uj>pA<;a*g!{u&nqA?XfTV?Y5>uEnH zJoMt3L3^bkk0DP++#DFC!-3LK0A&3N)&;qKx=fQW@O>~^=j6LW^_0+z_ONiwpkr7 zaFSw`MAA5f&!ayKNUh!tpVc~A!g)!l2hxf&tj~n|5fXx@9z=;xv3(7FnE|Oh3{Zre zdNECbP5a@8md9q+EZ`!hOn3QD<}Vmcb*YeNlJM)6lCY*oU^EVW zsNcYvgiU{WOAoS&caHN3TU$JoSB@1%RU6X>Q35I;2Y_%1bU_p*TTtiY*OYlwjcbFY zoi$ZdgbGq(T0sd)AzQ+t8sf3rOr$Hg{qyTap?V6CGn^uRzX>TlCpQ+&Ka2wZ8PUt7 zS0yGdLpI?W8(Z(RJjC{QT|R zq7xLy&tjijjLbxqUp+?2+{Y89{q%Yl~v15BoHAlrlPkF}W#?Jv|7n zypqXr%c-Pn$^q++AiA@GBs`)~nX~bdeA+jmA~OGYV6K^k((qYENs{2S$GKYGX?w~s zAI=Zz8P4qZT$MdBg@t=$l^;)8&>$6NYVgX!E0Cg!OQa@!>HO9tMXf*_F=Mqx??ATCIXGe2fAmljQfHb)f}W)l4*_w+C(rB$~`BbIvZ0Bb+Flwg~7 z_O|#7yzee)u0X=t2tBy)_BGegV_L_07>D}?MLrwhT(`>Cqp|gHj<|G%$=-}d ze4t_k6umx}492qAte@jnN&Ud$W2DqC!G>|0Q35JPgq&Lr$0ZTKt7N75ssVbm(hx@E zI#4)l%^|R?n||Q!6{Fy6#Xq4S6j|VPJmj74=TF3R ziER-V#K;mz@`P}a*%GMfzvNT^wW+nQK%1(diYR@$=bm_)(C(3w^Vb$U2Tvg-;(<@! zuYQjNnlcUPtnXVr$P#w|*SnR|$OCv8fQT3edK3wVdkU&qul;wTVKc~fOm*-;8|#d4 zDt;cirSd1SVUXmNGL$={yRUY0D7!OnA7l&1RjHE02d1CSNJB;XRlm04Ve5%)OSr6G zcND8q0?+^feIC4EoaZyjyncbV-9x7Pfy{t}tcpVJ?G_t;OwGx(eR$KWysfEBka2%P z=3DyH+=X$6X~!R_?_|1y6;5Tq4%c5biBVUINet5eJ&uV;$E=B{FR|k9q~8BPLEpW{ z1K)`-M568%!QF6I)e0MiaUY(8aNJS!B0KGAj&S*DXtJ9+#eAB0Lm>r$Zg0g^C=W0H z#L>M$Zm8N0$oXM!5UtD~12=#oqQp&kqCBMUqqjI#oR^0vPvpC$rk987#Cz#`vajNx z3fn`^`)4huheO>8PCj>>TglZIAYC_xu&Zu-CGz;)K?;Gb!DydxVW?%b(Nw5~uqIep zFktO+ljAa1SLo(f4H0z()}U-j+W`U+0#WrE$y*e=UHCv>gs za{t%wulL+L4P|$CWna#!Y#f7*-4%vFlg@a+Ci-N&rP!mFX}5xza)yf38v6pnQn=qW zgErEqcdMHQ9bKNzn6?kCv$4vmXTSOQT6u+d_#ZYRgaJ#zPhn_7r3}#)`c?x*D=B?H zS6VZS9&IR=h2IT)c-G(VKow^-bsV>+vOa{u=zVrgnl>f;Q5CJY9m4$@TDIktR*MAuUPCju|u=L)}%dZESs>h`RfD zes{ns`uvKt^Y}fFO%~*d{E=ZGoO@jewkzMEOJy~mO{FllGO8}2-xb?o?l}reP#aV- zCM_=NA3Yrlnk++uL4Xz}m9)^@?Ms@;ofKOFQDW3D>9EF!eC zyQSL*QCQ*aY2NuMzwWVOuaD{wxZg3)5M$;1*#BQbOpjwqwErGrviW%aX{}*z&LCMI z3Y0i#%ID^3!TzB-am*A9TEwNtDwxlh*iusxEz3~+IFM%MgvBU;rum@Xm_O`Ol zR3pZH1T_T!%bII)9fd9hy_&cUucAbJRqGA&iWz%FS^pA*v2D50xx^sW&wNfaZSk-a zLAP{(%6uSiea!W8DSe;SS2=zXsCx{Rzqu3D<Tny0gfU??-r5g zkMdB`bBu|xGdzhSvg0@}F@M=?(O$A9+F3miDn=M5P7j7{^h8HI3X_&m7*RY0(?5Z1 zgiS6aA;CVU+R0D(+-Vm%cm&-$4Vq&e1K!*inqvPjpajPo12%x|?m;CWuoEMy z;0OlZ90q<+Fn||HNyg&+atFBYRsjjEu3P9q-gA7NG^(grOM$O|{X_RdSAQEs2jk>> z@BVt5hFADLh6u}rPmoU$o<#f<(Xp8qS`J?Fv02wQ7pE%^4@2+LcNi}^rW(Ryssl