Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'main' into renovate/main-platform-security-modules
Browse files Browse the repository at this point in the history
jeramysoucy authored Jan 10, 2025
2 parents fc12e5d + d891807 commit 9eb271d
Showing 29 changed files with 567 additions and 54 deletions.
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -108,9 +108,9 @@
"@dnd-kit/core": "^6.1.0",
"@dnd-kit/sortable": "^8.0.0",
"@dnd-kit/utilities": "^3.2.2",
"@elastic/apm-rum": "^5.16.1",
"@elastic/apm-rum-core": "^5.21.1",
"@elastic/apm-rum-react": "^2.0.3",
"@elastic/apm-rum": "^5.16.3",
"@elastic/apm-rum-core": "^5.22.1",
"@elastic/apm-rum-react": "^2.0.5",
"@elastic/charts": "68.0.4",
"@elastic/datemath": "5.0.3",
"@elastic/ebt": "^1.1.1",
6 changes: 3 additions & 3 deletions renovate.json
Original file line number Diff line number Diff line change
@@ -67,7 +67,7 @@
"team:kibana-operations"
],
"matchBaseBranches": [
"*"
"/^[8-9].*/"
],
"labels": [
"Team:Operations",
@@ -94,7 +94,7 @@
"team:kibana-operations"
],
"matchBaseBranches": [
"*"
"/.*/"
],
"labels": [
"Team:Operations",
@@ -3213,7 +3213,7 @@
"team:kibana-operations"
],
"matchBaseBranches": [
"*"
"/.*/"
],
"labels": [
"Team:Operations",
Original file line number Diff line number Diff line change
@@ -11,6 +11,7 @@ export const MICROSOFT_DEFENDER_ENDPOINT_CONNECTOR_ID = '.microsoft_defender_end
export enum MICROSOFT_DEFENDER_ENDPOINT_SUB_ACTION {
TEST_CONNECTOR = 'testConnector',
GET_AGENT_DETAILS = 'getAgentDetails',
GET_AGENT_LIST = 'getAgentList',
ISOLATE_HOST = 'isolateHost',
RELEASE_HOST = 'releaseHost',
GET_ACTIONS = 'getActions',
Original file line number Diff line number Diff line change
@@ -37,6 +37,105 @@ export const AgentDetailsParamsSchema = schema.object({
id: schema.string({ minLength: 1 }),
});

const MachineHealthStatusSchema = schema.oneOf([
schema.literal('Active'),
schema.literal('Inactive'),
schema.literal('ImpairedCommunication'),
schema.literal('NoSensorData'),
schema.literal('NoSensorDataImpairedCommunication'),
schema.literal('Unknown'),
]);

export const AgentListParamsSchema = schema.object({
computerDnsName: schema.maybe(
schema.oneOf([
schema.string({ minLength: 1 }),
schema.arrayOf(schema.string({ minLength: 1 }), { minSize: 1 }),
])
),
id: schema.maybe(
schema.oneOf([
schema.string({ minLength: 1 }),
schema.arrayOf(schema.string({ minLength: 1 }), { minSize: 1 }),
])
),
version: schema.maybe(
schema.oneOf([
schema.string({ minLength: 1 }),
schema.arrayOf(schema.string({ minLength: 1 }), { minSize: 1 }),
])
),
deviceValue: schema.maybe(
schema.oneOf([
schema.string({ minLength: 1 }),
schema.arrayOf(schema.string({ minLength: 1 }), { minSize: 1 }),
])
),
aaDeviceId: schema.maybe(
schema.oneOf([
schema.string({ minLength: 1 }),
schema.arrayOf(schema.string({ minLength: 1 }), { minSize: 1 }),
])
),
machineTags: schema.maybe(
schema.oneOf([
schema.string({ minLength: 1 }),
schema.arrayOf(schema.string({ minLength: 1 }), { minSize: 1 }),
])
),
lastSeen: schema.maybe(
schema.oneOf([
schema.string({ minLength: 1 }),
schema.arrayOf(schema.string({ minLength: 1 }), { minSize: 1 }),
])
),
exposureLevel: schema.maybe(
schema.oneOf([
schema.string({ minLength: 1 }),
schema.arrayOf(schema.string({ minLength: 1 }), { minSize: 1 }),
])
),
onboardingStatus: schema.maybe(
schema.oneOf([
schema.string({ minLength: 1 }),
schema.arrayOf(schema.string({ minLength: 1 }), { minSize: 1 }),
])
),
lastIpAddress: schema.maybe(
schema.oneOf([
schema.string({ minLength: 1 }),
schema.arrayOf(schema.string({ minLength: 1 }), { minSize: 1 }),
])
),
healthStatus: schema.maybe(
schema.oneOf([
MachineHealthStatusSchema,
schema.arrayOf(MachineHealthStatusSchema, { minSize: 1 }),
])
),
osPlatform: schema.maybe(
schema.oneOf([
schema.string({ minLength: 1 }),
schema.arrayOf(schema.string({ minLength: 1 }), { minSize: 1 }),
])
),
riskScore: schema.maybe(
schema.oneOf([
schema.string({ minLength: 1 }),
schema.arrayOf(schema.string({ minLength: 1 }), { minSize: 1 }),
])
),
rbacGroupId: schema.maybe(
schema.oneOf([
schema.string({ minLength: 1 }),
schema.arrayOf(schema.string({ minLength: 1 }), { minSize: 1 }),
])
),

page: schema.maybe(schema.number({ min: 1, defaultValue: 1 })),
pageSize: schema.maybe(schema.number({ min: 1, max: 1000, defaultValue: 20 })),
});

export const IsolateHostParamsSchema = schema.object({
id: schema.string({ minLength: 1 }),
comment: schema.string({ minLength: 1 }),
Original file line number Diff line number Diff line change
@@ -17,6 +17,7 @@ import {
TestConnectorParamsSchema,
AgentDetailsParamsSchema,
GetActionsParamsSchema,
AgentListParamsSchema,
} from './schema';

export type MicrosoftDefenderEndpointConfig = TypeOf<typeof MicrosoftDefenderEndpointConfigSchema>;
@@ -35,6 +36,18 @@ export interface MicrosoftDefenderEndpointTestConnector {

export type MicrosoftDefenderEndpointAgentDetailsParams = TypeOf<typeof AgentDetailsParamsSchema>;

export type MicrosoftDefenderEndpointAgentListParams = TypeOf<typeof AgentListParamsSchema>;

export interface MicrosoftDefenderEndpointAgentListResponse {
'@odata.context': string;
'@odata.count'?: number;
/** If value is `-1`, then API did not provide a total count */
total: number;
page: number;
pageSize: number;
value: MicrosoftDefenderEndpointMachine[];
}

export type MicrosoftDefenderEndpointGetActionsParams = TypeOf<typeof GetActionsParamsSchema>;

export interface MicrosoftDefenderEndpointGetActionsResponse {
Original file line number Diff line number Diff line change
@@ -205,4 +205,31 @@ describe('Microsoft Defender for Endpoint Connector', () => {
}
);
});

describe('#getAgentList()', () => {
it('should return expected response', async () => {
await expect(
connectorMock.instanceMock.getAgentList({ id: '1-2-3' }, connectorMock.usageCollector)
).resolves.toEqual({
'@odata.context': 'https://api-us3.securitycenter.microsoft.com/api/$metadata#Machines',
'@odata.count': 1,
page: 1,
pageSize: 20,
total: 1,
value: [expect.any(Object)],
});
});

it('should call Microsoft API with expected query params', async () => {
await connectorMock.instanceMock.getAgentList({ id: '1-2-3' }, connectorMock.usageCollector);

expect(connectorMock.instanceMock.request).toHaveBeenCalledWith(
expect.objectContaining({
url: 'https://api.mock__microsoft.com/api/machines',
params: { $count: true, $filter: 'id eq 1-2-3', $top: 20 },
}),
connectorMock.usageCollector
);
});
});
});
Original file line number Diff line number Diff line change
@@ -18,6 +18,7 @@ import {
MicrosoftDefenderEndpointDoNotValidateResponseSchema,
GetActionsParamsSchema,
AgentDetailsParamsSchema,
AgentListParamsSchema,
} from '../../../common/microsoft_defender_endpoint/schema';
import {
MicrosoftDefenderEndpointAgentDetailsParams,
@@ -32,6 +33,8 @@ import {
MicrosoftDefenderEndpointTestConnector,
MicrosoftDefenderEndpointGetActionsParams,
MicrosoftDefenderEndpointGetActionsResponse,
MicrosoftDefenderEndpointAgentListParams,
MicrosoftDefenderEndpointAgentListResponse,
} from '../../../common/microsoft_defender_endpoint/types';

export class MicrosoftDefenderEndpointConnector extends SubActionConnector<
@@ -70,6 +73,11 @@ export class MicrosoftDefenderEndpointConnector extends SubActionConnector<
method: 'getAgentDetails',
schema: AgentDetailsParamsSchema,
});
this.registerSubAction({
name: MICROSOFT_DEFENDER_ENDPOINT_SUB_ACTION.GET_AGENT_LIST,
method: 'getAgentList',
schema: AgentListParamsSchema,
});

this.registerSubAction({
name: MICROSOFT_DEFENDER_ENDPOINT_SUB_ACTION.ISOLATE_HOST,
@@ -243,6 +251,30 @@ export class MicrosoftDefenderEndpointConnector extends SubActionConnector<
);
}

public async getAgentList(
{ page = 1, pageSize = 20, ...filter }: MicrosoftDefenderEndpointAgentListParams,
connectorUsageCollector: ConnectorUsageCollector
): Promise<MicrosoftDefenderEndpointAgentListResponse> {
// API Reference: https://learn.microsoft.com/en-us/defender-endpoint/api/get-machines
// OData usage reference: https://learn.microsoft.com/en-us/defender-endpoint/api/exposed-apis-odata-samples

const response = await this.fetchFromMicrosoft<MicrosoftDefenderEndpointAgentListResponse>(
{
url: `${this.urls.machines}`,
method: 'GET',
params: this.buildODataUrlParams({ filter, page, pageSize }),
},
connectorUsageCollector
);

return {
...response,
page,
pageSize,
total: response['@odata.count'] ?? -1,
};
}

public async isolateHost(
{ id, comment }: MicrosoftDefenderEndpointIsolateHostParams,
connectorUsageCollector: ConnectorUsageCollector
Original file line number Diff line number Diff line change
@@ -78,6 +78,14 @@ const createMicrosoftDefenderConnectorMock = (): CreateMicrosoftDefenderConnecto
'@odata.count': 1,
value: [createMicrosoftMachineAction()],
}),

// Machine List
[`${apiUrl}/api/machines`]: () =>
createAxiosResponseMock({
'@odata.context': 'https://api-us3.securitycenter.microsoft.com/api/$metadata#Machines',
'@odata.count': 1,
value: [createMicrosoftMachineMock()],
}),
};

instanceMock.request.mockImplementation(
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import type { EuiThemeComputed } from '@elastic/eui';

export const getDestinationIpColor = (euiTheme: EuiThemeComputed) =>
euiTheme.flags.hasVisColorAdjustment ? '#9170b8' : euiTheme.colors.vis.euiColorVis2;

export const getSourceIpColor = (euiTheme: EuiThemeComputed) =>
euiTheme.flags.hasVisColorAdjustment ? '#d36186' : euiTheme.colors.vis.euiColorVis4;

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -7,6 +7,7 @@

import { DESTINATION_CHART_LABEL, SOURCE_CHART_LABEL } from '../../translations';
import type { GetLensAttributes, LensAttributes } from '../../types';
import { getDestinationIpColor, getSourceIpColor } from '../common/utils/unique_ips_palette';

const columnSourceTimestamp = 'a0cb6400-f708-46c3-ad96-24788f12dae4';
const columnSourceUniqueIp = 'd9a6eb6b-8b78-439e-98e7-a718f8ffbebe';
@@ -89,19 +90,15 @@ export const getKpiUniqueIpsAreaLensAttributes: GetLensAttributes = ({ euiTheme
layerType: 'data',
seriesType: 'area',
xAccessor: columnSourceTimestamp,
yConfig: [
{ color: euiTheme.colors.vis.euiColorVis4, forAccessor: columnSourceUniqueIp },
],
yConfig: [{ color: getSourceIpColor(euiTheme), forAccessor: columnSourceUniqueIp }],
},
{
accessors: [columnDestinationIp],
layerId: layerDestinationIp,
layerType: 'data',
seriesType: 'area',
xAccessor: columnDestinationTimestamp,
yConfig: [
{ color: euiTheme.colors.vis.euiColorVis2, forAccessor: columnDestinationIp },
],
yConfig: [{ color: getDestinationIpColor(euiTheme), forAccessor: columnDestinationIp }],
},
],
legend: { isVisible: false, position: 'right', showSingleSeries: false },
Original file line number Diff line number Diff line change
@@ -7,6 +7,7 @@

import type { GetLensAttributes, LensAttributes } from '../../types';
import { SOURCE_CHART_LABEL, DESTINATION_CHART_LABEL, UNIQUE_COUNT } from '../../translations';
import { getDestinationIpColor, getSourceIpColor } from '../common/utils/unique_ips_palette';
const columnSourceIp = '32f66676-f4e1-48fd-b7f8-d4de38318601';
const columnSourceFilter = 'f8bfa719-5c1c-4bf2-896e-c318d77fc08e';

@@ -96,17 +97,15 @@ export const getKpiUniqueIpsBarLensAttributes: GetLensAttributes = ({ euiTheme }
layerType: 'data',
seriesType: 'bar_horizontal_stacked',
xAccessor: columnSourceFilter,
yConfig: [{ color: euiTheme.colors.vis.euiColorVis4, forAccessor: columnSourceIp }],
yConfig: [{ color: getSourceIpColor(euiTheme), forAccessor: columnSourceIp }],
},
{
accessors: [columnDestinationIp],
layerId: layerDestinationIp,
layerType: 'data',
seriesType: 'bar_horizontal_stacked',
xAccessor: columnDestinationFilter,
yConfig: [
{ color: euiTheme.colors.vis.euiColorVis2, forAccessor: columnDestinationIp },
],
yConfig: [{ color: getDestinationIpColor(euiTheme), forAccessor: columnDestinationIp }],
},
],
legend: { isVisible: false, position: 'right', showSingleSeries: false },
Loading

0 comments on commit 9eb271d

Please sign in to comment.