Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export interface CaseConnector {

export interface CaseSettings {
syncAlerts: boolean;
extractObservables: boolean;
}

export interface CaseUserProfile {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export const createCasePayload: CaseCreateRequest = {
},
settings: {
syncAlerts: true,
extractObservables: false,
},
owner: '',
customFields: [],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@
* License v3.0 only", or the "Server Side Public License, v 1".
*/

import type { CodeSignature, Ext } from '../file';
import type { CodeSignature, Ext, Hash } from '../file';
import type { ProcessPe } from '../process';

export interface DllEcs {
Ext?: Ext;
path?: string;
code_signature?: CodeSignature;
pe?: ProcessPe;
hash?: Hash;
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@ export interface Hash {
md5?: string[];
sha1?: string[];
sha256: string[];
cdhash?: string[];
sha384?: string[];
sha512?: string[];
ssdeep?: string[];
tlsh?: string[];
}

export interface FileEcs {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ export interface ProcessHashData {
md5?: string[];
sha1?: string[];
sha256?: string[];
sha384?: string[];
sha512?: string[];
ssdeep?: string[];
tlsh?: string[];
cdhash?: string[];
}

export interface ProcessParentData {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -596,7 +596,10 @@ describe('AlertsTable', () => {
children: expect.anything(),
owner: ['cases'],
permissions: { create: true, read: true },
features: { alerts: { sync: false } },
features: {
alerts: { sync: false },
observables: { enabled: true, autoExtract: false },
},
},
{}
);
Expand All @@ -612,7 +615,10 @@ describe('AlertsTable', () => {
children: expect.anything(),
owner: [],
permissions: { create: true, read: true },
features: { alerts: { sync: false } },
features: {
alerts: { sync: false },
observables: { enabled: true, autoExtract: false },
},
},
{}
);
Expand All @@ -631,7 +637,10 @@ describe('AlertsTable', () => {
children: expect.anything(),
owner: [],
permissions: { create: false, read: false },
features: { alerts: { sync: false } },
features: {
alerts: { sync: false },
observables: { enabled: true, autoExtract: false },
},
},
{}
);
Expand All @@ -656,7 +665,7 @@ describe('AlertsTable', () => {
children: expect.anything(),
owner: ['cases'],
permissions: { create: true, read: true },
features: { alerts: { sync: true } },
features: { alerts: { sync: true }, observables: { enabled: true, autoExtract: false } },
},
{}
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -694,7 +694,13 @@ const AlertsTableContent = typedForwardRef(
<CasesContext
owner={casesConfiguration?.owner ?? []}
permissions={casesPermissions}
features={{ alerts: { sync: casesConfiguration?.syncAlerts ?? false } }}
features={{
alerts: { sync: casesConfiguration?.syncAlerts ?? false },
observables: {
enabled: true,
autoExtract: false,
Copy link
Contributor Author

@christineweng christineweng Sep 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use this flag to enable/disable auto extract observables in alerts table. Currently add to case from row action is working as expected, but bulk action isn't working yet and will be tackled in a separate PR

},
}}
>
<AlertsDataGrid {...dataGridProps} />
</CasesContext>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -482,6 +482,7 @@ export interface PublicAlertsDataGridProps
owner: Parameters<CasesService['helpers']['canUseCases']>[0];
appId?: string;
syncAlerts?: boolean;
extractObservables?: boolean;
};
/**
* If true, hides the bulk actions controls
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13757,7 +13757,6 @@
"xpack.cases.caseView.observables.type": "Beobachtbarer Typ",
"xpack.cases.caseView.observables.updated": "Observable wurde aktualisiert",
"xpack.cases.caseView.observables.value": "Beobachtbarer Wert",
"xpack.cases.caseView.observables.valuePlaceholder": "Beobachtbarer Wert",
"xpack.cases.caseView.openCase": "Fall öffnen",
"xpack.cases.caseView.optional": "Optional",
"xpack.cases.caseView.otherEndpoints": "und {endpoints} {endpoints, plural, =1 {other} other {andere}}",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13795,7 +13795,6 @@
"xpack.cases.caseView.observables.type": "Type d'observable",
"xpack.cases.caseView.observables.updated": "Observable mis à jour",
"xpack.cases.caseView.observables.value": "Valeur d'observable",
"xpack.cases.caseView.observables.valuePlaceholder": "Valeur d'observable",
"xpack.cases.caseView.openCase": "Ouvrir le cas",
"xpack.cases.caseView.optional": "Facultatif",
"xpack.cases.caseView.otherEndpoints": "et {endpoints} {endpoints, plural, =1 {other} other {autres}}",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13813,7 +13813,6 @@
"xpack.cases.caseView.observables.type": "オブザーバブルタイプ",
"xpack.cases.caseView.observables.updated": "オブザーバブルが更新されました",
"xpack.cases.caseView.observables.value": "オブザーバブル値",
"xpack.cases.caseView.observables.valuePlaceholder": "オブザーバブル値",
"xpack.cases.caseView.openCase": "ケースを開く",
"xpack.cases.caseView.optional": "オプション",
"xpack.cases.caseView.otherEndpoints": "および{endpoints} {endpoints, plural, =1 {other} other {件のエンドポイント}}",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13807,7 +13807,6 @@
"xpack.cases.caseView.observables.type": "可观察对象类型",
"xpack.cases.caseView.observables.updated": "可观察对象已更新",
"xpack.cases.caseView.observables.value": "可观察对象值",
"xpack.cases.caseView.observables.valuePlaceholder": "可观察对象值",
"xpack.cases.caseView.openCase": "创建案例",
"xpack.cases.caseView.optional": "可选",
"xpack.cases.caseView.otherEndpoints": "以及其他 {endpoints} 个",
Expand Down
5 changes: 5 additions & 0 deletions x-pack/platform/plugins/shared/cases/common/api/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import {
INTERNAL_CASE_OBSERVABLES_DELETE_URL,
INTERNAL_CASE_SUMMARY_URL,
INTERNAL_INFERENCE_CONNECTORS_URL,
INTERNAL_BULK_CREATE_CASE_OBSERVABLES_URL,
} from '../constants';

export const getCaseDetailsUrl = (id: string): string => {
Expand Down Expand Up @@ -110,6 +111,10 @@ export const getCaseDeleteObservableUrl = (id: string, observableId: string): st
);
};

export const getBulkCreateObservablesUrl = (id: string): string => {
return INTERNAL_BULK_CREATE_CASE_OBSERVABLES_URL.replace('{case_id}', id);
};

export const getCaseSimilarCasesUrl = (caseId: string) => {
return INTERNAL_CASE_SIMILAR_CASES_URL.replace('{case_id}', caseId);
};
Expand Down
58 changes: 3 additions & 55 deletions x-pack/platform/plugins/shared/cases/common/constants/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import type { CasesFeaturesAllRequired } from '../ui/types';
export * from './owners';
export * from './files';
export * from './application';
export * from './observables';
export { LENS_ATTACHMENT_TYPE } from './visualizations';

export const DEFAULT_DATE_FORMAT = 'dateFormat' as const;
Expand Down Expand Up @@ -98,6 +99,7 @@ export const INTERNAL_CASE_SUMMARY_URL = `${CASES_INTERNAL_URL}/{case_id}/summar
export const INTERNAL_INFERENCE_CONNECTORS_URL = '/internal/inference/connectors' as const;
export const INTERNAL_CASE_GET_CASES_BY_ATTACHMENT_URL =
`${CASES_INTERNAL_URL}/case/alerts/_find_containing_all` as const;
export const INTERNAL_BULK_CREATE_CASE_OBSERVABLES_URL = `${CASES_INTERNAL_URL}/{case_id}/observables/_bulk_create`;

/**
* Action routes
Expand Down Expand Up @@ -166,7 +168,7 @@ export const MAX_CUSTOM_OBSERVABLE_TYPES_LABEL_LENGTH = 50 as const;
export const DEFAULT_FEATURES: CasesFeaturesAllRequired = Object.freeze({
alerts: { sync: true, enabled: true, isExperimental: false },
metrics: [],
observables: { enabled: true },
observables: { enabled: true, autoExtract: false },
events: { enabled: true },
});

Expand Down Expand Up @@ -292,60 +294,6 @@ export const MAX_OBSERVABLE_TYPE_LABEL_LENGTH = 50;

export const MAX_CUSTOM_OBSERVABLE_TYPES = 10;

export const OBSERVABLE_TYPE_EMAIL = {
label: 'Email',
key: 'observable-type-email',
} as const;

export const OBSERVABLE_TYPE_DOMAIN = {
label: 'Domain',
key: 'observable-type-domain',
} as const;

export const OBSERVABLE_TYPE_IPV4 = {
label: 'IPv4',
key: 'observable-type-ipv4',
} as const;

export const OBSERVABLE_TYPE_IPV6 = {
label: 'IPv6',
key: 'observable-type-ipv6',
} as const;

export const OBSERVABLE_TYPE_URL = {
label: 'URL',
key: 'observable-type-url',
} as const;

/**
* Exporting an array of built-in observable types for use in the application
*/
export const OBSERVABLE_TYPES_BUILTIN = [
OBSERVABLE_TYPE_IPV4,
OBSERVABLE_TYPE_IPV6,
OBSERVABLE_TYPE_URL,
{
label: 'Hostname',
key: 'observable-type-hostname',
},
{
label: 'File hash',
key: 'observable-type-file-hash',
},
{
label: 'File path',
key: 'observable-type-file-path',
},
{
...OBSERVABLE_TYPE_EMAIL,
},
{
...OBSERVABLE_TYPE_DOMAIN,
},
];

export const OBSERVABLE_TYPES_BUILTIN_KEYS = OBSERVABLE_TYPES_BUILTIN.map(({ key }) => key);

/**
* EBT events
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* 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 OBSERVABLE_TYPE_IPV4 = {
label: 'IPv4',
key: 'observable-type-ipv4',
} as const;

export const OBSERVABLE_TYPE_IPV6 = {
label: 'IPv6',
key: 'observable-type-ipv6',
} as const;

export const OBSERVABLE_TYPE_URL = {
label: 'URL',
key: 'observable-type-url',
} as const;

export const OBSERVABLE_TYPE_HOSTNAME = {
label: 'Host name',
Copy link
Contributor Author

@christineweng christineweng Sep 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated label from Hostname to Host name. this should be fine, right? @lgestc

key: 'observable-type-hostname',
} as const;

export const OBSERVABLE_TYPE_FILE_HASH = {
label: 'File hash',
key: 'observable-type-file-hash',
} as const;

export const OBSERVABLE_TYPE_FILE_PATH = {
label: 'File path',
key: 'observable-type-file-path',
} as const;

export const OBSERVABLE_TYPE_EMAIL = {
label: 'Email',
key: 'observable-type-email',
} as const;

export const OBSERVABLE_TYPE_DOMAIN = {
label: 'Domain',
key: 'observable-type-domain',
} as const;

/**
* Exporting an array of built-in observable types for use in the application
*/
export const OBSERVABLE_TYPES_BUILTIN: { label: string; key: string }[] = [
OBSERVABLE_TYPE_IPV4,
OBSERVABLE_TYPE_IPV6,
OBSERVABLE_TYPE_URL,
OBSERVABLE_TYPE_HOSTNAME,
OBSERVABLE_TYPE_FILE_HASH,
OBSERVABLE_TYPE_FILE_PATH,
OBSERVABLE_TYPE_EMAIL,
OBSERVABLE_TYPE_DOMAIN,
];

export const OBSERVABLE_TYPES_BUILTIN_KEYS = OBSERVABLE_TYPES_BUILTIN.map(({ key }) => key);
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,11 @@ export const UpdateObservableRequestRt = rt.strict({
observable: ObservablePatchRt,
});

export const BulkAddObservablesRequestRt = rt.strict({
caseId: rt.string,
observables: rt.array(ObservablePostRt),
});

export type AddObservableRequest = rt.TypeOf<typeof AddObservableRequestRt>;
export type UpdateObservableRequest = rt.TypeOf<typeof UpdateObservableRequestRt>;
export type BulkAddObservablesRequest = rt.TypeOf<typeof BulkAddObservablesRequestRt>;
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ describe('Create case', () => {
title: 'sample title',
settings: {
syncAlerts: false,
extractObservables: false,
},
owner: 'cases',
},
Expand Down Expand Up @@ -144,6 +145,7 @@ describe('Create case', () => {
title: 'sample title',
settings: {
syncAlerts: false,
extractObservables: false,
},
owner: 'cases',
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { SettingsUserActionPayloadRt, SettingsUserActionRt } from './v1';
describe('Settings', () => {
describe('SettingsUserActionPayloadRt', () => {
const defaultRequest = {
settings: { syncAlerts: true },
settings: { syncAlerts: true, extractObservables: true },
};

it('has expected attributes in request', () => {
Expand All @@ -25,14 +25,14 @@ describe('Settings', () => {

it('removes foo:bar attributes from request', () => {
const query = SettingsUserActionPayloadRt.decode({
settings: { syncAlerts: false },
settings: { syncAlerts: false, extractObservables: false },
foo: 'bar',
});

expect(query).toStrictEqual({
_tag: 'Right',
right: {
settings: { syncAlerts: false },
settings: { syncAlerts: false, extractObservables: false },
},
});
});
Expand All @@ -42,7 +42,7 @@ describe('Settings', () => {
const defaultRequest = {
type: UserActionTypes.settings,
payload: {
settings: { syncAlerts: true },
settings: { syncAlerts: true, extractObservables: true },
},
};

Expand Down
2 changes: 1 addition & 1 deletion x-pack/platform/plugins/shared/cases/common/ui/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ type DeepRequired<T> = { [K in keyof T]: DeepRequired<T[K]> } & Required<T>;
export interface CasesContextFeatures {
alerts: { sync?: boolean; enabled?: boolean; isExperimental?: boolean };
metrics: SingleCaseMetricsFeature[];
observables?: { enabled: boolean };
observables?: { enabled: boolean; autoExtract?: boolean };
events?: { enabled: boolean };
}

Expand Down
Loading