Skip to content

Commit 162ed34

Browse files
[Security Solution][Endpoint][Admin] Task/endpoint list actions (#76555) (#77636)
Endpoint list actions to security solution endpoint admin Co-authored-by: Paul Tavares <paul.tavares@elastic.co>
1 parent 482050c commit 162ed34

File tree

13 files changed

+342
-33
lines changed

13 files changed

+342
-33
lines changed

x-pack/plugins/ingest_manager/public/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,5 @@ export {
2020

2121
export { NewPackagePolicy } from './applications/ingest_manager/types';
2222
export * from './applications/ingest_manager/types/intra_app_route_state';
23+
24+
export { pagePathGetters } from './applications/ingest_manager/constants';

x-pack/plugins/ingest_manager/scripts/dev_agent/script.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,11 @@ import {
1414
PostAgentEnrollRequest,
1515
PostAgentEnrollResponse,
1616
} from '../../common/types';
17+
import * as kibanaPackage from '../../package.json';
1718

19+
// @ts-ignore
20+
// Using the ts-ignore because we are importing directly from a json to a script file
21+
const version = kibanaPackage.version;
1822
const CHECKIN_INTERVAL = 3000; // 3 seconds
1923

2024
type Agent = Pick<_Agent, 'id' | 'access_api_key'>;
@@ -104,6 +108,7 @@ async function enroll(kibanaURL: string, apiKey: string, log: ToolingLog): Promi
104108
ip: '127.0.0.1',
105109
system: `${os.type()} ${os.release()}`,
106110
memory: os.totalmem(),
111+
elastic: { agent: { version } },
107112
},
108113
user_provided: {
109114
dev_agent_version: '0.0.1',

x-pack/plugins/security_solution/public/common/hooks/endpoint/use_navigate_to_app_event_handler.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ type NavigateToAppHandlerOptions<S = unknown> = NavigateToAppOptions & {
1212
state?: S;
1313
onClick?: EventHandlerCallback;
1414
};
15-
type EventHandlerCallback = MouseEventHandler<HTMLButtonElement | HTMLAnchorElement>;
15+
type EventHandlerCallback = MouseEventHandler<HTMLButtonElement | HTMLAnchorElement | Element>;
1616

1717
/**
1818
* Provides an event handlers that can be used with (for example) `onClick` to prevent the

x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/action.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,11 @@ interface ServerReturnedEndpointNonExistingPolicies {
8282
payload: EndpointState['nonExistingPolicies'];
8383
}
8484

85+
interface ServerReturnedEndpointAgentPolicies {
86+
type: 'serverReturnedEndpointAgentPolicies';
87+
payload: EndpointState['agentPolicies'];
88+
}
89+
8590
interface ServerReturnedEndpointExistValue {
8691
type: 'serverReturnedEndpointExistValue';
8792
payload: boolean;
@@ -126,4 +131,5 @@ export type EndpointAction =
126131
| ServerFailedToReturnMetadataPatterns
127132
| AppRequestedEndpointList
128133
| ServerReturnedEndpointNonExistingPolicies
134+
| ServerReturnedEndpointAgentPolicies
129135
| UserUpdatedEndpointListRefreshOptions;

x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/index.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ describe('EndpointList store concerns', () => {
5252
policyItemsLoading: false,
5353
endpointPackageInfo: undefined,
5454
nonExistingPolicies: {},
55+
agentPolicies: {},
5556
endpointsExist: true,
5657
patterns: [],
5758
patternsError: undefined,

x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts

Lines changed: 52 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import {
1818
patterns,
1919
searchBarQuery,
2020
} from './selectors';
21-
import { EndpointState } from '../types';
21+
import { EndpointState, PolicyIds } from '../types';
2222
import {
2323
sendGetEndpointSpecificPackagePolicies,
2424
sendGetEndpointSecurityPackage,
@@ -105,15 +105,21 @@ export const endpointMiddlewareFactory: ImmutableMiddlewareFactory<EndpointState
105105
});
106106

107107
try {
108-
const missingPolicies = await getNonExistingPoliciesForEndpointsList(
108+
const ingestPolicies = await getAgentAndPoliciesForEndpointsList(
109109
coreStart.http,
110110
endpointResponse.hosts,
111111
nonExistingPolicies(getState())
112112
);
113-
if (missingPolicies !== undefined) {
113+
if (ingestPolicies?.packagePolicy !== undefined) {
114114
dispatch({
115115
type: 'serverReturnedEndpointNonExistingPolicies',
116-
payload: missingPolicies,
116+
payload: ingestPolicies.packagePolicy,
117+
});
118+
}
119+
if (ingestPolicies?.agentPolicy !== undefined) {
120+
dispatch({
121+
type: 'serverReturnedEndpointAgentPolicies',
122+
payload: ingestPolicies.agentPolicy,
117123
});
118124
}
119125
} catch (error) {
@@ -202,15 +208,21 @@ export const endpointMiddlewareFactory: ImmutableMiddlewareFactory<EndpointState
202208
});
203209

204210
try {
205-
const missingPolicies = await getNonExistingPoliciesForEndpointsList(
211+
const ingestPolicies = await getAgentAndPoliciesForEndpointsList(
206212
coreStart.http,
207213
response.hosts,
208214
nonExistingPolicies(getState())
209215
);
210-
if (missingPolicies !== undefined) {
216+
if (ingestPolicies?.packagePolicy !== undefined) {
211217
dispatch({
212218
type: 'serverReturnedEndpointNonExistingPolicies',
213-
payload: missingPolicies,
219+
payload: ingestPolicies.packagePolicy,
220+
});
221+
}
222+
if (ingestPolicies?.agentPolicy !== undefined) {
223+
dispatch({
224+
type: 'serverReturnedEndpointAgentPolicies',
225+
payload: ingestPolicies.agentPolicy,
214226
});
215227
}
216228
} catch (error) {
@@ -242,15 +254,21 @@ export const endpointMiddlewareFactory: ImmutableMiddlewareFactory<EndpointState
242254
});
243255

244256
try {
245-
const missingPolicies = await getNonExistingPoliciesForEndpointsList(
257+
const ingestPolicies = await getAgentAndPoliciesForEndpointsList(
246258
coreStart.http,
247259
[response],
248260
nonExistingPolicies(getState())
249261
);
250-
if (missingPolicies !== undefined) {
262+
if (ingestPolicies !== undefined) {
251263
dispatch({
252264
type: 'serverReturnedEndpointNonExistingPolicies',
253-
payload: missingPolicies,
265+
payload: ingestPolicies.packagePolicy,
266+
});
267+
}
268+
if (ingestPolicies?.agentPolicy !== undefined) {
269+
dispatch({
270+
type: 'serverReturnedEndpointAgentPolicies',
271+
payload: ingestPolicies.agentPolicy,
254272
});
255273
}
256274
} catch (error) {
@@ -284,11 +302,11 @@ export const endpointMiddlewareFactory: ImmutableMiddlewareFactory<EndpointState
284302
};
285303
};
286304

287-
const getNonExistingPoliciesForEndpointsList = async (
305+
const getAgentAndPoliciesForEndpointsList = async (
288306
http: HttpStart,
289307
hosts: HostResultList['hosts'],
290308
currentNonExistingPolicies: EndpointState['nonExistingPolicies']
291-
): Promise<EndpointState['nonExistingPolicies'] | undefined> => {
309+
): Promise<PolicyIds | undefined> => {
292310
if (hosts.length === 0) {
293311
return;
294312
}
@@ -318,29 +336,38 @@ const getNonExistingPoliciesForEndpointsList = async (
318336
)})`,
319337
},
320338
})
321-
).items.reduce<EndpointState['nonExistingPolicies']>((list, agentPolicy) => {
322-
(agentPolicy.package_policies as string[]).forEach((packagePolicy) => {
323-
list[packagePolicy as string] = true;
324-
});
325-
return list;
326-
}, {});
339+
).items.reduce<PolicyIds>(
340+
(list, agentPolicy) => {
341+
(agentPolicy.package_policies as string[]).forEach((packagePolicy) => {
342+
list.packagePolicy[packagePolicy as string] = true;
343+
list.agentPolicy[packagePolicy as string] = agentPolicy.id;
344+
});
345+
return list;
346+
},
347+
{ packagePolicy: {}, agentPolicy: {} }
348+
);
327349

328-
const nonExisting = policyIdsToCheck.reduce<EndpointState['nonExistingPolicies']>(
329-
(list, policyId) => {
330-
if (policiesFound[policyId]) {
350+
// packagePolicy contains non-existing packagePolicy ids whereas agentPolicy contains existing agentPolicy ids
351+
const nonExistingPackagePoliciesAndExistingAgentPolicies = policyIdsToCheck.reduce<PolicyIds>(
352+
(list, policyId: string) => {
353+
if (policiesFound.packagePolicy[policyId as string]) {
354+
list.agentPolicy[policyId as string] = policiesFound.agentPolicy[policyId];
331355
return list;
332356
}
333-
list[policyId] = true;
357+
list.packagePolicy[policyId as string] = true;
334358
return list;
335359
},
336-
{}
360+
{ packagePolicy: {}, agentPolicy: {} }
337361
);
338362

339-
if (Object.keys(nonExisting).length === 0) {
363+
if (
364+
Object.keys(nonExistingPackagePoliciesAndExistingAgentPolicies.packagePolicy).length === 0 &&
365+
Object.keys(nonExistingPackagePoliciesAndExistingAgentPolicies.agentPolicy).length === 0
366+
) {
340367
return;
341368
}
342369

343-
return nonExisting;
370+
return nonExistingPackagePoliciesAndExistingAgentPolicies;
344371
};
345372

346373
const doEndpointsExist = async (http: HttpStart): Promise<boolean> => {

x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/mock_endpoint_result_list.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import {
2020
} from '../../policy/store/policy_list/services/ingest';
2121
import {
2222
GetAgentPoliciesResponse,
23+
GetAgentPoliciesResponseItem,
2324
GetPackagesResponse,
2425
} from '../../../../../../ingest_manager/common/types/rest_spec';
2526
import { GetPolicyListResponse } from '../../policy/types';
@@ -43,7 +44,7 @@ export const mockEndpointResultList: (options?: {
4344
// total - numberToSkip is the count of non-skipped ones, but return no more than a pageSize, and no less than 0
4445
const actualCountToReturn = Math.max(Math.min(total - numberToSkip, requestPageSize), 0);
4546

46-
const hosts = [];
47+
const hosts: HostInfo[] = [];
4748
for (let index = 0; index < actualCountToReturn; index++) {
4849
hosts.push({
4950
metadata: generator.generateHostMetadata(),
@@ -78,12 +79,14 @@ const endpointListApiPathHandlerMocks = ({
7879
epmPackages = [generator.generateEpmPackage()],
7980
endpointPackagePolicies = [],
8081
policyResponse = generator.generatePolicyResponse(),
82+
agentPolicy = generator.generateAgentPolicy(),
8183
}: {
8284
/** route handlers will be setup for each individual host in this array */
8385
endpointsResults?: HostResultList['hosts'];
8486
epmPackages?: GetPackagesResponse['response'];
8587
endpointPackagePolicies?: GetPolicyListResponse['items'];
8688
policyResponse?: HostPolicyResponse;
89+
agentPolicy?: GetAgentPoliciesResponseItem;
8790
} = {}) => {
8891
const apiHandlers = {
8992
// endpoint package info
@@ -106,7 +109,6 @@ const endpointListApiPathHandlerMocks = ({
106109
// Do policies referenced in endpoint list exist
107110
// just returns 1 single agent policy that includes all of the packagePolicy IDs provided
108111
[INGEST_API_AGENT_POLICIES]: (): GetAgentPoliciesResponse => {
109-
const agentPolicy = generator.generateAgentPolicy();
110112
(agentPolicy.package_policies as string[]).push(
111113
...endpointPackagePolicies.map((packagePolicy) => packagePolicy.id)
112114
);

x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/reducer.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ export const initialEndpointListState: Immutable<EndpointState> = {
3030
policyItemsLoading: false,
3131
endpointPackageInfo: undefined,
3232
nonExistingPolicies: {},
33+
agentPolicies: {},
3334
endpointsExist: true,
3435
patterns: [],
3536
patternsError: undefined,
@@ -72,6 +73,14 @@ export const endpointListReducer: ImmutableReducer<EndpointState, AppAction> = (
7273
...action.payload,
7374
},
7475
};
76+
} else if (action.type === 'serverReturnedEndpointAgentPolicies') {
77+
return {
78+
...state,
79+
agentPolicies: {
80+
...state.agentPolicies,
81+
...action.payload,
82+
},
83+
};
7584
} else if (action.type === 'serverReturnedMetadataPatterns') {
7685
// handle error case
7786
return {

x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/selectors.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,13 @@ export const nonExistingPolicies: (
217217
state: Immutable<EndpointState>
218218
) => Immutable<EndpointState['nonExistingPolicies']> = (state) => state.nonExistingPolicies;
219219

220+
/**
221+
* returns the list of known existing agent policies
222+
*/
223+
export const agentPolicies: (
224+
state: Immutable<EndpointState>
225+
) => Immutable<EndpointState['agentPolicies']> = (state) => state.agentPolicies;
226+
220227
/**
221228
* Return boolean that indicates whether endpoints exist
222229
* @param state

x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/types.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,10 @@ export interface EndpointState {
5151
selectedPolicyId?: string;
5252
/** Endpoint package info */
5353
endpointPackageInfo?: GetPackagesResponse['response'][0];
54-
/** tracks the list of policies IDs used in Host metadata that may no longer exist */
55-
nonExistingPolicies: Record<string, boolean>;
54+
/** Tracks the list of policies IDs used in Host metadata that may no longer exist */
55+
nonExistingPolicies: PolicyIds['packagePolicy'];
56+
/** List of Package Policy Ids mapped to an associated Fleet Parent Agent Policy Id*/
57+
agentPolicies: PolicyIds['agentPolicy'];
5658
/** Tracks whether hosts exist and helps control if onboarding should be visible */
5759
endpointsExist: boolean;
5860
/** index patterns for query bar */
@@ -65,6 +67,15 @@ export interface EndpointState {
6567
autoRefreshInterval: number;
6668
}
6769

70+
/**
71+
* packagePolicy contains a list of Package Policy IDs (received via Endpoint metadata policy response) mapped to a boolean whether they exist or not.
72+
* agentPolicy contains a list of existing Package Policy Ids mapped to an associated Fleet parent Agent Config.
73+
*/
74+
export interface PolicyIds {
75+
packagePolicy: Record<string, boolean>;
76+
agentPolicy: Record<string, string>;
77+
}
78+
6879
/**
6980
* Query params on the host page parsed from the URL
7081
*/

0 commit comments

Comments
 (0)