[Defend workflows] Osquery license check + display errors (#156738)

This commit is contained in:
Tomasz Ciecierski 2023-05-08 19:32:43 +02:00 committed by GitHub
parent a61c63dc07
commit 952489fa71
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
25 changed files with 223 additions and 104 deletions

View file

@ -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 { i18n } from '@kbn/i18n';
export const LICENSE_TOO_LOW = i18n.translate(
'xpack.osquery.liveQueryActions.error.licenseTooLow',
{
defaultMessage: 'At least Platinum license is required to use Response Actions.',
}
);
export const PARAMETER_NOT_FOUND = i18n.translate(
'xpack.osquery.liveQueryActions.error.notFoundParameters',
{
defaultMessage:
"This query hasn't been called due to parameter used and its value not found in the alert.",
}
);

View file

@ -59,12 +59,7 @@ const ActionResultsSummaryComponent: React.FC<ActionResultsSummaryProps> = ({
if (error) {
edges.forEach((edge) => {
if (edge.fields) {
edge.fields['error.skipped'] = edge.fields.error = [
i18n.translate('xpack.osquery.liveQueryActionResults.table.skippedErrorText', {
defaultMessage:
"This query hasn't been called due to parameter used and its value not found in the alert.",
}),
];
edge.fields['error.skipped'] = edge.fields.error = [error];
}
});
} else if (expired) {

View file

@ -31,6 +31,7 @@ interface CreateActionHandlerOptions {
soClient?: SavedObjectsClientContract;
metadata?: Metadata;
alertData?: ParsedTechnicalFields;
error?: string;
}
export const createActionHandler = async (
@ -43,7 +44,7 @@ export const createActionHandler = async (
const internalSavedObjectsClient = await getInternalSavedObjectsClient(
osqueryContext.getStartServices
);
const { soClient, metadata, alertData } = options;
const { soClient, metadata, alertData, error } = options;
const savedObjectsClient = soClient ?? coreStartServices.savedObjects.createInternalRepository();
// eslint-disable-next-line @typescript-eslint/naming-convention
@ -98,6 +99,7 @@ export const createActionHandler = async (
action_id: uuidv4(),
id: packQueryId,
...replacedQuery,
...(error ? { error } : {}),
ecs_mapping: packQuery.ecs_mapping,
version: packQuery.version,
platform: packQuery.platform,
@ -106,22 +108,31 @@ export const createActionHandler = async (
(value) => !isEmpty(value)
);
})
: await createDynamicQueries({ params, alertData, agents: selectedAgents, osqueryContext }),
: await createDynamicQueries({
params,
alertData,
agents: selectedAgents,
osqueryContext,
error,
}),
};
const fleetActions = map(
filter(osqueryAction.queries, (query) => !query.error),
(query) => ({
action_id: query.action_id,
'@timestamp': moment().toISOString(),
expiration: moment().add(5, 'minutes').toISOString(),
type: 'INPUT_ACTION',
input_type: 'osquery',
agents: query.agents,
user_id: metadata?.currentUser,
data: pick(query, ['id', 'query', 'ecs_mapping', 'version', 'platform']),
})
);
const fleetActions = !error
? map(
filter(osqueryAction.queries, (query) => !query.error),
(query) => ({
action_id: query.action_id,
'@timestamp': moment().toISOString(),
expiration: moment().add(5, 'minutes').toISOString(),
type: 'INPUT_ACTION',
input_type: 'osquery',
agents: query.agents,
user_id: metadata?.currentUser,
data: pick(query, ['id', 'query', 'ecs_mapping', 'version', 'platform']),
})
)
: [];
if (fleetActions.length) {
await esClientInternal.bulk({
refresh: 'wait_for',
@ -129,24 +140,24 @@ export const createActionHandler = async (
fleetActions.map((action) => [{ index: { _index: AGENT_ACTIONS_INDEX } }, action])
),
});
}
const actionsComponentTemplateExists = await esClientInternal.indices.exists({
index: `${ACTIONS_INDEX}*`,
});
const actionsComponentTemplateExists = await esClientInternal.indices.exists({
index: `${ACTIONS_INDEX}*`,
});
if (actionsComponentTemplateExists) {
await esClientInternal.bulk({
refresh: 'wait_for',
body: [{ index: { _index: `${ACTIONS_INDEX}-default` } }, osqueryAction],
});
}
osqueryContext.telemetryEventsSender.reportEvent(TELEMETRY_EBT_LIVE_QUERY_EVENT, {
...omit(osqueryAction, ['type', 'input_type', 'user_id']),
agents: osqueryAction.agents.length,
if (actionsComponentTemplateExists) {
await esClientInternal.bulk({
refresh: 'wait_for',
body: [{ index: { _index: `${ACTIONS_INDEX}-default` } }, osqueryAction],
});
}
osqueryContext.telemetryEventsSender.reportEvent(TELEMETRY_EBT_LIVE_QUERY_EVENT, {
...omit(osqueryAction, ['type', 'input_type', 'user_id', 'error']),
agents: osqueryAction.agents.length,
});
return {
response: osqueryAction,
fleetActionsCount: fleetActions.length,

View file

@ -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 type { ParsedTechnicalFields } from '@kbn/rule-registry-plugin/common';
import type { Subscription } from 'rxjs';
import type { OsqueryAppContext } from '../../lib/osquery_app_context_services';
import type { CreateLiveQueryRequestBodySchema } from '../../../common/schemas/routes/live_query';
import type { OsqueryActiveLicenses } from './validate_license';
import { validateLicense } from './validate_license';
import { createActionHandler } from './create_action_handler';
export const createActionService = (osqueryContext: OsqueryAppContext) => {
let licenseSubscription: Subscription | null = null;
const licenses: OsqueryActiveLicenses = { isActivePlatinumLicense: false };
licenseSubscription = osqueryContext.licensing.license$.subscribe((license) => {
licenses.isActivePlatinumLicense = license.isActive && license.hasAtLeast('platinum');
});
const create = async (
params: CreateLiveQueryRequestBodySchema,
alertData?: ParsedTechnicalFields
) => {
const error = validateLicense(licenses);
return createActionHandler(osqueryContext, params, { alertData, error });
};
const stop = () => {
if (licenseSubscription) {
licenseSubscription.unsubscribe();
}
};
return {
create,
stop,
};
};

View file

@ -5,9 +5,10 @@
* 2.0.
*/
import { createDynamicQueries, PARAMETER_NOT_FOUND } from './create_queries';
import { createDynamicQueries } from './create_queries';
import type { ParsedTechnicalFields } from '@kbn/rule-registry-plugin/common';
import type { OsqueryAppContext } from '../../lib/osquery_app_context_services';
import { PARAMETER_NOT_FOUND } from '../../../common/translations/errors';
describe('create queries', () => {
const defualtQueryParams = {
@ -65,9 +66,7 @@ describe('create queries', () => {
expect(queries[0].query).toBe(`SELECT * FROM processes where pid=${pid};`);
expect(queries[0].error).toBe(undefined);
expect(queries[1].query).toBe('SELECT * FROM processes where pid={{process.not-existing}};');
expect(queries[1].error).toBe(
"This query hasn't been called due to parameter used and its value not found in the alert."
);
expect(queries[1].error).toBe(PARAMETER_NOT_FOUND);
expect(queries[2].query).toBe('SELECT * FROM processes;');
expect(queries[2].error).toBe(undefined);
});

View file

@ -7,33 +7,28 @@
import { isEmpty, map, pickBy } from 'lodash';
import { v4 as uuidv4 } from 'uuid';
import { i18n } from '@kbn/i18n';
import type { ParsedTechnicalFields } from '@kbn/rule-registry-plugin/common';
import { PARAMETER_NOT_FOUND } from '../../../common/translations/errors';
import type { OsqueryAppContext } from '../../lib/osquery_app_context_services';
import type { CreateLiveQueryRequestBodySchema } from '../../../common/schemas/routes/live_query';
import { replaceParamsQuery } from '../../../common/utils/replace_params_query';
import { isSavedQueryPrebuilt } from '../../routes/saved_query/utils';
export const PARAMETER_NOT_FOUND = i18n.translate(
'xpack.osquery.liveQueryActions.error.notFoundParameters',
{
defaultMessage:
"This query hasn't been called due to parameter used and its value not found in the alert.",
}
);
interface CreateDynamicQueriesParams {
params: CreateLiveQueryRequestBodySchema;
alertData?: ParsedTechnicalFields;
agents: string[];
osqueryContext: OsqueryAppContext;
error?: string;
}
export const createDynamicQueries = async ({
params,
alertData,
agents,
osqueryContext,
error,
}: CreateDynamicQueriesParams) =>
params.queries?.length
? map(params.queries, ({ query, ...restQuery }) => {
@ -43,6 +38,7 @@ export const createDynamicQueries = async ({
{
...replacedQuery,
...restQuery,
...(error ? { error } : {}),
action_id: uuidv4(),
alert_ids: params.alert_ids,
agents,
@ -66,6 +62,7 @@ export const createDynamicQueries = async ({
ecs_mapping: params.ecs_mapping,
alert_ids: params.alert_ids,
agents,
...(error ? { error } : {}),
},
(value) => !isEmpty(value)
),

View file

@ -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 { LICENSE_TOO_LOW } from '../../../common/translations/errors';
export interface OsqueryActiveLicenses {
isActivePlatinumLicense: boolean;
}
export const validateLicense = (license?: OsqueryActiveLicenses) => {
if (!license) {
return;
}
const { isActivePlatinumLicense } = license;
if (!isActivePlatinumLicense) {
return LICENSE_TOO_LOW;
}
};

View file

@ -15,6 +15,7 @@ import type {
PackagePolicyClient,
} from '@kbn/fleet-plugin/server';
import type { RuleRegistryPluginStartContract } from '@kbn/rule-registry-plugin/server';
import type { LicensingPluginSetup } from '@kbn/licensing-plugin/server';
import type { ConfigType } from '../../common/config';
import type { TelemetryEventsSender } from './telemetry/sender';
@ -82,6 +83,7 @@ export interface OsqueryAppContext {
security: SecurityPluginStart;
getStartServices: CoreSetup['getStartServices'];
telemetryEventsSender: TelemetryEventsSender;
licensing: LicensingPluginSetup;
/**
* Object readiness is tied to plugin start method
*/

View file

@ -17,12 +17,11 @@ import type { DataRequestHandlerContext } from '@kbn/data-plugin/server';
import type { DataViewsService } from '@kbn/data-views-plugin/common';
import type { NewPackagePolicy, UpdatePackagePolicy } from '@kbn/fleet-plugin/common';
import type { ParsedTechnicalFields } from '@kbn/rule-registry-plugin/common';
import type { Subscription } from 'rxjs';
import { upgradeIntegration } from './utils/upgrade_integration';
import type { PackSavedObjectAttributes } from './common/types';
import { updateGlobalPacksCreateCallback } from './lib/update_global_packs';
import { packSavedObjectType } from '../common/types';
import type { CreateLiveQueryRequestBodySchema } from '../common/schemas/routes/live_query';
import { createConfig } from './create_config';
import type { OsqueryPluginSetup, OsqueryPluginStart, SetupPlugins, StartPlugins } from './types';
import { defineRoutes } from './routes';
@ -39,10 +38,10 @@ import { TelemetryReceiver } from './lib/telemetry/receiver';
import { initializeTransformsIndices } from './create_indices/create_transforms_indices';
import { initializeTransforms } from './create_transforms/create_transforms';
import { createDataViews } from './create_data_views';
import { createActionHandler } from './handlers/action';
import { registerFeatures } from './utils/register_features';
import { CASE_ATTACHMENT_TYPE_ID } from '../common/constants';
import { createActionService } from './handlers/action/create_action_service';
export class OsqueryPlugin implements Plugin<OsqueryPluginSetup, OsqueryPluginStart> {
private readonly logger: Logger;
@ -50,6 +49,8 @@ export class OsqueryPlugin implements Plugin<OsqueryPluginSetup, OsqueryPluginSt
private readonly osqueryAppContextService = new OsqueryAppContextService();
private readonly telemetryReceiver: TelemetryReceiver;
private readonly telemetryEventsSender: TelemetryEventsSender;
private licenseSubscription: Subscription | null = null;
private createActionService: ReturnType<typeof createActionService> | null = null;
constructor(private readonly initializerContext: PluginInitializerContext) {
this.context = initializerContext;
@ -73,6 +74,7 @@ export class OsqueryPlugin implements Plugin<OsqueryPluginSetup, OsqueryPluginSt
config: (): ConfigType => config,
security: plugins.security,
telemetryEventsSender: this.telemetryEventsSender,
licensing: plugins.licensing,
};
initSavedObjects(core.savedObjects);
@ -82,6 +84,8 @@ export class OsqueryPlugin implements Plugin<OsqueryPluginSetup, OsqueryPluginSt
usageCollection: plugins.usageCollection,
});
this.createActionService = createActionService(osqueryContext);
core.getStartServices().then(([{ elasticsearch }, depsStart]) => {
const osquerySearchStrategy = osquerySearchStrategyProvider(
depsStart.data,
@ -97,10 +101,7 @@ export class OsqueryPlugin implements Plugin<OsqueryPluginSetup, OsqueryPluginSt
plugins.cases.attachmentFramework.registerExternalReference({ id: CASE_ATTACHMENT_TYPE_ID });
return {
osqueryCreateAction: (
params: CreateLiveQueryRequestBodySchema,
alertData?: ParsedTechnicalFields
) => createActionHandler(osqueryContext, params, { alertData }),
createActionService: this.createActionService,
};
}
@ -180,6 +181,8 @@ export class OsqueryPlugin implements Plugin<OsqueryPluginSetup, OsqueryPluginSt
this.logger.debug('osquery: Stopped');
this.telemetryEventsSender.stop();
this.osqueryAppContextService.stop();
this.licenseSubscription?.unsubscribe();
this.createActionService?.stop();
}
async initialize(core: CoreStart, dataViewsService: DataViewsService): Promise<void> {

View file

@ -11,7 +11,7 @@ import markdown from 'remark-parse-no-trim';
import { some, filter } from 'lodash';
import deepEqual from 'fast-deep-equal';
import type { ECSMappingOrUndefined } from '@kbn/osquery-io-ts-types';
import { PARAMETER_NOT_FOUND } from '../../handlers/action/create_queries';
import { PARAMETER_NOT_FOUND } from '../../../common/translations/errors';
import { replaceParamsQuery } from '../../../common/utils/replace_params_query';
import { createLiveQueryRequestBodySchema } from '../../../common/schemas/routes/live_query';
import type { CreateLiveQueryRequestBodySchema } from '../../../common/schemas/routes/live_query';

View file

@ -22,15 +22,12 @@ import type {
} from '@kbn/task-manager-plugin/server';
import type { PluginStart as DataViewsPluginStart } from '@kbn/data-views-plugin/server';
import type { RuleRegistryPluginStartContract } from '@kbn/rule-registry-plugin/server';
import type { ParsedTechnicalFields } from '@kbn/rule-registry-plugin/common';
import type { CasesSetup } from '@kbn/cases-plugin/server';
import type { CreateLiveQueryRequestBodySchema } from '../common/schemas/routes/live_query';
import type { LicensingPluginSetup } from '@kbn/licensing-plugin/server';
import type { createActionService } from './handlers/action/create_action_service';
export interface OsqueryPluginSetup {
osqueryCreateAction: (
payload: CreateLiveQueryRequestBodySchema,
alertData?: ParsedTechnicalFields
) => void;
createActionService: ReturnType<typeof createActionService>;
}
// eslint-disable-next-line @typescript-eslint/no-empty-interface
@ -45,6 +42,7 @@ export interface SetupPlugins {
security: SecurityPluginStart;
taskManager?: TaskManagerPluginSetup;
telemetry?: TelemetryPluginSetup;
licensing: LicensingPluginSetup;
}
export interface StartPlugins {

View file

@ -71,6 +71,7 @@
"@kbn/safer-lodash-set",
"@kbn/shared-ux-router",
"@kbn/securitysolution-ecs",
"@kbn/licensing-plugin",
"@kbn/core-saved-objects-server"
]
}

View file

@ -73,7 +73,7 @@ export const UNISOLATE_HOST_ROUTE = `${BASE_ENDPOINT_ROUTE}/unisolate`;
/** Base Actions route. Used to get a list of all actions and is root to other action related routes */
export const BASE_ENDPOINT_ACTION_ROUTE = `${BASE_ENDPOINT_ROUTE}/action`;
export const BASE_ENDPOINT_ACTION_ALERTS_ROUTE = `${BASE_ENDPOINT_ROUTE}/alerts`;
export const BASE_ENDPOINT_ACTION_ALERTS_ROUTE = `${BASE_ENDPOINT_ACTION_ROUTE}/alerts`;
export const ISOLATE_HOST_ROUTE_V2 = `${BASE_ENDPOINT_ACTION_ROUTE}/isolate`;
export const UNISOLATE_HOST_ROUTE_V2 = `${BASE_ENDPOINT_ACTION_ROUTE}/unisolate`;

View file

@ -49,7 +49,17 @@ export const fillUpNewRule = (name = 'Test', description = 'Test') => {
};
export const visitRuleActions = (ruleId: string) => {
cy.visit(`app/security/rules/id/${ruleId}/edit`);
cy.getByTestSubj('edit-rule-actions-tab').wait(500).click();
cy.getByTestSubj('edit-rule-actions-tab').should('exist');
// strange rerendering behaviour. the following make sure the test doesn't fail
cy.get('body').then(($body) => {
if ($body.find('[data-test-subj="globalLoadingIndicator"]').length) {
cy.getByTestSubj('globalLoadingIndicator').should('exist');
cy.getByTestSubj('globalLoadingIndicator').should('not.exist');
}
cy.getByTestSubj('globalLoadingIndicator').should('not.exist');
});
cy.getByTestSubj('edit-rule-actions-tab').click();
};
export const tryAddingDisabledResponseAction = (itemNumber = 0) => {
cy.getByTestSubj('response-actions-wrapper').within(() => {

View file

@ -37,6 +37,7 @@ import type { EndpointAuthz } from '../../common/endpoint/types/authz';
import { calculateEndpointAuthz } from '../../common/endpoint/service/authz';
import type { FeatureUsageService } from './services/feature_usage/service';
import type { ExperimentalFeatures } from '../../common/experimental_features';
import type { ActionCreateService } from './services';
import { doesArtifactHaveData } from './services';
import type { actionCreateService } from './services/actions';
@ -237,7 +238,7 @@ export class EndpointAppContextService {
return this.startDependencies.messageSigningService;
}
public getActionCreateService(): ReturnType<typeof actionCreateService> {
public getActionCreateService(): ActionCreateService {
if (!this.startDependencies?.actionCreateService) {
throw new EndpointAppContentServicesNotStartedError();
}

View file

@ -41,17 +41,20 @@ export function registerActionListRoutes(
actionListHandler(endpointContext)
)
);
// TODO: This route is a temporary solution until we decide on how RBAC should look like for Actions in Alerts
router.get(
{
path: BASE_ENDPOINT_ACTION_ALERTS_ROUTE,
validate: EndpointActionListRequestSchema,
options: { authRequired: true, tags: ['access:securitySolution'] },
},
withEndpointAuthz(
{},
endpointContext.logFactory.get('endpointActionList'),
actionListHandler(endpointContext)
)
);
if (endpointContext.experimentalFeatures.endpointResponseActionsEnabled) {
router.get(
{
path: BASE_ENDPOINT_ACTION_ALERTS_ROUTE,
validate: EndpointActionListRequestSchema,
options: { authRequired: true, tags: ['access:securitySolution'] },
},
withEndpointAuthz(
{},
endpointContext.logFactory.get('endpointActionList'),
actionListHandler(endpointContext)
)
);
}
}

View file

@ -132,11 +132,7 @@ describe('Response actions', () => {
endpointAppContextService.setup(createMockEndpointAppContextServiceSetupContract());
endpointAppContextService.start({
...startContract,
actionCreateService: actionCreateService(
mockScopedClient.asInternalUser,
endpointContext,
licenseService
),
actionCreateService: actionCreateService(mockScopedClient.asInternalUser, endpointContext),
licenseService,
});

View file

@ -68,12 +68,19 @@ interface CreateActionMetadata {
enableActionsWithErrors?: boolean;
}
export interface ActionCreateService {
createActionFromAlert: (payload: CreateActionPayload) => Promise<ActionDetails>;
createAction: (
payload: CreateActionPayload,
metadata: CreateActionMetadata
) => Promise<ActionDetails>;
}
export const actionCreateService = (
esClient: ElasticsearchClient,
endpointContext: EndpointAppContext,
licenseService: LicenseService
) => {
const createActionFromAlert = async (payload: CreateActionPayload) => {
endpointContext: EndpointAppContext
): ActionCreateService => {
const createActionFromAlert = async (payload: CreateActionPayload): Promise<ActionDetails> => {
return createAction({ ...payload }, { minimumLicenseRequired: 'enterprise' });
};
@ -86,6 +93,8 @@ export const actionCreateService = (
endpointContext.service.getFeatureUsageService().notifyUsage(featureKey);
}
const licenseService = endpointContext.service.getLicenseService();
const logger = endpointContext.logFactory.get('hostIsolation');
// fetch the Agent IDs to send the commands to
@ -341,11 +350,12 @@ interface CheckForAlertsArgs {
licenseService: LicenseService;
minimumLicenseRequired: LicenseType;
}
const checkForAlertErrors = ({
agents,
licenseService,
minimumLicenseRequired = 'basic',
}: CheckForAlertsArgs) => {
}: CheckForAlertsArgs): string | undefined => {
const licenseError = validateEndpointLicense(licenseService, minimumLicenseRequired);
const agentsError = validateAgents(agents);

View file

@ -13,7 +13,7 @@ import type { AlertsWithAgentType } from './types';
export const osqueryResponseAction = (
responseAction: RuleResponseOsqueryAction,
osqueryCreateAction: SetupPlugins['osquery']['osqueryCreateAction'],
osqueryCreateActionService: SetupPlugins['osquery']['createActionService'],
{ alerts, alertIds, agentIds }: AlertsWithAgentType
) => {
const temporaryQueries = responseAction.params.queries?.length
@ -27,7 +27,7 @@ export const osqueryResponseAction = (
const { savedQueryId, packId, queries, ecsMapping, ...rest } = responseAction.params;
if (!containsDynamicQueries) {
return osqueryCreateAction({
return osqueryCreateActionService.create({
...rest,
queries,
ecs_mapping: ecsMapping,
@ -37,7 +37,7 @@ export const osqueryResponseAction = (
});
}
each(alerts, (alert) => {
return osqueryCreateAction(
return osqueryCreateActionService.create(
{
...rest,
queries,

View file

@ -53,11 +53,14 @@ describe('ScheduleNotificationResponseActions', () => {
saved_query_id: undefined,
ecs_mapping: { testField: { field: 'testField', value: 'testValue' } },
};
const osqueryActionMock = jest.fn();
const osqueryActionMock = {
create: jest.fn(),
stop: jest.fn(),
};
const endpointActionMock = jest.fn();
const scheduleNotificationResponseActions = getScheduleNotificationResponseActionsService({
osqueryCreateAction: osqueryActionMock,
osqueryCreateActionService: osqueryActionMock,
endpointAppContextService: endpointActionMock as never,
});
@ -74,7 +77,7 @@ describe('ScheduleNotificationResponseActions', () => {
];
scheduleNotificationResponseActions({ signals, responseActions });
expect(osqueryActionMock).toHaveBeenCalledWith({
expect(osqueryActionMock.create).toHaveBeenCalledWith({
...defaultQueryResultParams,
query: simpleQuery,
});
@ -99,7 +102,7 @@ describe('ScheduleNotificationResponseActions', () => {
];
scheduleNotificationResponseActions({ signals, responseActions });
expect(osqueryActionMock).toHaveBeenCalledWith({
expect(osqueryActionMock.create).toHaveBeenCalledWith({
...defaultPackResultParams,
queries: [{ ...defaultQueries, id: 'query-1', query: simpleQuery }],
});

View file

@ -20,12 +20,12 @@ type Alerts = Array<ParsedTechnicalFields & { agent?: { id: string } }>;
interface ScheduleNotificationResponseActionsService {
endpointAppContextService: EndpointAppContextService;
osqueryCreateAction: SetupPlugins['osquery']['osqueryCreateAction'];
osqueryCreateActionService?: SetupPlugins['osquery']['createActionService'];
}
export const getScheduleNotificationResponseActionsService =
({
osqueryCreateAction,
osqueryCreateActionService,
endpointAppContextService,
}: ScheduleNotificationResponseActionsService) =>
({ signals, responseActions }: ScheduleNotificationActions) => {
@ -48,8 +48,11 @@ export const getScheduleNotificationResponseActionsService =
);
each(responseActions, (responseAction) => {
if (responseAction.actionTypeId === RESPONSE_ACTION_TYPES.OSQUERY && osqueryCreateAction) {
osqueryResponseAction(responseAction, osqueryCreateAction, {
if (
responseAction.actionTypeId === RESPONSE_ACTION_TYPES.OSQUERY &&
osqueryCreateActionService
) {
osqueryResponseAction(responseAction, osqueryCreateActionService, {
alerts,
alertIds,
agentIds,

View file

@ -57,7 +57,7 @@ import { registerEndpointRoutes } from './endpoint/routes/metadata';
import { registerPolicyRoutes } from './endpoint/routes/policy';
import { registerActionRoutes } from './endpoint/routes/actions';
import { registerEndpointSuggestionsRoutes } from './endpoint/routes/suggestions';
import { actionCreateService, EndpointArtifactClient, ManifestManager } from './endpoint/services';
import { EndpointArtifactClient, ManifestManager } from './endpoint/services';
import { EndpointAppContextService } from './endpoint/endpoint_app_context_services';
import type { EndpointAppContext } from './endpoint/types';
import { initUsageCollectors } from './usage';
@ -101,6 +101,7 @@ import type {
} from './plugin_contract';
import { EndpointFleetServicesFactory } from './endpoint/services/fleet';
import { featureUsageService } from './endpoint/services/feature_usage';
import { actionCreateService } from './endpoint/services/actions';
import { setIsElasticCloudDeployment } from './lib/telemetry/helpers';
import { artifactService } from './lib/telemetry/artifact';
import { endpointFieldsProvider } from './search_strategy/endpoint_fields';
@ -246,7 +247,7 @@ export class Plugin implements ISecuritySolutionPlugin {
const queryRuleAdditionalOptions: CreateQueryRuleAdditionalOptions = {
scheduleNotificationResponseActionsService: getScheduleNotificationResponseActionsService({
endpointAppContextService: this.endpointAppContextService,
osqueryCreateAction: plugins.osquery.osqueryCreateAction,
osqueryCreateActionService: plugins.osquery.createActionService,
}),
};
@ -505,8 +506,7 @@ export class Plugin implements ISecuritySolutionPlugin {
messageSigningService: plugins.fleet?.messageSigningService,
actionCreateService: actionCreateService(
core.elasticsearch.client.asInternalUser,
this.endpointContext,
licenseService
this.endpointContext
),
});

View file

@ -25807,7 +25807,6 @@
"xpack.osquery.liveQueryActionResults.table.expiredStatusText": "expiré",
"xpack.osquery.liveQueryActionResults.table.pendingStatusText": "en attente",
"xpack.osquery.liveQueryActionResults.table.resultRowsNumberColumnTitle": "Nombre de lignes de résultats",
"xpack.osquery.liveQueryActionResults.table.skippedErrorText": "Cette requête n'a pas été appelée en raison du paramètre utilisé et de sa valeur non trouvée dans l'alerte.",
"xpack.osquery.liveQueryActionResults.table.skippedStatusText": "ignoré",
"xpack.osquery.liveQueryActionResults.table.statusColumnTitle": "Statut",
"xpack.osquery.liveQueryActionResults.table.successStatusText": "réussite",

View file

@ -25788,7 +25788,6 @@
"xpack.osquery.liveQueryActionResults.table.expiredStatusText": "期限切れ",
"xpack.osquery.liveQueryActionResults.table.pendingStatusText": "保留中",
"xpack.osquery.liveQueryActionResults.table.resultRowsNumberColumnTitle": "結果行数",
"xpack.osquery.liveQueryActionResults.table.skippedErrorText": "このクエリは、使用されているパラメーターとその値がアラートで見つからないため、呼び出されていません。",
"xpack.osquery.liveQueryActionResults.table.skippedStatusText": "スキップ済み",
"xpack.osquery.liveQueryActionResults.table.statusColumnTitle": "ステータス",
"xpack.osquery.liveQueryActionResults.table.successStatusText": "成功",

View file

@ -25805,7 +25805,6 @@
"xpack.osquery.liveQueryActionResults.table.expiredStatusText": "已过期",
"xpack.osquery.liveQueryActionResults.table.pendingStatusText": "待处理",
"xpack.osquery.liveQueryActionResults.table.resultRowsNumberColumnTitle": "结果行数",
"xpack.osquery.liveQueryActionResults.table.skippedErrorText": "尚未调用此查询,因为在告警中找不到所使用的参数及其值。",
"xpack.osquery.liveQueryActionResults.table.skippedStatusText": "已跳过",
"xpack.osquery.liveQueryActionResults.table.statusColumnTitle": "状态",
"xpack.osquery.liveQueryActionResults.table.successStatusText": "成功",