[EDR Workflows][Osquery] Adapt to policy_ids array instead of policy_id (#193150)

This commit is contained in:
Tomasz Ciecierski 2024-09-18 15:39:52 +02:00 committed by GitHub
parent b3b776fb99
commit 299439252c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 91 additions and 49 deletions

View file

@ -19,12 +19,12 @@ export const useOsqueryPolicies = () => {
return useQuery(
['osqueryPolicies'],
() =>
http.get<{ items: Array<{ policy_id: string }> }>(
http.get<{ items: Array<{ policy_id: string; policy_ids: string[] }> }>(
'/internal/osquery/fleet_wrapper/package_policies',
{ version: API_VERSIONS.internal.v1 }
),
{
select: (response) => uniq<string>(response.items.map((p) => p.policy_id)),
select: (response) => uniq<string>(response.items.flatMap((p) => p.policy_ids)),
onSuccess: () => setErrorToast(),
onError: (error: Error) =>
setErrorToast(error, {

View file

@ -14,25 +14,29 @@ import { useKibana, isModifiedEvent, isLeftClickEvent } from '../common/lib/kiba
interface NavigationButtonsProps {
isDisabled?: boolean;
agentPolicyId?: string | null;
agentPolicyIds?: string[];
}
const NavigationButtonsComponent: React.FC<NavigationButtonsProps> = ({
isDisabled = false,
agentPolicyId,
agentPolicyIds,
}) => {
const {
application: { getUrlForApp, navigateToApp },
} = useKibana().services;
const agentPolicyIdsQueryParam = useMemo(
() => agentPolicyIds?.map((id) => `agentPolicyId=${id}`).join('&'),
[agentPolicyIds]
);
const liveQueryHref = useMemo(
() =>
getUrlForApp(PLUGIN_ID, {
path: agentPolicyId
? `/live_queries/new?agentPolicyId=${agentPolicyId}`
path: agentPolicyIds?.length
? `/live_queries/new?${agentPolicyIdsQueryParam}`
: '/live_queries/new',
}),
[agentPolicyId, getUrlForApp]
[agentPolicyIdsQueryParam, agentPolicyIds?.length, getUrlForApp]
);
const liveQueryClick = useCallback(
@ -40,13 +44,13 @@ const NavigationButtonsComponent: React.FC<NavigationButtonsProps> = ({
if (!isModifiedEvent(event) && isLeftClickEvent(event)) {
event.preventDefault();
navigateToApp(PLUGIN_ID, {
path: agentPolicyId
? `/live_queries/new?agentPolicyId=${agentPolicyId}`
path: agentPolicyIds?.length
? `/live_queries/new?${agentPolicyIdsQueryParam}`
: '/live_queries/new',
});
}
},
[agentPolicyId, navigateToApp]
[agentPolicyIdsQueryParam, agentPolicyIds?.length, navigateToApp]
);
const packsHref = getUrlForApp(PLUGIN_ID, {

View file

@ -146,14 +146,21 @@ export const OsqueryManagedPolicyCreateImportExtension = React.memo<
policy?: PackagePolicyEditExtensionComponentProps['policy'];
}
>(({ onChange, policy, newPolicy }) => {
const [policyAgentsCount, setPolicyAgentsCount] = useState<number | null>(null);
const [agentPolicy, setAgentPolicy] = useState<AgentPolicy | null>(null);
const [agentlessPolicyIds, setAgentlessPolicyIds] = useState<string[]>([]);
const [agentPolicies, setAgentPolicies] = useState<AgentPolicy[]>([]);
const [editMode] = useState(!!policy);
const {
application: { getUrlForApp },
http,
} = useKibana().services;
const policyIdsWithAgents = useMemo(
() =>
agentlessPolicyIds?.length
? policy?.policy_ids.filter((id) => !agentlessPolicyIds.includes(id))
: policy?.policy_ids,
[agentlessPolicyIds, policy?.policy_ids]
);
const { form: configForm } = useForm({
defaultValue: {
config: JSON.stringify(get(newPolicy, 'inputs[0].config.osquery.value', {}), null, 2),
@ -185,13 +192,16 @@ export const OsqueryManagedPolicyCreateImportExtension = React.memo<
const [{ config }] = useFormData({ form: configForm, watch: 'config' });
const { isValid, setFieldValue } = configForm;
const agentsLinkHref = useMemo(() => {
if (!policy?.policy_id) return '#';
const agentsLinkHref = useCallback(
(policyId) => {
if (!policy?.policy_ids?.length) return '#';
return getUrlForApp(PLUGIN_ID, {
path: pagePathGetters.policy_details({ policyId: policy?.policy_id })[1],
});
}, [getUrlForApp, policy?.policy_id]);
return getUrlForApp(PLUGIN_ID, {
path: pagePathGetters.policy_details({ policyId })[1],
});
},
[getUrlForApp, policy?.policy_ids?.length]
);
const handleConfigUpload = useCallback(
(newConfig: any) => {
@ -248,42 +258,57 @@ export const OsqueryManagedPolicyCreateImportExtension = React.memo<
);
useEffect(() => {
if (editMode && policyAgentsCount === null) {
const policyIdsWithNoAgent: string[] = [];
if (editMode && !agentlessPolicyIds?.length) {
const fetchAgentsCount = async () => {
try {
const response = await http.fetch<{ results: { total: number } }>(
agentRouteService.getStatusPath(),
{
query: {
policyId: policy?.policy_id,
},
}
);
if (response.results) {
setPolicyAgentsCount(response.results.total);
if (policy?.policy_ids?.length) {
await Promise.all(
policy.policy_ids.map(async (id: string) => {
const response = await http.fetch<{ results: { total: number } }>(
agentRouteService.getStatusPath(),
{
query: {
policyId: id,
},
}
);
if (response.results.total === 0) {
policyIdsWithNoAgent.push(id);
}
})
);
setAgentlessPolicyIds(policyIdsWithNoAgent);
}
// eslint-disable-next-line no-empty
} catch (e) {}
};
const fetchAgentPolicyDetails = async () => {
if (policy?.policy_id) {
if (policyIdsWithNoAgent?.length) {
const policiesWithoutAgent: AgentPolicy[] = [];
try {
const response = await http.fetch<{ item: AgentPolicy }>(
agentPolicyRouteService.getInfoPath(policy?.policy_id)
await Promise.all(
policyIdsWithNoAgent.map(async (id) => {
const response = await http.fetch<{ item: AgentPolicy }>(
agentPolicyRouteService.getInfoPath(id)
);
if (response.item) {
policiesWithoutAgent.push(response.item);
}
})
);
if (response.item) {
setAgentPolicy(response.item);
if (policiesWithoutAgent.length) {
setAgentPolicies(policiesWithoutAgent);
}
// eslint-disable-next-line no-empty
} catch (e) {}
}
};
fetchAgentsCount();
fetchAgentPolicyDetails();
fetchAgentsCount().then(() => fetchAgentPolicyDetails());
}
}, [editMode, http, policy?.policy_id, policyAgentsCount]);
}, [editMode, http, agentlessPolicyIds?.length, agentlessPolicyIds, policy?.policy_ids]);
useEffect(() => {
/*
@ -363,21 +388,30 @@ export const OsqueryManagedPolicyCreateImportExtension = React.memo<
return (
<>
{!editMode ? <DisabledCallout /> : null}
{policyAgentsCount === 0 ? (
{agentlessPolicyIds?.length ? (
<>
<EuiFlexGroup>
<EuiFlexItem>
<EuiCallOut title="No agents in the policy" color="warning" iconType="help">
<p>
{`Fleet has detected that you have not assigned yet any agent to the `}
{
<EuiLink href={agentsLinkHref}>
{agentPolicy?.name ?? policy?.policy_id}
</EuiLink>
}
{i18n.translate(
'xpack.osquery.fleetIntegration.osqueryConfig.noAgentsWarningMessage',
{
defaultMessage:
'Fleet has detected that you have not assigned yet any agent to the ',
}
)}
{agentPolicies?.map((agentPolicy, index) => (
<React.Fragment key={agentPolicy.id}>
<EuiLink href={agentsLinkHref(agentPolicy.id)}>
{agentPolicy.name || agentPolicy?.id}
</EuiLink>
{index < agentPolicies.length - 1 && `, `}
</React.Fragment>
))}
{`. `}
<br />
<strong>{`Only agents within the policy with active Osquery Manager integration support the functionality presented below.`}</strong>
<strong>{`Only agents within the policies with active Osquery Manager integration support the functionality presented below.`}</strong>
</p>
</EuiCallOut>
</EuiFlexItem>
@ -385,10 +419,9 @@ export const OsqueryManagedPolicyCreateImportExtension = React.memo<
<EuiSpacer />
</>
) : null}
{!permissionDenied && (
<>
<NavigationButtons isDisabled={!editMode} agentPolicyId={policy?.policy_id} />
<NavigationButtons isDisabled={!editMode} agentPolicyIds={policyIdsWithAgents} />
<EuiSpacer size="xxl" />
<EuiAccordion
css={euiAccordionCss}

View file

@ -11,6 +11,7 @@ import React, { useEffect, useMemo, useState } from 'react';
import { useHistory, useLocation } from 'react-router-dom';
import qs from 'query-string';
import { isArray } from 'lodash';
import { WithHeaderLayout } from '../../../components/layouts';
import { useRouterNavigate } from '../../../common/lib/kibana';
import { LiveQuery } from '../../../live_queries';
@ -30,7 +31,11 @@ const NewLiveQueryPageComponent = () => {
const agentPolicyIds = useMemo(() => {
const queryParams = qs.parse(location.search);
return queryParams?.agentPolicyId ? ([queryParams?.agentPolicyId] as string[]) : undefined;
return queryParams?.agentPolicyId
? isArray(queryParams?.agentPolicyId)
? queryParams?.agentPolicyId
: [queryParams?.agentPolicyId]
: undefined;
}, [location.search]);
useEffect(() => {
@ -68,7 +73,7 @@ const NewLiveQueryPageComponent = () => {
return (
<WithHeaderLayout leftColumn={LeftColumn}>
<LiveQuery agentPolicyIds={agentPolicyIds} {...initialFormData} />
<LiveQuery {...initialFormData} agentPolicyIds={agentPolicyIds} />
</WithHeaderLayout>
);
};