From 022584ffae1505972c8e168ac922bd1abf8b4aac Mon Sep 17 00:00:00 2001 From: parkiino Date: Wed, 12 Jul 2023 17:26:46 -0400 Subject: [PATCH 01/22] disable switch and show conditional icon tip if defend integration not present --- .../agent_policy_advanced_fields/index.tsx | 30 ++++++++++++++++--- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.tsx index 8811a7d97ed610..369046c281f780 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.tsx @@ -103,6 +103,12 @@ export const AgentPolicyAdvancedOptionsContent: React.FunctionComponent = 'package_policies' in agentPolicy && agentPolicy?.package_policies?.some((packagePolicy) => packagePolicy.is_managed); + const defendIntegrationInstalled = + 'package_policies' in agentPolicy && + agentPolicy?.package_policies?.some( + (packagePolicy) => packagePolicy.package?.name === 'endpoint' + ); + const { agentTamperProtectionEnabled } = ExperimentalFeaturesService.get(); const licenseService = useLicense(); const [isUninstallCommandFlyoutOpen, setIsUninstallCommandFlyoutOpen] = useState(false); @@ -317,13 +323,29 @@ export const AgentPolicyAdvancedOptionsContent: React.FunctionComponent = } > + {' '} + {!defendIntegrationInstalled && ( + + )} + + } checked={agentPolicy.is_protected ?? false} onChange={(e) => { updateAgentPolicy({ is_protected: e.target.checked }); }} + disabled={!defendIntegrationInstalled} data-test-subj="tamperProtectionSwitch" /> {agentPolicy.id && ( @@ -333,7 +355,7 @@ export const AgentPolicyAdvancedOptionsContent: React.FunctionComponent = onClick={() => { setIsUninstallCommandFlyoutOpen(true); }} - disabled={agentPolicy.is_protected === false} + disabled={agentPolicy.is_protected === false || !defendIntegrationInstalled} data-test-subj="uninstallCommandLink" > {i18n.translate('xpack.fleet.agentPolicyForm.tamperingUninstallLink', { From e197b47a4d5757f10c4f3be7486d3dec7aeffb3d Mon Sep 17 00:00:00 2001 From: parkiino Date: Fri, 14 Jul 2023 10:57:19 -0400 Subject: [PATCH 02/22] unit tests for ui --- .../index.test.tsx | 35 +++++++++++++++++-- .../agent_policy_advanced_fields/index.tsx | 18 +++++----- 2 files changed, 43 insertions(+), 10 deletions(-) diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.test.tsx index 019395c0cb5f60..b36bd15bd34843 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.test.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.test.tsx @@ -17,6 +17,7 @@ import { allowedExperimentalValues } from '../../../../../../../common/experimen import { ExperimentalFeaturesService } from '../../../../../../services/experimental_features'; +import { createPackagePolicyMock } from '../../../../../../../common/mocks'; import type { NewAgentPolicy, AgentPolicy } from '../../../../../../../common/types'; import { useLicense } from '../../../../../../hooks/use_license'; @@ -48,7 +49,11 @@ describe('Agent policy advanced options content', () => { isPlatinum: () => true, } as unknown as LicenseService); - const render = ({ isProtected = false, policyId = 'agent-policy-1' } = {}) => { + const render = ({ + isProtected = false, + policyId = 'agent-policy-1', + packagePolicy = [createPackagePolicyMock()], + } = {}) => { // remove when feature flag is removed ExperimentalFeaturesService.init({ ...allowedExperimentalValues, @@ -57,7 +62,12 @@ describe('Agent policy advanced options content', () => { renderResult = testRender.render( @@ -118,5 +128,26 @@ describe('Agent policy advanced options content', () => { }); expect(mockUpdateAgentPolicy).toHaveBeenCalledWith({ is_protected: true }); }); + describe('when the defend integration is not installed', () => { + beforeEach(() => { + usePlatinumLicense(); + render({ + packagePolicy: [ + { + ...createPackagePolicyMock(), + package: { name: 'not-endpoint', title: 'Not Endpoint', version: '0.1.0' }, + }, + ], + is_protected: true, + }); + }); + it('should disable the switch and uninstall command link', () => { + expect(renderResult.getByTestId('tamperProtectionSwitch')).toBeDisabled(); + expect(renderResult.getByTestId('uninstallCommandLink')).toBeDisabled(); + }); + it('should show an icon tip explaining why the switch is disabled', () => { + expect(renderResult.getByTestId('tamperMissingIntegrationTooltip')).toBeTruthy(); + }); + }); }); }); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.tsx index 369046c281f780..bde7d34bcbc0f4 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.tsx @@ -330,14 +330,16 @@ export const AgentPolicyAdvancedOptionsContent: React.FunctionComponent = defaultMessage="Prevent agent tampering" />{' '} {!defendIntegrationInstalled && ( - + + + )} } From b3c30d0e726577302a220fd8b95c68dcda6b1e7c Mon Sep 17 00:00:00 2001 From: Candace Park Date: Tue, 25 Jul 2023 02:03:08 -0400 Subject: [PATCH 03/22] change tamper protection to false when endpoint package is deleted --- .../common/services/agent_policies_helpers.ts | 11 ++++++++- x-pack/plugins/fleet/common/services/index.ts | 1 + .../agent_policy_advanced_fields/index.tsx | 14 ++++------- .../fleet/server/services/agent_policy.ts | 23 +++++++++++++++---- .../fleet/server/services/package_policy.ts | 10 ++++++++ 5 files changed, 45 insertions(+), 14 deletions(-) diff --git a/x-pack/plugins/fleet/common/services/agent_policies_helpers.ts b/x-pack/plugins/fleet/common/services/agent_policies_helpers.ts index 52ce24634886e2..87789f7d6a298a 100644 --- a/x-pack/plugins/fleet/common/services/agent_policies_helpers.ts +++ b/x-pack/plugins/fleet/common/services/agent_policies_helpers.ts @@ -6,7 +6,12 @@ */ import type { AgentPolicy } from '../types'; -import { FLEET_SERVER_PACKAGE, FLEET_APM_PACKAGE, FLEET_SYNTHETICS_PACKAGE } from '../constants'; +import { + FLEET_SERVER_PACKAGE, + FLEET_APM_PACKAGE, + FLEET_SYNTHETICS_PACKAGE, + FLEET_ENDPOINT_PACKAGE, +} from '../constants'; export function policyHasFleetServer(agentPolicy: AgentPolicy) { if (!agentPolicy.package_policies) { @@ -26,6 +31,10 @@ export function policyHasSyntheticsIntegration(agentPolicy: AgentPolicy) { return policyHasIntegration(agentPolicy, FLEET_SYNTHETICS_PACKAGE); } +export function policyHasDefendSecurity(agentPolicy: AgentPolicy) { + return policyHasIntegration(agentPolicy, FLEET_ENDPOINT_PACKAGE); +} + function policyHasIntegration(agentPolicy: AgentPolicy, packageName: string) { if (!agentPolicy.package_policies) { return false; diff --git a/x-pack/plugins/fleet/common/services/index.ts b/x-pack/plugins/fleet/common/services/index.ts index abf06ac54b07cf..04f74404ba382e 100644 --- a/x-pack/plugins/fleet/common/services/index.ts +++ b/x-pack/plugins/fleet/common/services/index.ts @@ -66,6 +66,7 @@ export { agentStatusesToSummary } from './agent_statuses_to_summary'; export { policyHasFleetServer, policyHasAPMIntegration, + policyHasEndpointSecurity, policyHasSyntheticsIntegration, } from './agent_policies_helpers'; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.tsx index bde7d34bcbc0f4..d9f864e44a4d52 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.tsx @@ -46,6 +46,8 @@ import type { ValidationResults } from '../agent_policy_validation'; import { ExperimentalFeaturesService, policyHasFleetServer } from '../../../../services'; +import { policyHasEndpointSecurity } from '../../../../../../../common/services'; + import { useOutputOptions, useDownloadSourcesOptions, @@ -103,12 +105,6 @@ export const AgentPolicyAdvancedOptionsContent: React.FunctionComponent = 'package_policies' in agentPolicy && agentPolicy?.package_policies?.some((packagePolicy) => packagePolicy.is_managed); - const defendIntegrationInstalled = - 'package_policies' in agentPolicy && - agentPolicy?.package_policies?.some( - (packagePolicy) => packagePolicy.package?.name === 'endpoint' - ); - const { agentTamperProtectionEnabled } = ExperimentalFeaturesService.get(); const licenseService = useLicense(); const [isUninstallCommandFlyoutOpen, setIsUninstallCommandFlyoutOpen] = useState(false); @@ -329,7 +325,7 @@ export const AgentPolicyAdvancedOptionsContent: React.FunctionComponent = id="xpack.fleet.agentPolicyForm.tamperingSwitchLabel" defaultMessage="Prevent agent tampering" />{' '} - {!defendIntegrationInstalled && ( + {!policyHasEndpointSecurity && ( = onChange={(e) => { updateAgentPolicy({ is_protected: e.target.checked }); }} - disabled={!defendIntegrationInstalled} + disabled={!policyHasEndpointSecurity} data-test-subj="tamperProtectionSwitch" /> {agentPolicy.id && ( @@ -357,7 +353,7 @@ export const AgentPolicyAdvancedOptionsContent: React.FunctionComponent = onClick={() => { setIsUninstallCommandFlyoutOpen(true); }} - disabled={agentPolicy.is_protected === false || !defendIntegrationInstalled} + disabled={agentPolicy.is_protected === false || !policyHasEndpointSecurity} data-test-subj="uninstallCommandLink" > {i18n.translate('xpack.fleet.agentPolicyForm.tamperingUninstallLink', { diff --git a/x-pack/plugins/fleet/server/services/agent_policy.ts b/x-pack/plugins/fleet/server/services/agent_policy.ts index 6958ea80c00d60..197e4331d376ed 100644 --- a/x-pack/plugins/fleet/server/services/agent_policy.ts +++ b/x-pack/plugins/fleet/server/services/agent_policy.ts @@ -22,6 +22,8 @@ import type { BulkResponseItem } from '@elastic/elasticsearch/lib/api/typesWithB import { DEFAULT_SPACE_ID } from '@kbn/spaces-plugin/common/constants'; +import { policyHasEndpointSecurity } from '../../common/services'; + import { populateAssignedAgentsCount } from '../routes/agent_policy/handlers'; import type { HTTPAuthorizationHeader } from '../../common/http_authorization_header'; @@ -113,7 +115,10 @@ class AgentPolicyService { id: string, agentPolicy: Partial, user?: AuthenticatedUser, - options: { bumpRevision: boolean } = { bumpRevision: true } + options: { bumpRevision: boolean; removeProtection: boolean } = { + bumpRevision: true, + removeProtection: false, + } ): Promise { auditLoggingService.writeCustomSoAuditLog({ action: 'update', @@ -145,11 +150,14 @@ class AgentPolicyService { await soClient.update(SAVED_OBJECT_TYPE, id, { ...agentPolicy, ...(options.bumpRevision ? { revision: existingAgentPolicy.revision + 1 } : {}), + ...(options.removeProtection + ? { is_protected: false } + : { is_protected: existingAgentPolicy.is_protected }), updated_at: new Date().toISOString(), updated_by: user ? user.username : 'system', }); - if (options.bumpRevision) { + if (options.bumpRevision || options.removeProtection) { await this.triggerAgentPolicyUpdatedEvent(soClient, esClient, 'updated', id); } @@ -491,6 +499,10 @@ class AgentPolicyService { this.checkTamperProtectionLicense(agentPolicy); + if (agentPolicy?.is_protected && !policyHasEndpointSecurity) { + throw new Error('Agent policy requires Elastic Defend integration'); + } + if (existingAgentPolicy.is_managed && !options?.force) { Object.entries(agentPolicy) .filter(([key]) => !KEY_EDITABLE_FOR_MANAGED_POLICIES.includes(key)) @@ -586,9 +598,12 @@ class AgentPolicyService { soClient: SavedObjectsClientContract, esClient: ElasticsearchClient, id: string, - options?: { user?: AuthenticatedUser } + options?: { user?: AuthenticatedUser; removeProtection?: boolean } ): Promise { - const res = await this._update(soClient, esClient, id, {}, options?.user); + const res = await this._update(soClient, esClient, id, {}, options?.user, { + bumpRevision: true, + removeProtection: options?.removeProtection ?? false, + }); return res; } diff --git a/x-pack/plugins/fleet/server/services/package_policy.ts b/x-pack/plugins/fleet/server/services/package_policy.ts index c17f8f4ec2ea3c..019fab3fe1d156 100644 --- a/x-pack/plugins/fleet/server/services/package_policy.ts +++ b/x-pack/plugins/fleet/server/services/package_policy.ts @@ -1162,13 +1162,23 @@ class PackagePolicyClientImpl implements PackagePolicyClient { ...new Set(result.filter((r) => r.success && r.policy_id).map((r) => r.policy_id!)), ]; + const agentPoliciesWithEndpointPackagePolicies = [ + ...new Set( + result + .filter((r) => r.success && r.policy_id && r.package?.name === 'endpoint') + .map((r) => r.policy_id!) + ), + ]; + const agentPolicies = await agentPolicyService.getByIDs(soClient, uniquePolicyIdsR); for (const policyId of uniquePolicyIdsR) { const agentPolicy = agentPolicies.find((p) => p.id === policyId); if (agentPolicy) { + // is the agent policy attached to package policy with endpoint await agentPolicyService.bumpRevision(soClient, esClient, policyId, { user: options?.user, + removeProtection: agentPoliciesWithEndpointPackagePolicies.includes(policyId), }); } } From c4e900e34660496a1c53f2065d0538103e0fd79d Mon Sep 17 00:00:00 2001 From: Candace Park Date: Tue, 25 Jul 2023 10:50:15 -0400 Subject: [PATCH 04/22] fix type errors --- x-pack/plugins/fleet/common/services/agent_policies_helpers.ts | 2 +- .../components/agent_policy_advanced_fields/index.test.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/fleet/common/services/agent_policies_helpers.ts b/x-pack/plugins/fleet/common/services/agent_policies_helpers.ts index 87789f7d6a298a..85de9b73a69ad0 100644 --- a/x-pack/plugins/fleet/common/services/agent_policies_helpers.ts +++ b/x-pack/plugins/fleet/common/services/agent_policies_helpers.ts @@ -31,7 +31,7 @@ export function policyHasSyntheticsIntegration(agentPolicy: AgentPolicy) { return policyHasIntegration(agentPolicy, FLEET_SYNTHETICS_PACKAGE); } -export function policyHasDefendSecurity(agentPolicy: AgentPolicy) { +export function policyHasEndpointSecurity(agentPolicy: AgentPolicy) { return policyHasIntegration(agentPolicy, FLEET_ENDPOINT_PACKAGE); } diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.test.tsx index b36bd15bd34843..f6cd62719098cc 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.test.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.test.tsx @@ -138,7 +138,7 @@ describe('Agent policy advanced options content', () => { package: { name: 'not-endpoint', title: 'Not Endpoint', version: '0.1.0' }, }, ], - is_protected: true, + isProtected: true, }); }); it('should disable the switch and uninstall command link', () => { From 06450af3a636cd7c0d367d94704df1382a13d662 Mon Sep 17 00:00:00 2001 From: Candace Park Date: Thu, 27 Jul 2023 02:10:43 -0400 Subject: [PATCH 05/22] wip remove is protected from agent policy create --- .../services/generate_new_agent_policy.ts | 1 - .../fleet/common/types/models/agent_policy.ts | 1 - .../agent_policy_advanced_fields/index.tsx | 19 +++++++++++++------ .../fleet/server/services/agent_policy.ts | 3 --- .../fleet/server/types/models/agent_policy.ts | 2 +- 5 files changed, 14 insertions(+), 12 deletions(-) diff --git a/x-pack/plugins/fleet/common/services/generate_new_agent_policy.ts b/x-pack/plugins/fleet/common/services/generate_new_agent_policy.ts index 58e01bb2748ee9..1dc5045aaf68e0 100644 --- a/x-pack/plugins/fleet/common/services/generate_new_agent_policy.ts +++ b/x-pack/plugins/fleet/common/services/generate_new_agent_policy.ts @@ -21,7 +21,6 @@ export function generateNewAgentPolicyWithDefaults( namespace: 'default', monitoring_enabled: Object.values(dataTypes), inactivity_timeout: TWO_WEEKS_SECONDS, - is_protected: false, ...overrideProps, }; } diff --git a/x-pack/plugins/fleet/common/types/models/agent_policy.ts b/x-pack/plugins/fleet/common/types/models/agent_policy.ts index 4268bcca3b042a..12aeb553517d51 100644 --- a/x-pack/plugins/fleet/common/types/models/agent_policy.ts +++ b/x-pack/plugins/fleet/common/types/models/agent_policy.ts @@ -33,7 +33,6 @@ export interface NewAgentPolicy { fleet_server_host_id?: string | null; schema_version?: string; agent_features?: Array<{ name: string; enabled: boolean }>; - is_protected?: boolean; overrides?: { [key: string]: any } | null; } diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.tsx index d9f864e44a4d52..d1f79e625ffddd 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.tsx @@ -109,6 +109,9 @@ export const AgentPolicyAdvancedOptionsContent: React.FunctionComponent = const licenseService = useLicense(); const [isUninstallCommandFlyoutOpen, setIsUninstallCommandFlyoutOpen] = useState(false); + const isAgentPolicy = (policy: Partial): policy is AgentPolicy => + (policy as AgentPolicy).is_protected !== undefined; + return ( <> = id="xpack.fleet.agentPolicyForm.tamperingSwitchLabel" defaultMessage="Prevent agent tampering" />{' '} - {!policyHasEndpointSecurity && ( + {!policyHasEndpointSecurity(agentPolicy) && ( = )} } - checked={agentPolicy.is_protected ?? false} + checked={isAgentPolicy(agentPolicy) ? agentPolicy.is_protected : false} onChange={(e) => { updateAgentPolicy({ is_protected: e.target.checked }); }} - disabled={!policyHasEndpointSecurity} + disabled={!policyHasEndpointSecurity(agentPolicy)} data-test-subj="tamperProtectionSwitch" /> {agentPolicy.id && ( @@ -353,7 +356,11 @@ export const AgentPolicyAdvancedOptionsContent: React.FunctionComponent = onClick={() => { setIsUninstallCommandFlyoutOpen(true); }} - disabled={agentPolicy.is_protected === false || !policyHasEndpointSecurity} + disabled={ + isAgentPolicy(agentPolicy) + ? agentPolicy.is_protected + : false || !policyHasEndpointSecurity(agentPolicy) + } data-test-subj="uninstallCommandLink" > {i18n.translate('xpack.fleet.agentPolicyForm.tamperingUninstallLink', { diff --git a/x-pack/plugins/fleet/server/services/agent_policy.ts b/x-pack/plugins/fleet/server/services/agent_policy.ts index 197e4331d376ed..e2b80e9523107d 100644 --- a/x-pack/plugins/fleet/server/services/agent_policy.ts +++ b/x-pack/plugins/fleet/server/services/agent_policy.ts @@ -245,8 +245,6 @@ class AgentPolicyService { savedObjectType: AGENT_POLICY_SAVED_OBJECT_TYPE, }); - this.checkTamperProtectionLicense(agentPolicy); - await this.requireUniqueName(soClient, agentPolicy); await validateOutputForPolicy(soClient, agentPolicy); @@ -261,7 +259,6 @@ class AgentPolicyService { updated_at: new Date().toISOString(), updated_by: options?.user?.username || 'system', schema_version: FLEET_AGENT_POLICIES_SCHEMA_VERSION, - is_protected: agentPolicy.is_protected ?? false, } as AgentPolicy, options ); diff --git a/x-pack/plugins/fleet/server/types/models/agent_policy.ts b/x-pack/plugins/fleet/server/types/models/agent_policy.ts index 0fb27475c0779e..58eed676c64b48 100644 --- a/x-pack/plugins/fleet/server/types/models/agent_policy.ts +++ b/x-pack/plugins/fleet/server/types/models/agent_policy.ts @@ -47,7 +47,6 @@ export const AgentPolicyBaseSchema = { }) ) ), - is_protected: schema.maybe(schema.boolean()), overrides: schema.maybe( schema.nullable( schema.recordOf(schema.string(), schema.any(), { @@ -73,6 +72,7 @@ export const AgentPolicySchema = schema.object({ schema.literal(agentPolicyStatuses.Active), schema.literal(agentPolicyStatuses.Inactive), ]), + is_protected: schema.maybe(schema.boolean()), package_policies: schema.oneOf([ schema.arrayOf(schema.string()), schema.arrayOf(PackagePolicySchema), From bafa87ee48a465bcd04c4ae867af518ad426f756 Mon Sep 17 00:00:00 2001 From: Candace Park Date: Thu, 27 Jul 2023 15:52:39 -0400 Subject: [PATCH 06/22] fix type, fix test --- .../common/services/agent_policies_helpers.ts | 16 +++++++++++++--- .../services/generate_new_agent_policy.test.ts | 2 -- .../agent_policy_advanced_fields/index.tsx | 5 +---- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/x-pack/plugins/fleet/common/services/agent_policies_helpers.ts b/x-pack/plugins/fleet/common/services/agent_policies_helpers.ts index 85de9b73a69ad0..e8f2c1d28d890c 100644 --- a/x-pack/plugins/fleet/common/services/agent_policies_helpers.ts +++ b/x-pack/plugins/fleet/common/services/agent_policies_helpers.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { AgentPolicy } from '../types'; +import type { NewAgentPolicy, AgentPolicy } from '../types'; import { FLEET_SERVER_PACKAGE, FLEET_APM_PACKAGE, @@ -13,6 +13,12 @@ import { FLEET_ENDPOINT_PACKAGE, } from '../constants'; +export function isAgentPolicy( + policy: Partial +): policy is AgentPolicy { + return (policy as AgentPolicy).is_protected !== undefined; +} + export function policyHasFleetServer(agentPolicy: AgentPolicy) { if (!agentPolicy.package_policies) { return false; @@ -31,8 +37,12 @@ export function policyHasSyntheticsIntegration(agentPolicy: AgentPolicy) { return policyHasIntegration(agentPolicy, FLEET_SYNTHETICS_PACKAGE); } -export function policyHasEndpointSecurity(agentPolicy: AgentPolicy) { - return policyHasIntegration(agentPolicy, FLEET_ENDPOINT_PACKAGE); +export function policyHasEndpointSecurity(agentPolicy: Partial) { + if (!isAgentPolicy(agentPolicy)) { + return false; + } else { + return policyHasIntegration(agentPolicy, FLEET_ENDPOINT_PACKAGE); + } } function policyHasIntegration(agentPolicy: AgentPolicy, packageName: string) { diff --git a/x-pack/plugins/fleet/common/services/generate_new_agent_policy.test.ts b/x-pack/plugins/fleet/common/services/generate_new_agent_policy.test.ts index 97e63be4bd7013..930c734f76299c 100644 --- a/x-pack/plugins/fleet/common/services/generate_new_agent_policy.test.ts +++ b/x-pack/plugins/fleet/common/services/generate_new_agent_policy.test.ts @@ -17,7 +17,6 @@ describe('generateNewAgentPolicyWithDefaults', () => { namespace: 'default', monitoring_enabled: ['logs', 'metrics'], inactivity_timeout: 1209600, - is_protected: false, }); }); @@ -27,7 +26,6 @@ describe('generateNewAgentPolicyWithDefaults', () => { description: 'test description', namespace: 'test-namespace', monitoring_enabled: ['logs'], - is_protected: true, }); expect(newAgentPolicy).toEqual({ diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.tsx index d1f79e625ffddd..831ec502251a09 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.tsx @@ -46,7 +46,7 @@ import type { ValidationResults } from '../agent_policy_validation'; import { ExperimentalFeaturesService, policyHasFleetServer } from '../../../../services'; -import { policyHasEndpointSecurity } from '../../../../../../../common/services'; +import { isAgentPolicy, policyHasEndpointSecurity } from '../../../../../../../common/services'; import { useOutputOptions, @@ -109,9 +109,6 @@ export const AgentPolicyAdvancedOptionsContent: React.FunctionComponent = const licenseService = useLicense(); const [isUninstallCommandFlyoutOpen, setIsUninstallCommandFlyoutOpen] = useState(false); - const isAgentPolicy = (policy: Partial): policy is AgentPolicy => - (policy as AgentPolicy).is_protected !== undefined; - return ( <> Date: Thu, 27 Jul 2023 15:53:41 -0400 Subject: [PATCH 07/22] update index --- x-pack/plugins/fleet/common/services/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/x-pack/plugins/fleet/common/services/index.ts b/x-pack/plugins/fleet/common/services/index.ts index 04f74404ba382e..22da0d06783865 100644 --- a/x-pack/plugins/fleet/common/services/index.ts +++ b/x-pack/plugins/fleet/common/services/index.ts @@ -64,6 +64,7 @@ export { getAllowedOutputTypeForPolicy } from './output_helpers'; export { agentStatusesToSummary } from './agent_statuses_to_summary'; export { + isAgentPolicy, policyHasFleetServer, policyHasAPMIntegration, policyHasEndpointSecurity, From 55b797f67bd985de95377277cc03b26d659ab2e5 Mon Sep 17 00:00:00 2001 From: Candace Park Date: Thu, 27 Jul 2023 16:35:37 -0400 Subject: [PATCH 08/22] fixing tests --- x-pack/plugins/fleet/server/services/agent_policy.test.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/x-pack/plugins/fleet/server/services/agent_policy.test.ts b/x-pack/plugins/fleet/server/services/agent_policy.test.ts index 710ac46b945923..fd2f4f12818fa1 100644 --- a/x-pack/plugins/fleet/server/services/agent_policy.test.ts +++ b/x-pack/plugins/fleet/server/services/agent_policy.test.ts @@ -192,7 +192,6 @@ describe('agent policy', () => { agentPolicyService.create(soClient, esClient, { name: 'test', namespace: 'default', - is_protected: true, }) ).rejects.toThrowError( new FleetUnauthorizedError('Tamper protection requires Platinum license') From 2c602b5b3a1475bd9eb21f7d7686235162ff83a0 Mon Sep 17 00:00:00 2001 From: parkiino Date: Mon, 31 Jul 2023 16:50:04 -0400 Subject: [PATCH 09/22] remove is_protected from create agent policy tests --- .../server/integration_tests/cloud_preconfiguration.test.ts | 1 - x-pack/plugins/fleet/server/services/agent_policy.test.ts | 2 +- .../fleet_api_integration/apis/agent_policy/agent_policy.ts | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/x-pack/plugins/fleet/server/integration_tests/cloud_preconfiguration.test.ts b/x-pack/plugins/fleet/server/integration_tests/cloud_preconfiguration.test.ts index c6eaba98135f39..0c0d3104e39b7d 100644 --- a/x-pack/plugins/fleet/server/integration_tests/cloud_preconfiguration.test.ts +++ b/x-pack/plugins/fleet/server/integration_tests/cloud_preconfiguration.test.ts @@ -177,7 +177,6 @@ describe('Fleet preconfiguration reset', () => { metrics: false, }, protection: { - enabled: false, signing_key: '', uninstall_token_hash: '', }, diff --git a/x-pack/plugins/fleet/server/services/agent_policy.test.ts b/x-pack/plugins/fleet/server/services/agent_policy.test.ts index fd2f4f12818fa1..eb5bf788f14d81 100644 --- a/x-pack/plugins/fleet/server/services/agent_policy.test.ts +++ b/x-pack/plugins/fleet/server/services/agent_policy.test.ts @@ -182,7 +182,7 @@ describe('agent policy', () => { }); }); - it('should throw FleetUnauthorizedError if is_protected=true with insufficient license', () => { + it.skip('should throw FleetUnauthorizedError if is_protected=true with insufficient license', () => { jest.spyOn(licenseService, 'hasAtLeast').mockReturnValue(false); const soClient = getAgentPolicyCreateMock(); diff --git a/x-pack/test/fleet_api_integration/apis/agent_policy/agent_policy.ts b/x-pack/test/fleet_api_integration/apis/agent_policy/agent_policy.ts index 47d3f93fd8ddf5..615d8921d60899 100644 --- a/x-pack/test/fleet_api_integration/apis/agent_policy/agent_policy.ts +++ b/x-pack/test/fleet_api_integration/apis/agent_policy/agent_policy.ts @@ -119,7 +119,6 @@ export default function (providerContext: FtrProviderContext) { expect(body.item.is_managed).to.equal(false); expect(body.item.inactivity_timeout).to.equal(1209600); expect(body.item.status).to.be('active'); - expect(body.item.is_protected).to.equal(false); }); it('sets given is_managed value', async () => { From e92802814ab0b59b63203bc37592d3a7325bd50c Mon Sep 17 00:00:00 2001 From: parkiino Date: Mon, 31 Jul 2023 22:55:33 -0400 Subject: [PATCH 10/22] fix jest tests --- .../fleet/common/services/generate_new_agent_policy.test.ts | 1 - .../single_page_layout/index.test.tsx | 2 -- .../fleet_api_integration/apis/agent_policy/agent_policy.ts | 1 - 3 files changed, 4 deletions(-) diff --git a/x-pack/plugins/fleet/common/services/generate_new_agent_policy.test.ts b/x-pack/plugins/fleet/common/services/generate_new_agent_policy.test.ts index 930c734f76299c..5cd6c5d144019e 100644 --- a/x-pack/plugins/fleet/common/services/generate_new_agent_policy.test.ts +++ b/x-pack/plugins/fleet/common/services/generate_new_agent_policy.test.ts @@ -34,7 +34,6 @@ describe('generateNewAgentPolicyWithDefaults', () => { namespace: 'test-namespace', monitoring_enabled: ['logs'], inactivity_timeout: 1209600, - is_protected: true, }); }); }); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/index.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/index.test.tsx index 12ac34bf9fbb55..cec6f96b0532a0 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/index.test.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/index.test.tsx @@ -401,7 +401,6 @@ describe('when on the package policy create page', () => { name: 'Agent policy 2', namespace: 'default', inactivity_timeout: 1209600, - is_protected: false, }, { withSysMonitoring: false } ); @@ -433,7 +432,6 @@ describe('when on the package policy create page', () => { name: 'Agent policy 2', namespace: 'default', inactivity_timeout: 1209600, - is_protected: false, }, { withSysMonitoring: true } ); diff --git a/x-pack/test/fleet_api_integration/apis/agent_policy/agent_policy.ts b/x-pack/test/fleet_api_integration/apis/agent_policy/agent_policy.ts index 615d8921d60899..d2c2756928038f 100644 --- a/x-pack/test/fleet_api_integration/apis/agent_policy/agent_policy.ts +++ b/x-pack/test/fleet_api_integration/apis/agent_policy/agent_policy.ts @@ -444,7 +444,6 @@ export default function (providerContext: FtrProviderContext) { status: 'active', description: 'Test', is_managed: false, - is_protected: false, namespace: 'default', monitoring_enabled: ['logs', 'metrics'], revision: 1, From a201f24d60e0500faad699f6cd511ba18503ce59 Mon Sep 17 00:00:00 2001 From: parkiino Date: Tue, 1 Aug 2023 16:09:14 -0400 Subject: [PATCH 11/22] fix logic and memoize --- .../agent_policy_advanced_fields/index.tsx | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.tsx index 831ec502251a09..c6f1102119f4ec 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { useState } from 'react'; +import React, { useState, useMemo } from 'react'; import { EuiDescribedFormGroup, EuiFormRow, @@ -46,7 +46,10 @@ import type { ValidationResults } from '../agent_policy_validation'; import { ExperimentalFeaturesService, policyHasFleetServer } from '../../../../services'; -import { isAgentPolicy, policyHasEndpointSecurity } from '../../../../../../../common/services'; +import { + isAgentPolicy as isAgentPolicyType, + policyHasEndpointSecurity as hasElasticDefend, +} from '../../../../../../../common/services'; import { useOutputOptions, @@ -108,6 +111,8 @@ export const AgentPolicyAdvancedOptionsContent: React.FunctionComponent = const { agentTamperProtectionEnabled } = ExperimentalFeaturesService.get(); const licenseService = useLicense(); const [isUninstallCommandFlyoutOpen, setIsUninstallCommandFlyoutOpen] = useState(false); + const policyHasElasticDefend = useMemo(() => hasElasticDefend(agentPolicy), [agentPolicy]); + const isAgentPolicy = useMemo(() => isAgentPolicyType(agentPolicy), [agentPolicy]); return ( <> @@ -325,7 +330,7 @@ export const AgentPolicyAdvancedOptionsContent: React.FunctionComponent = id="xpack.fleet.agentPolicyForm.tamperingSwitchLabel" defaultMessage="Prevent agent tampering" />{' '} - {!policyHasEndpointSecurity(agentPolicy) && ( + {!policyHasElasticDefend && ( = )} } - checked={isAgentPolicy(agentPolicy) ? agentPolicy.is_protected : false} + checked={isAgentPolicy ? agentPolicy.is_protected : false} onChange={(e) => { updateAgentPolicy({ is_protected: e.target.checked }); }} - disabled={!policyHasEndpointSecurity(agentPolicy)} + disabled={!policyHasElasticDefend} data-test-subj="tamperProtectionSwitch" /> {agentPolicy.id && ( @@ -354,9 +359,9 @@ export const AgentPolicyAdvancedOptionsContent: React.FunctionComponent = setIsUninstallCommandFlyoutOpen(true); }} disabled={ - isAgentPolicy(agentPolicy) - ? agentPolicy.is_protected - : false || !policyHasEndpointSecurity(agentPolicy) + isAgentPolicy + ? agentPolicy.is_protected !== true || !policyHasElasticDefend + : false } data-test-subj="uninstallCommandLink" > From 4cb96e1dcc60b54ea61db86f34b5f84ef6b4b6d3 Mon Sep 17 00:00:00 2001 From: parkiino Date: Wed, 2 Aug 2023 16:43:24 -0400 Subject: [PATCH 12/22] fix agent tamper ui --- .../common/services/agent_policies_helpers.ts | 2 +- .../services/agent_policy_config.test.ts | 9 ++++----- .../services/generate_new_agent_policy.ts | 18 +++++++++++++++++- x-pack/plugins/fleet/common/services/index.ts | 1 + .../agent_policy_advanced_fields/index.tsx | 5 ++--- .../fleet/server/services/agent_policy.ts | 4 ++-- .../fleet/server/services/package_policy.ts | 15 +++++++-------- .../fleet/server/types/models/agent_policy.ts | 1 - .../server/types/rest_spec/agent_policy.ts | 1 + 9 files changed, 35 insertions(+), 21 deletions(-) diff --git a/x-pack/plugins/fleet/common/services/agent_policies_helpers.ts b/x-pack/plugins/fleet/common/services/agent_policies_helpers.ts index e8f2c1d28d890c..0c3f22f14c0bf2 100644 --- a/x-pack/plugins/fleet/common/services/agent_policies_helpers.ts +++ b/x-pack/plugins/fleet/common/services/agent_policies_helpers.ts @@ -16,7 +16,7 @@ import { export function isAgentPolicy( policy: Partial ): policy is AgentPolicy { - return (policy as AgentPolicy).is_protected !== undefined; + return (policy as AgentPolicy).revision !== undefined; } export function policyHasFleetServer(agentPolicy: AgentPolicy) { diff --git a/x-pack/plugins/fleet/common/services/agent_policy_config.test.ts b/x-pack/plugins/fleet/common/services/agent_policy_config.test.ts index 70ee2ae631a3cc..d3233683f1ba1f 100644 --- a/x-pack/plugins/fleet/common/services/agent_policy_config.test.ts +++ b/x-pack/plugins/fleet/common/services/agent_policy_config.test.ts @@ -5,15 +5,14 @@ * 2.0. */ -import { pick } from 'lodash'; - import { licenseMock } from '@kbn/licensing-plugin/common/licensing.mock'; +import { pick } from 'lodash'; import { isAgentPolicyValidForLicense, unsetAgentPolicyAccordingToLicenseLevel, } from './agent_policy_config'; -import { generateNewAgentPolicyWithDefaults } from './generate_new_agent_policy'; +import { generateAgentPolicyWithDefaults } from './generate_new_agent_policy'; describe('agent policy config and licenses', () => { const Platinum = licenseMock.createLicense({ license: { type: 'platinum', mode: 'platinum' } }); @@ -34,13 +33,13 @@ describe('agent policy config and licenses', () => { }); describe('unsetAgentPolicyAccordingToLicenseLevel', () => { it('resets all paid features to default if license is gold', () => { - const defaults = pick(generateNewAgentPolicyWithDefaults(), 'is_protected'); + const defaults = pick(generateAgentPolicyWithDefaults(), 'is_protected'); const partialPolicy = { is_protected: true }; const retPolicy = unsetAgentPolicyAccordingToLicenseLevel(partialPolicy, Gold); expect(retPolicy).toEqual(defaults); }); it('does not change paid features if license is platinum', () => { - const expected = pick(generateNewAgentPolicyWithDefaults(), 'is_protected'); + const expected = pick(generateAgentPolicyWithDefaults(), 'is_protected'); const partialPolicy = { is_protected: false }; const expected2 = { is_protected: true }; const partialPolicy2 = { is_protected: true }; diff --git a/x-pack/plugins/fleet/common/services/generate_new_agent_policy.ts b/x-pack/plugins/fleet/common/services/generate_new_agent_policy.ts index 1dc5045aaf68e0..3da0fd219d3351 100644 --- a/x-pack/plugins/fleet/common/services/generate_new_agent_policy.ts +++ b/x-pack/plugins/fleet/common/services/generate_new_agent_policy.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { dataTypes } from '../constants'; +import { agentPolicyStatuses, dataTypes } from '../constants'; import type { AgentPolicy, NewAgentPolicy } from '../types'; @@ -25,6 +25,22 @@ export function generateNewAgentPolicyWithDefaults( }; } +export function generateAgentPolicyWithDefaults( + overrideProps: Partial = {} +): AgentPolicy { + return { + ...generateNewAgentPolicyWithDefaults(), + id: 'some-agent-policy-id', + status: agentPolicyStatuses.Active, + is_managed: false, + updated_at: '2023-08-21T19:20:23.794Z', + updated_by: 'elastic', + revision: 2, + is_protected: false, + ...overrideProps, + }; +} + export function agentPolicyWithoutPaidFeatures( agentPolicy: Partial ): Partial { diff --git a/x-pack/plugins/fleet/common/services/index.ts b/x-pack/plugins/fleet/common/services/index.ts index 22da0d06783865..4e3b0263c2a9a6 100644 --- a/x-pack/plugins/fleet/common/services/index.ts +++ b/x-pack/plugins/fleet/common/services/index.ts @@ -73,6 +73,7 @@ export { export { generateNewAgentPolicyWithDefaults, + generateAgentPolicyWithDefaults, agentPolicyWithoutPaidFeatures, } from './generate_new_agent_policy'; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.tsx index c6f1102119f4ec..b06ae687da4567 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.tsx @@ -112,7 +112,6 @@ export const AgentPolicyAdvancedOptionsContent: React.FunctionComponent = const licenseService = useLicense(); const [isUninstallCommandFlyoutOpen, setIsUninstallCommandFlyoutOpen] = useState(false); const policyHasElasticDefend = useMemo(() => hasElasticDefend(agentPolicy), [agentPolicy]); - const isAgentPolicy = useMemo(() => isAgentPolicyType(agentPolicy), [agentPolicy]); return ( <> @@ -344,7 +343,7 @@ export const AgentPolicyAdvancedOptionsContent: React.FunctionComponent = )} } - checked={isAgentPolicy ? agentPolicy.is_protected : false} + checked={isAgentPolicyType(agentPolicy) ? agentPolicy.is_protected : false} onChange={(e) => { updateAgentPolicy({ is_protected: e.target.checked }); }} @@ -359,7 +358,7 @@ export const AgentPolicyAdvancedOptionsContent: React.FunctionComponent = setIsUninstallCommandFlyoutOpen(true); }} disabled={ - isAgentPolicy + isAgentPolicyType(agentPolicy) ? agentPolicy.is_protected !== true || !policyHasElasticDefend : false } diff --git a/x-pack/plugins/fleet/server/services/agent_policy.ts b/x-pack/plugins/fleet/server/services/agent_policy.ts index e2b80e9523107d..b44a3b0b6522eb 100644 --- a/x-pack/plugins/fleet/server/services/agent_policy.ts +++ b/x-pack/plugins/fleet/server/services/agent_policy.ts @@ -152,7 +152,7 @@ class AgentPolicyService { ...(options.bumpRevision ? { revision: existingAgentPolicy.revision + 1 } : {}), ...(options.removeProtection ? { is_protected: false } - : { is_protected: existingAgentPolicy.is_protected }), + : { is_protected: agentPolicy.is_protected }), updated_at: new Date().toISOString(), updated_by: user ? user.username : 'system', }); @@ -496,7 +496,7 @@ class AgentPolicyService { this.checkTamperProtectionLicense(agentPolicy); - if (agentPolicy?.is_protected && !policyHasEndpointSecurity) { + if (agentPolicy?.is_protected && !policyHasEndpointSecurity(existingAgentPolicy)) { throw new Error('Agent policy requires Elastic Defend integration'); } diff --git a/x-pack/plugins/fleet/server/services/package_policy.ts b/x-pack/plugins/fleet/server/services/package_policy.ts index 019fab3fe1d156..293c504278decc 100644 --- a/x-pack/plugins/fleet/server/services/package_policy.ts +++ b/x-pack/plugins/fleet/server/services/package_policy.ts @@ -1162,13 +1162,12 @@ class PackagePolicyClientImpl implements PackagePolicyClient { ...new Set(result.filter((r) => r.success && r.policy_id).map((r) => r.policy_id!)), ]; - const agentPoliciesWithEndpointPackagePolicies = [ - ...new Set( - result - .filter((r) => r.success && r.policy_id && r.package?.name === 'endpoint') - .map((r) => r.policy_id!) - ), - ]; + const agentPoliciesWithEndpointPackagePolicies = result.reduce((acc, cur) => { + if (cur.success && cur.policy_id && cur.package?.name === 'endpoint') { + return acc.add(cur.policy_id); + } + return acc; + }, new Set()); const agentPolicies = await agentPolicyService.getByIDs(soClient, uniquePolicyIdsR); @@ -1178,7 +1177,7 @@ class PackagePolicyClientImpl implements PackagePolicyClient { // is the agent policy attached to package policy with endpoint await agentPolicyService.bumpRevision(soClient, esClient, policyId, { user: options?.user, - removeProtection: agentPoliciesWithEndpointPackagePolicies.includes(policyId), + removeProtection: agentPoliciesWithEndpointPackagePolicies.has(policyId), }); } } diff --git a/x-pack/plugins/fleet/server/types/models/agent_policy.ts b/x-pack/plugins/fleet/server/types/models/agent_policy.ts index 58eed676c64b48..bb8fd904d3c698 100644 --- a/x-pack/plugins/fleet/server/types/models/agent_policy.ts +++ b/x-pack/plugins/fleet/server/types/models/agent_policy.ts @@ -72,7 +72,6 @@ export const AgentPolicySchema = schema.object({ schema.literal(agentPolicyStatuses.Active), schema.literal(agentPolicyStatuses.Inactive), ]), - is_protected: schema.maybe(schema.boolean()), package_policies: schema.oneOf([ schema.arrayOf(schema.string()), schema.arrayOf(PackagePolicySchema), diff --git a/x-pack/plugins/fleet/server/types/rest_spec/agent_policy.ts b/x-pack/plugins/fleet/server/types/rest_spec/agent_policy.ts index 88cc6df372c119..88f03d2739ba61 100644 --- a/x-pack/plugins/fleet/server/types/rest_spec/agent_policy.ts +++ b/x-pack/plugins/fleet/server/types/rest_spec/agent_policy.ts @@ -65,6 +65,7 @@ export const UpdateAgentPolicyRequestSchema = { ...GetOneAgentPolicyRequestSchema, body: NewAgentPolicySchema.extends({ force: schema.maybe(schema.boolean()), + is_protected: schema.maybe(schema.boolean()), }), }; From e8b51a6e6c5e4f894b2860068b04d8063a5f3af5 Mon Sep 17 00:00:00 2001 From: parkiino Date: Thu, 3 Aug 2023 11:06:03 -0400 Subject: [PATCH 13/22] fix tests please? --- .../index.test.tsx | 27 ++++++++++++++----- .../apis/agent_policy/agent_policy.ts | 4 +-- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.test.tsx index f6cd62719098cc..8042ddbb0bc8b5 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.test.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.test.tsx @@ -18,11 +18,15 @@ import { allowedExperimentalValues } from '../../../../../../../common/experimen import { ExperimentalFeaturesService } from '../../../../../../services/experimental_features'; import { createPackagePolicyMock } from '../../../../../../../common/mocks'; -import type { NewAgentPolicy, AgentPolicy } from '../../../../../../../common/types'; +import type { AgentPolicy } from '../../../../../../../common/types'; import { useLicense } from '../../../../../../hooks/use_license'; import type { LicenseService } from '../../../../../../../common/services'; +import { + generateAgentPolicyWithDefaults, + generateNewAgentPolicyWithDefaults, +} from '../../../../../../../common/services'; import type { ValidationResults } from '../agent_policy_validation'; @@ -35,12 +39,7 @@ const mockedUseLicence = useLicense as jest.MockedFunction; describe('Agent policy advanced options content', () => { let testRender: TestRenderer; let renderResult: RenderResult; - - const mockAgentPolicy: Partial = { - name: 'some-agent-policy', - is_managed: false, - }; - + let mockAgentPolicy: Partial; const mockUpdateAgentPolicy = jest.fn(); const mockValidation = jest.fn() as unknown as ValidationResults; const usePlatinumLicense = () => @@ -52,6 +51,7 @@ describe('Agent policy advanced options content', () => { const render = ({ isProtected = false, policyId = 'agent-policy-1', + newAgentPolicy = false, packagePolicy = [createPackagePolicyMock()], } = {}) => { // remove when feature flag is removed @@ -60,6 +60,12 @@ describe('Agent policy advanced options content', () => { agentTamperProtectionEnabled: true, }); + if (newAgentPolicy) { + mockAgentPolicy = generateNewAgentPolicyWithDefaults(); + } else { + mockAgentPolicy = generateAgentPolicyWithDefaults(); + } + renderResult = testRender.render( { expect(renderResult.getByTestId('tamperMissingIntegrationTooltip')).toBeTruthy(); }); }); + describe('when the user is creating a new agent policy', () => { + it('should be disabled, since it has no package policies and therefore elastic defend integration is not installed', async () => { + usePlatinumLicense(); + render({ newAgentPolicy: true }); + expect(renderResult.getByTestId('tamperProtectionSwitch')).toBeDisabled(); + }); + }); }); }); diff --git a/x-pack/test/fleet_api_integration/apis/agent_policy/agent_policy.ts b/x-pack/test/fleet_api_integration/apis/agent_policy/agent_policy.ts index d2c2756928038f..f27d04db6b9c0e 100644 --- a/x-pack/test/fleet_api_integration/apis/agent_policy/agent_policy.ts +++ b/x-pack/test/fleet_api_integration/apis/agent_policy/agent_policy.ts @@ -730,7 +730,7 @@ export default function (providerContext: FtrProviderContext) { name: 'Updated name', description: 'Updated description', namespace: 'default', - is_protected: true, + is_protected: false, }) .expect(200); createdPolicyIds.push(updatedPolicy.id); @@ -748,7 +748,7 @@ export default function (providerContext: FtrProviderContext) { updated_by: 'elastic', inactivity_timeout: 1209600, package_policies: [], - is_protected: true, + is_protected: false, }); }); From b6000113c1562ac50a780c51449025054ee9edb0 Mon Sep 17 00:00:00 2001 From: parkiino Date: Thu, 3 Aug 2023 11:57:26 -0400 Subject: [PATCH 14/22] import --- .../components/agent_policy_advanced_fields/index.test.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.test.tsx index 8042ddbb0bc8b5..dca50236930bfa 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.test.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.test.tsx @@ -18,7 +18,7 @@ import { allowedExperimentalValues } from '../../../../../../../common/experimen import { ExperimentalFeaturesService } from '../../../../../../services/experimental_features'; import { createPackagePolicyMock } from '../../../../../../../common/mocks'; -import type { AgentPolicy } from '../../../../../../../common/types'; +import type { AgentPolicy, NewAgentPolicy } from '../../../../../../../common/types'; import { useLicense } from '../../../../../../hooks/use_license'; From 3f0b851f59f432d2a5c770c67046c80458e762ba Mon Sep 17 00:00:00 2001 From: parkiino Date: Tue, 8 Aug 2023 09:05:49 -0400 Subject: [PATCH 15/22] use agent policy mock --- .../services/agent_policy_config.test.ts | 7 ++++--- .../services/generate_new_agent_policy.ts | 18 +----------------- x-pack/plugins/fleet/common/services/index.ts | 1 - .../index.test.tsx | 9 +++------ 4 files changed, 8 insertions(+), 27 deletions(-) diff --git a/x-pack/plugins/fleet/common/services/agent_policy_config.test.ts b/x-pack/plugins/fleet/common/services/agent_policy_config.test.ts index d3233683f1ba1f..e9bd5aa23b5d9f 100644 --- a/x-pack/plugins/fleet/common/services/agent_policy_config.test.ts +++ b/x-pack/plugins/fleet/common/services/agent_policy_config.test.ts @@ -8,11 +8,12 @@ import { licenseMock } from '@kbn/licensing-plugin/common/licensing.mock'; import { pick } from 'lodash'; +import { createAgentPolicyMock } from '../mocks'; + import { isAgentPolicyValidForLicense, unsetAgentPolicyAccordingToLicenseLevel, } from './agent_policy_config'; -import { generateAgentPolicyWithDefaults } from './generate_new_agent_policy'; describe('agent policy config and licenses', () => { const Platinum = licenseMock.createLicense({ license: { type: 'platinum', mode: 'platinum' } }); @@ -33,13 +34,13 @@ describe('agent policy config and licenses', () => { }); describe('unsetAgentPolicyAccordingToLicenseLevel', () => { it('resets all paid features to default if license is gold', () => { - const defaults = pick(generateAgentPolicyWithDefaults(), 'is_protected'); + const defaults = pick(createAgentPolicyMock(), 'is_protected'); const partialPolicy = { is_protected: true }; const retPolicy = unsetAgentPolicyAccordingToLicenseLevel(partialPolicy, Gold); expect(retPolicy).toEqual(defaults); }); it('does not change paid features if license is platinum', () => { - const expected = pick(generateAgentPolicyWithDefaults(), 'is_protected'); + const expected = pick(createAgentPolicyMock(), 'is_protected'); const partialPolicy = { is_protected: false }; const expected2 = { is_protected: true }; const partialPolicy2 = { is_protected: true }; diff --git a/x-pack/plugins/fleet/common/services/generate_new_agent_policy.ts b/x-pack/plugins/fleet/common/services/generate_new_agent_policy.ts index 3da0fd219d3351..1dc5045aaf68e0 100644 --- a/x-pack/plugins/fleet/common/services/generate_new_agent_policy.ts +++ b/x-pack/plugins/fleet/common/services/generate_new_agent_policy.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { agentPolicyStatuses, dataTypes } from '../constants'; +import { dataTypes } from '../constants'; import type { AgentPolicy, NewAgentPolicy } from '../types'; @@ -25,22 +25,6 @@ export function generateNewAgentPolicyWithDefaults( }; } -export function generateAgentPolicyWithDefaults( - overrideProps: Partial = {} -): AgentPolicy { - return { - ...generateNewAgentPolicyWithDefaults(), - id: 'some-agent-policy-id', - status: agentPolicyStatuses.Active, - is_managed: false, - updated_at: '2023-08-21T19:20:23.794Z', - updated_by: 'elastic', - revision: 2, - is_protected: false, - ...overrideProps, - }; -} - export function agentPolicyWithoutPaidFeatures( agentPolicy: Partial ): Partial { diff --git a/x-pack/plugins/fleet/common/services/index.ts b/x-pack/plugins/fleet/common/services/index.ts index 4e3b0263c2a9a6..22da0d06783865 100644 --- a/x-pack/plugins/fleet/common/services/index.ts +++ b/x-pack/plugins/fleet/common/services/index.ts @@ -73,7 +73,6 @@ export { export { generateNewAgentPolicyWithDefaults, - generateAgentPolicyWithDefaults, agentPolicyWithoutPaidFeatures, } from './generate_new_agent_policy'; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.test.tsx index dca50236930bfa..98ed0bd06dad76 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.test.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.test.tsx @@ -17,16 +17,13 @@ import { allowedExperimentalValues } from '../../../../../../../common/experimen import { ExperimentalFeaturesService } from '../../../../../../services/experimental_features'; -import { createPackagePolicyMock } from '../../../../../../../common/mocks'; +import { createAgentPolicyMock, createPackagePolicyMock } from '../../../../../../../common/mocks'; import type { AgentPolicy, NewAgentPolicy } from '../../../../../../../common/types'; import { useLicense } from '../../../../../../hooks/use_license'; import type { LicenseService } from '../../../../../../../common/services'; -import { - generateAgentPolicyWithDefaults, - generateNewAgentPolicyWithDefaults, -} from '../../../../../../../common/services'; +import { generateNewAgentPolicyWithDefaults } from '../../../../../../../common/services'; import type { ValidationResults } from '../agent_policy_validation'; @@ -63,7 +60,7 @@ describe('Agent policy advanced options content', () => { if (newAgentPolicy) { mockAgentPolicy = generateNewAgentPolicyWithDefaults(); } else { - mockAgentPolicy = generateAgentPolicyWithDefaults(); + mockAgentPolicy = createAgentPolicyMock(); } renderResult = testRender.render( From 4d9ee3818a103981eba14463e411a5de31993703 Mon Sep 17 00:00:00 2001 From: parkiino Date: Thu, 10 Aug 2023 00:22:25 -0400 Subject: [PATCH 16/22] fix package.json and one api integration test --- x-pack/plugins/security_solution/package.json | 4 ++-- .../fleet_api_integration/apis/agent_policy/agent_policy.ts | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/security_solution/package.json b/x-pack/plugins/security_solution/package.json index e5e4b0b71caf85..37e207bf43e58e 100644 --- a/x-pack/plugins/security_solution/package.json +++ b/x-pack/plugins/security_solution/package.json @@ -13,10 +13,10 @@ "cypress:run:cases": "yarn cypress:run:reporter --browser chrome --spec './cypress/e2e/explore/cases/*.cy.ts' --ftr-config-file ../../../../../../x-pack/test/security_solution_cypress/cli_config; status=$?; yarn junit:merge && exit $status", "cypress:run:reporter": "TZ=UTC node ./scripts/start_cypress_parallel run --config-file ./cypress/cypress_ci.config.ts --ftr-config-file ../../../../../../x-pack/test/security_solution_cypress/cli_config --reporter ../../../node_modules/cypress-multi-reporters --reporter-options configFile=./cypress/reporter_config.json", "cypress:run:respops": "yarn cypress:run:reporter --browser chrome --spec './cypress/e2e/(detection_alerts|detection_rules|exceptions)/*.cy.ts' --ftr-config-file ../../../../../../x-pack/test/security_solution_cypress/cli_config; status=$?; yarn junit:merge && exit $status", - "cypress:dw:open": "node ./scripts/start_cypress_parallel open --config-file ./public/management/cypress.config.ts ts --ftr-config-file ../../../../../../x-pack/test/defend_workflows_cypress/cli_config", + "cypress:dw:open": "node ./scripts/start_cypress_parallel open --config-file ./public/management/cypress.config.ts --ftr-config-file ../../../../../../x-pack/test/defend_workflows_cypress/cli_config", "cypress:dw:run": "node ./scripts/start_cypress_parallel run --config-file ./public/management/cypress.config.ts --ftr-config-file ../../../../../../x-pack/test/defend_workflows_cypress/cli_config --reporter ../../../node_modules/cypress-multi-reporters --reporter-options configFile=./cypress/reporter_config.json; status=$?; yarn junit:merge && exit $status", "cypress:dw:endpoint:run": "node ./scripts/start_cypress_parallel run --config-file ./public/management/cypress_endpoint.config.ts --ftr-config-file ../../../../../../x-pack/test/defend_workflows_cypress/endpoint_config --reporter ../../../node_modules/cypress-multi-reporters --reporter-options configFile=./cypress/reporter_config.json --concurrency 1; status=$?; yarn junit:merge && exit $status", - "cypress:dw:endpoint:open": "node ./scripts/start_cypress_parallel open --config-file ./public/management/cypress_endpoint.config.ts ts --ftr-config-file ../../../../../../x-pack/test/defend_workflows_cypress/endpoint_config", + "cypress:dw:endpoint:open": "node ./scripts/start_cypress_parallel open --config-file ./public/management/cypress_endpoint.config.ts --ftr-config-file ../../../../../../x-pack/test/defend_workflows_cypress/endpoint_config", "cypress:investigations:run": "yarn cypress:run:reporter --browser chrome --spec './cypress/e2e/investigations/**/*.cy.ts' --ftr-config-file ../../../../../../x-pack/test/security_solution_cypress/cli_config; status=$?; yarn junit:merge && exit $status", "cypress:explore:run": "yarn cypress:run:reporter --browser chrome --spec './cypress/e2e/explore/**/*.cy.ts' --ftr-config-file ../../../../../../x-pack/test/security_solution_cypress/cli_config; status=$?; yarn junit:merge && exit $status", "junit:merge": "../../../node_modules/.bin/mochawesome-merge ../../../target/kibana-security-solution/cypress/results/mochawesome*.json > ../../../target/kibana-security-solution/cypress/results/output.json && ../../../node_modules/.bin/marge ../../../target/kibana-security-solution/cypress/results/output.json --reportDir ../../../target/kibana-security-solution/cypress/results && yarn junit:transform && mkdir -p ../../../target/junit && cp ../../../target/kibana-security-solution/cypress/results/*.xml ../../../target/junit/", diff --git a/x-pack/test/fleet_api_integration/apis/agent_policy/agent_policy.ts b/x-pack/test/fleet_api_integration/apis/agent_policy/agent_policy.ts index f27d04db6b9c0e..c11346faa750f7 100644 --- a/x-pack/test/fleet_api_integration/apis/agent_policy/agent_policy.ts +++ b/x-pack/test/fleet_api_integration/apis/agent_policy/agent_policy.ts @@ -969,7 +969,6 @@ export default function (providerContext: FtrProviderContext) { updated_by: 'elastic', inactivity_timeout: 1209600, package_policies: [], - is_protected: false, overrides: { agent: { logging: { From a6f4af3b598b6b2d786d763e5cf74ea136de8866 Mon Sep 17 00:00:00 2001 From: parkiino Date: Thu, 10 Aug 2023 01:48:30 -0400 Subject: [PATCH 17/22] add back is_protected in newagentpolicy and SO, set to false in new agent policy --- .../fleet/common/services/agent_policies_helpers.ts | 12 +----------- .../services/generate_new_agent_policy.test.ts | 2 ++ .../common/services/generate_new_agent_policy.ts | 1 + x-pack/plugins/fleet/common/services/index.ts | 1 - .../fleet/common/types/models/agent_policy.ts | 1 + .../agent_policy_advanced_fields/index.tsx | 13 +++---------- .../fleet/server/services/agent_policy.test.ts | 1 + .../plugins/fleet/server/services/agent_policy.ts | 13 ++++++++++++- .../fleet/server/types/models/agent_policy.ts | 1 + .../apis/agent_policy/agent_policy.ts | 2 ++ 10 files changed, 24 insertions(+), 23 deletions(-) diff --git a/x-pack/plugins/fleet/common/services/agent_policies_helpers.ts b/x-pack/plugins/fleet/common/services/agent_policies_helpers.ts index 0c3f22f14c0bf2..1ebe49ef4ed395 100644 --- a/x-pack/plugins/fleet/common/services/agent_policies_helpers.ts +++ b/x-pack/plugins/fleet/common/services/agent_policies_helpers.ts @@ -13,12 +13,6 @@ import { FLEET_ENDPOINT_PACKAGE, } from '../constants'; -export function isAgentPolicy( - policy: Partial -): policy is AgentPolicy { - return (policy as AgentPolicy).revision !== undefined; -} - export function policyHasFleetServer(agentPolicy: AgentPolicy) { if (!agentPolicy.package_policies) { return false; @@ -38,11 +32,7 @@ export function policyHasSyntheticsIntegration(agentPolicy: AgentPolicy) { } export function policyHasEndpointSecurity(agentPolicy: Partial) { - if (!isAgentPolicy(agentPolicy)) { - return false; - } else { - return policyHasIntegration(agentPolicy, FLEET_ENDPOINT_PACKAGE); - } + return policyHasIntegration(agentPolicy as AgentPolicy, FLEET_ENDPOINT_PACKAGE); } function policyHasIntegration(agentPolicy: AgentPolicy, packageName: string) { diff --git a/x-pack/plugins/fleet/common/services/generate_new_agent_policy.test.ts b/x-pack/plugins/fleet/common/services/generate_new_agent_policy.test.ts index 5cd6c5d144019e..bc4a6b55f75ee8 100644 --- a/x-pack/plugins/fleet/common/services/generate_new_agent_policy.test.ts +++ b/x-pack/plugins/fleet/common/services/generate_new_agent_policy.test.ts @@ -17,6 +17,7 @@ describe('generateNewAgentPolicyWithDefaults', () => { namespace: 'default', monitoring_enabled: ['logs', 'metrics'], inactivity_timeout: 1209600, + is_protected: false, }); }); @@ -34,6 +35,7 @@ describe('generateNewAgentPolicyWithDefaults', () => { namespace: 'test-namespace', monitoring_enabled: ['logs'], inactivity_timeout: 1209600, + is_protected: false, }); }); }); diff --git a/x-pack/plugins/fleet/common/services/generate_new_agent_policy.ts b/x-pack/plugins/fleet/common/services/generate_new_agent_policy.ts index 1dc5045aaf68e0..58e01bb2748ee9 100644 --- a/x-pack/plugins/fleet/common/services/generate_new_agent_policy.ts +++ b/x-pack/plugins/fleet/common/services/generate_new_agent_policy.ts @@ -21,6 +21,7 @@ export function generateNewAgentPolicyWithDefaults( namespace: 'default', monitoring_enabled: Object.values(dataTypes), inactivity_timeout: TWO_WEEKS_SECONDS, + is_protected: false, ...overrideProps, }; } diff --git a/x-pack/plugins/fleet/common/services/index.ts b/x-pack/plugins/fleet/common/services/index.ts index 22da0d06783865..04f74404ba382e 100644 --- a/x-pack/plugins/fleet/common/services/index.ts +++ b/x-pack/plugins/fleet/common/services/index.ts @@ -64,7 +64,6 @@ export { getAllowedOutputTypeForPolicy } from './output_helpers'; export { agentStatusesToSummary } from './agent_statuses_to_summary'; export { - isAgentPolicy, policyHasFleetServer, policyHasAPMIntegration, policyHasEndpointSecurity, diff --git a/x-pack/plugins/fleet/common/types/models/agent_policy.ts b/x-pack/plugins/fleet/common/types/models/agent_policy.ts index 12aeb553517d51..4268bcca3b042a 100644 --- a/x-pack/plugins/fleet/common/types/models/agent_policy.ts +++ b/x-pack/plugins/fleet/common/types/models/agent_policy.ts @@ -33,6 +33,7 @@ export interface NewAgentPolicy { fleet_server_host_id?: string | null; schema_version?: string; agent_features?: Array<{ name: string; enabled: boolean }>; + is_protected?: boolean; overrides?: { [key: string]: any } | null; } diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.tsx index b06ae687da4567..cb5b9b26f97ed5 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.tsx @@ -46,10 +46,7 @@ import type { ValidationResults } from '../agent_policy_validation'; import { ExperimentalFeaturesService, policyHasFleetServer } from '../../../../services'; -import { - isAgentPolicy as isAgentPolicyType, - policyHasEndpointSecurity as hasElasticDefend, -} from '../../../../../../../common/services'; +import { policyHasEndpointSecurity as hasElasticDefend } from '../../../../../../../common/services'; import { useOutputOptions, @@ -343,7 +340,7 @@ export const AgentPolicyAdvancedOptionsContent: React.FunctionComponent = )} } - checked={isAgentPolicyType(agentPolicy) ? agentPolicy.is_protected : false} + checked={agentPolicy.is_protected ?? false} onChange={(e) => { updateAgentPolicy({ is_protected: e.target.checked }); }} @@ -357,11 +354,7 @@ export const AgentPolicyAdvancedOptionsContent: React.FunctionComponent = onClick={() => { setIsUninstallCommandFlyoutOpen(true); }} - disabled={ - isAgentPolicyType(agentPolicy) - ? agentPolicy.is_protected !== true || !policyHasElasticDefend - : false - } + disabled={!agentPolicy.is_protected || !policyHasElasticDefend} data-test-subj="uninstallCommandLink" > {i18n.translate('xpack.fleet.agentPolicyForm.tamperingUninstallLink', { diff --git a/x-pack/plugins/fleet/server/services/agent_policy.test.ts b/x-pack/plugins/fleet/server/services/agent_policy.test.ts index eb5bf788f14d81..410520efec72b8 100644 --- a/x-pack/plugins/fleet/server/services/agent_policy.test.ts +++ b/x-pack/plugins/fleet/server/services/agent_policy.test.ts @@ -192,6 +192,7 @@ describe('agent policy', () => { agentPolicyService.create(soClient, esClient, { name: 'test', namespace: 'default', + is_protected: true, }) ).rejects.toThrowError( new FleetUnauthorizedError('Tamper protection requires Platinum license') diff --git a/x-pack/plugins/fleet/server/services/agent_policy.ts b/x-pack/plugins/fleet/server/services/agent_policy.ts index b44a3b0b6522eb..2f937b1ec7e682 100644 --- a/x-pack/plugins/fleet/server/services/agent_policy.ts +++ b/x-pack/plugins/fleet/server/services/agent_policy.ts @@ -245,6 +245,13 @@ class AgentPolicyService { savedObjectType: AGENT_POLICY_SAVED_OBJECT_TYPE, }); + this.checkTamperProtectionLicense(agentPolicy); + + if (agentPolicy?.is_protected) { + // throw new Error('Agent policy requires Elastic Defend integration'); + // need to add messaging to show above instead of error + } + await this.requireUniqueName(soClient, agentPolicy); await validateOutputForPolicy(soClient, agentPolicy); @@ -259,6 +266,7 @@ class AgentPolicyService { updated_at: new Date().toISOString(), updated_by: options?.user?.username || 'system', schema_version: FLEET_AGENT_POLICIES_SCHEMA_VERSION, + is_protected: false, } as AgentPolicy, options ); @@ -497,7 +505,10 @@ class AgentPolicyService { this.checkTamperProtectionLicense(agentPolicy); if (agentPolicy?.is_protected && !policyHasEndpointSecurity(existingAgentPolicy)) { - throw new Error('Agent policy requires Elastic Defend integration'); + // throw new Error('Agent policy requires Elastic Defend integration'); + // need to add messaging to show above instead of error + // force agent policy to be false if elastic defend is not present + agentPolicy.is_protected = false; } if (existingAgentPolicy.is_managed && !options?.force) { diff --git a/x-pack/plugins/fleet/server/types/models/agent_policy.ts b/x-pack/plugins/fleet/server/types/models/agent_policy.ts index bb8fd904d3c698..0fb27475c0779e 100644 --- a/x-pack/plugins/fleet/server/types/models/agent_policy.ts +++ b/x-pack/plugins/fleet/server/types/models/agent_policy.ts @@ -47,6 +47,7 @@ export const AgentPolicyBaseSchema = { }) ) ), + is_protected: schema.maybe(schema.boolean()), overrides: schema.maybe( schema.nullable( schema.recordOf(schema.string(), schema.any(), { diff --git a/x-pack/test/fleet_api_integration/apis/agent_policy/agent_policy.ts b/x-pack/test/fleet_api_integration/apis/agent_policy/agent_policy.ts index c11346faa750f7..90426d9bdfa3ed 100644 --- a/x-pack/test/fleet_api_integration/apis/agent_policy/agent_policy.ts +++ b/x-pack/test/fleet_api_integration/apis/agent_policy/agent_policy.ts @@ -450,6 +450,7 @@ export default function (providerContext: FtrProviderContext) { schema_version: FLEET_AGENT_POLICIES_SCHEMA_VERSION, updated_by: 'elastic', package_policies: [], + is_protected: false, }); }); @@ -969,6 +970,7 @@ export default function (providerContext: FtrProviderContext) { updated_by: 'elastic', inactivity_timeout: 1209600, package_policies: [], + is_protected: false, overrides: { agent: { logging: { From c3ac2cae1e7f034116cf4a9cca04993cf38a043f Mon Sep 17 00:00:00 2001 From: parkiino Date: Thu, 10 Aug 2023 15:49:03 -0400 Subject: [PATCH 18/22] reenable more is protected stuff --- .../single_page_layout/index.test.tsx | 2 ++ .../server/integration_tests/cloud_preconfiguration.test.ts | 1 + x-pack/plugins/fleet/server/services/agent_policy.test.ts | 2 +- x-pack/plugins/fleet/server/types/rest_spec/agent_policy.ts | 1 - 4 files changed, 4 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/index.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/index.test.tsx index cec6f96b0532a0..12ac34bf9fbb55 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/index.test.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/index.test.tsx @@ -401,6 +401,7 @@ describe('when on the package policy create page', () => { name: 'Agent policy 2', namespace: 'default', inactivity_timeout: 1209600, + is_protected: false, }, { withSysMonitoring: false } ); @@ -432,6 +433,7 @@ describe('when on the package policy create page', () => { name: 'Agent policy 2', namespace: 'default', inactivity_timeout: 1209600, + is_protected: false, }, { withSysMonitoring: true } ); diff --git a/x-pack/plugins/fleet/server/integration_tests/cloud_preconfiguration.test.ts b/x-pack/plugins/fleet/server/integration_tests/cloud_preconfiguration.test.ts index 0c0d3104e39b7d..c1dba845c1cef6 100644 --- a/x-pack/plugins/fleet/server/integration_tests/cloud_preconfiguration.test.ts +++ b/x-pack/plugins/fleet/server/integration_tests/cloud_preconfiguration.test.ts @@ -177,6 +177,7 @@ describe('Fleet preconfiguration reset', () => { metrics: false, }, protection: { + is_protected: false, signing_key: '', uninstall_token_hash: '', }, diff --git a/x-pack/plugins/fleet/server/services/agent_policy.test.ts b/x-pack/plugins/fleet/server/services/agent_policy.test.ts index 410520efec72b8..710ac46b945923 100644 --- a/x-pack/plugins/fleet/server/services/agent_policy.test.ts +++ b/x-pack/plugins/fleet/server/services/agent_policy.test.ts @@ -182,7 +182,7 @@ describe('agent policy', () => { }); }); - it.skip('should throw FleetUnauthorizedError if is_protected=true with insufficient license', () => { + it('should throw FleetUnauthorizedError if is_protected=true with insufficient license', () => { jest.spyOn(licenseService, 'hasAtLeast').mockReturnValue(false); const soClient = getAgentPolicyCreateMock(); diff --git a/x-pack/plugins/fleet/server/types/rest_spec/agent_policy.ts b/x-pack/plugins/fleet/server/types/rest_spec/agent_policy.ts index 88f03d2739ba61..88cc6df372c119 100644 --- a/x-pack/plugins/fleet/server/types/rest_spec/agent_policy.ts +++ b/x-pack/plugins/fleet/server/types/rest_spec/agent_policy.ts @@ -65,7 +65,6 @@ export const UpdateAgentPolicyRequestSchema = { ...GetOneAgentPolicyRequestSchema, body: NewAgentPolicySchema.extends({ force: schema.maybe(schema.boolean()), - is_protected: schema.maybe(schema.boolean()), }), }; From 30c1bb94aca3b18cc60845a9af6fa8244b627e7b Mon Sep 17 00:00:00 2001 From: parkiino Date: Thu, 10 Aug 2023 16:46:14 -0400 Subject: [PATCH 19/22] add kibana warning message --- .../cloud_preconfiguration.test.ts | 2 +- .../plugins/fleet/server/services/agent_policy.ts | 14 ++++++++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/x-pack/plugins/fleet/server/integration_tests/cloud_preconfiguration.test.ts b/x-pack/plugins/fleet/server/integration_tests/cloud_preconfiguration.test.ts index c1dba845c1cef6..c6eaba98135f39 100644 --- a/x-pack/plugins/fleet/server/integration_tests/cloud_preconfiguration.test.ts +++ b/x-pack/plugins/fleet/server/integration_tests/cloud_preconfiguration.test.ts @@ -177,7 +177,7 @@ describe('Fleet preconfiguration reset', () => { metrics: false, }, protection: { - is_protected: false, + enabled: false, signing_key: '', uninstall_token_hash: '', }, diff --git a/x-pack/plugins/fleet/server/services/agent_policy.ts b/x-pack/plugins/fleet/server/services/agent_policy.ts index 2f937b1ec7e682..1b23a02bc93690 100644 --- a/x-pack/plugins/fleet/server/services/agent_policy.ts +++ b/x-pack/plugins/fleet/server/services/agent_policy.ts @@ -247,9 +247,12 @@ class AgentPolicyService { this.checkTamperProtectionLicense(agentPolicy); + const logger = appContextService.getLogger(); + if (agentPolicy?.is_protected) { - // throw new Error('Agent policy requires Elastic Defend integration'); - // need to add messaging to show above instead of error + logger.warn( + 'Agent policy requires Elastic Defend integration to set tamper protection to true' + ); } await this.requireUniqueName(soClient, agentPolicy); @@ -504,9 +507,12 @@ class AgentPolicyService { this.checkTamperProtectionLicense(agentPolicy); + const logger = appContextService.getLogger(); + if (agentPolicy?.is_protected && !policyHasEndpointSecurity(existingAgentPolicy)) { - // throw new Error('Agent policy requires Elastic Defend integration'); - // need to add messaging to show above instead of error + logger.warn( + 'Agent policy requires Elastic Defend integration to set tamper protection to true' + ); // force agent policy to be false if elastic defend is not present agentPolicy.is_protected = false; } From cb807ebea05bbe639168f5e3806175ebc603901e Mon Sep 17 00:00:00 2001 From: parkiino Date: Thu, 10 Aug 2023 23:12:03 -0400 Subject: [PATCH 20/22] adjust tests --- .../agent_policy_advanced_fields/index.test.tsx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.test.tsx index 98ed0bd06dad76..fe21159ab347b3 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.test.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.test.tsx @@ -60,16 +60,18 @@ describe('Agent policy advanced options content', () => { if (newAgentPolicy) { mockAgentPolicy = generateNewAgentPolicyWithDefaults(); } else { - mockAgentPolicy = createAgentPolicyMock(); + mockAgentPolicy = { + ...createAgentPolicyMock(), + package_policies: packagePolicy, + id: policyId, + }; } renderResult = testRender.render( Date: Fri, 11 Aug 2023 15:28:56 -0400 Subject: [PATCH 21/22] update text to something more appropriate --- .../components/agent_policy_advanced_fields/index.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.tsx index cb5b9b26f97ed5..49288da22c9350 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.tsx @@ -333,7 +333,10 @@ export const AgentPolicyAdvancedOptionsContent: React.FunctionComponent = color="subdued" content={i18n.translate( 'xpack.fleet.agentPolicyForm.tamperingSwitchLabel.disabledWarning', - { defaultMessage: 'this is why its disabled' } + { + defaultMessage: + 'Elastic Defend integration is required to enable this feature', + } )} /> From ecb40ebf10aeb3b39dc1e90d1db56c1519435843 Mon Sep 17 00:00:00 2001 From: parkiino Date: Mon, 14 Aug 2023 00:39:22 -0400 Subject: [PATCH 22/22] add a logger for when agent policy tamper protection is set to false --- x-pack/plugins/fleet/server/services/agent_policy.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/x-pack/plugins/fleet/server/services/agent_policy.ts b/x-pack/plugins/fleet/server/services/agent_policy.ts index 1b23a02bc93690..44635eee45200a 100644 --- a/x-pack/plugins/fleet/server/services/agent_policy.ts +++ b/x-pack/plugins/fleet/server/services/agent_policy.ts @@ -141,6 +141,12 @@ class AgentPolicyService { ); } + const logger = appContextService.getLogger(); + + if (options.removeProtection) { + logger.warn(`Setting tamper protection for Agent Policy ${id} to false`); + } + await validateOutputForPolicy( soClient, agentPolicy,