@@ -38,7 +38,7 @@ import { ManifestManager } from './manifest_manager';
3838import type { EndpointArtifactClientInterface } from '../artifact_client' ;
3939import { EndpointError } from '../../../../../common/endpoint/errors' ;
4040import type { Artifact } from '@kbn/fleet-plugin/server' ;
41- import { ProductFeatureSecurityKey } from '@kbn/security-solution-features/keys' ;
41+ import { ProductFeatureKey } from '@kbn/security-solution-features/keys' ;
4242import type { ExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-types/src/response/exception_list_item_schema' ;
4343import {
4444 createFetchAllArtifactsIterableMock ,
@@ -47,6 +47,7 @@ import {
4747import type { ExperimentalFeatures } from '../../../../../common' ;
4848import { allowedExperimentalValues } from '../../../../../common' ;
4949import { SavedObjectsErrorHelpers } from '@kbn/core-saved-objects-server' ;
50+ import { createLicenseServiceMock } from '../../../../../common/license/mocks' ;
5051
5152const getArtifactObject = ( artifact : InternalArtifactSchema ) =>
5253 JSON . parse ( Buffer . from ( artifact . body ! , 'base64' ) . toString ( ) ) ;
@@ -863,7 +864,7 @@ describe('ManifestManager', () => {
863864 tags : [ 'policy:all' ] ,
864865 } ) ;
865866 const context = buildManifestManagerContextMock ( { } , [
866- ProductFeatureSecurityKey . endpointArtifactManagement ,
867+ ProductFeatureKey . endpointArtifactManagement ,
867868 ] ) ;
868869 const manifestManager = new ManifestManager ( context ) ;
869870
@@ -943,8 +944,8 @@ describe('ManifestManager', () => {
943944 tags : [ 'policy:all' ] ,
944945 } ) ;
945946 const context = buildManifestManagerContextMock ( { } , [
946- ProductFeatureSecurityKey . endpointArtifactManagement ,
947- ProductFeatureSecurityKey . endpointHostIsolationExceptions ,
947+ ProductFeatureKey . endpointArtifactManagement ,
948+ ProductFeatureKey . endpointHostIsolationExceptions ,
948949 ] ) ;
949950 const manifestManager = new ManifestManager ( context ) ;
950951
@@ -1129,6 +1130,15 @@ describe('ManifestManager', () => {
11291130 const context = buildManifestManagerContextMock ( {
11301131 experimentalFeatures : [ 'trustedDevices' ] ,
11311132 } ) ;
1133+ // Set up licensing to allow trusted devices (both PLI and enterprise)
1134+ context . productFeaturesService . isEnabled = jest . fn ( ) . mockImplementation ( ( key ) => {
1135+ return (
1136+ key === ProductFeatureKey . endpointTrustedDevices ||
1137+ key === ProductFeatureKey . endpointArtifactManagement
1138+ ) ;
1139+ } ) ;
1140+ context . licenseService = createLicenseServiceMock ( ) ;
1141+ context . licenseService . isEnterprise = jest . fn ( ) . mockReturnValue ( true ) ;
11321142 const manifestManager = new ManifestManager ( context ) ;
11331143
11341144 context . exceptionListClient . findExceptionListItem = mockFindExceptionListItemResponses ( { } ) ;
@@ -1224,6 +1234,14 @@ describe('ManifestManager', () => {
12241234 const context = buildManifestManagerContextMock ( {
12251235 experimentalFeatures : [ 'trustedDevices' ] ,
12261236 } ) ;
1237+ context . productFeaturesService . isEnabled = jest . fn ( ) . mockImplementation ( ( key ) => {
1238+ return (
1239+ key === ProductFeatureKey . endpointTrustedDevices ||
1240+ key === ProductFeatureKey . endpointArtifactManagement
1241+ ) ;
1242+ } ) ;
1243+ context . licenseService = createLicenseServiceMock ( ) ;
1244+ context . licenseService . isEnterprise = jest . fn ( ) . mockReturnValue ( true ) ;
12271245 const manifestManager = new ManifestManager ( context ) ;
12281246
12291247 context . exceptionListClient . findExceptionListItem = mockFindExceptionListItemResponses ( {
@@ -2428,4 +2446,176 @@ describe('ManifestManager', () => {
24282446 } ) ;
24292447 } ) ;
24302448 } ) ;
2449+
2450+ describe ( 'shouldRetrieveExceptions for trusted devices licensing logic' , ( ) => {
2451+ let manifestManager : ManifestManager ;
2452+ let context : ManifestManagerContext ;
2453+
2454+ beforeEach ( ( ) => {
2455+ context = buildManifestManagerContextMock ( { } ) ;
2456+ } ) ;
2457+
2458+ interface ManifestManagerWithPrivateMethods {
2459+ shouldRetrieveExceptions : ( listId : string ) => boolean ;
2460+ }
2461+
2462+ describe ( 'when trustedDevices feature flag is disabled' , ( ) => {
2463+ beforeEach ( ( ) => {
2464+ context = buildManifestManagerContextMock ( {
2465+ experimentalFeatures : [ ] , // No trustedDevices feature
2466+ } ) ;
2467+ context . licenseService = createLicenseServiceMock ( ) ;
2468+ manifestManager = new ManifestManager ( context ) ;
2469+ } ) ;
2470+
2471+ test ( 'should return false for trusted devices artifacts when feature flag is disabled' , ( ) => {
2472+ const shouldRetrieve = (
2473+ manifestManager as unknown as ManifestManagerWithPrivateMethods
2474+ ) . shouldRetrieveExceptions ( ENDPOINT_ARTIFACT_LISTS . trustedDevices . id ) ;
2475+ expect ( shouldRetrieve ) . toBe ( false ) ;
2476+ } ) ;
2477+
2478+ test ( 'should return true for other artifact types regardless of feature flag' , ( ) => {
2479+ const shouldRetrieveExceptions = (
2480+ manifestManager as unknown as ManifestManagerWithPrivateMethods
2481+ ) . shouldRetrieveExceptions ( ENDPOINT_ARTIFACT_LISTS . endpointExceptions . id ) ;
2482+ const shouldRetrieveTrustedApps = (
2483+ manifestManager as unknown as ManifestManagerWithPrivateMethods
2484+ ) . shouldRetrieveExceptions ( ENDPOINT_ARTIFACT_LISTS . trustedApps . id ) ;
2485+
2486+ expect ( shouldRetrieveExceptions ) . toBe ( true ) ;
2487+ expect ( shouldRetrieveTrustedApps ) . toBe ( true ) ;
2488+ } ) ;
2489+ } ) ;
2490+
2491+ describe ( 'when trustedDevices feature flag is enabled' , ( ) => {
2492+ beforeEach ( ( ) => {
2493+ context = buildManifestManagerContextMock ( {
2494+ experimentalFeatures : [ 'trustedDevices' ] ,
2495+ } ) ;
2496+ context . licenseService = createLicenseServiceMock ( ) ;
2497+ } ) ;
2498+
2499+ test ( 'should return false when only PLI is enabled (enterprise required)' , ( ) => {
2500+ context . productFeaturesService . isEnabled = jest . fn ( ) . mockImplementation ( ( key ) => {
2501+ return key === ProductFeatureKey . endpointTrustedDevices ;
2502+ } ) ;
2503+ context . licenseService . isEnterprise = jest . fn ( ) . mockReturnValue ( false ) ;
2504+ manifestManager = new ManifestManager ( context ) ;
2505+
2506+ const shouldRetrieve = (
2507+ manifestManager as unknown as ManifestManagerWithPrivateMethods
2508+ ) . shouldRetrieveExceptions ( ENDPOINT_ARTIFACT_LISTS . trustedDevices . id ) ;
2509+
2510+ expect ( shouldRetrieve ) . toBe ( false ) ;
2511+ expect ( context . productFeaturesService . isEnabled ) . toHaveBeenCalledWith (
2512+ ProductFeatureKey . endpointTrustedDevices
2513+ ) ;
2514+ } ) ;
2515+
2516+ test ( 'should return false when only enterprise license is present (PLI required)' , ( ) => {
2517+ context . productFeaturesService . isEnabled = jest . fn ( ) . mockReturnValue ( false ) ;
2518+ context . licenseService . isEnterprise = jest . fn ( ) . mockReturnValue ( true ) ;
2519+ manifestManager = new ManifestManager ( context ) ;
2520+
2521+ const shouldRetrieve = (
2522+ manifestManager as unknown as ManifestManagerWithPrivateMethods
2523+ ) . shouldRetrieveExceptions ( ENDPOINT_ARTIFACT_LISTS . trustedDevices . id ) ;
2524+
2525+ expect ( shouldRetrieve ) . toBe ( false ) ;
2526+ } ) ;
2527+
2528+ test ( 'should return true when both PLI and enterprise license are enabled' , ( ) => {
2529+ context . productFeaturesService . isEnabled = jest . fn ( ) . mockImplementation ( ( key ) => {
2530+ return key === ProductFeatureKey . endpointTrustedDevices ;
2531+ } ) ;
2532+ context . licenseService . isEnterprise = jest . fn ( ) . mockReturnValue ( true ) ;
2533+ manifestManager = new ManifestManager ( context ) ;
2534+
2535+ const shouldRetrieve = (
2536+ manifestManager as unknown as ManifestManagerWithPrivateMethods
2537+ ) . shouldRetrieveExceptions ( ENDPOINT_ARTIFACT_LISTS . trustedDevices . id ) ;
2538+
2539+ expect ( shouldRetrieve ) . toBe ( true ) ;
2540+ expect ( context . productFeaturesService . isEnabled ) . toHaveBeenCalledWith (
2541+ ProductFeatureKey . endpointTrustedDevices
2542+ ) ;
2543+ expect ( context . licenseService . isEnterprise ) . toHaveBeenCalled ( ) ;
2544+ } ) ;
2545+
2546+ test ( 'should return false when neither PLI nor enterprise license are enabled' , ( ) => {
2547+ context . productFeaturesService . isEnabled = jest . fn ( ) . mockReturnValue ( false ) ;
2548+ context . licenseService . isEnterprise = jest . fn ( ) . mockReturnValue ( false ) ;
2549+ manifestManager = new ManifestManager ( context ) ;
2550+
2551+ const shouldRetrieve = (
2552+ manifestManager as unknown as ManifestManagerWithPrivateMethods
2553+ ) . shouldRetrieveExceptions ( ENDPOINT_ARTIFACT_LISTS . trustedDevices . id ) ;
2554+
2555+ expect ( shouldRetrieve ) . toBe ( false ) ;
2556+ expect ( context . productFeaturesService . isEnabled ) . toHaveBeenCalledWith (
2557+ ProductFeatureKey . endpointTrustedDevices
2558+ ) ;
2559+ } ) ;
2560+ } ) ;
2561+
2562+ describe ( 'host isolation exceptions licensing logic' , ( ) => {
2563+ beforeEach ( ( ) => {
2564+ context = buildManifestManagerContextMock ( { } ) ;
2565+ context . licenseService = createLicenseServiceMock ( ) ;
2566+ } ) ;
2567+
2568+ test ( 'should return true for host isolation exceptions when product feature is enabled' , ( ) => {
2569+ context . productFeaturesService . isEnabled = jest . fn ( ) . mockImplementation ( ( key ) => {
2570+ return key === ProductFeatureKey . endpointHostIsolationExceptions ;
2571+ } ) ;
2572+ manifestManager = new ManifestManager ( context ) ;
2573+
2574+ const shouldRetrieve = (
2575+ manifestManager as unknown as ManifestManagerWithPrivateMethods
2576+ ) . shouldRetrieveExceptions ( ENDPOINT_ARTIFACT_LISTS . hostIsolationExceptions . id ) ;
2577+
2578+ expect ( shouldRetrieve ) . toBe ( true ) ;
2579+ expect ( context . productFeaturesService . isEnabled ) . toHaveBeenCalledWith (
2580+ ProductFeatureKey . endpointHostIsolationExceptions
2581+ ) ;
2582+ } ) ;
2583+
2584+ test ( 'should return false for host isolation exceptions when product feature is disabled' , ( ) => {
2585+ context . productFeaturesService . isEnabled = jest . fn ( ) . mockReturnValue ( false ) ;
2586+ manifestManager = new ManifestManager ( context ) ;
2587+
2588+ const shouldRetrieve = (
2589+ manifestManager as unknown as ManifestManagerWithPrivateMethods
2590+ ) . shouldRetrieveExceptions ( ENDPOINT_ARTIFACT_LISTS . hostIsolationExceptions . id ) ;
2591+
2592+ expect ( shouldRetrieve ) . toBe ( false ) ;
2593+ expect ( context . productFeaturesService . isEnabled ) . toHaveBeenCalledWith (
2594+ ProductFeatureKey . endpointHostIsolationExceptions
2595+ ) ;
2596+ } ) ;
2597+ } ) ;
2598+
2599+ describe ( 'default behavior for non-licensed artifacts' , ( ) => {
2600+ beforeEach ( ( ) => {
2601+ context = buildManifestManagerContextMock ( { } ) ;
2602+ context . licenseService = createLicenseServiceMock ( ) ;
2603+ manifestManager = new ManifestManager ( context ) ;
2604+ } ) ;
2605+
2606+ const nonLicensedArtifacts = [
2607+ { name : 'exceptions' , id : ENDPOINT_ARTIFACT_LISTS . endpointExceptions . id } ,
2608+ { name : 'trusted apps' , id : ENDPOINT_ARTIFACT_LISTS . trustedApps . id } ,
2609+ { name : 'event filters' , id : ENDPOINT_ARTIFACT_LISTS . eventFilters . id } ,
2610+ { name : 'blocklists' , id : ENDPOINT_ARTIFACT_LISTS . blocklists . id } ,
2611+ ] ;
2612+
2613+ test . each ( nonLicensedArtifacts ) ( 'should return true for $name artifacts' , ( { id } ) => {
2614+ const shouldRetrieve = (
2615+ manifestManager as unknown as ManifestManagerWithPrivateMethods
2616+ ) . shouldRetrieveExceptions ( id ) ;
2617+ expect ( shouldRetrieve ) . toBe ( true ) ;
2618+ } ) ;
2619+ } ) ;
2620+ } ) ;
24312621} ) ;
0 commit comments