mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
[8.x] [Defend Workflows][Staged Artifact Rollout] Propagate global telemetry config to endpoint policies (#207106) (#208095)
# Backport This will backport the following commits from `main` to `8.x`: - [[Defend Workflows][Staged Artifact Rollout] Propagate global telemetry config to endpoint policies (#207106)](https://github.com/elastic/kibana/pull/207106) <!--- Backport version: 9.6.4 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sorenlouv/backport) <!--BACKPORT [{"author":{"name":"Gergő Ábrahám","email":"gergo.abraham@elastic.co"},"sourceCommit":{"committedDate":"2025-01-23T15:26:18Z","message":"[Defend Workflows][Staged Artifact Rollout] Propagate global telemetry config to endpoint policies (#207106)\n\n## Summary\r\n\r\n\r\nThe goal to propagate `isOptedIn` from the Telemetry plugin to Endpoint\r\npolicies as a field named `global_telemetry_config`.\r\n\r\nFor this:\r\n- telemetry plugin is marked as required for security solution\r\n- a new `TelemetryConfigProvider` subscribes to the Observable, and\r\npersists the pushed value to functions that need it\r\n(note: here we could have used the already public `getIsOptedIn()`, but\r\nthat's now deprecated, and we need the Observable for watching changes\r\nanyway)\r\n- the config value is added to newly created policies\r\n- a new `TelemetryConfigWatcher` is subscribed to the `isOptedIn# Backport This will backport the following commits from `main` to `8.x`: - [[Defend Workflows][Staged Artifact Rollout] Propagate global telemetry config to endpoint policies (#207106)](https://github.com/elastic/kibana/pull/207106) <!--- Backport version: 9.6.4 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sorenlouv/backport) <!--BACKPORT \r\nobservable, and updates package policies accordingly\r\n- as this is performed on Kibana startup, it acts as a backfill\r\nfunctionality as well, no need for adding a backfill/migration ✅\r\n\r\n### Checklist\r\n\r\nCheck the PR satisfies following conditions. \r\n\r\nReviewers should verify this PR satisfies this list as well.\r\n\r\n- [x] [Unit or functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere updated or added to match the most common scenarios\r\n\r\n---------\r\n\r\nCo-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>","sha":"c579b8e4412b85ebae31f9d6bb1d4e677455fd2f","branchLabelMapping":{"^v9.0.0$":"main","^v8.18.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","v9.0.0","Team:Defend Workflows","backport:prev-minor"],"title":"[Defend Workflows][Staged Artifact Rollout] Propagate global telemetry config to endpoint policies","number":207106,"url":"https://github.com/elastic/kibana/pull/207106","mergeCommit":{"message":"[Defend Workflows][Staged Artifact Rollout] Propagate global telemetry config to endpoint policies (#207106)\n\n## Summary\r\n\r\n\r\nThe goal to propagate `isOptedIn` from the Telemetry plugin to Endpoint\r\npolicies as a field named `global_telemetry_config`.\r\n\r\nFor this:\r\n- telemetry plugin is marked as required for security solution\r\n- a new `TelemetryConfigProvider` subscribes to the Observable, and\r\npersists the pushed value to functions that need it\r\n(note: here we could have used the already public `getIsOptedIn()`, but\r\nthat's now deprecated, and we need the Observable for watching changes\r\nanyway)\r\n- the config value is added to newly created policies\r\n- a new `TelemetryConfigWatcher` is subscribed to the `isOptedIn# Backport This will backport the following commits from `main` to `8.x`: - [[Defend Workflows][Staged Artifact Rollout] Propagate global telemetry config to endpoint policies (#207106)](https://github.com/elastic/kibana/pull/207106) <!--- Backport version: 9.6.4 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sorenlouv/backport) <!--BACKPORT \r\nobservable, and updates package policies accordingly\r\n- as this is performed on Kibana startup, it acts as a backfill\r\nfunctionality as well, no need for adding a backfill/migration ✅\r\n\r\n### Checklist\r\n\r\nCheck the PR satisfies following conditions. \r\n\r\nReviewers should verify this PR satisfies this list as well.\r\n\r\n- [x] [Unit or functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere updated or added to match the most common scenarios\r\n\r\n---------\r\n\r\nCo-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>","sha":"c579b8e4412b85ebae31f9d6bb1d4e677455fd2f"}},"sourceBranch":"main","suggestedTargetBranches":[],"targetPullRequestStates":[{"branch":"main","label":"v9.0.0","branchLabelMappingKey":"^v9.0.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/207106","number":207106,"mergeCommit":{"message":"[Defend Workflows][Staged Artifact Rollout] Propagate global telemetry config to endpoint policies (#207106)\n\n## Summary\r\n\r\n\r\nThe goal to propagate `isOptedIn` from the Telemetry plugin to Endpoint\r\npolicies as a field named `global_telemetry_config`.\r\n\r\nFor this:\r\n- telemetry plugin is marked as required for security solution\r\n- a new `TelemetryConfigProvider` subscribes to the Observable, and\r\npersists the pushed value to functions that need it\r\n(note: here we could have used the already public `getIsOptedIn()`, but\r\nthat's now deprecated, and we need the Observable for watching changes\r\nanyway)\r\n- the config value is added to newly created policies\r\n- a new `TelemetryConfigWatcher` is subscribed to the `isOptedIn# Backport This will backport the following commits from `main` to `8.x`: - [[Defend Workflows][Staged Artifact Rollout] Propagate global telemetry config to endpoint policies (#207106)](https://github.com/elastic/kibana/pull/207106) <!--- Backport version: 9.6.4 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sorenlouv/backport) <!--BACKPORT \r\nobservable, and updates package policies accordingly\r\n- as this is performed on Kibana startup, it acts as a backfill\r\nfunctionality as well, no need for adding a backfill/migration ✅\r\n\r\n### Checklist\r\n\r\nCheck the PR satisfies following conditions. \r\n\r\nReviewers should verify this PR satisfies this list as well.\r\n\r\n- [x] [Unit or functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere updated or added to match the most common scenarios\r\n\r\n---------\r\n\r\nCo-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>","sha":"c579b8e4412b85ebae31f9d6bb1d4e677455fd2f"}}]}] BACKPORT-->
This commit is contained in:
parent
7dba4975fe
commit
8a5f3ecede
20 changed files with 512 additions and 55 deletions
|
@ -13,24 +13,26 @@ import { isBillablePolicy } from './policy_config_helpers';
|
|||
/**
|
||||
* Return a new default `PolicyConfig` for platinum and above licenses
|
||||
*/
|
||||
export const policyFactory = (
|
||||
export const policyFactory = ({
|
||||
license = '',
|
||||
cloud = false,
|
||||
licenseUid = '',
|
||||
licenseUuid = '',
|
||||
clusterUuid = '',
|
||||
clusterName = '',
|
||||
serverless = false
|
||||
): PolicyConfig => {
|
||||
serverless = false,
|
||||
isGlobalTelemetryEnabled = false,
|
||||
} = {}): PolicyConfig => {
|
||||
const policy: PolicyConfig = {
|
||||
meta: {
|
||||
license,
|
||||
license_uuid: licenseUid,
|
||||
license_uuid: licenseUuid,
|
||||
cluster_uuid: clusterUuid,
|
||||
cluster_name: clusterName,
|
||||
cloud,
|
||||
serverless,
|
||||
},
|
||||
global_manifest_version: 'latest',
|
||||
global_telemetry_enabled: isGlobalTelemetryEnabled,
|
||||
windows: {
|
||||
events: {
|
||||
credential_access: true,
|
||||
|
|
|
@ -333,6 +333,7 @@ describe('Policy Config helpers', () => {
|
|||
// the logic for disabling protections is also modified due to type check.
|
||||
export const eventsOnlyPolicy = (): PolicyConfig => ({
|
||||
global_manifest_version: 'latest',
|
||||
global_telemetry_enabled: false,
|
||||
meta: {
|
||||
license: '',
|
||||
cloud: false,
|
||||
|
|
|
@ -973,6 +973,7 @@ export interface PolicyConfig {
|
|||
heartbeatinterval?: number;
|
||||
};
|
||||
global_manifest_version: 'latest' | string;
|
||||
global_telemetry_enabled: boolean;
|
||||
windows: {
|
||||
advanced?: {
|
||||
[key: string]: unknown;
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
* 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 { TelemetryConfigProvider } from './telemetry_config_provider';
|
||||
|
||||
export const createTelemetryConfigProviderMock = (): jest.Mocked<TelemetryConfigProvider> => ({
|
||||
start: jest.fn(),
|
||||
stop: jest.fn(),
|
||||
getObservable: jest.fn(),
|
||||
getIsOptedIn: jest.fn().mockReturnValue(true),
|
||||
});
|
|
@ -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 { Observable } from 'rxjs';
|
||||
import { TelemetryConfigProvider } from './telemetry_config_provider';
|
||||
|
||||
describe('TelemetryConfigProvider', () => {
|
||||
let telemetryConfigProvider: TelemetryConfigProvider;
|
||||
|
||||
beforeEach(() => {
|
||||
telemetryConfigProvider = new TelemetryConfigProvider();
|
||||
});
|
||||
|
||||
describe('getIsOptedIn()', () => {
|
||||
it('returns undefined when object is uninitialized', () => {
|
||||
expect(telemetryConfigProvider.getIsOptedIn()).toBe(undefined);
|
||||
});
|
||||
|
||||
it.each([true, false])('returns pushed %s value after subscribed', (value) => {
|
||||
const observable$ = new Observable<boolean>((subscriber) => {
|
||||
subscriber.next(value);
|
||||
});
|
||||
|
||||
telemetryConfigProvider.start(observable$);
|
||||
|
||||
expect(telemetryConfigProvider.getIsOptedIn()).toBe(value);
|
||||
});
|
||||
});
|
||||
|
||||
it('stop() unsubscribes from Observable', async () => {
|
||||
const unsubscribeMock = jest.fn();
|
||||
const observableMock = {
|
||||
subscribe: () => ({
|
||||
unsubscribe: unsubscribeMock,
|
||||
}),
|
||||
} as unknown as Observable<boolean>;
|
||||
|
||||
telemetryConfigProvider.start(observableMock);
|
||||
expect(unsubscribeMock).not.toBeCalled();
|
||||
|
||||
telemetryConfigProvider.stop();
|
||||
expect(unsubscribeMock).toBeCalled();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* 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 { Observable, Subscription } from 'rxjs';
|
||||
|
||||
export class TelemetryConfigProvider {
|
||||
private isOptedIn$?: Observable<boolean>;
|
||||
private _isOptedIn?: boolean;
|
||||
|
||||
private subscription?: Subscription;
|
||||
|
||||
public start(isOptedIn$: Observable<boolean>) {
|
||||
this.isOptedIn$ = isOptedIn$;
|
||||
this.subscription = this.isOptedIn$.subscribe((isOptedIn) => {
|
||||
this._isOptedIn = isOptedIn;
|
||||
});
|
||||
}
|
||||
|
||||
public stop() {
|
||||
this.subscription?.unsubscribe();
|
||||
}
|
||||
|
||||
public getIsOptedIn() {
|
||||
return this._isOptedIn;
|
||||
}
|
||||
|
||||
public getObservable() {
|
||||
return this.isOptedIn$;
|
||||
}
|
||||
}
|
|
@ -60,7 +60,8 @@
|
|||
"charts",
|
||||
"entityManager",
|
||||
"inference",
|
||||
"productDocBase"
|
||||
"productDocBase",
|
||||
"telemetry"
|
||||
],
|
||||
"optionalPlugins": [
|
||||
"encryptedSavedObjects",
|
||||
|
@ -72,7 +73,6 @@
|
|||
"lists",
|
||||
"home",
|
||||
"management",
|
||||
"telemetry",
|
||||
"dataViewFieldEditor",
|
||||
"osquery",
|
||||
"savedObjectsTaggingOss",
|
||||
|
@ -95,4 +95,4 @@
|
|||
"common"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -272,6 +272,7 @@ describe('policy details: ', () => {
|
|||
policy: {
|
||||
value: {
|
||||
global_manifest_version: 'latest',
|
||||
global_telemetry_enabled: false,
|
||||
meta: {
|
||||
license: '',
|
||||
cloud: false,
|
||||
|
|
|
@ -26,6 +26,7 @@ import type { CloudSetup } from '@kbn/cloud-plugin/server';
|
|||
import type { FleetActionsClientInterface } from '@kbn/fleet-plugin/server/services/actions/types';
|
||||
import type { PluginStartContract as ActionsPluginStartContract } from '@kbn/actions-plugin/server';
|
||||
import { DEFAULT_SPACE_ID } from '@kbn/spaces-plugin/common';
|
||||
import type { TelemetryConfigProvider } from '../../common/telemetry_config/telemetry_config_provider';
|
||||
import { SavedObjectsClientFactory } from './services/saved_objects';
|
||||
import type { ResponseActionsClient } from './services';
|
||||
import { getResponseActionsClient, NormalizedExternalConnectorClient } from './services';
|
||||
|
@ -86,6 +87,7 @@ export interface EndpointAppContextServiceStartContract {
|
|||
productFeaturesService: ProductFeaturesService;
|
||||
savedObjectsServiceStart: SavedObjectsServiceStart;
|
||||
connectorActions: ActionsPluginStartContract;
|
||||
telemetryConfigProvider: TelemetryConfigProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -154,6 +156,7 @@ export class EndpointAppContextService {
|
|||
manifestManager,
|
||||
alerting,
|
||||
licenseService,
|
||||
telemetryConfigProvider,
|
||||
exceptionListsClient,
|
||||
featureUsageService,
|
||||
esClient,
|
||||
|
@ -184,7 +187,8 @@ export class EndpointAppContextService {
|
|||
licenseService,
|
||||
exceptionListsClient,
|
||||
this.setupDependencies.cloud,
|
||||
productFeaturesService
|
||||
productFeaturesService,
|
||||
telemetryConfigProvider
|
||||
)
|
||||
);
|
||||
|
||||
|
|
|
@ -22,7 +22,9 @@ import { createPackagePolicyMock } from '@kbn/fleet-plugin/common/mocks';
|
|||
import { policyFactory } from '../../../../common/endpoint/models/policy_config';
|
||||
import type { PolicyConfig } from '../../../../common/endpoint/types';
|
||||
|
||||
const MockPPWithEndpointPolicy = (cb?: (p: PolicyConfig) => PolicyConfig): PackagePolicy => {
|
||||
const MockPackagePolicyWithEndpointPolicy = (
|
||||
cb?: (p: PolicyConfig) => PolicyConfig
|
||||
): PackagePolicy => {
|
||||
const packagePolicy = createPackagePolicyMock();
|
||||
if (!cb) {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
|
@ -30,6 +32,7 @@ const MockPPWithEndpointPolicy = (cb?: (p: PolicyConfig) => PolicyConfig): Packa
|
|||
}
|
||||
const policyConfig = cb(policyFactory());
|
||||
packagePolicy.inputs[0].config = { policy: { value: policyConfig } };
|
||||
|
||||
return packagePolicy;
|
||||
};
|
||||
|
||||
|
@ -78,19 +81,19 @@ describe('Policy-Changing license watcher', () => {
|
|||
// set up the mocked package policy service to return and do what we want
|
||||
packagePolicySvcMock.list
|
||||
.mockResolvedValueOnce({
|
||||
items: Array.from({ length: 100 }, () => MockPPWithEndpointPolicy()),
|
||||
items: Array.from({ length: 100 }, () => MockPackagePolicyWithEndpointPolicy()),
|
||||
total: TOTAL,
|
||||
page: 1,
|
||||
perPage: 100,
|
||||
})
|
||||
.mockResolvedValueOnce({
|
||||
items: Array.from({ length: 100 }, () => MockPPWithEndpointPolicy()),
|
||||
items: Array.from({ length: 100 }, () => MockPackagePolicyWithEndpointPolicy()),
|
||||
total: TOTAL,
|
||||
page: 2,
|
||||
perPage: 100,
|
||||
})
|
||||
.mockResolvedValueOnce({
|
||||
items: Array.from({ length: TOTAL - 200 }, () => MockPPWithEndpointPolicy()),
|
||||
items: Array.from({ length: TOTAL - 200 }, () => MockPackagePolicyWithEndpointPolicy()),
|
||||
total: TOTAL,
|
||||
page: 3,
|
||||
perPage: 100,
|
||||
|
@ -113,7 +116,7 @@ describe('Policy-Changing license watcher', () => {
|
|||
// mock a Policy with a higher-tiered feature enabled
|
||||
packagePolicySvcMock.list.mockResolvedValueOnce({
|
||||
items: [
|
||||
MockPPWithEndpointPolicy((pc: PolicyConfig): PolicyConfig => {
|
||||
MockPackagePolicyWithEndpointPolicy((pc: PolicyConfig): PolicyConfig => {
|
||||
pc.windows.popup.malware.message = CustomMessage;
|
||||
return pc;
|
||||
}),
|
||||
|
|
|
@ -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 { Subject } from 'rxjs';
|
||||
import { elasticsearchServiceMock, savedObjectsServiceMock } from '@kbn/core/server/mocks';
|
||||
import { createPackagePolicyServiceMock } from '@kbn/fleet-plugin/server/mocks';
|
||||
import type { PackagePolicyClient } from '@kbn/fleet-plugin/server';
|
||||
import type { PackagePolicy, UpdatePackagePolicy } from '@kbn/fleet-plugin/common';
|
||||
import { createPackagePolicyMock } from '@kbn/fleet-plugin/common/mocks';
|
||||
import { policyFactory } from '../../../../common/endpoint/models/policy_config';
|
||||
import type { PolicyConfig } from '../../../../common/endpoint/types';
|
||||
import { TelemetryConfigWatcher } from './telemetry_watch';
|
||||
import { TelemetryConfigProvider } from '../../../../common/telemetry_config/telemetry_config_provider';
|
||||
import { createMockEndpointAppContextService } from '../../mocks';
|
||||
|
||||
const MockPackagePolicyWithEndpointPolicy = (
|
||||
cb?: (p: PolicyConfig) => PolicyConfig
|
||||
): PackagePolicy => {
|
||||
const packagePolicy = createPackagePolicyMock();
|
||||
if (!cb) {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
cb = (p) => p;
|
||||
}
|
||||
const policyConfig = cb(policyFactory());
|
||||
packagePolicy.inputs[0].config = { policy: { value: policyConfig } };
|
||||
|
||||
return packagePolicy;
|
||||
};
|
||||
|
||||
describe('Telemetry config watcher', () => {
|
||||
const soStartMock = savedObjectsServiceMock.createStartContract();
|
||||
const esStartMock = elasticsearchServiceMock.createStart();
|
||||
let packagePolicySvcMock: jest.Mocked<PackagePolicyClient>;
|
||||
let telemetryWatcher: TelemetryConfigWatcher;
|
||||
|
||||
const preparePackagePolicyMock = ({
|
||||
isGlobalTelemetryEnabled,
|
||||
}: {
|
||||
isGlobalTelemetryEnabled: boolean;
|
||||
}) => {
|
||||
packagePolicySvcMock.list.mockResolvedValueOnce({
|
||||
items: [
|
||||
MockPackagePolicyWithEndpointPolicy((pc: PolicyConfig): PolicyConfig => {
|
||||
pc.global_telemetry_enabled = isGlobalTelemetryEnabled;
|
||||
return pc;
|
||||
}),
|
||||
],
|
||||
total: 1,
|
||||
page: 1,
|
||||
perPage: 100,
|
||||
});
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
packagePolicySvcMock = createPackagePolicyServiceMock();
|
||||
|
||||
telemetryWatcher = new TelemetryConfigWatcher(
|
||||
packagePolicySvcMock,
|
||||
soStartMock,
|
||||
esStartMock,
|
||||
createMockEndpointAppContextService()
|
||||
);
|
||||
});
|
||||
|
||||
it('is activated on telemetry config changes', () => {
|
||||
const telemetryConfigEmitter: Subject<boolean> = new Subject();
|
||||
const telemetryConfigProvider = new TelemetryConfigProvider();
|
||||
|
||||
// spy on the watch() function
|
||||
const mockWatch = jest.fn();
|
||||
telemetryWatcher.watch = mockWatch;
|
||||
|
||||
telemetryConfigProvider.start(telemetryConfigEmitter);
|
||||
telemetryWatcher.start(telemetryConfigProvider);
|
||||
|
||||
telemetryConfigEmitter.next(true);
|
||||
|
||||
expect(mockWatch).toBeCalledTimes(1);
|
||||
|
||||
telemetryWatcher.stop();
|
||||
telemetryConfigProvider.stop();
|
||||
telemetryConfigEmitter.complete();
|
||||
});
|
||||
|
||||
it('pages through all endpoint policies', async () => {
|
||||
const TOTAL = 247;
|
||||
|
||||
// set up the mocked package policy service to return and do what we want
|
||||
packagePolicySvcMock.list
|
||||
.mockResolvedValueOnce({
|
||||
items: Array.from({ length: 100 }, () => MockPackagePolicyWithEndpointPolicy()),
|
||||
total: TOTAL,
|
||||
page: 1,
|
||||
perPage: 100,
|
||||
})
|
||||
.mockResolvedValueOnce({
|
||||
items: Array.from({ length: 100 }, () => MockPackagePolicyWithEndpointPolicy()),
|
||||
total: TOTAL,
|
||||
page: 2,
|
||||
perPage: 100,
|
||||
})
|
||||
.mockResolvedValueOnce({
|
||||
items: Array.from({ length: TOTAL - 200 }, () => MockPackagePolicyWithEndpointPolicy()),
|
||||
total: TOTAL,
|
||||
page: 3,
|
||||
perPage: 100,
|
||||
});
|
||||
|
||||
await telemetryWatcher.watch(true); // manual trigger
|
||||
|
||||
expect(packagePolicySvcMock.list).toBeCalledTimes(3);
|
||||
|
||||
// Assert: on the first call to packagePolicy.list, we asked for page 1
|
||||
expect(packagePolicySvcMock.list.mock.calls[0][1].page).toBe(1);
|
||||
expect(packagePolicySvcMock.list.mock.calls[1][1].page).toBe(2); // second call, asked for page 2
|
||||
expect(packagePolicySvcMock.list.mock.calls[2][1].page).toBe(3); // etc
|
||||
});
|
||||
|
||||
it.each([true, false])(
|
||||
'does not update policies if both global telemetry config and policy fields are %s',
|
||||
async (value) => {
|
||||
preparePackagePolicyMock({ isGlobalTelemetryEnabled: value });
|
||||
|
||||
await telemetryWatcher.watch(value);
|
||||
|
||||
expect(packagePolicySvcMock.bulkUpdate).not.toHaveBeenCalled();
|
||||
}
|
||||
);
|
||||
|
||||
it.each([true, false])('updates `global_telemetry_config` field to %s', async (value) => {
|
||||
preparePackagePolicyMock({ isGlobalTelemetryEnabled: !value });
|
||||
|
||||
await telemetryWatcher.watch(value);
|
||||
|
||||
expect(packagePolicySvcMock.bulkUpdate).toHaveBeenCalled();
|
||||
const policyUpdates: UpdatePackagePolicy[] = packagePolicySvcMock.bulkUpdate.mock.calls[0][2];
|
||||
expect(policyUpdates.length).toBe(1);
|
||||
const updatedPolicyConfigs: PolicyConfig = policyUpdates[0].inputs[0].config?.policy.value;
|
||||
expect(updatedPolicyConfigs.global_telemetry_enabled).toBe(value);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
* 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 { Subscription } from 'rxjs';
|
||||
|
||||
import type {
|
||||
ElasticsearchClient,
|
||||
ElasticsearchServiceStart,
|
||||
KibanaRequest,
|
||||
Logger,
|
||||
SavedObjectsClientContract,
|
||||
SavedObjectsServiceStart,
|
||||
} from '@kbn/core/server';
|
||||
import type { PackagePolicy, UpdatePackagePolicy } from '@kbn/fleet-plugin/common';
|
||||
import { PACKAGE_POLICY_SAVED_OBJECT_TYPE } from '@kbn/fleet-plugin/common';
|
||||
import type { PackagePolicyClient } from '@kbn/fleet-plugin/server';
|
||||
import { SECURITY_EXTENSION_ID } from '@kbn/core-saved-objects-server';
|
||||
import type { TelemetryConfigProvider } from '../../../../common/telemetry_config/telemetry_config_provider';
|
||||
import type { PolicyData } from '../../../../common/endpoint/types';
|
||||
import { getPolicyDataForUpdate } from '../../../../common/endpoint/service/policy';
|
||||
import type { EndpointAppContextService } from '../../endpoint_app_context_services';
|
||||
|
||||
export class TelemetryConfigWatcher {
|
||||
private logger: Logger;
|
||||
private esClient: ElasticsearchClient;
|
||||
private policyService: PackagePolicyClient;
|
||||
private subscription: Subscription | undefined;
|
||||
private soStart: SavedObjectsServiceStart;
|
||||
constructor(
|
||||
policyService: PackagePolicyClient,
|
||||
soStart: SavedObjectsServiceStart,
|
||||
esStart: ElasticsearchServiceStart,
|
||||
endpointAppContextService: EndpointAppContextService
|
||||
) {
|
||||
this.policyService = policyService;
|
||||
this.esClient = esStart.client.asInternalUser;
|
||||
this.logger = endpointAppContextService.createLogger(this.constructor.name);
|
||||
this.soStart = soStart;
|
||||
}
|
||||
|
||||
/**
|
||||
* The policy watcher is not called as part of a HTTP request chain, where the
|
||||
* request-scoped SOClient could be passed down. It is called via telemetry observable
|
||||
* changes. We are acting as the 'system' in response to telemetry changes, so we are
|
||||
* intentionally using the system user here. Be very aware of what you are using this
|
||||
* client to do
|
||||
*/
|
||||
private makeInternalSOClient(soStart: SavedObjectsServiceStart): SavedObjectsClientContract {
|
||||
const fakeRequest = {
|
||||
headers: {},
|
||||
getBasePath: () => '',
|
||||
path: '/',
|
||||
route: { settings: {} },
|
||||
url: { href: {} },
|
||||
raw: { req: { url: '/' } },
|
||||
} as unknown as KibanaRequest;
|
||||
return soStart.getScopedClient(fakeRequest, { excludedExtensions: [SECURITY_EXTENSION_ID] });
|
||||
}
|
||||
|
||||
public start(telemetryConfigProvider: TelemetryConfigProvider) {
|
||||
this.subscription = telemetryConfigProvider.getObservable()?.subscribe(this.watch.bind(this));
|
||||
}
|
||||
|
||||
public stop() {
|
||||
if (this.subscription) {
|
||||
this.subscription.unsubscribe();
|
||||
}
|
||||
}
|
||||
|
||||
public async watch(isTelemetryEnabled: boolean) {
|
||||
let page = 1;
|
||||
let response: {
|
||||
items: PackagePolicy[];
|
||||
total: number;
|
||||
page: number;
|
||||
perPage: number;
|
||||
};
|
||||
|
||||
this.logger.debug(
|
||||
`Checking Endpoint policies to update due to changed global telemetry config setting. (New value: ${isTelemetryEnabled})`
|
||||
);
|
||||
|
||||
do {
|
||||
try {
|
||||
response = await this.policyService.list(this.makeInternalSOClient(this.soStart), {
|
||||
page: page++,
|
||||
perPage: 100,
|
||||
kuery: `${PACKAGE_POLICY_SAVED_OBJECT_TYPE}.package.name: endpoint`,
|
||||
});
|
||||
} catch (e) {
|
||||
this.logger.warn(
|
||||
`Unable to verify endpoint policies in line with telemetry change: failed to fetch package policies: ${e.message}`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const updates: UpdatePackagePolicy[] = [];
|
||||
for (const policy of response.items as PolicyData[]) {
|
||||
const updatePolicy = getPolicyDataForUpdate(policy);
|
||||
const policyConfig = updatePolicy.inputs[0].config.policy.value;
|
||||
|
||||
if (isTelemetryEnabled !== policyConfig.global_telemetry_enabled) {
|
||||
policyConfig.global_telemetry_enabled = isTelemetryEnabled;
|
||||
|
||||
updates.push({ ...updatePolicy, id: policy.id });
|
||||
}
|
||||
}
|
||||
|
||||
if (updates.length) {
|
||||
try {
|
||||
await this.policyService.bulkUpdate(
|
||||
this.makeInternalSOClient(this.soStart),
|
||||
this.esClient,
|
||||
updates
|
||||
);
|
||||
} catch (e) {
|
||||
// try again for transient issues
|
||||
try {
|
||||
await this.policyService.bulkUpdate(
|
||||
this.makeInternalSOClient(this.soStart),
|
||||
this.esClient,
|
||||
updates
|
||||
);
|
||||
} catch (ee) {
|
||||
this.logger.warn(
|
||||
`Unable to update telemetry config state to ${isTelemetryEnabled} in policies: ${updates.map(
|
||||
(update) => update.id
|
||||
)}`
|
||||
);
|
||||
this.logger.warn(ee);
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (response.page * response.perPage < response.total);
|
||||
}
|
||||
}
|
|
@ -50,6 +50,7 @@ import { unsecuredActionsClientMock } from '@kbn/actions-plugin/server/unsecured
|
|||
import type { PluginStartContract as ActionPluginStartContract } from '@kbn/actions-plugin/server';
|
||||
import type { Mutable } from 'utility-types';
|
||||
import type { DeeplyMockedKeys } from '@kbn/utility-types-jest';
|
||||
import { createTelemetryConfigProviderMock } from '../../../common/telemetry_config/mocks';
|
||||
import { createSavedObjectsClientFactoryMock } from '../services/saved_objects/saved_objects_client_factory.mocks';
|
||||
import { EndpointMetadataService } from '../services/metadata';
|
||||
import { createEndpointFleetServicesFactoryMock } from '../services/fleet/endpoint_fleet_services_factory.mocks';
|
||||
|
@ -216,6 +217,7 @@ export const createMockEndpointAppContextServiceStartContract =
|
|||
connectorActions: {
|
||||
getUnsecuredActionsClient: jest.fn().mockReturnValue(unsecuredActionsClientMock.create()),
|
||||
} as unknown as jest.Mocked<ActionPluginStartContract>,
|
||||
telemetryConfigProvider: createTelemetryConfigProviderMock(),
|
||||
};
|
||||
|
||||
return startContract;
|
||||
|
|
|
@ -83,6 +83,7 @@ import type {
|
|||
import type { EndpointMetadataService } from '../endpoint/services/metadata';
|
||||
import { createEndpointMetadataServiceTestContextMock } from '../endpoint/services/metadata/mocks';
|
||||
import { createPolicyDataStreamsIfNeeded as _createPolicyDataStreamsIfNeeded } from './handlers/create_policy_datastreams';
|
||||
import { createTelemetryConfigProviderMock } from '../../common/telemetry_config/mocks';
|
||||
|
||||
jest.mock('uuid', () => ({
|
||||
v4: (): string => 'NEW_UUID',
|
||||
|
@ -118,6 +119,7 @@ describe('Fleet integrations', () => {
|
|||
});
|
||||
const generator = new EndpointDocGenerator();
|
||||
const cloudService = cloudMock.createSetup();
|
||||
const telemetryConfigProviderMock = createTelemetryConfigProviderMock();
|
||||
let productFeaturesService: ProductFeaturesService;
|
||||
let endpointMetadataService: EndpointMetadataService;
|
||||
let logger: Logger;
|
||||
|
@ -157,7 +159,8 @@ describe('Fleet integrations', () => {
|
|||
licenseUuid = 'updated-uid',
|
||||
clusterUuid = '',
|
||||
clusterName = '',
|
||||
isServerlessEnabled = cloudService.isServerlessEnabled
|
||||
isServerlessEnabled = cloudService.isServerlessEnabled,
|
||||
isTelemetryEnabled = true
|
||||
) => ({
|
||||
type: 'endpoint',
|
||||
enabled: true,
|
||||
|
@ -166,14 +169,15 @@ describe('Fleet integrations', () => {
|
|||
integration_config: {},
|
||||
policy: {
|
||||
value: disableProtections(
|
||||
policyFactory(
|
||||
policyFactory({
|
||||
license,
|
||||
cloud,
|
||||
licenseUuid,
|
||||
clusterUuid,
|
||||
clusterName,
|
||||
isServerlessEnabled
|
||||
)
|
||||
serverless: isServerlessEnabled,
|
||||
isGlobalTelemetryEnabled: isTelemetryEnabled,
|
||||
})
|
||||
),
|
||||
},
|
||||
artifact_manifest: { value: manifest },
|
||||
|
@ -189,7 +193,8 @@ describe('Fleet integrations', () => {
|
|||
licenseService,
|
||||
exceptionListClient,
|
||||
cloudService,
|
||||
productFeaturesService
|
||||
productFeaturesService,
|
||||
telemetryConfigProviderMock
|
||||
);
|
||||
|
||||
return callback(
|
||||
|
@ -365,6 +370,19 @@ describe('Fleet integrations', () => {
|
|||
|
||||
isBillablePolicySpy.mockRestore();
|
||||
});
|
||||
|
||||
it.each([false, true])(
|
||||
'should correctly set `global_telemetry_enabled` to %s',
|
||||
async (targetValue) => {
|
||||
const manifestManager = buildManifestManagerMock();
|
||||
telemetryConfigProviderMock.getIsOptedIn.mockReturnValue(targetValue);
|
||||
|
||||
const packagePolicy = await invokeCallback(manifestManager);
|
||||
|
||||
const policyConfig: PolicyConfig = packagePolicy.inputs[0].config!.policy.value;
|
||||
expect(policyConfig.global_telemetry_enabled).toBe(targetValue);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
describe('package policy post create callback', () => {
|
||||
|
|
|
@ -31,6 +31,7 @@ import type {
|
|||
PostAgentPolicyUpdateCallback,
|
||||
PutPackagePolicyPostUpdateCallback,
|
||||
} from '@kbn/fleet-plugin/server/types';
|
||||
import type { TelemetryConfigProvider } from '../../common/telemetry_config/telemetry_config_provider';
|
||||
import type { EndpointInternalFleetServicesInterface } from '../endpoint/services/fleet';
|
||||
import type { EndpointAppContextService } from '../endpoint/endpoint_app_context_services';
|
||||
import { createPolicyDataStreamsIfNeeded } from './handlers/create_policy_datastreams';
|
||||
|
@ -123,7 +124,8 @@ export const getPackagePolicyCreateCallback = (
|
|||
licenseService: LicenseService,
|
||||
exceptionsClient: ExceptionListClient | undefined,
|
||||
cloud: CloudSetup,
|
||||
productFeatures: ProductFeaturesService
|
||||
productFeatures: ProductFeaturesService,
|
||||
telemetryConfigProvider: TelemetryConfigProvider
|
||||
): PostPackagePolicyCreateCallback => {
|
||||
return async (
|
||||
newPackagePolicy,
|
||||
|
@ -196,7 +198,8 @@ export const getPackagePolicyCreateCallback = (
|
|||
endpointIntegrationConfig,
|
||||
cloud,
|
||||
esClientInfo,
|
||||
productFeatures
|
||||
productFeatures,
|
||||
telemetryConfigProvider
|
||||
);
|
||||
|
||||
return {
|
||||
|
|
|
@ -23,6 +23,7 @@ import type {
|
|||
} from '../types';
|
||||
import type { ProductFeaturesService } from '../../lib/product_features_service/product_features_service';
|
||||
import { createProductFeaturesServiceMock } from '../../lib/product_features_service/mocks';
|
||||
import { createTelemetryConfigProviderMock } from '../../../common/telemetry_config/mocks';
|
||||
|
||||
describe('Create Default Policy tests ', () => {
|
||||
const cloud = cloudMock.createSetup();
|
||||
|
@ -33,14 +34,22 @@ describe('Create Default Policy tests ', () => {
|
|||
let licenseEmitter: Subject<ILicense>;
|
||||
let licenseService: LicenseService;
|
||||
let productFeaturesService: ProductFeaturesService;
|
||||
const telemetryConfigProviderMock = createTelemetryConfigProviderMock();
|
||||
|
||||
const createDefaultPolicyCallback = async (
|
||||
config: AnyPolicyCreateConfig | undefined
|
||||
config?: AnyPolicyCreateConfig
|
||||
): Promise<PolicyConfig> => {
|
||||
const esClientInfo = await elasticsearchServiceMock.createClusterClient().asInternalUser.info();
|
||||
esClientInfo.cluster_name = '';
|
||||
esClientInfo.cluster_uuid = '';
|
||||
return createDefaultPolicy(licenseService, config, cloud, esClientInfo, productFeaturesService);
|
||||
return createDefaultPolicy(
|
||||
licenseService,
|
||||
config,
|
||||
cloud,
|
||||
esClientInfo,
|
||||
productFeaturesService,
|
||||
telemetryConfigProviderMock
|
||||
);
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
|
@ -202,11 +211,15 @@ describe('Create Default Policy tests ', () => {
|
|||
it('Should return the default config when preset is EDR Complete', async () => {
|
||||
const config = createEndpointConfig({ preset: 'EDRComplete' });
|
||||
const policy = await createDefaultPolicyCallback(config);
|
||||
const licenseType = 'platinum';
|
||||
const license = 'platinum';
|
||||
const isCloud = true;
|
||||
const defaultPolicy = policyFactory(licenseType, isCloud);
|
||||
const defaultPolicy = policyFactory({
|
||||
license,
|
||||
cloud: isCloud,
|
||||
isGlobalTelemetryEnabled: true,
|
||||
});
|
||||
// update defaultPolicy w/ platinum license & cloud info
|
||||
defaultPolicy.meta.license = licenseType;
|
||||
defaultPolicy.meta.license = license;
|
||||
defaultPolicy.meta.cloud = isCloud;
|
||||
expect(policy).toMatchObject(defaultPolicy);
|
||||
});
|
||||
|
@ -279,4 +292,22 @@ describe('Create Default Policy tests ', () => {
|
|||
expect(policy.windows.ransomware.mode).toBe('off');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Global Telemetry Config', () => {
|
||||
it('should save telemetry config state in policy based on telemetry config provider', async () => {
|
||||
telemetryConfigProviderMock.getIsOptedIn.mockReturnValue(false);
|
||||
let policyConfig = await createDefaultPolicyCallback();
|
||||
expect(policyConfig.global_telemetry_enabled).toBe(false);
|
||||
|
||||
telemetryConfigProviderMock.getIsOptedIn.mockReturnValue(true);
|
||||
policyConfig = await createDefaultPolicyCallback();
|
||||
expect(policyConfig.global_telemetry_enabled).toBe(true);
|
||||
});
|
||||
|
||||
it('should fallback to `false` when global telemetry config is unavailable', async () => {
|
||||
telemetryConfigProviderMock.getIsOptedIn.mockReturnValue(undefined);
|
||||
const policyConfig = await createDefaultPolicyCallback();
|
||||
expect(policyConfig.global_telemetry_enabled).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
import type { CloudSetup } from '@kbn/cloud-plugin/server';
|
||||
import type { InfoResponse } from '@elastic/elasticsearch/lib/api/types';
|
||||
import { ProductFeatureSecurityKey } from '@kbn/security-solution-features/keys';
|
||||
import type { TelemetryConfigProvider } from '../../../common/telemetry_config/telemetry_config_provider';
|
||||
import {
|
||||
policyFactory as policyConfigFactory,
|
||||
policyFactoryWithoutPaidFeatures as policyConfigFactoryWithoutPaidFeatures,
|
||||
|
@ -36,17 +37,19 @@ export const createDefaultPolicy = (
|
|||
config: AnyPolicyCreateConfig | undefined,
|
||||
cloud: CloudSetup,
|
||||
esClientInfo: InfoResponse,
|
||||
productFeatures: ProductFeaturesService
|
||||
productFeatures: ProductFeaturesService,
|
||||
telemetryConfigProvider: TelemetryConfigProvider
|
||||
): PolicyConfig => {
|
||||
// Pass license and cloud information to use in Policy creation
|
||||
const factoryPolicy = policyConfigFactory(
|
||||
licenseService.getLicenseType(),
|
||||
cloud?.isCloudEnabled,
|
||||
licenseService.getLicenseUID(),
|
||||
esClientInfo?.cluster_uuid,
|
||||
esClientInfo?.cluster_name,
|
||||
cloud?.isServerlessEnabled
|
||||
);
|
||||
const factoryPolicy = policyConfigFactory({
|
||||
license: licenseService.getLicenseType(),
|
||||
cloud: cloud?.isCloudEnabled,
|
||||
licenseUuid: licenseService.getLicenseUID(),
|
||||
clusterUuid: esClientInfo?.cluster_uuid,
|
||||
clusterName: esClientInfo?.cluster_name,
|
||||
serverless: cloud?.isServerlessEnabled,
|
||||
isGlobalTelemetryEnabled: telemetryConfigProvider.getIsOptedIn(),
|
||||
});
|
||||
|
||||
let defaultPolicyPerType: PolicyConfig =
|
||||
config?.type === 'cloud'
|
||||
|
|
|
@ -130,6 +130,8 @@ import { getCriblPackagePolicyPostCreateOrUpdateCallback } from './security_inte
|
|||
import { scheduleEntityAnalyticsMigration } from './lib/entity_analytics/migrations';
|
||||
import { SiemMigrationsService } from './lib/siem_migrations/siem_migrations_service';
|
||||
import { registerRiskScoreModulesDeprecation } from './deprecations/register_risk_score_modules_deprecation';
|
||||
import { TelemetryConfigProvider } from '../common/telemetry_config/telemetry_config_provider';
|
||||
import { TelemetryConfigWatcher } from './endpoint/lib/policy/telemetry_watch';
|
||||
|
||||
export type { SetupPlugins, StartPlugins, PluginSetup, PluginStart } from './plugin_contract';
|
||||
|
||||
|
@ -150,6 +152,8 @@ export class Plugin implements ISecuritySolutionPlugin {
|
|||
private lists: ListPluginSetup | undefined; // TODO: can we create ListPluginStart?
|
||||
private licensing$!: Observable<ILicense>;
|
||||
private policyWatcher?: PolicyWatcher;
|
||||
private telemetryConfigProvider: TelemetryConfigProvider;
|
||||
private telemetryWatcher?: TelemetryConfigWatcher;
|
||||
|
||||
private manifestTask: ManifestTask | undefined;
|
||||
private completeExternalResponseActionsTask: CompleteExternalResponseActionsTask;
|
||||
|
@ -179,7 +183,8 @@ export class Plugin implements ISecuritySolutionPlugin {
|
|||
this.asyncTelemetryEventsSender = new AsyncTelemetryEventsSender(this.logger);
|
||||
this.telemetryReceiver = new TelemetryReceiver(this.logger);
|
||||
|
||||
this.logger.debug('plugin initialized');
|
||||
this.telemetryConfigProvider = new TelemetryConfigProvider();
|
||||
|
||||
this.endpointContext = {
|
||||
logFactory: this.pluginContext.logger,
|
||||
service: this.endpointAppContextService,
|
||||
|
@ -192,6 +197,8 @@ export class Plugin implements ISecuritySolutionPlugin {
|
|||
this.completeExternalResponseActionsTask = new CompleteExternalResponseActionsTask({
|
||||
endpointAppContext: this.endpointContext,
|
||||
});
|
||||
|
||||
this.logger.debug('plugin initialized');
|
||||
}
|
||||
|
||||
public setup(
|
||||
|
@ -580,6 +587,8 @@ export class Plugin implements ISecuritySolutionPlugin {
|
|||
|
||||
this.licensing$ = plugins.licensing.license$;
|
||||
|
||||
this.telemetryConfigProvider.start(plugins.telemetry.isOptedIn$);
|
||||
|
||||
// Assistant Tool and Feature Registration
|
||||
plugins.elasticAssistant.registerTools(APP_UI_ID, assistantTools);
|
||||
const features = {
|
||||
|
@ -611,6 +620,7 @@ export class Plugin implements ISecuritySolutionPlugin {
|
|||
cases: plugins.cases,
|
||||
manifestManager,
|
||||
licenseService,
|
||||
telemetryConfigProvider: this.telemetryConfigProvider,
|
||||
exceptionListsClient: exceptionListClient,
|
||||
registerListsServerExtension: this.lists?.registerExtension,
|
||||
featureUsageService,
|
||||
|
@ -662,6 +672,14 @@ export class Plugin implements ISecuritySolutionPlugin {
|
|||
logger
|
||||
);
|
||||
this.policyWatcher.start(licenseService);
|
||||
|
||||
this.telemetryWatcher = new TelemetryConfigWatcher(
|
||||
plugins.fleet.packagePolicyService,
|
||||
core.savedObjects,
|
||||
core.elasticsearch,
|
||||
this.endpointContext.service
|
||||
);
|
||||
this.telemetryWatcher.start(this.telemetryConfigProvider);
|
||||
}
|
||||
|
||||
if (plugins.taskManager) {
|
||||
|
|
|
@ -83,7 +83,7 @@ export interface SecuritySolutionPluginStartDependencies {
|
|||
security: SecurityPluginStart;
|
||||
spaces?: SpacesPluginStart;
|
||||
taskManager?: TaskManagerPluginStart;
|
||||
telemetry?: TelemetryPluginStart;
|
||||
telemetry: TelemetryPluginStart;
|
||||
share: SharePluginStart;
|
||||
actions: ActionsPluginStartContract;
|
||||
inference: InferenceServerStart;
|
||||
|
|
|
@ -86,12 +86,8 @@ describe('setEndpointPackagePolicyServerlessBillingFlags', () => {
|
|||
});
|
||||
|
||||
it('does NOT update serverless flag for endpoint policies with the flag already set', async () => {
|
||||
const packagePolicy1 = generatePackagePolicy(
|
||||
policyFactory(undefined, undefined, undefined, undefined, undefined, true)
|
||||
);
|
||||
const packagePolicy2 = generatePackagePolicy(
|
||||
policyFactory(undefined, undefined, undefined, undefined, undefined, true)
|
||||
);
|
||||
const packagePolicy1 = generatePackagePolicy(policyFactory({ serverless: true }));
|
||||
const packagePolicy2 = generatePackagePolicy(policyFactory({ serverless: true }));
|
||||
packagePolicyServiceMock.list.mockResolvedValue({
|
||||
items: [packagePolicy1, packagePolicy2],
|
||||
page: 1,
|
||||
|
@ -116,23 +112,15 @@ describe('setEndpointPackagePolicyServerlessBillingFlags', () => {
|
|||
|
||||
it('correctly updates billable flag for endpoint policies', async () => {
|
||||
// billable: false - serverless false
|
||||
const packagePolicy1 = generatePackagePolicy(
|
||||
policyFactory(undefined, undefined, undefined, undefined, undefined, false)
|
||||
);
|
||||
const packagePolicy1 = generatePackagePolicy(policyFactory({ serverless: false }));
|
||||
// billable: true - serverless + protections
|
||||
const packagePolicy2 = generatePackagePolicy(
|
||||
policyFactory(undefined, undefined, undefined, undefined, undefined, true)
|
||||
);
|
||||
const packagePolicy2 = generatePackagePolicy(policyFactory({ serverless: true }));
|
||||
// billable: false - serverless true but event collection only
|
||||
const packagePolicy3 = generatePackagePolicy(
|
||||
ensureOnlyEventCollectionIsAllowed(
|
||||
policyFactory(undefined, undefined, undefined, undefined, undefined, true)
|
||||
)
|
||||
ensureOnlyEventCollectionIsAllowed(policyFactory({ serverless: true }))
|
||||
);
|
||||
// ignored since flag already set
|
||||
const packagePolicy4 = generatePackagePolicy(
|
||||
policyFactory(undefined, undefined, undefined, undefined, undefined, true)
|
||||
);
|
||||
const packagePolicy4 = generatePackagePolicy(policyFactory({ serverless: true }));
|
||||
packagePolicyServiceMock.list.mockResolvedValue({
|
||||
items: [packagePolicy1, packagePolicy2, packagePolicy3, packagePolicy4],
|
||||
page: 1,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue