Skip to content

Commit

Permalink
[EDR Workflows] Add new backfill function to set on_write_scan to `…
Browse files Browse the repository at this point in the history
…false` if Malware protection is off (elastic#182598)

## Summary

This PR adds an additional backfill for `on_write_scan`. This is a fix,
because it has been backfilled with a `true` value, but it should be
`false` when Malware protection is off.

This should be a safe backfill, because:
- the feature is behind feature flag, so users did not have the
opportunity to modify the value,
- and if they would have, still, `malware=off && on_write_scan=true` is
an invalid combination, the user cannot achieve it, so there is no
chance of destroying user created settings.

Additionally, the new model version is added to a different folder to
help transitioning our mindsets from migrations to model versions.

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

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
  • Loading branch information
gergoabraham and kibanamachine authored May 17, 2024
1 parent 8f9c4ab commit 60cf299
Show file tree
Hide file tree
Showing 5 changed files with 243 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ describe('checking migration metadata changes on all registered SO types', () =>
"ingest-agent-policies": "803dc27e106440c41e8f3c3d8ee8bbb0821bcde2",
"ingest-download-sources": "279a68147e62e4d8858c09ad1cf03bd5551ce58d",
"ingest-outputs": "daafff49255ab700e07491376fe89f04fc998b91",
"ingest-package-policies": "d63e091b2b3cf2eecaa46ae2533bdd5214a983fc",
"ingest-package-policies": "e6da7d0ee2996241ade23b3a7811fe5d3e449cb2",
"ingest_manager_settings": "91445219e7115ff0c45d1dabd5d614a80b421797",
"inventory-view": "b8683c8e352a286b4aca1ab21003115a4800af83",
"kql-telemetry": "93c1d16c1a0dfca9c8842062cf5ef8f62ae401ad",
Expand Down
9 changes: 9 additions & 0 deletions x-pack/plugins/fleet/server/saved_objects/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ import {
migratePackagePolicyEvictionsFromV81102,
} from './migrations/security_solution/to_v8_11_0_2';
import { settingsV1 } from './model_versions/v1';
import { packagePolicyV10OnWriteScanFix } from './model_versions/security_solution';

/*
* Saved object types and mappings
Expand Down Expand Up @@ -540,6 +541,14 @@ export const getSavedObjectTypes = (
},
],
},
'10': {
changes: [
{
type: 'data_backfill',
backfillFn: packagePolicyV10OnWriteScanFix,
},
],
},
},
migrations: {
'7.10.0': migratePackagePolicyToV7100,
Expand Down
Original file line number Diff line number Diff line change
@@ -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 { packagePolicyV10OnWriteScanFix } from './v10_on_write_scan_fix';
Original file line number Diff line number Diff line change
@@ -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 type { SavedObject } from '@kbn/core-saved-objects-api-server';
import type { ModelVersionTestMigrator } from '@kbn/core-test-helpers-model-versions';
import { createModelVersionTestMigrator } from '@kbn/core-test-helpers-model-versions';

import { getSavedObjectTypes } from '../..';

import type { PackagePolicy } from '../../../../common';
import { PACKAGE_POLICY_SAVED_OBJECT_TYPE } from '../../../../common';

describe('backfill for modelVersion 10 - fix on_write_scan field', () => {
let migrator: ModelVersionTestMigrator;
let policyConfigSO: SavedObject<PackagePolicy>;

beforeEach(() => {
migrator = createModelVersionTestMigrator({
type: getSavedObjectTypes()[PACKAGE_POLICY_SAVED_OBJECT_TYPE],
});

policyConfigSO = {
id: 'mock-saved-object-id',
attributes: {
name: 'Some Policy Name',
package: {
name: 'endpoint',
title: '',
version: '',
},
id: 'endpoint',
policy_id: '',
enabled: true,
namespace: '',
revision: 0,
updated_at: '',
updated_by: '',
created_at: '',
created_by: '',
inputs: [
{
type: 'endpoint',
enabled: true,
streams: [],
config: {
policy: {
value: {
windows: {
malware: {
mode: 'detect',
},
antivirus_registration: {
enabled: true,
},
},
mac: {
malware: {
mode: 'detect',
},
},
linux: {
malware: {
mode: 'detect',
},
},
},
},
},
},
],
},
type: PACKAGE_POLICY_SAVED_OBJECT_TYPE,
references: [],
};
});

describe('when updating to model version 10', () => {
it('should change `on_write_scan` from `true` to `false` if Malware is off', () => {
setMalwareMode(policyConfigSO, 'off');
setOnWriteScan(policyConfigSO, true);

const migratedPolicyConfigSO = migrator.migrate<PackagePolicy, PackagePolicy>({
document: policyConfigSO,
fromVersion: 9,
toVersion: 10,
});

expectOnWriteScanToBe(false, migratedPolicyConfigSO);
});

it('should not change `on_write_scan` if Malware is detect', () => {
setMalwareMode(policyConfigSO, 'detect');
setOnWriteScan(policyConfigSO, true);

const migratedPolicyConfigSO = migrator.migrate<PackagePolicy, PackagePolicy>({
document: policyConfigSO,
fromVersion: 9,
toVersion: 10,
});

expectOnWriteScanToBe(true, migratedPolicyConfigSO);
});

it('should not change `on_write_scan` if Malware is prevent', () => {
setMalwareMode(policyConfigSO, 'prevent');
setOnWriteScan(policyConfigSO, true);

const migratedPolicyConfigSO = migrator.migrate<PackagePolicy, PackagePolicy>({
document: policyConfigSO,
fromVersion: 9,
toVersion: 10,
});

expectOnWriteScanToBe(true, migratedPolicyConfigSO);
});
});

describe('additional test: when updating from model version 5 to model version 10', () => {
it('should add `on_write_scan=false` if Malware is off', () => {
setMalwareMode(policyConfigSO, 'off');

const migratedPolicyConfigSO = migrator.migrate<PackagePolicy, PackagePolicy>({
document: policyConfigSO,
fromVersion: 5,
toVersion: 10,
});

expectOnWriteScanToBe(false, migratedPolicyConfigSO);
});

it('should add `on_write_scan=true` if Malware is detect', () => {
setMalwareMode(policyConfigSO, 'detect');

const migratedPolicyConfigSO = migrator.migrate<PackagePolicy, PackagePolicy>({
document: policyConfigSO,
fromVersion: 5,
toVersion: 10,
});

expectOnWriteScanToBe(true, migratedPolicyConfigSO);
});

it('should add `on_write_scan=true` if Malware is prevent', () => {
setMalwareMode(policyConfigSO, 'prevent');

const migratedPolicyConfigSO = migrator.migrate<PackagePolicy, PackagePolicy>({
document: policyConfigSO,
fromVersion: 5,
toVersion: 10,
});

expectOnWriteScanToBe(true, migratedPolicyConfigSO);
});
});

const setMalwareMode = (so: SavedObject<PackagePolicy>, level: 'off' | 'detect' | 'prevent') => {
const config = so.attributes.inputs[0].config?.policy.value;

config.windows.malware.mode = level;
config.mac.malware.mode = level;
config.linux.malware.mode = level;
};

const setOnWriteScan = (so: SavedObject<PackagePolicy>, value: boolean) => {
const config = so.attributes.inputs[0].config?.policy.value;

config.windows.malware.on_write_scan = value;
config.mac.malware.on_write_scan = value;
config.linux.malware.on_write_scan = value;
};

const expectOnWriteScanToBe = (expectedValue: boolean, so: SavedObject<PackagePolicy>) => {
const config = so.attributes.inputs[0].config?.policy.value;

expect(config.windows.malware.on_write_scan).toBe(expectedValue);
expect(config.mac.malware.on_write_scan).toBe(expectedValue);
expect(config.linux.malware.on_write_scan).toBe(expectedValue);
};
});
Original file line number Diff line number Diff line change
@@ -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 {
SavedObjectModelDataBackfillFn,
SavedObjectUnsanitizedDoc,
} from '@kbn/core-saved-objects-server';

import type { PackagePolicy } from '../../../../common';

export const packagePolicyV10OnWriteScanFix: SavedObjectModelDataBackfillFn<
PackagePolicy,
PackagePolicy
> = (packagePolicyDoc) => {
if (packagePolicyDoc.attributes.package?.name !== 'endpoint') {
return { attributes: packagePolicyDoc.attributes };
}

const updatedPackagePolicyDoc: SavedObjectUnsanitizedDoc<PackagePolicy> = packagePolicyDoc;

const input = updatedPackagePolicyDoc.attributes.inputs[0];

if (input && input.config) {
const policy = input.config.policy.value;

if (policy.windows.malware.mode === 'off') {
policy.windows.malware.on_write_scan = false;
}
if (policy.mac.malware.mode === 'off') {
policy.mac.malware.on_write_scan = false;
}
if (policy.linux.malware.mode === 'off') {
policy.linux.malware.on_write_scan = false;
}
}

return { attributes: updatedPackagePolicyDoc.attributes };
};

0 comments on commit 60cf299

Please sign in to comment.