[Security Solution] Use Agent.id for endpoint pivot ID (#74272)
* switch endpoint meta query to use agent.id * update policy route to use agent ID * update policy unit test, with schema change * security front-end use agent.id as identifier * update test to check the right field * update SIEM to get endpoint data by agent.id * fix type in test, but need to fix data, will still fail * test: pull agent ID from esarchive data * magnets, how do they work? * cleanup * apparently this test works differently now Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
4120f1a0c7
commit
5514eca36c
|
@ -7,6 +7,6 @@ import { schema } from '@kbn/config-schema';
|
|||
|
||||
export const GetPolicyResponseSchema = {
|
||||
query: schema.object({
|
||||
hostId: schema.string(),
|
||||
agentId: schema.string(),
|
||||
}),
|
||||
};
|
||||
|
|
|
@ -1412,6 +1412,14 @@
|
|||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "agent",
|
||||
"description": "",
|
||||
"args": [],
|
||||
"type": { "kind": "OBJECT", "name": "AgentFields", "ofType": null },
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "cloud",
|
||||
"description": "",
|
||||
|
@ -1458,6 +1466,25 @@
|
|||
"enumValues": null,
|
||||
"possibleTypes": null
|
||||
},
|
||||
{
|
||||
"kind": "OBJECT",
|
||||
"name": "AgentFields",
|
||||
"description": "",
|
||||
"fields": [
|
||||
{
|
||||
"name": "id",
|
||||
"description": "",
|
||||
"args": [],
|
||||
"type": { "kind": "SCALAR", "name": "String", "ofType": null },
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
}
|
||||
],
|
||||
"inputFields": null,
|
||||
"interfaces": [],
|
||||
"enumValues": null,
|
||||
"possibleTypes": null
|
||||
},
|
||||
{
|
||||
"kind": "OBJECT",
|
||||
"name": "CloudFields",
|
||||
|
|
|
@ -490,6 +490,8 @@ export interface HostsEdges {
|
|||
export interface HostItem {
|
||||
_id?: Maybe<string>;
|
||||
|
||||
agent?: Maybe<AgentFields>;
|
||||
|
||||
cloud?: Maybe<CloudFields>;
|
||||
|
||||
endpoint?: Maybe<EndpointFields>;
|
||||
|
@ -501,6 +503,10 @@ export interface HostItem {
|
|||
lastSeen?: Maybe<string>;
|
||||
}
|
||||
|
||||
export interface AgentFields {
|
||||
id?: Maybe<string>;
|
||||
}
|
||||
|
||||
export interface CloudFields {
|
||||
instance?: Maybe<CloudInstance>;
|
||||
|
||||
|
@ -1728,6 +1734,8 @@ export namespace GetHostOverviewQuery {
|
|||
|
||||
_id: Maybe<string>;
|
||||
|
||||
agent: Maybe<Agent>;
|
||||
|
||||
host: Maybe<Host>;
|
||||
|
||||
cloud: Maybe<Cloud>;
|
||||
|
@ -1737,6 +1745,12 @@ export namespace GetHostOverviewQuery {
|
|||
endpoint: Maybe<Endpoint>;
|
||||
};
|
||||
|
||||
export type Agent = {
|
||||
__typename?: 'AgentFields';
|
||||
|
||||
id: Maybe<string>;
|
||||
}
|
||||
|
||||
export type Host = {
|
||||
__typename?: 'HostEcsFields';
|
||||
|
||||
|
|
|
@ -18,6 +18,9 @@ export const HostOverviewQuery = gql`
|
|||
id
|
||||
HostOverview(hostName: $hostName, timerange: $timerange, defaultIndex: $defaultIndex) {
|
||||
_id
|
||||
agent {
|
||||
id
|
||||
}
|
||||
host {
|
||||
architecture
|
||||
id
|
||||
|
|
|
@ -314,7 +314,7 @@ export const endpointMiddlewareFactory: ImmutableMiddlewareFactory<EndpointState
|
|||
// call the policy response api
|
||||
try {
|
||||
const policyResponse = await coreStart.http.get(`/api/endpoint/policy_response`, {
|
||||
query: { hostId: selectedEndpoint },
|
||||
query: { agentId: selectedEndpoint },
|
||||
});
|
||||
dispatch({
|
||||
type: 'serverReturnedEndpointPolicyResponse',
|
||||
|
|
|
@ -164,7 +164,7 @@ const endpointListApiPathHandlerMocks = ({
|
|||
if (endpointsResults) {
|
||||
endpointsResults.forEach((host) => {
|
||||
// @ts-expect-error
|
||||
apiHandlers[`/api/endpoint/metadata/${host.metadata.host.id}`] = () => host;
|
||||
apiHandlers[`/api/endpoint/metadata/${host.metadata.agent.id}`] = () => host;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -89,16 +89,16 @@ export const EndpointDetails = memo(({ details }: { details: HostMetadata }) =>
|
|||
getEndpointDetailsPath({
|
||||
name: 'endpointPolicyResponse',
|
||||
...currentUrlParams,
|
||||
selected_endpoint: details.host.id,
|
||||
selected_endpoint: details.agent.id,
|
||||
})
|
||||
),
|
||||
getEndpointDetailsPath({
|
||||
name: 'endpointPolicyResponse',
|
||||
...currentUrlParams,
|
||||
selected_endpoint: details.host.id,
|
||||
selected_endpoint: details.agent.id,
|
||||
}),
|
||||
];
|
||||
}, [details.host.id, formatUrl, queryParams]);
|
||||
}, [details.agent.id, formatUrl, queryParams]);
|
||||
|
||||
const agentDetailsWithFlyoutPath = `${agentDetailsAppPath}${openReassignFlyoutSearch}`;
|
||||
const agentDetailsWithFlyoutUrl = `${agentDetailsUrl}${openReassignFlyoutSearch}`;
|
||||
|
@ -112,7 +112,7 @@ export const EndpointDetails = memo(({ details }: { details: HostMetadata }) =>
|
|||
{
|
||||
path: getEndpointDetailsPath({
|
||||
name: 'endpointDetails',
|
||||
selected_endpoint: details.host.id,
|
||||
selected_endpoint: details.agent.id,
|
||||
}),
|
||||
},
|
||||
],
|
||||
|
|
|
@ -131,16 +131,16 @@ const PolicyResponseFlyoutPanel = memo<{
|
|||
getEndpointListPath({
|
||||
name: 'endpointList',
|
||||
...queryParams,
|
||||
selected_endpoint: hostMeta.host.id,
|
||||
selected_endpoint: hostMeta.agent.id,
|
||||
})
|
||||
),
|
||||
getEndpointListPath({
|
||||
name: 'endpointList',
|
||||
...queryParams,
|
||||
selected_endpoint: hostMeta.host.id,
|
||||
selected_endpoint: hostMeta.agent.id,
|
||||
}),
|
||||
],
|
||||
[hostMeta.host.id, formatUrl, queryParams]
|
||||
[hostMeta.agent.id, formatUrl, queryParams]
|
||||
);
|
||||
const backToDetailsClickHandler = useNavigateByRouterEventHandler(detailsRoutePath);
|
||||
const backButtonProp = useMemo((): FlyoutSubHeaderProps['backButton'] => {
|
||||
|
|
|
@ -397,13 +397,13 @@ describe('when on the list page', () => {
|
|||
|
||||
describe('when there is a selected host in the url', () => {
|
||||
let hostDetails: HostInfo;
|
||||
let agentId: string;
|
||||
let elasticAgentId: string;
|
||||
let renderAndWaitForData: () => Promise<ReturnType<AppContextTestRender['render']>>;
|
||||
const mockEndpointListApi = (mockedPolicyResponse?: HostPolicyResponse) => {
|
||||
const {
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
host_status,
|
||||
metadata: { host, ...details },
|
||||
metadata: { agent, ...details },
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
query_strategy_version,
|
||||
} = mockEndpointDetailsApiResult();
|
||||
|
@ -412,15 +412,15 @@ describe('when on the list page', () => {
|
|||
host_status,
|
||||
metadata: {
|
||||
...details,
|
||||
host: {
|
||||
...host,
|
||||
agent: {
|
||||
...agent,
|
||||
id: '1',
|
||||
},
|
||||
},
|
||||
query_strategy_version,
|
||||
};
|
||||
|
||||
agentId = hostDetails.metadata.elastic.agent.id;
|
||||
elasticAgentId = hostDetails.metadata.elastic.agent.id;
|
||||
|
||||
const policy = docGenerator.generatePolicyPackagePolicy();
|
||||
policy.id = hostDetails.metadata.Endpoint.policy.applied.id;
|
||||
|
@ -618,7 +618,7 @@ describe('when on the list page', () => {
|
|||
expect(linkToReassign).not.toBeNull();
|
||||
expect(linkToReassign.textContent).toEqual('Reassign Policy');
|
||||
expect(linkToReassign.getAttribute('href')).toEqual(
|
||||
`/app/ingestManager#/fleet/agents/${agentId}/activity?openReassignFlyout=true`
|
||||
`/app/ingestManager#/fleet/agents/${elasticAgentId}/activity?openReassignFlyout=true`
|
||||
);
|
||||
});
|
||||
|
||||
|
|
|
@ -261,11 +261,11 @@ export const EndpointList = () => {
|
|||
|
||||
return [
|
||||
{
|
||||
field: 'metadata.host',
|
||||
field: 'metadata',
|
||||
name: i18n.translate('xpack.securitySolution.endpoint.list.hostname', {
|
||||
defaultMessage: 'Hostname',
|
||||
}),
|
||||
render: ({ hostname, id }: HostInfo['metadata']['host']) => {
|
||||
render: ({ host: { hostname }, agent: { id } }: HostInfo['metadata']) => {
|
||||
const toRoutePath = getEndpointDetailsPath(
|
||||
{
|
||||
...queryParams,
|
||||
|
@ -342,7 +342,7 @@ export const EndpointList = () => {
|
|||
const toRoutePath = getEndpointDetailsPath({
|
||||
name: 'endpointPolicyResponse',
|
||||
...queryParams,
|
||||
selected_endpoint: item.metadata.host.id,
|
||||
selected_endpoint: item.metadata.agent.id,
|
||||
});
|
||||
const toRouteUrl = formatUrl(toRoutePath);
|
||||
return (
|
||||
|
|
|
@ -255,11 +255,11 @@ async function enrichHostMetadata(
|
|||
const log = metadataRequestContext.logger;
|
||||
try {
|
||||
/**
|
||||
* Get agent status by elastic agent id if available or use the host id.
|
||||
* Get agent status by elastic agent id if available or use the endpoint-agent id.
|
||||
*/
|
||||
|
||||
if (!elasticAgentId) {
|
||||
elasticAgentId = hostMetadata.host.id;
|
||||
elasticAgentId = hostMetadata.agent.id;
|
||||
log.warn(`Missing elastic agent id, using host id instead ${elasticAgentId}`);
|
||||
}
|
||||
|
||||
|
|
|
@ -230,7 +230,7 @@ describe('query builder', () => {
|
|||
|
||||
expect(query).toEqual({
|
||||
body: {
|
||||
query: { match: { 'HostDetails.host.id': mockID } },
|
||||
query: { match: { 'HostDetails.agent.id': mockID } },
|
||||
sort: [{ 'HostDetails.event.created': { order: 'desc' } }],
|
||||
size: 1,
|
||||
},
|
||||
|
|
|
@ -116,14 +116,14 @@ function buildQueryBody(
|
|||
}
|
||||
|
||||
export function getESQueryHostMetadataByID(
|
||||
hostID: string,
|
||||
agentID: string,
|
||||
metadataQueryStrategy: MetadataQueryStrategy
|
||||
) {
|
||||
return {
|
||||
body: {
|
||||
query: {
|
||||
match: {
|
||||
[metadataQueryStrategy.hostIdProperty]: hostID,
|
||||
[metadataQueryStrategy.hostIdProperty]: agentID,
|
||||
},
|
||||
},
|
||||
sort: metadataQueryStrategy.sortProperty,
|
||||
|
|
|
@ -31,7 +31,7 @@ describe('query builder v1', () => {
|
|||
match_all: {},
|
||||
},
|
||||
collapse: {
|
||||
field: 'host.id',
|
||||
field: 'agent.id',
|
||||
inner_hits: {
|
||||
name: 'most_recent',
|
||||
size: 1,
|
||||
|
@ -41,7 +41,7 @@ describe('query builder v1', () => {
|
|||
aggs: {
|
||||
total: {
|
||||
cardinality: {
|
||||
field: 'host.id',
|
||||
field: 'agent.id',
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -92,7 +92,7 @@ describe('query builder v1', () => {
|
|||
},
|
||||
},
|
||||
collapse: {
|
||||
field: 'host.id',
|
||||
field: 'agent.id',
|
||||
inner_hits: {
|
||||
name: 'most_recent',
|
||||
size: 1,
|
||||
|
@ -102,7 +102,7 @@ describe('query builder v1', () => {
|
|||
aggs: {
|
||||
total: {
|
||||
cardinality: {
|
||||
field: 'host.id',
|
||||
field: 'agent.id',
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -165,7 +165,7 @@ describe('query builder v1', () => {
|
|||
},
|
||||
},
|
||||
collapse: {
|
||||
field: 'host.id',
|
||||
field: 'agent.id',
|
||||
inner_hits: {
|
||||
name: 'most_recent',
|
||||
size: 1,
|
||||
|
@ -175,7 +175,7 @@ describe('query builder v1', () => {
|
|||
aggs: {
|
||||
total: {
|
||||
cardinality: {
|
||||
field: 'host.id',
|
||||
field: 'agent.id',
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -251,7 +251,7 @@ describe('query builder v1', () => {
|
|||
},
|
||||
},
|
||||
collapse: {
|
||||
field: 'host.id',
|
||||
field: 'agent.id',
|
||||
inner_hits: {
|
||||
name: 'most_recent',
|
||||
size: 1,
|
||||
|
@ -261,7 +261,7 @@ describe('query builder v1', () => {
|
|||
aggs: {
|
||||
total: {
|
||||
cardinality: {
|
||||
field: 'host.id',
|
||||
field: 'agent.id',
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -289,7 +289,7 @@ describe('query builder v1', () => {
|
|||
|
||||
expect(query).toEqual({
|
||||
body: {
|
||||
query: { match: { 'host.id': mockID } },
|
||||
query: { match: { 'agent.id': mockID } },
|
||||
sort: [{ 'event.created': { order: 'desc' } }],
|
||||
size: 1,
|
||||
},
|
||||
|
|
|
@ -23,7 +23,7 @@ export function metadataQueryStrategyV1(): MetadataQueryStrategy {
|
|||
return {
|
||||
index: metadataIndexPattern,
|
||||
elasticAgentIdProperty: 'elastic.agent.id',
|
||||
hostIdProperty: 'host.id',
|
||||
hostIdProperty: 'agent.id',
|
||||
sortProperty: [
|
||||
{
|
||||
'event.created': {
|
||||
|
@ -33,7 +33,7 @@ export function metadataQueryStrategyV1(): MetadataQueryStrategy {
|
|||
],
|
||||
extraBodyProperties: {
|
||||
collapse: {
|
||||
field: 'host.id',
|
||||
field: 'agent.id',
|
||||
inner_hits: {
|
||||
name: 'most_recent',
|
||||
size: 1,
|
||||
|
@ -43,7 +43,7 @@ export function metadataQueryStrategyV1(): MetadataQueryStrategy {
|
|||
aggs: {
|
||||
total: {
|
||||
cardinality: {
|
||||
field: 'host.id',
|
||||
field: 'agent.id',
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -78,7 +78,7 @@ export function metadataQueryStrategyV2(): MetadataQueryStrategy {
|
|||
return {
|
||||
index: metadataCurrentIndexPattern,
|
||||
elasticAgentIdProperty: 'HostDetails.elastic.agent.id',
|
||||
hostIdProperty: 'HostDetails.host.id',
|
||||
hostIdProperty: 'HostDetails.agent.id',
|
||||
sortProperty: [
|
||||
{
|
||||
'HostDetails.event.created': {
|
||||
|
|
|
@ -51,7 +51,7 @@ describe('test policy response handler', () => {
|
|||
|
||||
mockScopedClient.callAsCurrentUser.mockImplementationOnce(() => Promise.resolve(response));
|
||||
const mockRequest = httpServerMock.createKibanaRequest({
|
||||
params: { hostId: 'id' },
|
||||
params: { agentId: 'id' },
|
||||
});
|
||||
|
||||
await hostPolicyResponseHandler(
|
||||
|
@ -62,7 +62,7 @@ describe('test policy response handler', () => {
|
|||
|
||||
expect(mockResponse.ok).toBeCalled();
|
||||
const result = mockResponse.ok.mock.calls[0][0]?.body as GetHostPolicyResponse;
|
||||
expect(result.policy_response.host.id).toEqual(response.hits.hits[0]._source.host.id);
|
||||
expect(result.policy_response.agent.id).toEqual(response.hits.hits[0]._source.agent.id);
|
||||
});
|
||||
|
||||
it('should return not found when there is no response policy for host', async () => {
|
||||
|
@ -77,7 +77,7 @@ describe('test policy response handler', () => {
|
|||
);
|
||||
|
||||
const mockRequest = httpServerMock.createKibanaRequest({
|
||||
params: { hostId: 'id' },
|
||||
params: { agentId: 'id' },
|
||||
});
|
||||
|
||||
await hostPolicyResponseHandler(
|
||||
|
|
|
@ -8,16 +8,16 @@ import { TypeOf } from '@kbn/config-schema';
|
|||
import { policyIndexPattern } from '../../../../common/endpoint/constants';
|
||||
import { GetPolicyResponseSchema } from '../../../../common/endpoint/schema/policy';
|
||||
import { EndpointAppContext } from '../../types';
|
||||
import { getPolicyResponseByHostId } from './service';
|
||||
import { getPolicyResponseByAgentId } from './service';
|
||||
|
||||
export const getHostPolicyResponseHandler = function (
|
||||
endpointAppContext: EndpointAppContext
|
||||
): RequestHandler<undefined, TypeOf<typeof GetPolicyResponseSchema.query>, undefined> {
|
||||
return async (context, request, response) => {
|
||||
try {
|
||||
const doc = await getPolicyResponseByHostId(
|
||||
const doc = await getPolicyResponseByAgentId(
|
||||
policyIndexPattern,
|
||||
request.query.hostId,
|
||||
request.query.agentId,
|
||||
context.core.elasticsearch.legacy.client
|
||||
);
|
||||
|
||||
|
|
|
@ -5,13 +5,13 @@
|
|||
*/
|
||||
|
||||
import { GetPolicyResponseSchema } from '../../../../common/endpoint/schema/policy';
|
||||
import { getESQueryPolicyResponseByHostID } from './service';
|
||||
import { getESQueryPolicyResponseByAgentID } from './service';
|
||||
|
||||
describe('test policy handlers schema', () => {
|
||||
it('validate that get policy response query schema', async () => {
|
||||
expect(
|
||||
GetPolicyResponseSchema.query.validate({
|
||||
hostId: 'id',
|
||||
agentId: 'id',
|
||||
})
|
||||
).toBeTruthy();
|
||||
|
||||
|
@ -21,13 +21,13 @@ describe('test policy handlers schema', () => {
|
|||
|
||||
describe('test policy query', () => {
|
||||
it('queries for the correct host', async () => {
|
||||
const hostID = 'f757d3c0-e874-11ea-9ad9-015510b487f4';
|
||||
const query = getESQueryPolicyResponseByHostID(hostID, 'anyindex');
|
||||
expect(query.body.query.bool.filter.term).toEqual({ 'host.id': hostID });
|
||||
const agentId = 'f757d3c0-e874-11ea-9ad9-015510b487f4';
|
||||
const query = getESQueryPolicyResponseByAgentID(agentId, 'anyindex');
|
||||
expect(query.body.query.bool.filter.term).toEqual({ 'agent.id': agentId });
|
||||
});
|
||||
|
||||
it('filters out initial policy by ID', async () => {
|
||||
const query = getESQueryPolicyResponseByHostID(
|
||||
const query = getESQueryPolicyResponseByAgentID(
|
||||
'f757d3c0-e874-11ea-9ad9-015510b487f4',
|
||||
'anyindex'
|
||||
);
|
||||
|
|
|
@ -9,14 +9,14 @@ import { ILegacyScopedClusterClient } from 'kibana/server';
|
|||
import { GetHostPolicyResponse, HostPolicyResponse } from '../../../../common/endpoint/types';
|
||||
import { INITIAL_POLICY_ID } from './index';
|
||||
|
||||
export function getESQueryPolicyResponseByHostID(hostID: string, index: string) {
|
||||
export function getESQueryPolicyResponseByAgentID(agentID: string, index: string) {
|
||||
return {
|
||||
body: {
|
||||
query: {
|
||||
bool: {
|
||||
filter: {
|
||||
term: {
|
||||
'host.id': hostID,
|
||||
'agent.id': agentID,
|
||||
},
|
||||
},
|
||||
must_not: {
|
||||
|
@ -39,12 +39,12 @@ export function getESQueryPolicyResponseByHostID(hostID: string, index: string)
|
|||
};
|
||||
}
|
||||
|
||||
export async function getPolicyResponseByHostId(
|
||||
export async function getPolicyResponseByAgentId(
|
||||
index: string,
|
||||
hostId: string,
|
||||
agentID: string,
|
||||
dataClient: ILegacyScopedClusterClient
|
||||
): Promise<GetHostPolicyResponse | undefined> {
|
||||
const query = getESQueryPolicyResponseByHostID(hostId, index);
|
||||
const query = getESQueryPolicyResponseByAgentID(agentID, index);
|
||||
const response = (await dataClient.callAsCurrentUser('search', query)) as SearchResponse<
|
||||
HostPolicyResponse
|
||||
>;
|
||||
|
|
|
@ -26,6 +26,10 @@ export const hostsSchema = gql`
|
|||
type: String
|
||||
}
|
||||
|
||||
type AgentFields {
|
||||
id: String
|
||||
}
|
||||
|
||||
type CloudInstance {
|
||||
id: [String]
|
||||
}
|
||||
|
@ -55,6 +59,7 @@ export const hostsSchema = gql`
|
|||
|
||||
type HostItem {
|
||||
_id: String
|
||||
agent: AgentFields
|
||||
cloud: CloudFields
|
||||
endpoint: EndpointFields
|
||||
host: HostEcsFields
|
||||
|
|
|
@ -492,6 +492,8 @@ export interface HostsEdges {
|
|||
export interface HostItem {
|
||||
_id?: Maybe<string>;
|
||||
|
||||
agent?: Maybe<AgentFields>;
|
||||
|
||||
cloud?: Maybe<CloudFields>;
|
||||
|
||||
endpoint?: Maybe<EndpointFields>;
|
||||
|
@ -503,6 +505,10 @@ export interface HostItem {
|
|||
lastSeen?: Maybe<string>;
|
||||
}
|
||||
|
||||
export interface AgentFields {
|
||||
id?: Maybe<string>;
|
||||
}
|
||||
|
||||
export interface CloudFields {
|
||||
instance?: Maybe<CloudInstance>;
|
||||
|
||||
|
@ -2268,6 +2274,8 @@ export namespace HostItemResolvers {
|
|||
export interface Resolvers<TContext = SiemContext, TypeParent = HostItem> {
|
||||
_id?: _IdResolver<Maybe<string>, TypeParent, TContext>;
|
||||
|
||||
agent?: AgentResolver<Maybe<AgentFields>, TypeParent, TContext>;
|
||||
|
||||
cloud?: CloudResolver<Maybe<CloudFields>, TypeParent, TContext>;
|
||||
|
||||
endpoint?: EndpointResolver<Maybe<EndpointFields>, TypeParent, TContext>;
|
||||
|
@ -2284,6 +2292,11 @@ export namespace HostItemResolvers {
|
|||
Parent,
|
||||
TContext
|
||||
>;
|
||||
export type AgentResolver<
|
||||
R = Maybe<AgentFields>,
|
||||
Parent = HostItem,
|
||||
TContext = SiemContext
|
||||
> = Resolver<R, Parent, TContext>;
|
||||
export type CloudResolver<
|
||||
R = Maybe<CloudFields>,
|
||||
Parent = HostItem,
|
||||
|
@ -2311,6 +2324,19 @@ export namespace HostItemResolvers {
|
|||
> = Resolver<R, Parent, TContext>;
|
||||
}
|
||||
|
||||
export namespace AgentFieldsResolvers {
|
||||
export interface Resolvers<TContext = SiemContext, TypeParent = AgentFields> {
|
||||
id?: IdResolver<Maybe<string>, TypeParent, TContext>;
|
||||
}
|
||||
|
||||
export type IdResolver<
|
||||
R = Maybe<string>,
|
||||
Parent = AgentFields,
|
||||
TContext = SiemContext
|
||||
> = Resolver<R, Parent, TContext>;
|
||||
}
|
||||
|
||||
|
||||
export namespace CloudFieldsResolvers {
|
||||
export interface Resolvers<TContext = SiemContext, TypeParent = CloudFields> {
|
||||
instance?: InstanceResolver<Maybe<CloudInstance>, TypeParent, TContext>;
|
||||
|
@ -6043,6 +6069,7 @@ export type IResolvers<TContext = SiemContext> = {
|
|||
HostsData?: HostsDataResolvers.Resolvers<TContext>;
|
||||
HostsEdges?: HostsEdgesResolvers.Resolvers<TContext>;
|
||||
HostItem?: HostItemResolvers.Resolvers<TContext>;
|
||||
AgentFields?: AgentFieldsResolvers.Resolvers<TContext>;
|
||||
CloudFields?: CloudFieldsResolvers.Resolvers<TContext>;
|
||||
CloudInstance?: CloudInstanceResolvers.Resolvers<TContext>;
|
||||
CloudMachine?: CloudMachineResolvers.Resolvers<TContext>;
|
||||
|
|
|
@ -85,6 +85,7 @@ export const processFieldsMap: Readonly<Record<string, string>> = {
|
|||
|
||||
export const agentFieldsMap: Readonly<Record<string, string>> = {
|
||||
'agent.type': 'agent.type',
|
||||
'agent.id': 'agent.id',
|
||||
};
|
||||
|
||||
export const userFieldsMap: Readonly<Record<string, string>> = {
|
||||
|
|
|
@ -95,19 +95,19 @@ export class ElasticsearchHostsAdapter implements HostsAdapter {
|
|||
response: [inspectStringifyObject(response)],
|
||||
};
|
||||
const formattedHostItem = formatHostItem(options.fields, aggregations);
|
||||
const hostId =
|
||||
formattedHostItem.host && formattedHostItem.host.id
|
||||
? Array.isArray(formattedHostItem.host.id)
|
||||
? formattedHostItem.host.id[0]
|
||||
: formattedHostItem.host.id
|
||||
const ident = // endpoint-generated ID, NOT elastic-agent-id
|
||||
formattedHostItem.agent && formattedHostItem.agent.id
|
||||
? Array.isArray(formattedHostItem.agent.id)
|
||||
? formattedHostItem.agent.id[0]
|
||||
: formattedHostItem.agent.id
|
||||
: null;
|
||||
const endpoint: EndpointFields | null = await this.getHostEndpoint(request, hostId);
|
||||
const endpoint: EndpointFields | null = await this.getHostEndpoint(request, ident);
|
||||
return { inspect, _id: options.hostName, ...formattedHostItem, endpoint };
|
||||
}
|
||||
|
||||
public async getHostEndpoint(
|
||||
request: FrameworkRequest,
|
||||
hostId: string | null
|
||||
id: string | null
|
||||
): Promise<EndpointFields | null> {
|
||||
const logger = this.endpointContext.logFactory.get('metadata');
|
||||
try {
|
||||
|
@ -121,8 +121,8 @@ export class ElasticsearchHostsAdapter implements HostsAdapter {
|
|||
requestHandlerContext: request.context,
|
||||
};
|
||||
const endpointData =
|
||||
hostId != null && metadataRequestContext.endpointAppContextService.getAgentService() != null
|
||||
? await getHostData(metadataRequestContext, hostId)
|
||||
id != null && metadataRequestContext.endpointAppContextService.getAgentService() != null
|
||||
? await getHostData(metadataRequestContext, id)
|
||||
: null;
|
||||
return endpointData != null && endpointData.metadata
|
||||
? {
|
||||
|
|
|
@ -299,6 +299,7 @@ export const mockGetHostOverviewOptions: HostOverviewRequestOptions = {
|
|||
defaultIndex: DEFAULT_INDEX_PATTERN,
|
||||
fields: [
|
||||
'_id',
|
||||
'agent.id',
|
||||
'host.architecture',
|
||||
'host.id',
|
||||
'host.ip',
|
||||
|
@ -328,7 +329,7 @@ export const mockGetHostOverviewRequest = {
|
|||
operationName: 'GetHostOverviewQuery',
|
||||
variables: { sourceId: 'default', hostName: 'siem-es' },
|
||||
query:
|
||||
'query GetHostOverviewQuery($sourceId: ID!, $hostName: String!, $timerange: TimerangeInput!) {\n source(id: $sourceId) {\n id\n HostOverview(hostName: $hostName, timerange: $timerange) {\n _id\n host {\n architecture\n id\n ip\n mac\n name\n os {\n family\n name\n platform\n version\n __typename\n }\n type\n __typename\n }\n cloud {\n instance {\n id\n __typename\n }\n machine {\n type\n __typename\n }\n provider\n region\n __typename\n }\n __typename\n }\n __typename\n }\n}\n',
|
||||
'query GetHostOverviewQuery($sourceId: ID!, $hostName: String!, $timerange: TimerangeInput!) {\n source(id: $sourceId) {\n id\n HostOverview(hostName: $hostName, timerange: $timerange) {\n _id\n agent {\n id\n }\n host {\n architecture\n id\n ip\n mac\n name\n os {\n family\n name\n platform\n version\n __typename\n }\n type\n __typename\n }\n cloud {\n instance {\n id\n __typename\n }\n machine {\n type\n __typename\n }\n provider\n region\n __typename\n }\n __typename\n }\n __typename\n }\n}\n',
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -461,6 +462,17 @@ export const mockGetHostOverviewResponse = {
|
|||
},
|
||||
],
|
||||
},
|
||||
agent_id: {
|
||||
doc_count_error_upper_bound: 0,
|
||||
sum_other_doc_count: 0,
|
||||
buckets: [
|
||||
{
|
||||
key: '9f48a9ab-749a-4ff0-b4e2-7e53910a985',
|
||||
doc_count: 611894,
|
||||
timestamp: { value: 1554826117972, value_as_string: '2019-04-09T16:08:37.972Z' },
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -474,6 +486,9 @@ export const mockGetHostOverviewResult = {
|
|||
response: [JSON.stringify(mockGetHostOverviewResponse, null, 2)],
|
||||
},
|
||||
_id: 'siem-es',
|
||||
agent: {
|
||||
id: '9f48a9ab-749a-4ff0-b4e2-7e53910a985',
|
||||
},
|
||||
host: {
|
||||
architecture: 'x86_64',
|
||||
id: 'b6d5264e4b9c8880ad1053841067a4a6',
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
*/
|
||||
|
||||
import { reduceFields } from '../../utils/build_query/reduce_fields';
|
||||
import { cloudFieldsMap, hostFieldsMap } from '../ecs_fields';
|
||||
import { cloudFieldsMap, hostFieldsMap, agentFieldsMap } from '../ecs_fields';
|
||||
|
||||
import { buildFieldsTermAggregation } from './helpers';
|
||||
import { HostOverviewRequestOptions } from './types';
|
||||
|
@ -19,7 +19,7 @@ export const buildHostOverviewQuery = ({
|
|||
},
|
||||
timerange: { from, to },
|
||||
}: HostOverviewRequestOptions) => {
|
||||
const esFields = reduceFields(fields, { ...hostFieldsMap, ...cloudFieldsMap });
|
||||
const esFields = reduceFields(fields, { ...hostFieldsMap, ...cloudFieldsMap, ...agentFieldsMap });
|
||||
|
||||
const filter = [
|
||||
{ term: { 'host.name': hostName } },
|
||||
|
|
|
@ -162,7 +162,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
|
|||
describe.skip("has a url with an endpoint host's id", () => {
|
||||
before(async () => {
|
||||
await pageObjects.endpoint.navigateToEndpointList(
|
||||
'selected_host=fc0ff548-feba-41b6-8367-65e8790d0eaf'
|
||||
'selected_endpoint=3838df35-a095-4af4-8fce-0b6d78793f2e'
|
||||
);
|
||||
});
|
||||
|
||||
|
|
|
@ -19,20 +19,20 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
// to do it manually
|
||||
after(async () => await deletePolicyStream(getService));
|
||||
|
||||
it('should return one policy response for host', async () => {
|
||||
const expectedHostId = '4f3b9858-a96d-49d8-a326-230d7763d767';
|
||||
it('should return one policy response for an id', async () => {
|
||||
const expectedAgentId = 'a10ac658-a3bc-4ac6-944a-68d9bd1c5a5e';
|
||||
const { body } = await supertest
|
||||
.get(`/api/endpoint/policy_response?hostId=${expectedHostId}`)
|
||||
.get(`/api/endpoint/policy_response?agentId=${expectedAgentId}`)
|
||||
.send()
|
||||
.expect(200);
|
||||
|
||||
expect(body.policy_response.host.id).to.eql(expectedHostId);
|
||||
expect(body.policy_response.agent.id).to.eql(expectedAgentId);
|
||||
expect(body.policy_response.Endpoint.policy).to.not.be(undefined);
|
||||
});
|
||||
|
||||
it('should return not found if host has no policy response', async () => {
|
||||
const { body } = await supertest
|
||||
.get(`/api/endpoint/policy_response?hostId=bad_host_id`)
|
||||
.get(`/api/endpoint/policy_response?agentId=bad_id`)
|
||||
.send()
|
||||
.expect(404);
|
||||
|
||||
|
|
Loading…
Reference in a new issue